From e8b429b2d4b38a09848728a29e3db1344febd899 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: [PATCH] The R13B03 release. --- AUTHORS | 13 + lib/cosEvent/AUTHORS | 5 + lib/cosEvent/Makefile | 41 + lib/cosEvent/doc/html/.gitignore | 0 lib/cosEvent/doc/man3/.gitignore | 0 lib/cosEvent/doc/man6/.gitignore | 0 lib/cosEvent/doc/pdf/.gitignore | 0 lib/cosEvent/doc/src/CosEventChannelAdmin.xml | 81 + .../CosEventChannelAdmin_ConsumerAdmin.xml | 73 + .../src/CosEventChannelAdmin_EventChannel.xml | 95 + ...CosEventChannelAdmin_ProxyPullConsumer.xml | 85 + ...CosEventChannelAdmin_ProxyPullSupplier.xml | 112 + ...CosEventChannelAdmin_ProxyPushConsumer.xml | 99 + ...CosEventChannelAdmin_ProxyPushSupplier.xml | 85 + .../CosEventChannelAdmin_SupplierAdmin.xml | 73 + lib/cosEvent/doc/src/Makefile | 230 ++ lib/cosEvent/doc/src/book.gif | Bin 0 -> 1081 bytes lib/cosEvent/doc/src/book.xml | 49 + lib/cosEvent/doc/src/ch_contents.xml | 70 + lib/cosEvent/doc/src/ch_event_service.xml | 221 ++ lib/cosEvent/doc/src/ch_introduction.xml | 56 + lib/cosEvent/doc/src/cosEventApp.xml | 168 ++ lib/cosEvent/doc/src/e_s_components.gif | Bin 0 -> 4458 bytes lib/cosEvent/doc/src/e_s_components.ps | Bin 0 -> 247544 bytes lib/cosEvent/doc/src/e_s_models.gif | Bin 0 -> 10354 bytes lib/cosEvent/doc/src/e_s_models.ps | Bin 0 -> 49664 bytes lib/cosEvent/doc/src/fascicules.xml | 18 + lib/cosEvent/doc/src/make.dep | 34 + lib/cosEvent/doc/src/notes.gif | Bin 0 -> 2005 bytes lib/cosEvent/doc/src/notes.xml | 172 ++ lib/cosEvent/doc/src/part.xml | 39 + lib/cosEvent/doc/src/part_notes.xml | 37 + lib/cosEvent/doc/src/ref_man.gif | Bin 0 -> 1530 bytes lib/cosEvent/doc/src/ref_man.xml | 45 + lib/cosEvent/doc/src/summary.html.src | 1 + lib/cosEvent/doc/src/user_guide.gif | Bin 0 -> 1581 bytes lib/cosEvent/ebin/.gitignore | 0 lib/cosEvent/example/.gitignore | 0 lib/cosEvent/include/.gitignore | 0 lib/cosEvent/info | 2 + lib/cosEvent/src/CosEventChannelAdmin.cfg | 6 + lib/cosEvent/src/CosEventChannelAdmin.idl | 66 + ...entChannelAdmin_ProxyPullConsumer_impl.erl | 205 ++ ...entChannelAdmin_ProxyPushConsumer_impl.erl | 169 ++ ...osEventChannelAdmin_SupplierAdmin_impl.erl | 159 ++ lib/cosEvent/src/CosEventComm.idl | 37 + lib/cosEvent/src/Makefile | 214 ++ lib/cosEvent/src/cosEvent.app.src | 45 + lib/cosEvent/src/cosEvent.appup.src | 6 + lib/cosEvent/src/cosEventApp.cfg | 15 + lib/cosEvent/src/cosEventApp.erl | 290 ++ lib/cosEvent/src/cosEventApp.hrl | 62 + lib/cosEvent/src/cosEventApp.idl | 26 + .../src/oe_CosEventComm_CAdmin_impl.erl | 233 ++ .../src/oe_CosEventComm_Channel_impl.erl | 246 ++ .../src/oe_CosEventComm_PullerS_impl.erl | 280 ++ .../src/oe_CosEventComm_PusherS_impl.erl | 217 ++ lib/cosEvent/vsn.mk | 10 + lib/cosEventDomain/AUTHORS | 4 + lib/cosEventDomain/Makefile | 41 + lib/cosEventDomain/doc/html/.gitignore | 0 lib/cosEventDomain/doc/man3/.gitignore | 0 lib/cosEventDomain/doc/man6/.gitignore | 0 lib/cosEventDomain/doc/pdf/.gitignore | 0 .../doc/src/CosEventDomainAdmin.xml | 92 + .../src/CosEventDomainAdmin_EventDomain.xml | 627 +++++ ...CosEventDomainAdmin_EventDomainFactory.xml | 88 + lib/cosEventDomain/doc/src/Makefile | 227 ++ lib/cosEventDomain/doc/src/book.gif | Bin 0 -> 1081 bytes lib/cosEventDomain/doc/src/book.xml | 48 + lib/cosEventDomain/doc/src/ch_QoS.xml | 117 + lib/cosEventDomain/doc/src/ch_contents.xml | 68 + .../doc/src/ch_event_domain_service.xml | 110 + .../doc/src/ch_introduction.xml | 52 + .../doc/src/cosEventDomainApp.xml | 149 + lib/cosEventDomain/doc/src/fascicules.xml | 18 + lib/cosEventDomain/doc/src/make.dep | 23 + lib/cosEventDomain/doc/src/notes.gif | Bin 0 -> 2005 bytes lib/cosEventDomain/doc/src/notes.xml | 168 ++ lib/cosEventDomain/doc/src/part.xml | 39 + lib/cosEventDomain/doc/src/part_notes.xml | 36 + lib/cosEventDomain/doc/src/ref_man.gif | Bin 0 -> 1530 bytes lib/cosEventDomain/doc/src/ref_man.xml | 39 + lib/cosEventDomain/doc/src/summary.html.src | 1 + lib/cosEventDomain/doc/src/user_guide.gif | Bin 0 -> 1581 bytes lib/cosEventDomain/ebin/.gitignore | 0 lib/cosEventDomain/example/.gitignore | 0 lib/cosEventDomain/include/.gitignore | 0 lib/cosEventDomain/info | 2 + .../src/CosEventDomainAdmin.cfg | 4 + .../src/CosEventDomainAdmin.idl | 280 ++ ...entDomainAdmin_EventDomainFactory_impl.erl | 182 ++ .../CosEventDomainAdmin_EventDomain_impl.erl | 1415 ++++++++++ lib/cosEventDomain/src/Makefile | 179 ++ lib/cosEventDomain/src/cosEventDomain.app.src | 31 + .../src/cosEventDomain.appup.src | 6 + lib/cosEventDomain/src/cosEventDomainApp.erl | 363 +++ lib/cosEventDomain/src/cosEventDomainApp.hrl | 69 + lib/cosEventDomain/vsn.mk | 10 + lib/cosFileTransfer/AUTHORS | 4 + lib/cosFileTransfer/Makefile | 41 + lib/cosFileTransfer/doc/html/.gitignore | 0 lib/cosFileTransfer/doc/man3/.gitignore | 0 lib/cosFileTransfer/doc/man6/.gitignore | 0 lib/cosFileTransfer/doc/pdf/.gitignore | 0 .../doc/src/CosFileTransfer.gif | Bin 0 -> 10889 bytes .../doc/src/CosFileTransfer.ps | Bin 0 -> 1281353 bytes .../doc/src/CosFileTransfer_Directory.xml | 69 + .../doc/src/CosFileTransfer_File.xml | 94 + .../doc/src/CosFileTransfer_FileIterator.xml | 86 + .../CosFileTransfer_FileTransferSession.xml | 191 ++ .../src/CosFileTransfer_VirtualFileSystem.xml | 83 + lib/cosFileTransfer/doc/src/Makefile | 230 ++ lib/cosFileTransfer/doc/src/book.gif | Bin 0 -> 1081 bytes lib/cosFileTransfer/doc/src/book.xml | 48 + lib/cosFileTransfer/doc/src/ch_contents.xml | 74 + lib/cosFileTransfer/doc/src/ch_example.xml | 95 + lib/cosFileTransfer/doc/src/ch_install.xml | 57 + .../doc/src/ch_introduction.xml | 56 + lib/cosFileTransfer/doc/src/ch_system.xml | 137 + .../doc/src/cosFileTransferApp.xml | 172 ++ lib/cosFileTransfer/doc/src/fascicules.xml | 18 + lib/cosFileTransfer/doc/src/make.dep | 30 + lib/cosFileTransfer/doc/src/notes.gif | Bin 0 -> 2005 bytes lib/cosFileTransfer/doc/src/notes.xml | 211 ++ lib/cosFileTransfer/doc/src/part.xml | 40 + lib/cosFileTransfer/doc/src/part_notes.xml | 36 + lib/cosFileTransfer/doc/src/ref_man.gif | Bin 0 -> 1530 bytes lib/cosFileTransfer/doc/src/ref_man.xml | 41 + lib/cosFileTransfer/doc/src/summary.html.src | 1 + lib/cosFileTransfer/doc/src/user_guide.gif | Bin 0 -> 1581 bytes lib/cosFileTransfer/ebin/.gitignore | 0 lib/cosFileTransfer/examples/.gitignore | 0 lib/cosFileTransfer/include/.gitignore | 0 lib/cosFileTransfer/info | 3 + lib/cosFileTransfer/priv/.gitignore | 0 lib/cosFileTransfer/src/CosFileTransfer.cfg | 10 + lib/cosFileTransfer/src/CosFileTransfer.idl | 157 ++ .../src/CosFileTransfer_Directory_impl.erl | 452 +++ .../src/CosFileTransfer_FileIterator_impl.erl | 157 ++ ...sFileTransfer_FileTransferSession_impl.erl | 1060 ++++++++ .../src/CosFileTransfer_File_impl.erl | 384 +++ ...CosFileTransfer_VirtualFileSystem_impl.erl | 216 ++ lib/cosFileTransfer/src/Makefile | 182 ++ .../src/cosFileTransfer.app.src | 41 + .../src/cosFileTransfer.appup.src | 7 + .../src/cosFileTransferApp.erl | 469 ++++ .../src/cosFileTransferApp.hrl | 68 + .../src/cosFileTransferNATIVE_file.erl | 358 +++ lib/cosFileTransfer/vsn.mk | 13 + lib/cosNotification/AUTHORS | 4 + lib/cosNotification/Makefile | 41 + lib/cosNotification/doc/html/.gitignore | 0 lib/cosNotification/doc/man3/.gitignore | 0 lib/cosNotification/doc/man6/.gitignore | 0 lib/cosNotification/doc/pdf/.gitignore | 0 .../doc/src/CosNotification.xml | 234 ++ .../CosNotification_AdminPropertiesAdmin.xml | 79 + .../doc/src/CosNotification_QoSAdmin.xml | 106 + .../CosNotifyChannelAdmin_ConsumerAdmin.xml | 242 ++ .../CosNotifyChannelAdmin_EventChannel.xml | 226 ++ ...NotifyChannelAdmin_EventChannelFactory.xml | 89 + .../CosNotifyChannelAdmin_ProxyConsumer.xml | 128 + ...osNotifyChannelAdmin_ProxyPullConsumer.xml | 113 + ...osNotifyChannelAdmin_ProxyPullSupplier.xml | 112 + ...osNotifyChannelAdmin_ProxyPushConsumer.xml | 98 + ...osNotifyChannelAdmin_ProxyPushSupplier.xml | 110 + .../CosNotifyChannelAdmin_ProxySupplier.xml | 175 ++ ...ChannelAdmin_SequenceProxyPullConsumer.xml | 112 + ...ChannelAdmin_SequenceProxyPullSupplier.xml | 146 + ...ChannelAdmin_SequenceProxyPushConsumer.xml | 109 + ...ChannelAdmin_SequenceProxyPushSupplier.xml | 111 + ...annelAdmin_StructuredProxyPullConsumer.xml | 110 + ...annelAdmin_StructuredProxyPullSupplier.xml | 140 + ...annelAdmin_StructuredProxyPushConsumer.xml | 110 + ...annelAdmin_StructuredProxyPushSupplier.xml | 110 + .../CosNotifyChannelAdmin_SupplierAdmin.xml | 195 ++ .../doc/src/CosNotifyComm_NotifyPublish.xml | 65 + .../doc/src/CosNotifyComm_NotifySubscribe.xml | 64 + .../doc/src/CosNotifyFilter_Filter.xml | 222 ++ .../doc/src/CosNotifyFilter_FilterAdmin.xml | 111 + .../doc/src/CosNotifyFilter_FilterFactory.xml | 73 + .../doc/src/CosNotifyFilter_MappingFilter.xml | 227 ++ lib/cosNotification/doc/src/Makefile | 254 ++ lib/cosNotification/doc/src/book.gif | Bin 0 -> 1081 bytes lib/cosNotification/doc/src/book.xml | 48 + lib/cosNotification/doc/src/ch_BNF.xml | 456 ++++ lib/cosNotification/doc/src/ch_QoS.xml | 251 ++ lib/cosNotification/doc/src/ch_contents.xml | 74 + lib/cosNotification/doc/src/ch_example.xml | 169 ++ lib/cosNotification/doc/src/ch_install.xml | 146 + .../doc/src/ch_introduction.xml | 57 + lib/cosNotification/doc/src/ch_system.xml | 83 + .../doc/src/cosNotificationApp.xml | 308 +++ .../doc/src/eventstructure.gif | Bin 0 -> 89760 bytes lib/cosNotification/doc/src/eventstructure.ps | Bin 0 -> 164840 bytes lib/cosNotification/doc/src/fascicules.xml | 18 + lib/cosNotification/doc/src/make.dep | 48 + lib/cosNotification/doc/src/notes.gif | Bin 0 -> 2005 bytes lib/cosNotification/doc/src/notes.xml | 391 +++ .../doc/src/notificationFlow.gif | Bin 0 -> 167734 bytes .../doc/src/notificationFlow.ps | Bin 0 -> 304286 bytes lib/cosNotification/doc/src/part.xml | 42 + lib/cosNotification/doc/src/part_notes.xml | 36 + lib/cosNotification/doc/src/ref_man.gif | Bin 0 -> 1530 bytes lib/cosNotification/doc/src/ref_man.xml | 63 + lib/cosNotification/doc/src/summary.html.src | 1 + lib/cosNotification/doc/src/user_guide.gif | Bin 0 -> 1581 bytes lib/cosNotification/ebin/.gitignore | 0 lib/cosNotification/examples/.gitignore | 0 lib/cosNotification/include/.gitignore | 0 lib/cosNotification/info | 3 + lib/cosNotification/priv/.gitignore | 0 lib/cosNotification/src/CosEvent.cfg | 20 + lib/cosNotification/src/CosNotification.cfg | 0 lib/cosNotification/src/CosNotification.idl | 146 + .../src/CosNotification_Common.erl | 1210 +++++++++ .../src/CosNotification_Definitions.hrl | 340 +++ .../src/CosNotifyChannelAdmin.cfg | 60 + .../src/CosNotifyChannelAdmin.idl | 275 ++ ...sNotifyChannelAdmin_ConsumerAdmin_impl.erl | 670 +++++ ...yChannelAdmin_EventChannelFactory_impl.erl | 142 + ...osNotifyChannelAdmin_EventChannel_impl.erl | 721 +++++ ...sNotifyChannelAdmin_SupplierAdmin_impl.erl | 579 ++++ lib/cosNotification/src/CosNotifyComm.cfg | 0 lib/cosNotification/src/CosNotifyComm.idl | 83 + lib/cosNotification/src/CosNotifyFilter.cfg | 6 + lib/cosNotification/src/CosNotifyFilter.idl | 140 + .../CosNotifyFilter_FilterFactory_impl.erl | 125 + .../src/CosNotifyFilter_Filter_impl.erl | 670 +++++ .../CosNotifyFilter_MappingFilter_impl.erl | 578 ++++ lib/cosNotification/src/CosTypedEvent.idl | 57 + .../src/CosTypedNotification.idl | 109 + lib/cosNotification/src/Makefile | 369 +++ .../src/PullerConsumer_impl.erl | 773 ++++++ .../src/PullerSupplier_impl.erl | 914 +++++++ .../src/PusherConsumer_impl.erl | 729 +++++ .../src/PusherSupplier_impl.erl | 1052 +++++++ .../src/cosNotification.app.src | 120 + .../src/cosNotification.appup.src | 7 + .../src/cosNotificationApp.erl | 447 +++ .../src/cosNotificationAppComm.idl | 17 + .../src/cosNotificationComm.cfg | 3 + .../src/cosNotification_Filter.erl | 964 +++++++ .../src/cosNotification_Grammar.yrl | 166 ++ .../src/cosNotification_Scanner.erl | 268 ++ .../src/cosNotification_eventDB.erl | 1350 +++++++++ lib/cosNotification/vsn.mk | 11 + lib/cosProperty/AUTHORS | 4 + lib/cosProperty/Makefile | 41 + lib/cosProperty/doc/html/.gitignore | 0 lib/cosProperty/doc/man3/.gitignore | 0 lib/cosProperty/doc/man6/.gitignore | 0 lib/cosProperty/doc/pdf/.gitignore | 0 .../CosPropertyService_PropertiesIterator.xml | 95 + ...sPropertyService_PropertyNamesIterator.xml | 97 + .../src/CosPropertyService_PropertySet.xml | 201 ++ .../src/CosPropertyService_PropertySetDef.xml | 168 ++ ...sPropertyService_PropertySetDefFactory.xml | 95 + .../CosPropertyService_PropertySetFactory.xml | 93 + lib/cosProperty/doc/src/Makefile | 243 ++ lib/cosProperty/doc/src/book.gif | Bin 0 -> 1081 bytes lib/cosProperty/doc/src/book.xml | 48 + lib/cosProperty/doc/src/ch_contents.xml | 74 + lib/cosProperty/doc/src/ch_example.xml | 75 + lib/cosProperty/doc/src/ch_install.xml | 55 + lib/cosProperty/doc/src/ch_introduction.xml | 53 + lib/cosProperty/doc/src/cosProperty.xml | 149 + lib/cosProperty/doc/src/fascicules.xml | 18 + lib/cosProperty/doc/src/make.dep | 26 + lib/cosProperty/doc/src/notes.gif | Bin 0 -> 2005 bytes lib/cosProperty/doc/src/notes.xml | 206 ++ lib/cosProperty/doc/src/part.xml | 39 + lib/cosProperty/doc/src/part_notes.xml | 36 + lib/cosProperty/doc/src/ref_man.gif | Bin 0 -> 1530 bytes lib/cosProperty/doc/src/ref_man.xml | 42 + lib/cosProperty/doc/src/summary.html.src | 1 + lib/cosProperty/doc/src/user_guide.gif | Bin 0 -> 1581 bytes lib/cosProperty/ebin/.gitignore | 0 lib/cosProperty/examples/.gitignore | 0 lib/cosProperty/include/.gitignore | 0 lib/cosProperty/info | 2 + lib/cosProperty/priv/.gitignore | 0 lib/cosProperty/src/CosProperty.cfg | 5 + lib/cosProperty/src/CosProperty.idl | 192 ++ ...ropertyService_PropertiesIterator_impl.erl | 166 ++ ...ertyService_PropertyNamesIterator_impl.erl | 158 ++ ...ertyService_PropertySetDefFactory_impl.erl | 179 ++ ...CosPropertyService_PropertySetDef_impl.erl | 1041 +++++++ ...ropertyService_PropertySetFactory_impl.erl | 176 ++ lib/cosProperty/src/Makefile | 183 ++ lib/cosProperty/src/cosProperty.app.src | 45 + lib/cosProperty/src/cosProperty.appup.src | 6 + lib/cosProperty/src/cosProperty.erl | 414 +++ lib/cosProperty/src/cosProperty.hrl | 81 + lib/cosProperty/vsn.mk | 9 + lib/cosTime/AUTHORS | 4 + lib/cosTime/Makefile | 41 + lib/cosTime/doc/html/.gitignore | 0 lib/cosTime/doc/man3/.gitignore | 0 lib/cosTime/doc/man6/.gitignore | 0 lib/cosTime/doc/pdf/.gitignore | 0 lib/cosTime/doc/src/CosTime_TIO.xml | 108 + lib/cosTime/doc/src/CosTime_TimeService.xml | 103 + lib/cosTime/doc/src/CosTime_UTO.xml | 155 ++ .../src/CosTimerEvent_TimerEventHandler.xml | 125 + .../src/CosTimerEvent_TimerEventService.xml | 84 + lib/cosTime/doc/src/Makefile | 225 ++ lib/cosTime/doc/src/book.gif | Bin 0 -> 1081 bytes lib/cosTime/doc/src/book.xml | 48 + lib/cosTime/doc/src/ch_contents.xml | 74 + lib/cosTime/doc/src/ch_example.xml | 112 + lib/cosTime/doc/src/ch_install.xml | 55 + lib/cosTime/doc/src/ch_introduction.xml | 58 + lib/cosTime/doc/src/cosTime.xml | 174 ++ lib/cosTime/doc/src/fascicules.xml | 18 + lib/cosTime/doc/src/make.dep | 22 + lib/cosTime/doc/src/notes.gif | Bin 0 -> 2005 bytes lib/cosTime/doc/src/notes.xml | 187 ++ lib/cosTime/doc/src/part.xml | 39 + lib/cosTime/doc/src/part_notes.xml | 36 + lib/cosTime/doc/src/ref_man.gif | Bin 0 -> 1530 bytes lib/cosTime/doc/src/ref_man.xml | 41 + lib/cosTime/doc/src/summary.html.src | 1 + lib/cosTime/doc/src/user_guide.gif | Bin 0 -> 1581 bytes lib/cosTime/ebin/.gitignore | 0 lib/cosTime/examples/.gitignore | 0 lib/cosTime/include/.gitignore | 0 lib/cosTime/info | 12 + lib/cosTime/priv/.gitignore | 0 lib/cosTime/src/CosTime.cfg | 6 + lib/cosTime/src/CosTime.idl | 59 + lib/cosTime/src/CosTime_TIO_impl.erl | 200 ++ lib/cosTime/src/CosTime_TimeService_impl.erl | 180 ++ lib/cosTime/src/CosTime_UTO_impl.erl | 241 ++ lib/cosTime/src/CosTimerEvent.cfg | 4 + lib/cosTime/src/CosTimerEvent.idl | 45 + .../CosTimerEvent_TimerEventHandler_impl.erl | 304 +++ .../CosTimerEvent_TimerEventService_impl.erl | 118 + lib/cosTime/src/Makefile | 205 ++ lib/cosTime/src/TimeBase.idl | 22 + lib/cosTime/src/cosTime.app.src | 30 + lib/cosTime/src/cosTime.appup.src | 6 + lib/cosTime/src/cosTime.erl | 321 +++ lib/cosTime/src/cosTimeApp.hrl | 76 + lib/cosTime/vsn.mk | 9 + lib/cosTransactions/AUTHORS | 4 + lib/cosTransactions/Makefile | 41 + lib/cosTransactions/doc/html/.gitignore | 0 lib/cosTransactions/doc/man3/.gitignore | 0 lib/cosTransactions/doc/man6/.gitignore | 0 lib/cosTransactions/doc/pdf/.gitignore | 0 .../doc/src/CosTransactions_Control.xml | 73 + .../doc/src/CosTransactions_Coordinator.xml | 229 ++ .../CosTransactions_RecoveryCoordinator.xml | 82 + .../doc/src/CosTransactions_Resource.xml | 128 + ...ansactions_SubtransactionAwareResource.xml | 75 + .../src/CosTransactions_Synchronization.xml | 69 + .../doc/src/CosTransactions_Terminator.xml | 72 + .../CosTransactions_TransactionFactory.xml | 64 + .../CosTransactions_TransactionalObject.xml | 42 + lib/cosTransactions/doc/src/Makefile | 229 ++ lib/cosTransactions/doc/src/book.gif | Bin 0 -> 1081 bytes lib/cosTransactions/doc/src/book.xml | 48 + lib/cosTransactions/doc/src/ch_contents.xml | 74 + lib/cosTransactions/doc/src/ch_example.xml | 280 ++ lib/cosTransactions/doc/src/ch_install.xml | 103 + .../doc/src/ch_introduction.xml | 64 + lib/cosTransactions/doc/src/ch_skeletons.xml | 213 ++ .../doc/src/cosTransactions.xml | 141 + lib/cosTransactions/doc/src/fascicules.xml | 18 + lib/cosTransactions/doc/src/make.dep | 27 + lib/cosTransactions/doc/src/notes.gif | Bin 0 -> 2005 bytes lib/cosTransactions/doc/src/notes.xml | 243 ++ lib/cosTransactions/doc/src/part.xml | 40 + lib/cosTransactions/doc/src/part_notes.xml | 36 + lib/cosTransactions/doc/src/ref_man.gif | Bin 0 -> 1530 bytes lib/cosTransactions/doc/src/ref_man.xml | 43 + lib/cosTransactions/doc/src/summary.html.src | 1 + lib/cosTransactions/doc/src/user_guide.gif | Bin 0 -> 1581 bytes lib/cosTransactions/ebin/.gitignore | 0 lib/cosTransactions/examples/Makefile | 157 ++ lib/cosTransactions/include/.gitignore | 0 lib/cosTransactions/info | 2 + lib/cosTransactions/priv/.gitignore | 0 lib/cosTransactions/src/CosTransactions.cfg | 15 + lib/cosTransactions/src/CosTransactions.idl | 193 ++ .../src/CosTransactions_Terminator_impl.erl | 362 +++ ...osTransactions_TransactionFactory_impl.erl | 178 ++ lib/cosTransactions/src/ETraP_Common.erl | 185 ++ lib/cosTransactions/src/ETraP_Common.hrl | 340 +++ lib/cosTransactions/src/ETraP_Server_impl.erl | 1739 ++++++++++++ lib/cosTransactions/src/Makefile | 175 ++ .../src/cosTransactions.app.src | 43 + .../src/cosTransactions.appup.src | 6 + lib/cosTransactions/src/cosTransactions.erl | 115 + lib/cosTransactions/src/etrap_logmgr.erl | 200 ++ lib/cosTransactions/vsn.mk | 9 + lib/ic/AUTHORS | 8 + lib/ic/Makefile | 41 + lib/ic/c_src/Makefile | 24 + lib/ic/c_src/Makefile.in | 160 ++ lib/ic/c_src/Makefile.win32 | 108 + lib/ic/c_src/ic.c | 612 +++++ lib/ic/c_src/ic_tmo.c | 135 + lib/ic/c_src/oe_ei_code_erlang_binary.c | 105 + lib/ic/c_src/oe_ei_decode_longlong.c | 25 + lib/ic/c_src/oe_ei_decode_ulonglong.c | 25 + lib/ic/c_src/oe_ei_decode_wchar.c | 25 + lib/ic/c_src/oe_ei_decode_wstring.c | 107 + lib/ic/c_src/oe_ei_encode_atom.c | 46 + lib/ic/c_src/oe_ei_encode_char.c | 44 + lib/ic/c_src/oe_ei_encode_double.c | 43 + lib/ic/c_src/oe_ei_encode_list_header.c | 41 + lib/ic/c_src/oe_ei_encode_long.c | 44 + lib/ic/c_src/oe_ei_encode_longlong.c | 44 + lib/ic/c_src/oe_ei_encode_pid.c | 45 + lib/ic/c_src/oe_ei_encode_port.c | 46 + lib/ic/c_src/oe_ei_encode_ref.c | 46 + lib/ic/c_src/oe_ei_encode_string.c | 47 + lib/ic/c_src/oe_ei_encode_term.c | 48 + lib/ic/c_src/oe_ei_encode_tuple_header.c | 44 + lib/ic/c_src/oe_ei_encode_ulong.c | 43 + lib/ic/c_src/oe_ei_encode_ulonglong.c | 44 + lib/ic/c_src/oe_ei_encode_version.c | 42 + lib/ic/c_src/oe_ei_encode_wchar.c | 27 + lib/ic/c_src/oe_ei_encode_wstring.c | 62 + lib/ic/doc/html/.gitignore | 0 lib/ic/doc/man1/.gitignore | 0 lib/ic/doc/man3/.gitignore | 0 lib/ic/doc/pdf/.gitignore | 0 lib/ic/doc/src/CORBA_Environment_alloc.xml | 142 + lib/ic/doc/src/Makefile | 320 +++ lib/ic/doc/src/book.gif | Bin 0 -> 1081 bytes lib/ic/doc/src/book.xml | 49 + lib/ic/doc/src/c-part.xml | 40 + lib/ic/doc/src/ch_basic_idl.xml | 163 ++ lib/ic/doc/src/ch_c_client.xml | 149 + lib/ic/doc/src/ch_c_corba_env.xml | 385 +++ lib/ic/doc/src/ch_c_mapping.xml | 892 ++++++ lib/ic/doc/src/ch_c_server.xml | 148 + lib/ic/doc/src/ch_erl_genserv.xml | 205 ++ lib/ic/doc/src/ch_erl_plain.xml | 175 ++ lib/ic/doc/src/ch_ic_protocol.xml | 233 ++ lib/ic/doc/src/ch_introduction.xml | 148 + lib/ic/doc/src/ch_java.xml | 737 +++++ lib/ic/doc/src/erl-part.xml | 38 + lib/ic/doc/src/fascicules.xml | 18 + lib/ic/doc/src/ic.gif | Bin 0 -> 17015 bytes lib/ic/doc/src/ic.xml | 469 ++++ lib/ic/doc/src/ic_c_protocol.xml | 158 ++ lib/ic/doc/src/ic_clib.xml | 246 ++ lib/ic/doc/src/java-part.xml | 37 + lib/ic/doc/src/make.dep | 24 + lib/ic/doc/src/notes.gif | Bin 0 -> 2005 bytes lib/ic/doc/src/notes.xml | 444 +++ lib/ic/doc/src/old_notes.xml | 1565 +++++++++++ lib/ic/doc/src/part.xml | 45 + lib/ic/doc/src/part_notes.xml | 37 + lib/ic/doc/src/ref_man.gif | Bin 0 -> 1530 bytes lib/ic/doc/src/ref_man.xml | 38 + lib/ic/doc/src/summary.html.src | 1 + lib/ic/doc/src/user_guide.gif | Bin 0 -> 1581 bytes lib/ic/ebin/.gitignore | 0 lib/ic/examples/all-against-all/Makefile | 117 + .../examples/all-against-all/Makefile.win32 | 138 + lib/ic/examples/all-against-all/ReadMe | 122 + lib/ic/examples/all-against-all/callbacks.c | 45 + lib/ic/examples/all-against-all/client.c | 153 ++ lib/ic/examples/all-against-all/client.erl | 53 + lib/ic/examples/all-against-all/client.java | 60 + lib/ic/examples/all-against-all/random.idl | 50 + .../all-against-all/rmod_random_impl.erl | 48 + lib/ic/examples/all-against-all/server.c | 261 ++ lib/ic/examples/all-against-all/server.erl | 40 + lib/ic/examples/all-against-all/server.java | 82 + .../examples/all-against-all/serverImpl.java | 42 + lib/ic/examples/c-client/Makefile | 86 + lib/ic/examples/c-client/ReadMe | 46 + lib/ic/examples/c-client/client.c | 130 + lib/ic/examples/c-client/random.idl | 51 + lib/ic/examples/c-client/rmod_random_impl.erl | 52 + lib/ic/examples/c-client/test.erl | 43 + lib/ic/examples/c-server/Makefile | 89 + lib/ic/examples/c-server/ReadMe | 45 + lib/ic/examples/c-server/callbacks.c | 45 + lib/ic/examples/c-server/client.c | 124 + lib/ic/examples/c-server/client.erl | 44 + lib/ic/examples/c-server/random.idl | 49 + lib/ic/examples/c-server/server.c | 245 ++ lib/ic/examples/erl-genserv/ReadMe | 30 + lib/ic/examples/erl-genserv/random.idl | 50 + .../examples/erl-genserv/rmod_random_impl.erl | 63 + lib/ic/examples/erl-plain/ReadMe | 27 + lib/ic/examples/erl-plain/random.idl | 52 + .../examples/erl-plain/rmod_random_impl.erl | 32 + lib/ic/examples/java-client-server/ReadMe | 69 + .../examples/java-client-server/client.java | 60 + lib/ic/examples/java-client-server/random.idl | 49 + .../examples/java-client-server/server.java | 82 + .../java-client-server/serverImpl.java | 42 + lib/ic/examples/pre_post_condition/Makefile | 128 + lib/ic/examples/pre_post_condition/ReadMe.txt | 73 + lib/ic/examples/pre_post_condition/ex.idl | 29 + .../examples/pre_post_condition/m_i_impl.erl | 49 + lib/ic/examples/pre_post_condition/tracer.erl | 56 + lib/ic/include/erlang.idl | 57 + lib/ic/include/ic.h | 431 +++ lib/ic/info | 2 + lib/ic/internal_doc/c-improvements-1.txt | 84 + lib/ic/internal_doc/protocol.txt | 182 ++ lib/ic/java_src/Makefile | 41 + lib/ic/java_src/com/ericsson/otp/ic/Any.java | 1023 +++++++ .../com/ericsson/otp/ic/AnyHelper.java | 78 + .../com/ericsson/otp/ic/AnyHolder.java | 60 + .../com/ericsson/otp/ic/BooleanHolder.java | 62 + .../com/ericsson/otp/ic/ByteHolder.java | 61 + .../com/ericsson/otp/ic/CharHolder.java | 63 + .../com/ericsson/otp/ic/DoubleHolder.java | 61 + .../com/ericsson/otp/ic/Environment.java | 475 ++++ .../com/ericsson/otp/ic/FloatHolder.java | 62 + .../java_src/com/ericsson/otp/ic/Holder.java | 33 + .../com/ericsson/otp/ic/IntHolder.java | 62 + .../com/ericsson/otp/ic/LongHolder.java | 60 + lib/ic/java_src/com/ericsson/otp/ic/Makefile | 118 + lib/ic/java_src/com/ericsson/otp/ic/Pid.java | 55 + .../com/ericsson/otp/ic/PidHelper.java | 144 + .../com/ericsson/otp/ic/PidHolder.java | 54 + lib/ic/java_src/com/ericsson/otp/ic/Port.java | 48 + .../com/ericsson/otp/ic/PortHelper.java | 140 + .../com/ericsson/otp/ic/PortHolder.java | 56 + lib/ic/java_src/com/ericsson/otp/ic/Ref.java | 60 + .../com/ericsson/otp/ic/RefHelper.java | 141 + .../com/ericsson/otp/ic/RefHolder.java | 54 + .../com/ericsson/otp/ic/ShortHolder.java | 61 + .../com/ericsson/otp/ic/StringHolder.java | 62 + .../java_src/com/ericsson/otp/ic/TCKind.java | 199 ++ lib/ic/java_src/com/ericsson/otp/ic/Term.java | 1109 ++++++++ .../com/ericsson/otp/ic/TermHelper.java | 139 + .../com/ericsson/otp/ic/TermHolder.java | 58 + .../com/ericsson/otp/ic/TypeCode.java | 875 ++++++ .../ericsson/otp/ic/ignore_config_record.inf | 1 + lib/ic/prebuild.skip | 1 + lib/ic/priv/lib/.gitignore | 0 lib/ic/priv/obj/.gitignore | 0 lib/ic/src/Makefile | 218 ++ lib/ic/src/ic.app.src | 52 + lib/ic/src/ic.erl | 414 +++ lib/ic/src/ic.hrl | 158 ++ lib/ic/src/ic_array_java.erl | 295 ++ lib/ic/src/ic_attribute_java.erl | 412 +++ lib/ic/src/ic_cbe.erl | 1306 +++++++++ lib/ic/src/ic_cclient.erl | 1209 ++++++++ lib/ic/src/ic_code.erl | 584 ++++ lib/ic/src/ic_codegen.erl | 419 +++ lib/ic/src/ic_constant_java.erl | 99 + lib/ic/src/ic_cserver.erl | 2419 +++++++++++++++++ lib/ic/src/ic_debug.hrl | 37 + lib/ic/src/ic_enum_java.erl | 312 +++ lib/ic/src/ic_erl_template.erl | 639 +++++ lib/ic/src/ic_erlbe.erl | 1141 ++++++++ lib/ic/src/ic_error.erl | 375 +++ lib/ic/src/ic_fetch.erl | 388 +++ lib/ic/src/ic_file.erl | 447 +++ lib/ic/src/ic_forms.erl | 437 +++ lib/ic/src/ic_genobj.erl | 244 ++ lib/ic/src/ic_java_type.erl | 1213 +++++++++ lib/ic/src/ic_jbe.erl | 1487 ++++++++++ lib/ic/src/ic_noc.erl | 1113 ++++++++ lib/ic/src/ic_options.erl | 363 +++ lib/ic/src/ic_plainbe.erl | 355 +++ lib/ic/src/ic_pp.erl | 2139 +++++++++++++++ lib/ic/src/ic_pragma.erl | 1957 +++++++++++++ lib/ic/src/ic_sequence_java.erl | 239 ++ lib/ic/src/ic_struct_java.erl | 314 +++ lib/ic/src/ic_symtab.erl | 232 ++ lib/ic/src/ic_union_java.erl | 754 +++++ lib/ic/src/ic_util.erl | 313 +++ lib/ic/src/icenum.erl | 205 ++ lib/ic/src/iceval.erl | 555 ++++ lib/ic/src/icforms.hrl | 68 + lib/ic/src/icparse.yrl | 864 ++++++ lib/ic/src/icpreproc.erl | 111 + lib/ic/src/icscan.erl | 452 +++ lib/ic/src/icstruct.erl | 1916 +++++++++++++ lib/ic/src/ictk.erl | 873 ++++++ lib/ic/src/ictype.erl | 1413 ++++++++++ lib/ic/src/icunion.erl | 1490 ++++++++++ lib/ic/src/icyeccpre.hrl | 124 + lib/ic/vsn.mk | 13 + lib/orber/AUTHORS | 8 + .../CosNaming_BindingIterator_impl.erl | 93 + .../CosNaming_NamingContextExt_impl.erl | 751 +++++ lib/orber/COSS/CosNaming/Makefile | 150 + lib/orber/COSS/CosNaming/cos_naming.idl | 77 + lib/orber/COSS/CosNaming/cos_naming_ext.idl | 37 + lib/orber/COSS/CosNaming/lname.erl | 133 + lib/orber/COSS/CosNaming/lname.hrl | 33 + lib/orber/COSS/CosNaming/lname_component.erl | 83 + lib/orber/COSS/CosNaming/orber_cosnaming.hrl | 63 + .../COSS/CosNaming/orber_cosnaming_utils.erl | 750 +++++ lib/orber/Makefile | 41 + lib/orber/c_src/InitialReference.cc | 205 ++ lib/orber/c_src/InitialReference.hh | 59 + lib/orber/c_src/Makefile | 23 + lib/orber/c_src/Makefile.in | 113 + lib/orber/c_src/main.cc | 31 + lib/orber/doc/etc/.gitignore | 0 lib/orber/doc/html/.gitignore | 0 lib/orber/doc/javadoc/.gitignore | 0 lib/orber/doc/man1/.gitignore | 0 lib/orber/doc/man3/.gitignore | 0 lib/orber/doc/pdf/.gitignore | 0 lib/orber/doc/src/CosNaming.xml | 74 + .../doc/src/CosNaming_BindingIterator.xml | 98 + lib/orber/doc/src/CosNaming_NamingContext.xml | 249 ++ .../doc/src/CosNaming_NamingContextExt.xml | 102 + lib/orber/doc/src/Makefile | 272 ++ lib/orber/doc/src/Module_Interface.xml | 355 +++ lib/orber/doc/src/Orber/InitialReference.java | 130 + lib/orber/doc/src/Orber/Makefile | 70 + .../doc/src/Orber/ignore_config_record.inf | 1 + lib/orber/doc/src/any.xml | 116 + lib/orber/doc/src/book.gif | Bin 0 -> 1081 bytes lib/orber/doc/src/book.xml | 48 + lib/orber/doc/src/ch_contents.xml | 172 ++ lib/orber/doc/src/ch_debugging.xml | 209 ++ lib/orber/doc/src/ch_example.xml | 170 ++ lib/orber/doc/src/ch_exceptions.xml | 237 ++ .../doc/src/ch_idl_to_erlang_mapping.xml | 1471 ++++++++++ lib/orber/doc/src/ch_ifr.xml | 49 + lib/orber/doc/src/ch_install.xml | 1071 ++++++++ lib/orber/doc/src/ch_interceptors.xml | 278 ++ lib/orber/doc/src/ch_introduction.xml | 144 + lib/orber/doc/src/ch_naming_service.xml | 461 ++++ lib/orber/doc/src/ch_orber_kernel.xml | 102 + lib/orber/doc/src/ch_orberweb.xml | 221 ++ lib/orber/doc/src/ch_security.xml | 148 + lib/orber/doc/src/ch_stubs.xml | 283 ++ lib/orber/doc/src/corba.xml | 451 +++ lib/orber/doc/src/corba_object.xml | 196 ++ lib/orber/doc/src/dataframe1.gif | Bin 0 -> 21074 bytes lib/orber/doc/src/dataframe1.ps | Bin 0 -> 423743 bytes lib/orber/doc/src/dataframe2.gif | Bin 0 -> 27848 bytes lib/orber/doc/src/dataframe2.ps | Bin 0 -> 618198 bytes lib/orber/doc/src/dataframe3.gif | Bin 0 -> 30290 bytes lib/orber/doc/src/dataframe3.ps | Bin 0 -> 1060785 bytes lib/orber/doc/src/dataframe4.gif | Bin 0 -> 40114 bytes lib/orber/doc/src/dataframe4.ps | Bin 0 -> 1050366 bytes lib/orber/doc/src/dataframe5.gif | Bin 0 -> 11184 bytes lib/orber/doc/src/dataframe5.ps | Bin 0 -> 265690 bytes lib/orber/doc/src/dataframe6.gif | Bin 0 -> 12331 bytes lib/orber/doc/src/dataframe6.ps | Bin 0 -> 472111 bytes lib/orber/doc/src/dataframe7.gif | Bin 0 -> 12768 bytes lib/orber/doc/src/dataframe7.ps | Bin 0 -> 369889 bytes lib/orber/doc/src/dataframe8.gif | Bin 0 -> 29939 bytes lib/orber/doc/src/dataframe8.ps | Bin 0 -> 1465854 bytes lib/orber/doc/src/dependent.gif | Bin 0 -> 1936 bytes lib/orber/doc/src/dependent.ps | Bin 0 -> 19164 bytes lib/orber/doc/src/example_part.xml | 38 + lib/orber/doc/src/fascicules.xml | 18 + lib/orber/doc/src/firewall_nat.gif | Bin 0 -> 11939 bytes lib/orber/doc/src/firewall_nat.ps | Bin 0 -> 665418 bytes lib/orber/doc/src/fixed.xml | 160 ++ lib/orber/doc/src/ifr_notes.txt | 53 + lib/orber/doc/src/iiop.gif | Bin 0 -> 5899 bytes lib/orber/doc/src/iiop.ps | Bin 0 -> 44376 bytes lib/orber/doc/src/images/GridBagEx.gif | Bin 0 -> 2453 bytes lib/orber/doc/src/images/OpenBookIcon.gif | Bin 0 -> 2241 bytes lib/orber/doc/src/images/blue-ball-small.gif | Bin 0 -> 255 bytes lib/orber/doc/src/images/blue-ball.gif | Bin 0 -> 925 bytes lib/orber/doc/src/images/class-index.gif | Bin 0 -> 1497 bytes .../doc/src/images/constructor-index.gif | Bin 0 -> 1711 bytes lib/orber/doc/src/images/constructors.gif | Bin 0 -> 1565 bytes lib/orber/doc/src/images/cyan-ball-small.gif | Bin 0 -> 255 bytes lib/orber/doc/src/images/cyan-ball.gif | Bin 0 -> 925 bytes lib/orber/doc/src/images/error-index.gif | Bin 0 -> 1438 bytes lib/orber/doc/src/images/exception-index.gif | Bin 0 -> 1707 bytes lib/orber/doc/src/images/green-ball-small.gif | Bin 0 -> 102 bytes lib/orber/doc/src/images/green-ball.gif | Bin 0 -> 886 bytes lib/orber/doc/src/images/interface-index.gif | Bin 0 -> 1648 bytes .../doc/src/images/magenta-ball-small.gif | Bin 0 -> 104 bytes lib/orber/doc/src/images/magenta-ball.gif | Bin 0 -> 896 bytes lib/orber/doc/src/images/method-index.gif | Bin 0 -> 1588 bytes lib/orber/doc/src/images/methods.gif | Bin 0 -> 1403 bytes lib/orber/doc/src/images/package-index.gif | Bin 0 -> 1607 bytes lib/orber/doc/src/images/red-ball-small.gif | Bin 0 -> 255 bytes lib/orber/doc/src/images/red-ball.gif | Bin 0 -> 527 bytes lib/orber/doc/src/images/variable-index.gif | Bin 0 -> 1576 bytes lib/orber/doc/src/images/variables.gif | Bin 0 -> 1380 bytes .../doc/src/images/yellow-ball-small.gif | Bin 0 -> 255 bytes lib/orber/doc/src/images/yellow-ball.gif | Bin 0 -> 925 bytes lib/orber/doc/src/interceptor_operations.gif | Bin 0 -> 14537 bytes lib/orber/doc/src/interceptor_operations.ps | Bin 0 -> 1621300 bytes lib/orber/doc/src/interceptors.xml | 283 ++ lib/orber/doc/src/intro_part.xml | 40 + lib/orber/doc/src/lname.xml | 165 ++ lib/orber/doc/src/lname_component.xml | 112 + lib/orber/doc/src/make.dep | 69 + lib/orber/doc/src/menuframe.gif | Bin 0 -> 12007 bytes lib/orber/doc/src/menuframe.ps | Bin 0 -> 348388 bytes lib/orber/doc/src/name.gif | Bin 0 -> 5015 bytes lib/orber/doc/src/name.ps | Bin 0 -> 50769 bytes lib/orber/doc/src/naming_graph.ps | Bin 0 -> 21595 bytes lib/orber/doc/src/notes.gif | Bin 0 -> 2005 bytes lib/orber/doc/src/notes.xml | 410 +++ lib/orber/doc/src/notes_history.xml | 1523 +++++++++++ lib/orber/doc/src/orber.gif | Bin 0 -> 17015 bytes lib/orber/doc/src/orber.xml | 689 +++++ lib/orber/doc/src/orber_acl.xml | 106 + lib/orber/doc/src/orber_diagnostics.xml | 80 + lib/orber/doc/src/orber_ifr.xml | 1034 +++++++ lib/orber/doc/src/orber_tc.xml | 258 ++ lib/orber/doc/src/orbs.gif | Bin 0 -> 2817 bytes lib/orber/doc/src/orbs.ps | Bin 0 -> 25859 bytes lib/orber/doc/src/part.xml | 49 + lib/orber/doc/src/part_notes.xml | 38 + lib/orber/doc/src/part_notes_history.xml | 38 + lib/orber/doc/src/ref_man.gif | Bin 0 -> 1530 bytes lib/orber/doc/src/ref_man.xml | 52 + lib/orber/doc/src/summary.html.src | 1 + lib/orber/doc/src/theORB.gif | Bin 0 -> 4706 bytes lib/orber/doc/src/theORB.ps | Bin 0 -> 30942 bytes lib/orber/doc/src/tools_debugging_part.xml | 39 + lib/orber/doc/src/user_guide.gif | Bin 0 -> 1581 bytes lib/orber/ebin/.gitignore | 0 lib/orber/examples/Makefile | 41 + .../examples/Stack/InitialReferences.idl | 12 + lib/orber/examples/Stack/Makefile | 121 + lib/orber/examples/Stack/StackClient.cc | 96 + lib/orber/examples/Stack/StackClient.java | 72 + .../Stack/StackModule_StackFactory_impl.erl | 40 + .../examples/Stack/StackModule_Stack_impl.erl | 46 + lib/orber/examples/Stack/stack.idl | 27 + lib/orber/examples/Stack/stack_client.erl | 55 + lib/orber/examples/Stack/stack_factory.erl | 37 + lib/orber/include/Makefile | 66 + lib/orber/include/corba.hrl | 148 + lib/orber/include/ifr_types.hrl | 72 + lib/orber/include/orber_pi.hrl | 76 + lib/orber/info | 2 + lib/orber/java_src/Makefile | 41 + .../java_src/Orber/InitialReference.java | 130 + lib/orber/java_src/Orber/Makefile | 70 + lib/orber/prebuild.skip | 5 + lib/orber/priv/Makefile | 66 + lib/orber/priv/Orber/.gitignore | 0 lib/orber/priv/bin/.gitignore | 0 lib/orber/priv/blank.html | 6 + lib/orber/priv/info_frames.html | 9 + lib/orber/priv/main_frame.html | 9 + lib/orber/priv/obj/.gitignore | 0 lib/orber/priv/orber.tool | 2 + lib/orber/priv/orber_help.txt | 42 + lib/orber/priv/start_info.html | 31 + lib/orber/src/CORBA.idl | 22 + lib/orber/src/Makefile | 268 ++ lib/orber/src/OrberApp_IFR_impl.erl | 101 + lib/orber/src/OrberCSIv2.asn1 | 45 + lib/orber/src/OrberCSIv2.set.asn | 5 + lib/orber/src/OrberIFR.idl | 12 + lib/orber/src/PKIX1Algorithms88.asn1 | 274 ++ lib/orber/src/PKIX1Explicit88.asn1 | 619 +++++ lib/orber/src/PKIX1Implicit88.asn1 | 349 +++ lib/orber/src/PKIXAttributeCertificate.asn1 | 189 ++ lib/orber/src/any.erl | 73 + lib/orber/src/cdr_decode.erl | 1487 ++++++++++ lib/orber/src/cdr_encode.erl | 1151 ++++++++ lib/orber/src/cdrlib.erl | 414 +++ lib/orber/src/corba.erl | 2180 +++++++++++++++ lib/orber/src/corba_boa.erl | 134 + lib/orber/src/corba_nvlist.erl | 97 + lib/orber/src/corba_object.erl | 220 ++ lib/orber/src/corba_request.erl | 384 +++ lib/orber/src/fixed.erl | 305 +++ lib/orber/src/ifr_objects.hrl | 421 +++ lib/orber/src/iop_ior.erl | 1716 ++++++++++++ lib/orber/src/orber.app.src | 109 + lib/orber/src/orber.appup.src | 7 + lib/orber/src/orber.erl | 1216 +++++++++ lib/orber/src/orber_acl.erl | 396 +++ lib/orber/src/orber_diagnostics.erl | 240 ++ lib/orber/src/orber_env.erl | 1456 ++++++++++ lib/orber/src/orber_exceptions.erl | 717 +++++ lib/orber/src/orber_ifr.erl | 1817 +++++++++++++ lib/orber/src/orber_ifr.hrl | 34 + lib/orber/src/orber_ifr_aliasdef.erl | 134 + lib/orber/src/orber_ifr_arraydef.erl | 103 + lib/orber/src/orber_ifr_attributedef.erl | 137 + lib/orber/src/orber_ifr_constantdef.erl | 147 + lib/orber/src/orber_ifr_contained.erl | 247 ++ lib/orber/src/orber_ifr_container.erl | 463 ++++ lib/orber/src/orber_ifr_enumdef.erl | 129 + lib/orber/src/orber_ifr_exceptiondef.erl | 164 ++ lib/orber/src/orber_ifr_fixeddef.erl | 79 + lib/orber/src/orber_ifr_idltype.erl | 74 + lib/orber/src/orber_ifr_interfacedef.erl | 339 +++ lib/orber/src/orber_ifr_irobject.erl | 72 + lib/orber/src/orber_ifr_moduledef.erl | 183 ++ lib/orber/src/orber_ifr_operationdef.erl | 191 ++ lib/orber/src/orber_ifr_orb.erl | 98 + lib/orber/src/orber_ifr_primitivedef.erl | 69 + lib/orber/src/orber_ifr_repository.erl | 286 ++ lib/orber/src/orber_ifr_sequencedef.erl | 103 + lib/orber/src/orber_ifr_stringdef.erl | 74 + lib/orber/src/orber_ifr_structdef.erl | 155 ++ lib/orber/src/orber_ifr_typecode.erl | 107 + lib/orber/src/orber_ifr_typedef.erl | 124 + lib/orber/src/orber_ifr_uniondef.erl | 175 ++ lib/orber/src/orber_ifr_utils.erl | 437 +++ lib/orber/src/orber_ifr_wstringdef.erl | 72 + lib/orber/src/orber_iiop.erl | 550 ++++ lib/orber/src/orber_iiop.hrl | 1015 +++++++ lib/orber/src/orber_iiop_inproxy.erl | 398 +++ lib/orber/src/orber_iiop_inrequest.erl | 538 ++++ lib/orber/src/orber_iiop_insup.erl | 85 + lib/orber/src/orber_iiop_net.erl | 463 ++++ lib/orber/src/orber_iiop_net_accept.erl | 94 + lib/orber/src/orber_iiop_outproxy.erl | 530 ++++ lib/orber/src/orber_iiop_outsup.erl | 87 + lib/orber/src/orber_iiop_pm.erl | 821 ++++++ lib/orber/src/orber_iiop_socketsup.erl | 85 + lib/orber/src/orber_iiop_tracer.erl | 231 ++ lib/orber/src/orber_iiop_tracer_silent.erl | 190 ++ lib/orber/src/orber_iiop_tracer_stealth.erl | 186 ++ lib/orber/src/orber_initial_references.erl | 327 +++ lib/orber/src/orber_interceptors.erl | 162 ++ lib/orber/src/orber_objectkeys.erl | 570 ++++ lib/orber/src/orber_pi.erl | 1210 +++++++++ lib/orber/src/orber_request_number.erl | 82 + lib/orber/src/orber_socket.erl | 504 ++++ lib/orber/src/orber_tb.erl | 186 ++ lib/orber/src/orber_tc.erl | 283 ++ lib/orber/src/orber_typedefs.erl | 82 + lib/orber/src/orber_web.erl | 863 ++++++ lib/orber/src/orber_web_server.erl | 191 ++ lib/orber/vsn.mk | 12 + make/lazy_configure.mk | 81 + make/make_emakefile | 66 + make/otp.mk.in | 267 ++ make/otp_ded.mk.in | 22 + make/otp_release_targets.mk | 78 + make/otp_subdir.mk | 53 + make/run_make.mk | 42 + make/save_args | 71 + make/target.mk | 33 + 846 files changed, 143633 insertions(+) create mode 100644 AUTHORS create mode 100644 lib/cosEvent/AUTHORS create mode 100644 lib/cosEvent/Makefile create mode 100644 lib/cosEvent/doc/html/.gitignore create mode 100644 lib/cosEvent/doc/man3/.gitignore create mode 100644 lib/cosEvent/doc/man6/.gitignore create mode 100644 lib/cosEvent/doc/pdf/.gitignore create mode 100644 lib/cosEvent/doc/src/CosEventChannelAdmin.xml create mode 100644 lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml create mode 100644 lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml create mode 100644 lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml create mode 100644 lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml create mode 100644 lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml create mode 100644 lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml create mode 100644 lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml create mode 100644 lib/cosEvent/doc/src/Makefile create mode 100644 lib/cosEvent/doc/src/book.gif create mode 100644 lib/cosEvent/doc/src/book.xml create mode 100644 lib/cosEvent/doc/src/ch_contents.xml create mode 100644 lib/cosEvent/doc/src/ch_event_service.xml create mode 100644 lib/cosEvent/doc/src/ch_introduction.xml create mode 100644 lib/cosEvent/doc/src/cosEventApp.xml create mode 100644 lib/cosEvent/doc/src/e_s_components.gif create mode 100644 lib/cosEvent/doc/src/e_s_components.ps create mode 100644 lib/cosEvent/doc/src/e_s_models.gif create mode 100644 lib/cosEvent/doc/src/e_s_models.ps create mode 100644 lib/cosEvent/doc/src/fascicules.xml create mode 100644 lib/cosEvent/doc/src/make.dep create mode 100644 lib/cosEvent/doc/src/notes.gif create mode 100644 lib/cosEvent/doc/src/notes.xml create mode 100644 lib/cosEvent/doc/src/part.xml create mode 100644 lib/cosEvent/doc/src/part_notes.xml create mode 100644 lib/cosEvent/doc/src/ref_man.gif create mode 100644 lib/cosEvent/doc/src/ref_man.xml create mode 100644 lib/cosEvent/doc/src/summary.html.src create mode 100644 lib/cosEvent/doc/src/user_guide.gif create mode 100644 lib/cosEvent/ebin/.gitignore create mode 100644 lib/cosEvent/example/.gitignore create mode 100644 lib/cosEvent/include/.gitignore create mode 100644 lib/cosEvent/info create mode 100644 lib/cosEvent/src/CosEventChannelAdmin.cfg create mode 100644 lib/cosEvent/src/CosEventChannelAdmin.idl create mode 100644 lib/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer_impl.erl create mode 100644 lib/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer_impl.erl create mode 100644 lib/cosEvent/src/CosEventChannelAdmin_SupplierAdmin_impl.erl create mode 100644 lib/cosEvent/src/CosEventComm.idl create mode 100644 lib/cosEvent/src/Makefile create mode 100644 lib/cosEvent/src/cosEvent.app.src create mode 100644 lib/cosEvent/src/cosEvent.appup.src create mode 100644 lib/cosEvent/src/cosEventApp.cfg create mode 100644 lib/cosEvent/src/cosEventApp.erl create mode 100644 lib/cosEvent/src/cosEventApp.hrl create mode 100644 lib/cosEvent/src/cosEventApp.idl create mode 100644 lib/cosEvent/src/oe_CosEventComm_CAdmin_impl.erl create mode 100644 lib/cosEvent/src/oe_CosEventComm_Channel_impl.erl create mode 100644 lib/cosEvent/src/oe_CosEventComm_PullerS_impl.erl create mode 100644 lib/cosEvent/src/oe_CosEventComm_PusherS_impl.erl create mode 100644 lib/cosEvent/vsn.mk create mode 100644 lib/cosEventDomain/AUTHORS create mode 100644 lib/cosEventDomain/Makefile create mode 100644 lib/cosEventDomain/doc/html/.gitignore create mode 100644 lib/cosEventDomain/doc/man3/.gitignore create mode 100644 lib/cosEventDomain/doc/man6/.gitignore create mode 100644 lib/cosEventDomain/doc/pdf/.gitignore create mode 100644 lib/cosEventDomain/doc/src/CosEventDomainAdmin.xml create mode 100644 lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml create mode 100644 lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml create mode 100644 lib/cosEventDomain/doc/src/Makefile create mode 100644 lib/cosEventDomain/doc/src/book.gif create mode 100644 lib/cosEventDomain/doc/src/book.xml create mode 100644 lib/cosEventDomain/doc/src/ch_QoS.xml create mode 100644 lib/cosEventDomain/doc/src/ch_contents.xml create mode 100644 lib/cosEventDomain/doc/src/ch_event_domain_service.xml create mode 100644 lib/cosEventDomain/doc/src/ch_introduction.xml create mode 100644 lib/cosEventDomain/doc/src/cosEventDomainApp.xml create mode 100644 lib/cosEventDomain/doc/src/fascicules.xml create mode 100644 lib/cosEventDomain/doc/src/make.dep create mode 100644 lib/cosEventDomain/doc/src/notes.gif create mode 100644 lib/cosEventDomain/doc/src/notes.xml create mode 100644 lib/cosEventDomain/doc/src/part.xml create mode 100644 lib/cosEventDomain/doc/src/part_notes.xml create mode 100644 lib/cosEventDomain/doc/src/ref_man.gif create mode 100644 lib/cosEventDomain/doc/src/ref_man.xml create mode 100644 lib/cosEventDomain/doc/src/summary.html.src create mode 100644 lib/cosEventDomain/doc/src/user_guide.gif create mode 100644 lib/cosEventDomain/ebin/.gitignore create mode 100644 lib/cosEventDomain/example/.gitignore create mode 100644 lib/cosEventDomain/include/.gitignore create mode 100644 lib/cosEventDomain/info create mode 100644 lib/cosEventDomain/src/CosEventDomainAdmin.cfg create mode 100644 lib/cosEventDomain/src/CosEventDomainAdmin.idl create mode 100644 lib/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory_impl.erl create mode 100644 lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl create mode 100644 lib/cosEventDomain/src/Makefile create mode 100644 lib/cosEventDomain/src/cosEventDomain.app.src create mode 100644 lib/cosEventDomain/src/cosEventDomain.appup.src create mode 100644 lib/cosEventDomain/src/cosEventDomainApp.erl create mode 100644 lib/cosEventDomain/src/cosEventDomainApp.hrl create mode 100644 lib/cosEventDomain/vsn.mk create mode 100644 lib/cosFileTransfer/AUTHORS create mode 100644 lib/cosFileTransfer/Makefile create mode 100644 lib/cosFileTransfer/doc/html/.gitignore create mode 100644 lib/cosFileTransfer/doc/man3/.gitignore create mode 100644 lib/cosFileTransfer/doc/man6/.gitignore create mode 100644 lib/cosFileTransfer/doc/pdf/.gitignore create mode 100644 lib/cosFileTransfer/doc/src/CosFileTransfer.gif create mode 100644 lib/cosFileTransfer/doc/src/CosFileTransfer.ps create mode 100644 lib/cosFileTransfer/doc/src/CosFileTransfer_Directory.xml create mode 100644 lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml create mode 100644 lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml create mode 100644 lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml create mode 100644 lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml create mode 100644 lib/cosFileTransfer/doc/src/Makefile create mode 100644 lib/cosFileTransfer/doc/src/book.gif create mode 100644 lib/cosFileTransfer/doc/src/book.xml create mode 100644 lib/cosFileTransfer/doc/src/ch_contents.xml create mode 100644 lib/cosFileTransfer/doc/src/ch_example.xml create mode 100644 lib/cosFileTransfer/doc/src/ch_install.xml create mode 100644 lib/cosFileTransfer/doc/src/ch_introduction.xml create mode 100644 lib/cosFileTransfer/doc/src/ch_system.xml create mode 100644 lib/cosFileTransfer/doc/src/cosFileTransferApp.xml create mode 100644 lib/cosFileTransfer/doc/src/fascicules.xml create mode 100644 lib/cosFileTransfer/doc/src/make.dep create mode 100644 lib/cosFileTransfer/doc/src/notes.gif create mode 100644 lib/cosFileTransfer/doc/src/notes.xml create mode 100644 lib/cosFileTransfer/doc/src/part.xml create mode 100644 lib/cosFileTransfer/doc/src/part_notes.xml create mode 100644 lib/cosFileTransfer/doc/src/ref_man.gif create mode 100644 lib/cosFileTransfer/doc/src/ref_man.xml create mode 100644 lib/cosFileTransfer/doc/src/summary.html.src create mode 100644 lib/cosFileTransfer/doc/src/user_guide.gif create mode 100644 lib/cosFileTransfer/ebin/.gitignore create mode 100644 lib/cosFileTransfer/examples/.gitignore create mode 100644 lib/cosFileTransfer/include/.gitignore create mode 100644 lib/cosFileTransfer/info create mode 100644 lib/cosFileTransfer/priv/.gitignore create mode 100644 lib/cosFileTransfer/src/CosFileTransfer.cfg create mode 100644 lib/cosFileTransfer/src/CosFileTransfer.idl create mode 100644 lib/cosFileTransfer/src/CosFileTransfer_Directory_impl.erl create mode 100644 lib/cosFileTransfer/src/CosFileTransfer_FileIterator_impl.erl create mode 100644 lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl create mode 100644 lib/cosFileTransfer/src/CosFileTransfer_File_impl.erl create mode 100644 lib/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_impl.erl create mode 100644 lib/cosFileTransfer/src/Makefile create mode 100644 lib/cosFileTransfer/src/cosFileTransfer.app.src create mode 100644 lib/cosFileTransfer/src/cosFileTransfer.appup.src create mode 100644 lib/cosFileTransfer/src/cosFileTransferApp.erl create mode 100644 lib/cosFileTransfer/src/cosFileTransferApp.hrl create mode 100644 lib/cosFileTransfer/src/cosFileTransferNATIVE_file.erl create mode 100644 lib/cosFileTransfer/vsn.mk create mode 100644 lib/cosNotification/AUTHORS create mode 100644 lib/cosNotification/Makefile create mode 100644 lib/cosNotification/doc/html/.gitignore create mode 100644 lib/cosNotification/doc/man3/.gitignore create mode 100644 lib/cosNotification/doc/man6/.gitignore create mode 100644 lib/cosNotification/doc/pdf/.gitignore create mode 100644 lib/cosNotification/doc/src/CosNotification.xml create mode 100644 lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml create mode 100644 lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml create mode 100644 lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml create mode 100644 lib/cosNotification/doc/src/Makefile create mode 100644 lib/cosNotification/doc/src/book.gif create mode 100644 lib/cosNotification/doc/src/book.xml create mode 100644 lib/cosNotification/doc/src/ch_BNF.xml create mode 100644 lib/cosNotification/doc/src/ch_QoS.xml create mode 100644 lib/cosNotification/doc/src/ch_contents.xml create mode 100644 lib/cosNotification/doc/src/ch_example.xml create mode 100644 lib/cosNotification/doc/src/ch_install.xml create mode 100644 lib/cosNotification/doc/src/ch_introduction.xml create mode 100644 lib/cosNotification/doc/src/ch_system.xml create mode 100644 lib/cosNotification/doc/src/cosNotificationApp.xml create mode 100644 lib/cosNotification/doc/src/eventstructure.gif create mode 100644 lib/cosNotification/doc/src/eventstructure.ps create mode 100644 lib/cosNotification/doc/src/fascicules.xml create mode 100644 lib/cosNotification/doc/src/make.dep create mode 100644 lib/cosNotification/doc/src/notes.gif create mode 100644 lib/cosNotification/doc/src/notes.xml create mode 100644 lib/cosNotification/doc/src/notificationFlow.gif create mode 100644 lib/cosNotification/doc/src/notificationFlow.ps create mode 100644 lib/cosNotification/doc/src/part.xml create mode 100644 lib/cosNotification/doc/src/part_notes.xml create mode 100644 lib/cosNotification/doc/src/ref_man.gif create mode 100644 lib/cosNotification/doc/src/ref_man.xml create mode 100644 lib/cosNotification/doc/src/summary.html.src create mode 100644 lib/cosNotification/doc/src/user_guide.gif create mode 100644 lib/cosNotification/ebin/.gitignore create mode 100644 lib/cosNotification/examples/.gitignore create mode 100644 lib/cosNotification/include/.gitignore create mode 100644 lib/cosNotification/info create mode 100644 lib/cosNotification/priv/.gitignore create mode 100644 lib/cosNotification/src/CosEvent.cfg create mode 100644 lib/cosNotification/src/CosNotification.cfg create mode 100644 lib/cosNotification/src/CosNotification.idl create mode 100644 lib/cosNotification/src/CosNotification_Common.erl create mode 100644 lib/cosNotification/src/CosNotification_Definitions.hrl create mode 100644 lib/cosNotification/src/CosNotifyChannelAdmin.cfg create mode 100644 lib/cosNotification/src/CosNotifyChannelAdmin.idl create mode 100644 lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl create mode 100644 lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl create mode 100644 lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl create mode 100644 lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl create mode 100644 lib/cosNotification/src/CosNotifyComm.cfg create mode 100644 lib/cosNotification/src/CosNotifyComm.idl create mode 100644 lib/cosNotification/src/CosNotifyFilter.cfg create mode 100644 lib/cosNotification/src/CosNotifyFilter.idl create mode 100644 lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl create mode 100644 lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl create mode 100644 lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl create mode 100644 lib/cosNotification/src/CosTypedEvent.idl create mode 100644 lib/cosNotification/src/CosTypedNotification.idl create mode 100644 lib/cosNotification/src/Makefile create mode 100644 lib/cosNotification/src/PullerConsumer_impl.erl create mode 100644 lib/cosNotification/src/PullerSupplier_impl.erl create mode 100644 lib/cosNotification/src/PusherConsumer_impl.erl create mode 100644 lib/cosNotification/src/PusherSupplier_impl.erl create mode 100644 lib/cosNotification/src/cosNotification.app.src create mode 100644 lib/cosNotification/src/cosNotification.appup.src create mode 100644 lib/cosNotification/src/cosNotificationApp.erl create mode 100644 lib/cosNotification/src/cosNotificationAppComm.idl create mode 100644 lib/cosNotification/src/cosNotificationComm.cfg create mode 100644 lib/cosNotification/src/cosNotification_Filter.erl create mode 100644 lib/cosNotification/src/cosNotification_Grammar.yrl create mode 100644 lib/cosNotification/src/cosNotification_Scanner.erl create mode 100644 lib/cosNotification/src/cosNotification_eventDB.erl create mode 100644 lib/cosNotification/vsn.mk create mode 100644 lib/cosProperty/AUTHORS create mode 100644 lib/cosProperty/Makefile create mode 100644 lib/cosProperty/doc/html/.gitignore create mode 100644 lib/cosProperty/doc/man3/.gitignore create mode 100644 lib/cosProperty/doc/man6/.gitignore create mode 100644 lib/cosProperty/doc/pdf/.gitignore create mode 100644 lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml create mode 100644 lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml create mode 100644 lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml create mode 100644 lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml create mode 100644 lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml create mode 100644 lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml create mode 100644 lib/cosProperty/doc/src/Makefile create mode 100644 lib/cosProperty/doc/src/book.gif create mode 100644 lib/cosProperty/doc/src/book.xml create mode 100644 lib/cosProperty/doc/src/ch_contents.xml create mode 100644 lib/cosProperty/doc/src/ch_example.xml create mode 100644 lib/cosProperty/doc/src/ch_install.xml create mode 100644 lib/cosProperty/doc/src/ch_introduction.xml create mode 100644 lib/cosProperty/doc/src/cosProperty.xml create mode 100644 lib/cosProperty/doc/src/fascicules.xml create mode 100644 lib/cosProperty/doc/src/make.dep create mode 100644 lib/cosProperty/doc/src/notes.gif create mode 100644 lib/cosProperty/doc/src/notes.xml create mode 100644 lib/cosProperty/doc/src/part.xml create mode 100644 lib/cosProperty/doc/src/part_notes.xml create mode 100644 lib/cosProperty/doc/src/ref_man.gif create mode 100644 lib/cosProperty/doc/src/ref_man.xml create mode 100644 lib/cosProperty/doc/src/summary.html.src create mode 100644 lib/cosProperty/doc/src/user_guide.gif create mode 100644 lib/cosProperty/ebin/.gitignore create mode 100644 lib/cosProperty/examples/.gitignore create mode 100644 lib/cosProperty/include/.gitignore create mode 100644 lib/cosProperty/info create mode 100644 lib/cosProperty/priv/.gitignore create mode 100644 lib/cosProperty/src/CosProperty.cfg create mode 100644 lib/cosProperty/src/CosProperty.idl create mode 100644 lib/cosProperty/src/CosPropertyService_PropertiesIterator_impl.erl create mode 100644 lib/cosProperty/src/CosPropertyService_PropertyNamesIterator_impl.erl create mode 100644 lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl create mode 100644 lib/cosProperty/src/CosPropertyService_PropertySetDef_impl.erl create mode 100644 lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl create mode 100644 lib/cosProperty/src/Makefile create mode 100644 lib/cosProperty/src/cosProperty.app.src create mode 100644 lib/cosProperty/src/cosProperty.appup.src create mode 100644 lib/cosProperty/src/cosProperty.erl create mode 100644 lib/cosProperty/src/cosProperty.hrl create mode 100644 lib/cosProperty/vsn.mk create mode 100644 lib/cosTime/AUTHORS create mode 100644 lib/cosTime/Makefile create mode 100644 lib/cosTime/doc/html/.gitignore create mode 100644 lib/cosTime/doc/man3/.gitignore create mode 100644 lib/cosTime/doc/man6/.gitignore create mode 100644 lib/cosTime/doc/pdf/.gitignore create mode 100644 lib/cosTime/doc/src/CosTime_TIO.xml create mode 100644 lib/cosTime/doc/src/CosTime_TimeService.xml create mode 100644 lib/cosTime/doc/src/CosTime_UTO.xml create mode 100644 lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml create mode 100644 lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml create mode 100644 lib/cosTime/doc/src/Makefile create mode 100644 lib/cosTime/doc/src/book.gif create mode 100644 lib/cosTime/doc/src/book.xml create mode 100644 lib/cosTime/doc/src/ch_contents.xml create mode 100644 lib/cosTime/doc/src/ch_example.xml create mode 100644 lib/cosTime/doc/src/ch_install.xml create mode 100644 lib/cosTime/doc/src/ch_introduction.xml create mode 100644 lib/cosTime/doc/src/cosTime.xml create mode 100644 lib/cosTime/doc/src/fascicules.xml create mode 100644 lib/cosTime/doc/src/make.dep create mode 100644 lib/cosTime/doc/src/notes.gif create mode 100644 lib/cosTime/doc/src/notes.xml create mode 100644 lib/cosTime/doc/src/part.xml create mode 100644 lib/cosTime/doc/src/part_notes.xml create mode 100644 lib/cosTime/doc/src/ref_man.gif create mode 100644 lib/cosTime/doc/src/ref_man.xml create mode 100644 lib/cosTime/doc/src/summary.html.src create mode 100644 lib/cosTime/doc/src/user_guide.gif create mode 100644 lib/cosTime/ebin/.gitignore create mode 100644 lib/cosTime/examples/.gitignore create mode 100644 lib/cosTime/include/.gitignore create mode 100644 lib/cosTime/info create mode 100644 lib/cosTime/priv/.gitignore create mode 100644 lib/cosTime/src/CosTime.cfg create mode 100644 lib/cosTime/src/CosTime.idl create mode 100644 lib/cosTime/src/CosTime_TIO_impl.erl create mode 100644 lib/cosTime/src/CosTime_TimeService_impl.erl create mode 100644 lib/cosTime/src/CosTime_UTO_impl.erl create mode 100644 lib/cosTime/src/CosTimerEvent.cfg create mode 100644 lib/cosTime/src/CosTimerEvent.idl create mode 100644 lib/cosTime/src/CosTimerEvent_TimerEventHandler_impl.erl create mode 100644 lib/cosTime/src/CosTimerEvent_TimerEventService_impl.erl create mode 100644 lib/cosTime/src/Makefile create mode 100644 lib/cosTime/src/TimeBase.idl create mode 100644 lib/cosTime/src/cosTime.app.src create mode 100644 lib/cosTime/src/cosTime.appup.src create mode 100644 lib/cosTime/src/cosTime.erl create mode 100644 lib/cosTime/src/cosTimeApp.hrl create mode 100644 lib/cosTime/vsn.mk create mode 100644 lib/cosTransactions/AUTHORS create mode 100644 lib/cosTransactions/Makefile create mode 100644 lib/cosTransactions/doc/html/.gitignore create mode 100644 lib/cosTransactions/doc/man3/.gitignore create mode 100644 lib/cosTransactions/doc/man6/.gitignore create mode 100644 lib/cosTransactions/doc/pdf/.gitignore create mode 100644 lib/cosTransactions/doc/src/CosTransactions_Control.xml create mode 100644 lib/cosTransactions/doc/src/CosTransactions_Coordinator.xml create mode 100644 lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml create mode 100644 lib/cosTransactions/doc/src/CosTransactions_Resource.xml create mode 100644 lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml create mode 100644 lib/cosTransactions/doc/src/CosTransactions_Synchronization.xml create mode 100644 lib/cosTransactions/doc/src/CosTransactions_Terminator.xml create mode 100644 lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml create mode 100644 lib/cosTransactions/doc/src/CosTransactions_TransactionalObject.xml create mode 100644 lib/cosTransactions/doc/src/Makefile create mode 100644 lib/cosTransactions/doc/src/book.gif create mode 100644 lib/cosTransactions/doc/src/book.xml create mode 100644 lib/cosTransactions/doc/src/ch_contents.xml create mode 100644 lib/cosTransactions/doc/src/ch_example.xml create mode 100644 lib/cosTransactions/doc/src/ch_install.xml create mode 100644 lib/cosTransactions/doc/src/ch_introduction.xml create mode 100644 lib/cosTransactions/doc/src/ch_skeletons.xml create mode 100644 lib/cosTransactions/doc/src/cosTransactions.xml create mode 100644 lib/cosTransactions/doc/src/fascicules.xml create mode 100644 lib/cosTransactions/doc/src/make.dep create mode 100644 lib/cosTransactions/doc/src/notes.gif create mode 100644 lib/cosTransactions/doc/src/notes.xml create mode 100644 lib/cosTransactions/doc/src/part.xml create mode 100644 lib/cosTransactions/doc/src/part_notes.xml create mode 100644 lib/cosTransactions/doc/src/ref_man.gif create mode 100644 lib/cosTransactions/doc/src/ref_man.xml create mode 100644 lib/cosTransactions/doc/src/summary.html.src create mode 100644 lib/cosTransactions/doc/src/user_guide.gif create mode 100644 lib/cosTransactions/ebin/.gitignore create mode 100644 lib/cosTransactions/examples/Makefile create mode 100644 lib/cosTransactions/include/.gitignore create mode 100644 lib/cosTransactions/info create mode 100644 lib/cosTransactions/priv/.gitignore create mode 100644 lib/cosTransactions/src/CosTransactions.cfg create mode 100644 lib/cosTransactions/src/CosTransactions.idl create mode 100644 lib/cosTransactions/src/CosTransactions_Terminator_impl.erl create mode 100644 lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl create mode 100644 lib/cosTransactions/src/ETraP_Common.erl create mode 100644 lib/cosTransactions/src/ETraP_Common.hrl create mode 100644 lib/cosTransactions/src/ETraP_Server_impl.erl create mode 100644 lib/cosTransactions/src/Makefile create mode 100644 lib/cosTransactions/src/cosTransactions.app.src create mode 100644 lib/cosTransactions/src/cosTransactions.appup.src create mode 100644 lib/cosTransactions/src/cosTransactions.erl create mode 100644 lib/cosTransactions/src/etrap_logmgr.erl create mode 100644 lib/cosTransactions/vsn.mk create mode 100644 lib/ic/AUTHORS create mode 100644 lib/ic/Makefile create mode 100644 lib/ic/c_src/Makefile create mode 100644 lib/ic/c_src/Makefile.in create mode 100644 lib/ic/c_src/Makefile.win32 create mode 100644 lib/ic/c_src/ic.c create mode 100644 lib/ic/c_src/ic_tmo.c create mode 100644 lib/ic/c_src/oe_ei_code_erlang_binary.c create mode 100644 lib/ic/c_src/oe_ei_decode_longlong.c create mode 100644 lib/ic/c_src/oe_ei_decode_ulonglong.c create mode 100644 lib/ic/c_src/oe_ei_decode_wchar.c create mode 100644 lib/ic/c_src/oe_ei_decode_wstring.c create mode 100644 lib/ic/c_src/oe_ei_encode_atom.c create mode 100644 lib/ic/c_src/oe_ei_encode_char.c create mode 100644 lib/ic/c_src/oe_ei_encode_double.c create mode 100644 lib/ic/c_src/oe_ei_encode_list_header.c create mode 100644 lib/ic/c_src/oe_ei_encode_long.c create mode 100644 lib/ic/c_src/oe_ei_encode_longlong.c create mode 100644 lib/ic/c_src/oe_ei_encode_pid.c create mode 100644 lib/ic/c_src/oe_ei_encode_port.c create mode 100644 lib/ic/c_src/oe_ei_encode_ref.c create mode 100644 lib/ic/c_src/oe_ei_encode_string.c create mode 100644 lib/ic/c_src/oe_ei_encode_term.c create mode 100644 lib/ic/c_src/oe_ei_encode_tuple_header.c create mode 100644 lib/ic/c_src/oe_ei_encode_ulong.c create mode 100644 lib/ic/c_src/oe_ei_encode_ulonglong.c create mode 100644 lib/ic/c_src/oe_ei_encode_version.c create mode 100644 lib/ic/c_src/oe_ei_encode_wchar.c create mode 100644 lib/ic/c_src/oe_ei_encode_wstring.c create mode 100644 lib/ic/doc/html/.gitignore create mode 100644 lib/ic/doc/man1/.gitignore create mode 100644 lib/ic/doc/man3/.gitignore create mode 100644 lib/ic/doc/pdf/.gitignore create mode 100644 lib/ic/doc/src/CORBA_Environment_alloc.xml create mode 100644 lib/ic/doc/src/Makefile create mode 100644 lib/ic/doc/src/book.gif create mode 100644 lib/ic/doc/src/book.xml create mode 100644 lib/ic/doc/src/c-part.xml create mode 100644 lib/ic/doc/src/ch_basic_idl.xml create mode 100644 lib/ic/doc/src/ch_c_client.xml create mode 100644 lib/ic/doc/src/ch_c_corba_env.xml create mode 100644 lib/ic/doc/src/ch_c_mapping.xml create mode 100644 lib/ic/doc/src/ch_c_server.xml create mode 100644 lib/ic/doc/src/ch_erl_genserv.xml create mode 100644 lib/ic/doc/src/ch_erl_plain.xml create mode 100644 lib/ic/doc/src/ch_ic_protocol.xml create mode 100644 lib/ic/doc/src/ch_introduction.xml create mode 100644 lib/ic/doc/src/ch_java.xml create mode 100644 lib/ic/doc/src/erl-part.xml create mode 100644 lib/ic/doc/src/fascicules.xml create mode 100644 lib/ic/doc/src/ic.gif create mode 100644 lib/ic/doc/src/ic.xml create mode 100644 lib/ic/doc/src/ic_c_protocol.xml create mode 100644 lib/ic/doc/src/ic_clib.xml create mode 100644 lib/ic/doc/src/java-part.xml create mode 100644 lib/ic/doc/src/make.dep create mode 100644 lib/ic/doc/src/notes.gif create mode 100644 lib/ic/doc/src/notes.xml create mode 100644 lib/ic/doc/src/old_notes.xml create mode 100644 lib/ic/doc/src/part.xml create mode 100644 lib/ic/doc/src/part_notes.xml create mode 100644 lib/ic/doc/src/ref_man.gif create mode 100644 lib/ic/doc/src/ref_man.xml create mode 100644 lib/ic/doc/src/summary.html.src create mode 100644 lib/ic/doc/src/user_guide.gif create mode 100644 lib/ic/ebin/.gitignore create mode 100644 lib/ic/examples/all-against-all/Makefile create mode 100644 lib/ic/examples/all-against-all/Makefile.win32 create mode 100644 lib/ic/examples/all-against-all/ReadMe create mode 100644 lib/ic/examples/all-against-all/callbacks.c create mode 100644 lib/ic/examples/all-against-all/client.c create mode 100644 lib/ic/examples/all-against-all/client.erl create mode 100644 lib/ic/examples/all-against-all/client.java create mode 100644 lib/ic/examples/all-against-all/random.idl create mode 100644 lib/ic/examples/all-against-all/rmod_random_impl.erl create mode 100644 lib/ic/examples/all-against-all/server.c create mode 100644 lib/ic/examples/all-against-all/server.erl create mode 100644 lib/ic/examples/all-against-all/server.java create mode 100644 lib/ic/examples/all-against-all/serverImpl.java create mode 100644 lib/ic/examples/c-client/Makefile create mode 100644 lib/ic/examples/c-client/ReadMe create mode 100644 lib/ic/examples/c-client/client.c create mode 100644 lib/ic/examples/c-client/random.idl create mode 100644 lib/ic/examples/c-client/rmod_random_impl.erl create mode 100644 lib/ic/examples/c-client/test.erl create mode 100644 lib/ic/examples/c-server/Makefile create mode 100644 lib/ic/examples/c-server/ReadMe create mode 100644 lib/ic/examples/c-server/callbacks.c create mode 100644 lib/ic/examples/c-server/client.c create mode 100644 lib/ic/examples/c-server/client.erl create mode 100644 lib/ic/examples/c-server/random.idl create mode 100644 lib/ic/examples/c-server/server.c create mode 100644 lib/ic/examples/erl-genserv/ReadMe create mode 100644 lib/ic/examples/erl-genserv/random.idl create mode 100644 lib/ic/examples/erl-genserv/rmod_random_impl.erl create mode 100644 lib/ic/examples/erl-plain/ReadMe create mode 100644 lib/ic/examples/erl-plain/random.idl create mode 100644 lib/ic/examples/erl-plain/rmod_random_impl.erl create mode 100644 lib/ic/examples/java-client-server/ReadMe create mode 100644 lib/ic/examples/java-client-server/client.java create mode 100644 lib/ic/examples/java-client-server/random.idl create mode 100644 lib/ic/examples/java-client-server/server.java create mode 100644 lib/ic/examples/java-client-server/serverImpl.java create mode 100644 lib/ic/examples/pre_post_condition/Makefile create mode 100644 lib/ic/examples/pre_post_condition/ReadMe.txt create mode 100644 lib/ic/examples/pre_post_condition/ex.idl create mode 100644 lib/ic/examples/pre_post_condition/m_i_impl.erl create mode 100644 lib/ic/examples/pre_post_condition/tracer.erl create mode 100644 lib/ic/include/erlang.idl create mode 100644 lib/ic/include/ic.h create mode 100644 lib/ic/info create mode 100644 lib/ic/internal_doc/c-improvements-1.txt create mode 100644 lib/ic/internal_doc/protocol.txt create mode 100644 lib/ic/java_src/Makefile create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/Any.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/AnyHelper.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/AnyHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/BooleanHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/ByteHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/CharHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/DoubleHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/Environment.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/FloatHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/Holder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/IntHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/LongHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/Makefile create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/Pid.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/PidHelper.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/PidHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/Port.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/PortHelper.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/PortHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/Ref.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/RefHelper.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/RefHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/ShortHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/StringHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/TCKind.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/Term.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/TermHelper.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/TermHolder.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/TypeCode.java create mode 100644 lib/ic/java_src/com/ericsson/otp/ic/ignore_config_record.inf create mode 100644 lib/ic/prebuild.skip create mode 100644 lib/ic/priv/lib/.gitignore create mode 100644 lib/ic/priv/obj/.gitignore create mode 100644 lib/ic/src/Makefile create mode 100644 lib/ic/src/ic.app.src create mode 100644 lib/ic/src/ic.erl create mode 100644 lib/ic/src/ic.hrl create mode 100644 lib/ic/src/ic_array_java.erl create mode 100644 lib/ic/src/ic_attribute_java.erl create mode 100644 lib/ic/src/ic_cbe.erl create mode 100644 lib/ic/src/ic_cclient.erl create mode 100644 lib/ic/src/ic_code.erl create mode 100644 lib/ic/src/ic_codegen.erl create mode 100644 lib/ic/src/ic_constant_java.erl create mode 100644 lib/ic/src/ic_cserver.erl create mode 100644 lib/ic/src/ic_debug.hrl create mode 100644 lib/ic/src/ic_enum_java.erl create mode 100644 lib/ic/src/ic_erl_template.erl create mode 100644 lib/ic/src/ic_erlbe.erl create mode 100644 lib/ic/src/ic_error.erl create mode 100644 lib/ic/src/ic_fetch.erl create mode 100644 lib/ic/src/ic_file.erl create mode 100644 lib/ic/src/ic_forms.erl create mode 100644 lib/ic/src/ic_genobj.erl create mode 100644 lib/ic/src/ic_java_type.erl create mode 100644 lib/ic/src/ic_jbe.erl create mode 100644 lib/ic/src/ic_noc.erl create mode 100644 lib/ic/src/ic_options.erl create mode 100644 lib/ic/src/ic_plainbe.erl create mode 100644 lib/ic/src/ic_pp.erl create mode 100644 lib/ic/src/ic_pragma.erl create mode 100644 lib/ic/src/ic_sequence_java.erl create mode 100644 lib/ic/src/ic_struct_java.erl create mode 100644 lib/ic/src/ic_symtab.erl create mode 100644 lib/ic/src/ic_union_java.erl create mode 100644 lib/ic/src/ic_util.erl create mode 100644 lib/ic/src/icenum.erl create mode 100644 lib/ic/src/iceval.erl create mode 100644 lib/ic/src/icforms.hrl create mode 100644 lib/ic/src/icparse.yrl create mode 100644 lib/ic/src/icpreproc.erl create mode 100644 lib/ic/src/icscan.erl create mode 100644 lib/ic/src/icstruct.erl create mode 100644 lib/ic/src/ictk.erl create mode 100644 lib/ic/src/ictype.erl create mode 100644 lib/ic/src/icunion.erl create mode 100644 lib/ic/src/icyeccpre.hrl create mode 100644 lib/ic/vsn.mk create mode 100644 lib/orber/AUTHORS create mode 100644 lib/orber/COSS/CosNaming/CosNaming_BindingIterator_impl.erl create mode 100644 lib/orber/COSS/CosNaming/CosNaming_NamingContextExt_impl.erl create mode 100644 lib/orber/COSS/CosNaming/Makefile create mode 100644 lib/orber/COSS/CosNaming/cos_naming.idl create mode 100644 lib/orber/COSS/CosNaming/cos_naming_ext.idl create mode 100644 lib/orber/COSS/CosNaming/lname.erl create mode 100644 lib/orber/COSS/CosNaming/lname.hrl create mode 100644 lib/orber/COSS/CosNaming/lname_component.erl create mode 100644 lib/orber/COSS/CosNaming/orber_cosnaming.hrl create mode 100644 lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl create mode 100644 lib/orber/Makefile create mode 100644 lib/orber/c_src/InitialReference.cc create mode 100644 lib/orber/c_src/InitialReference.hh create mode 100644 lib/orber/c_src/Makefile create mode 100644 lib/orber/c_src/Makefile.in create mode 100644 lib/orber/c_src/main.cc create mode 100644 lib/orber/doc/etc/.gitignore create mode 100644 lib/orber/doc/html/.gitignore create mode 100644 lib/orber/doc/javadoc/.gitignore create mode 100644 lib/orber/doc/man1/.gitignore create mode 100644 lib/orber/doc/man3/.gitignore create mode 100644 lib/orber/doc/pdf/.gitignore create mode 100644 lib/orber/doc/src/CosNaming.xml create mode 100644 lib/orber/doc/src/CosNaming_BindingIterator.xml create mode 100644 lib/orber/doc/src/CosNaming_NamingContext.xml create mode 100644 lib/orber/doc/src/CosNaming_NamingContextExt.xml create mode 100644 lib/orber/doc/src/Makefile create mode 100644 lib/orber/doc/src/Module_Interface.xml create mode 100644 lib/orber/doc/src/Orber/InitialReference.java create mode 100644 lib/orber/doc/src/Orber/Makefile create mode 100644 lib/orber/doc/src/Orber/ignore_config_record.inf create mode 100644 lib/orber/doc/src/any.xml create mode 100644 lib/orber/doc/src/book.gif create mode 100644 lib/orber/doc/src/book.xml create mode 100644 lib/orber/doc/src/ch_contents.xml create mode 100644 lib/orber/doc/src/ch_debugging.xml create mode 100644 lib/orber/doc/src/ch_example.xml create mode 100644 lib/orber/doc/src/ch_exceptions.xml create mode 100644 lib/orber/doc/src/ch_idl_to_erlang_mapping.xml create mode 100644 lib/orber/doc/src/ch_ifr.xml create mode 100644 lib/orber/doc/src/ch_install.xml create mode 100644 lib/orber/doc/src/ch_interceptors.xml create mode 100644 lib/orber/doc/src/ch_introduction.xml create mode 100644 lib/orber/doc/src/ch_naming_service.xml create mode 100644 lib/orber/doc/src/ch_orber_kernel.xml create mode 100644 lib/orber/doc/src/ch_orberweb.xml create mode 100644 lib/orber/doc/src/ch_security.xml create mode 100644 lib/orber/doc/src/ch_stubs.xml create mode 100644 lib/orber/doc/src/corba.xml create mode 100644 lib/orber/doc/src/corba_object.xml create mode 100644 lib/orber/doc/src/dataframe1.gif create mode 100644 lib/orber/doc/src/dataframe1.ps create mode 100644 lib/orber/doc/src/dataframe2.gif create mode 100644 lib/orber/doc/src/dataframe2.ps create mode 100644 lib/orber/doc/src/dataframe3.gif create mode 100644 lib/orber/doc/src/dataframe3.ps create mode 100644 lib/orber/doc/src/dataframe4.gif create mode 100644 lib/orber/doc/src/dataframe4.ps create mode 100644 lib/orber/doc/src/dataframe5.gif create mode 100644 lib/orber/doc/src/dataframe5.ps create mode 100644 lib/orber/doc/src/dataframe6.gif create mode 100644 lib/orber/doc/src/dataframe6.ps create mode 100644 lib/orber/doc/src/dataframe7.gif create mode 100644 lib/orber/doc/src/dataframe7.ps create mode 100644 lib/orber/doc/src/dataframe8.gif create mode 100644 lib/orber/doc/src/dataframe8.ps create mode 100644 lib/orber/doc/src/dependent.gif create mode 100644 lib/orber/doc/src/dependent.ps create mode 100644 lib/orber/doc/src/example_part.xml create mode 100644 lib/orber/doc/src/fascicules.xml create mode 100644 lib/orber/doc/src/firewall_nat.gif create mode 100644 lib/orber/doc/src/firewall_nat.ps create mode 100644 lib/orber/doc/src/fixed.xml create mode 100644 lib/orber/doc/src/ifr_notes.txt create mode 100644 lib/orber/doc/src/iiop.gif create mode 100644 lib/orber/doc/src/iiop.ps create mode 100644 lib/orber/doc/src/images/GridBagEx.gif create mode 100644 lib/orber/doc/src/images/OpenBookIcon.gif create mode 100644 lib/orber/doc/src/images/blue-ball-small.gif create mode 100644 lib/orber/doc/src/images/blue-ball.gif create mode 100644 lib/orber/doc/src/images/class-index.gif create mode 100644 lib/orber/doc/src/images/constructor-index.gif create mode 100644 lib/orber/doc/src/images/constructors.gif create mode 100644 lib/orber/doc/src/images/cyan-ball-small.gif create mode 100644 lib/orber/doc/src/images/cyan-ball.gif create mode 100644 lib/orber/doc/src/images/error-index.gif create mode 100644 lib/orber/doc/src/images/exception-index.gif create mode 100644 lib/orber/doc/src/images/green-ball-small.gif create mode 100644 lib/orber/doc/src/images/green-ball.gif create mode 100644 lib/orber/doc/src/images/interface-index.gif create mode 100644 lib/orber/doc/src/images/magenta-ball-small.gif create mode 100644 lib/orber/doc/src/images/magenta-ball.gif create mode 100644 lib/orber/doc/src/images/method-index.gif create mode 100644 lib/orber/doc/src/images/methods.gif create mode 100644 lib/orber/doc/src/images/package-index.gif create mode 100644 lib/orber/doc/src/images/red-ball-small.gif create mode 100644 lib/orber/doc/src/images/red-ball.gif create mode 100644 lib/orber/doc/src/images/variable-index.gif create mode 100644 lib/orber/doc/src/images/variables.gif create mode 100644 lib/orber/doc/src/images/yellow-ball-small.gif create mode 100644 lib/orber/doc/src/images/yellow-ball.gif create mode 100644 lib/orber/doc/src/interceptor_operations.gif create mode 100644 lib/orber/doc/src/interceptor_operations.ps create mode 100644 lib/orber/doc/src/interceptors.xml create mode 100644 lib/orber/doc/src/intro_part.xml create mode 100644 lib/orber/doc/src/lname.xml create mode 100644 lib/orber/doc/src/lname_component.xml create mode 100644 lib/orber/doc/src/make.dep create mode 100644 lib/orber/doc/src/menuframe.gif create mode 100644 lib/orber/doc/src/menuframe.ps create mode 100644 lib/orber/doc/src/name.gif create mode 100644 lib/orber/doc/src/name.ps create mode 100644 lib/orber/doc/src/naming_graph.ps create mode 100644 lib/orber/doc/src/notes.gif create mode 100644 lib/orber/doc/src/notes.xml create mode 100644 lib/orber/doc/src/notes_history.xml create mode 100644 lib/orber/doc/src/orber.gif create mode 100644 lib/orber/doc/src/orber.xml create mode 100644 lib/orber/doc/src/orber_acl.xml create mode 100644 lib/orber/doc/src/orber_diagnostics.xml create mode 100644 lib/orber/doc/src/orber_ifr.xml create mode 100644 lib/orber/doc/src/orber_tc.xml create mode 100644 lib/orber/doc/src/orbs.gif create mode 100644 lib/orber/doc/src/orbs.ps create mode 100644 lib/orber/doc/src/part.xml create mode 100644 lib/orber/doc/src/part_notes.xml create mode 100644 lib/orber/doc/src/part_notes_history.xml create mode 100644 lib/orber/doc/src/ref_man.gif create mode 100644 lib/orber/doc/src/ref_man.xml create mode 100644 lib/orber/doc/src/summary.html.src create mode 100644 lib/orber/doc/src/theORB.gif create mode 100644 lib/orber/doc/src/theORB.ps create mode 100644 lib/orber/doc/src/tools_debugging_part.xml create mode 100644 lib/orber/doc/src/user_guide.gif create mode 100644 lib/orber/ebin/.gitignore create mode 100644 lib/orber/examples/Makefile create mode 100644 lib/orber/examples/Stack/InitialReferences.idl create mode 100644 lib/orber/examples/Stack/Makefile create mode 100644 lib/orber/examples/Stack/StackClient.cc create mode 100644 lib/orber/examples/Stack/StackClient.java create mode 100644 lib/orber/examples/Stack/StackModule_StackFactory_impl.erl create mode 100644 lib/orber/examples/Stack/StackModule_Stack_impl.erl create mode 100644 lib/orber/examples/Stack/stack.idl create mode 100644 lib/orber/examples/Stack/stack_client.erl create mode 100644 lib/orber/examples/Stack/stack_factory.erl create mode 100644 lib/orber/include/Makefile create mode 100644 lib/orber/include/corba.hrl create mode 100644 lib/orber/include/ifr_types.hrl create mode 100644 lib/orber/include/orber_pi.hrl create mode 100644 lib/orber/info create mode 100644 lib/orber/java_src/Makefile create mode 100644 lib/orber/java_src/Orber/InitialReference.java create mode 100644 lib/orber/java_src/Orber/Makefile create mode 100644 lib/orber/prebuild.skip create mode 100755 lib/orber/priv/Makefile create mode 100644 lib/orber/priv/Orber/.gitignore create mode 100644 lib/orber/priv/bin/.gitignore create mode 100755 lib/orber/priv/blank.html create mode 100755 lib/orber/priv/info_frames.html create mode 100755 lib/orber/priv/main_frame.html create mode 100644 lib/orber/priv/obj/.gitignore create mode 100755 lib/orber/priv/orber.tool create mode 100755 lib/orber/priv/orber_help.txt create mode 100755 lib/orber/priv/start_info.html create mode 100644 lib/orber/src/CORBA.idl create mode 100644 lib/orber/src/Makefile create mode 100644 lib/orber/src/OrberApp_IFR_impl.erl create mode 100644 lib/orber/src/OrberCSIv2.asn1 create mode 100644 lib/orber/src/OrberCSIv2.set.asn create mode 100644 lib/orber/src/OrberIFR.idl create mode 100644 lib/orber/src/PKIX1Algorithms88.asn1 create mode 100644 lib/orber/src/PKIX1Explicit88.asn1 create mode 100644 lib/orber/src/PKIX1Implicit88.asn1 create mode 100644 lib/orber/src/PKIXAttributeCertificate.asn1 create mode 100644 lib/orber/src/any.erl create mode 100644 lib/orber/src/cdr_decode.erl create mode 100644 lib/orber/src/cdr_encode.erl create mode 100644 lib/orber/src/cdrlib.erl create mode 100644 lib/orber/src/corba.erl create mode 100644 lib/orber/src/corba_boa.erl create mode 100644 lib/orber/src/corba_nvlist.erl create mode 100644 lib/orber/src/corba_object.erl create mode 100644 lib/orber/src/corba_request.erl create mode 100644 lib/orber/src/fixed.erl create mode 100644 lib/orber/src/ifr_objects.hrl create mode 100644 lib/orber/src/iop_ior.erl create mode 100644 lib/orber/src/orber.app.src create mode 100644 lib/orber/src/orber.appup.src create mode 100644 lib/orber/src/orber.erl create mode 100644 lib/orber/src/orber_acl.erl create mode 100644 lib/orber/src/orber_diagnostics.erl create mode 100644 lib/orber/src/orber_env.erl create mode 100644 lib/orber/src/orber_exceptions.erl create mode 100644 lib/orber/src/orber_ifr.erl create mode 100644 lib/orber/src/orber_ifr.hrl create mode 100644 lib/orber/src/orber_ifr_aliasdef.erl create mode 100644 lib/orber/src/orber_ifr_arraydef.erl create mode 100644 lib/orber/src/orber_ifr_attributedef.erl create mode 100644 lib/orber/src/orber_ifr_constantdef.erl create mode 100644 lib/orber/src/orber_ifr_contained.erl create mode 100644 lib/orber/src/orber_ifr_container.erl create mode 100644 lib/orber/src/orber_ifr_enumdef.erl create mode 100644 lib/orber/src/orber_ifr_exceptiondef.erl create mode 100644 lib/orber/src/orber_ifr_fixeddef.erl create mode 100644 lib/orber/src/orber_ifr_idltype.erl create mode 100644 lib/orber/src/orber_ifr_interfacedef.erl create mode 100644 lib/orber/src/orber_ifr_irobject.erl create mode 100644 lib/orber/src/orber_ifr_moduledef.erl create mode 100644 lib/orber/src/orber_ifr_operationdef.erl create mode 100644 lib/orber/src/orber_ifr_orb.erl create mode 100644 lib/orber/src/orber_ifr_primitivedef.erl create mode 100644 lib/orber/src/orber_ifr_repository.erl create mode 100644 lib/orber/src/orber_ifr_sequencedef.erl create mode 100644 lib/orber/src/orber_ifr_stringdef.erl create mode 100644 lib/orber/src/orber_ifr_structdef.erl create mode 100644 lib/orber/src/orber_ifr_typecode.erl create mode 100644 lib/orber/src/orber_ifr_typedef.erl create mode 100644 lib/orber/src/orber_ifr_uniondef.erl create mode 100644 lib/orber/src/orber_ifr_utils.erl create mode 100644 lib/orber/src/orber_ifr_wstringdef.erl create mode 100644 lib/orber/src/orber_iiop.erl create mode 100644 lib/orber/src/orber_iiop.hrl create mode 100644 lib/orber/src/orber_iiop_inproxy.erl create mode 100644 lib/orber/src/orber_iiop_inrequest.erl create mode 100644 lib/orber/src/orber_iiop_insup.erl create mode 100644 lib/orber/src/orber_iiop_net.erl create mode 100644 lib/orber/src/orber_iiop_net_accept.erl create mode 100644 lib/orber/src/orber_iiop_outproxy.erl create mode 100644 lib/orber/src/orber_iiop_outsup.erl create mode 100644 lib/orber/src/orber_iiop_pm.erl create mode 100644 lib/orber/src/orber_iiop_socketsup.erl create mode 100644 lib/orber/src/orber_iiop_tracer.erl create mode 100644 lib/orber/src/orber_iiop_tracer_silent.erl create mode 100644 lib/orber/src/orber_iiop_tracer_stealth.erl create mode 100644 lib/orber/src/orber_initial_references.erl create mode 100644 lib/orber/src/orber_interceptors.erl create mode 100644 lib/orber/src/orber_objectkeys.erl create mode 100644 lib/orber/src/orber_pi.erl create mode 100644 lib/orber/src/orber_request_number.erl create mode 100644 lib/orber/src/orber_socket.erl create mode 100644 lib/orber/src/orber_tb.erl create mode 100644 lib/orber/src/orber_tc.erl create mode 100644 lib/orber/src/orber_typedefs.erl create mode 100644 lib/orber/src/orber_web.erl create mode 100644 lib/orber/src/orber_web_server.erl create mode 100644 lib/orber/vsn.mk create mode 100644 make/lazy_configure.mk create mode 100755 make/make_emakefile create mode 100644 make/otp.mk.in create mode 100644 make/otp_ded.mk.in create mode 100644 make/otp_release_targets.mk create mode 100644 make/otp_subdir.mk create mode 100644 make/run_make.mk create mode 100755 make/save_args create mode 100644 make/target.mk diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..5cdce5a --- /dev/null +++ b/AUTHORS @@ -0,0 +1,13 @@ +AUTHORS + + Contributions - improvements, fixes, new features - from developers + make the Erlang 'Open Source' project a success. To give credit + where it's due, we've added a file called AUTHORS to each + application sub-directory with a list of everyone who has contributed + It might also contain the names of the original authors at Ericsson. + + Speaking of original authors, we don't want to forget all the people + working full time with Erlang and OTP. So, thanks to everyone + working with Erlang at the OTP group, the Computer Science + Laboratory and the Software Architecture Laboratory. + diff --git a/lib/cosEvent/AUTHORS b/lib/cosEvent/AUTHORS new file mode 100644 index 0000000..624d275 --- /dev/null +++ b/lib/cosEvent/AUTHORS @@ -0,0 +1,5 @@ +Original Authors: +Niclas Eklund + +Contributors: + diff --git a/lib/cosEvent/Makefile b/lib/cosEvent/Makefile new file mode 100644 index 0000000..4fa0b49 --- /dev/null +++ b/lib/cosEvent/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(COSEVENT_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk + diff --git a/lib/cosEvent/doc/html/.gitignore b/lib/cosEvent/doc/html/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEvent/doc/man3/.gitignore b/lib/cosEvent/doc/man3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEvent/doc/man6/.gitignore b/lib/cosEvent/doc/man6/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEvent/doc/pdf/.gitignore b/lib/cosEvent/doc/pdf/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin.xml new file mode 100644 index 0000000..25f2dc8 --- /dev/null +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin.xml @@ -0,0 +1,81 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventChannelAdmin + + + + + + 1997-11-13 + PA1 + CosEventChannelAdmin.xml +
+ CosEventChannelAdmin + The CosEventChannelAdmin defines a set if event service interfaces that enables decoupled asynchronous communication between objects and implements generic (untyped) version of the OMG COSS standard event service. + +

The event service defines two roles for objects: the supplier role and + the consumer role. Suppliers supply event data to the event channel and + consumers receive event data from the channel. Suppliers do not need to + know the identity of the consumers, and vice versa. Consumers and + suppliers are connected to the event channel via proxies, which are managed + by ConsumerAdmin and SupplierAdmin objects.

+

There are four general models of communication. These are:

+ + The canonical push model. It allows the suppliers of events to initiate the + transfer of event data to consumers. Event channels play the role of + . Active suppliers use event channel to push data to + passive consumers registered with the event channel. + The canonical pull model. It allows consumers to request events from + suppliers. Event channels play the role of since they + procure events on behalf of consumers. Active consumers can explicitly + pull data from passive suppliers via the event channels. + The hybrid push/pull model. It allows consumers request events queued at + a channel by suppliers. Event channels play the role of . + Active consumers explicitly pull data deposited by active suppliers via + the event channels. + The hybrid pull/push model. It allows the channel to pull events from + suppliers and push them to consumers. Event channels play the role of + . Active event channels can pull data from + passive suppliers to push it to passive consumers. + +

To get access to all definitions, e.g., exceptions, + include necessary files by using:

+

There are seven different interfaces supported in the service:

+ + ProxyPushConsumer + ProxyPullSupplier + ProxyPullConsumer + ProxyPushSupplier + ConsumerAdmin + SupplierAdmin + EventChannel + +

IDL specification for CosEventChannelAdmin:

+ +
+ +
+ diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml new file mode 100644 index 0000000..e579d6f --- /dev/null +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml @@ -0,0 +1,73 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventChannelAdmin_­ConsumerAdmin + ..._ConsumerAdmin + + + + + + 1997-11-13 + PA1 + CosEventChannelAdmin_ConsumerAdmin.xml +
+ CosEventChannelAdmin_ConsumerAdmin + This module implements a ConsumerAdmin interface, which allows consumers to be connected to the event channel. + +

The ConsumerAdmin interface defines the first step for connecting consumers + to the event channel. It acts as a factory for creating proxy suppliers. + Both consumer administration and supplier administration are defined as separate + objects so that the creator of the channel can control the addition of + suppliers and consumers.

+

To get access to all definitions include necessary files by using:

+
+ + + obtain_push_supplier(Object) -> Return + Create a ProxyPushSupplier object + + Object = #objref + Return = #objref + + +

This operation returns a ProxyPushSupplier object reference.

+
+
+ + obtain_pull_supplier(Object) -> Return + Create a ProxyPullSupplier object + + Object = #objref + Return = #objref + + +

This operation returns a ProxyPullSupplier object reference.

+
+
+
+ +
+ diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml new file mode 100644 index 0000000..809bf89 --- /dev/null +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml @@ -0,0 +1,95 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventChannelAdmin_­EventChannel + ..._EventChannel + + + + + + 1997-11-13 + PA1 + CosEventChannelAdmin_EventChannel.xml +
+ CosEventChannelAdmin_EventChannel + This module implements an Event Channel interface, which plays the role of a mediator between consumers and suppliers. + +

An event channel is an object that allows multiple suppliers to communicate + with multiple consumers in a highly decoupled, asynchronous manner. The event + channel is built up incrementally. When an event channel is + created no suppliers or consumers are connected to it. Event Channel can + implement group communication by serving as a replicator, broadcaster, or + multicaster that forward events from one or more suppliers to multiple + consumers.

+

It is up to the user to decide when an event channel is created and how + references to the event channel are obtained. By representing the event + channel as an object, it has all of the properties that apply to objects. + One way to manage an event channel is to register it in a naming context, + or export it through an operation on an object.

+

To get access to all definitions include necessary files by using:

+

Any object that possesses an object reference that supports the ProxyPullConsumer + interface can perform the following operations:

+
+ + + for_consumers(Object) -> Return + Return a ConsumerAdmin object + + Object = #objref + Return = #objref + + +

This operation returns a ConsumerAdmin object reference. If ConsumerAdmin + object does not exist already it creates one.

+
+
+ + for_suppliers(Object) -> Return + Return a SupplierAdmin object + + Object = #objref + Return = #objref + + +

This operation returns a SupplierAdmin object reference. If SupplierAdmin + object does not exist already it creates one.

+
+
+ + destroy(Object) -> Return + Destroy the event channel + + Object = #objref + Return = #objref + + +

+
+
+
+ +
+ diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml new file mode 100644 index 0000000..811c861 --- /dev/null +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml @@ -0,0 +1,85 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventChannelAdmin_­ProxyPullConsumer + ..._ProxyPullConsumer + + + + + + 1997-11-13 + PA1 + CosEventChannelAdmin_ProxyPullConsumer.xml +
+ CosEventChannelAdmin_ProxyPullConsumer + This module implements a ProxyPullConsumer interface which acts as a middleman between pull supplier and the event channel. + +

The ProxyPullConsumer interface defines the second step for connecting pull + suppliers to the event channel. A proxy consumer is similar to a normal consumer, + but includes an additional method for connecting a supplier to the proxy + consumer.

+

To get access to all definitions, e.g., exceptions, + include necessary files by using:

+

Any object that possesses an object reference that supports the ProxyPullConsumer + interface can perform the following operations:

+
+ + + connect_pull_supplier(Object, PullSupplier) -> Return + Connect the pull supplier to the proxy pull consumer + + Object = #objref + PullSupplier = #objref of PullSupplier type + Return = ok | {'EXCEPTION', E} + E = #'CosEventChannelAdmin_AlreadyConnected'{} | #'CosEventChannelAdmin_TypeError'{} + + +

This operation connects PullSupplier object to the ProxyPullConsumer object. + If a nil object reference is passed CORBA standard exception + is raised. If the ProxyPullConsumer is already connected to a PullSupplier, + then the exception is raised. + Implementations of ProxyPullConsumers may require additional interface + functionality; if these requirements are not met the + exception will be raised.

+
+
+ + disconnect_pull_consumer(Object) -> Return + Disconnect the ProxyPullConsumer object from the event channel. + + Object = #objref + Return = ok + + +

This operation disconnects proxy pull consumer from the event channel and + sends a notification about the loss of the connection to the pull supplier + attached to it.

+
+
+
+ +
+ diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml new file mode 100644 index 0000000..6c22c5e --- /dev/null +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml @@ -0,0 +1,112 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventChannelAdmin_­ProxyPullSupplier + ..._ProxyPullSupplier + + + + Lars Thors + + 1997-11-13 + PA1 + CosEventChannelAdmin_ProxyPullSupplier.xml +
+ CosEventChannelAdmin_ProxyPullSupplier + This module implements a ProxyPullSupplier interface which acts as a middleman between pull consumer and the event channel. + +

The ProxyPullSupplier interface defines the second step for connecting pull consumers to the event channel. A proxy supplier is similar to a normal supplier, + but includes an additional method for connecting a consumer to the proxy + supplier.

+

To get access to all definitions, e.g., exceptions, + include necessary files by using:

+

Any object that possesses an object reference that supports the ProxyPullSupplier + interface can perform the following operations:

+
+ + + connect_pull_consumer(Object, PullConsumer) -> Return + Connect the pull consumer to the proxy pull supplier + + Object = #objref + PullConsumer = #objref of PullConsumer type + Return = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} + + +

This operation connects PullConsumer object to the ProxyPullSupplier object. + A nil object reference can be passed to this operation. If so a channel + cannot invoke the disconnect_pull_consumer operation on the consumer; + the consumer may be disconnected from the channel without being + informed. If the ProxyPullSupplier is already connected to a + PullConsumer, then the + exception is raised.

+
+
+ + disconnect_pull_supplier(Object) -> Return + Disconnect the ProxyPullSupplier object from the event channel. + + Object = #objref + Return = ok + + +

This operation disconnects proxy pull supplier from the event channel. + It sends a notification about the loss of the connection to the pull consumer + attached to it, unless nil object reference was passed at the connection + time.

+
+
+ + pull(Object) -> Return + Transmit data from suppliers to consumers. + + Object = #objref + Return = any + + +

This operation blocks until the event data is available or the + exception is raised. + It returns the event data to the consumer.

+
+
+ + try_pull(Object) -> Return + Transmit data from suppliers to consumers. + + Object = #objref + Return = {any, bool()} + + +

This operation does not block: if the event data is available, it returns + the event data and sets the data availability flag to true; otherwise + it returns a long with an undefined value and sets the data availability to + false. If the event communication has already been disconnected, the + exception is raised.

+
+
+
+ +
+ diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml new file mode 100644 index 0000000..2b50f88 --- /dev/null +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml @@ -0,0 +1,99 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventChannelAdmin_­ProxyPushConsumer + ..._ProxyPushConsumer + + + + + + 1997-11-13 + PA1 + CosEventChannelAdmin_ProxyPushConsumer.xml +
+ CosEventChannelAdmin_ProxyPushConsumer + This module implements a ProxyPushConsumer interface which acts as a middleman between push supplier and the event channel. + +

The ProxyPushConsumer interface defines the second step for connecting push + suppliers to the event channel. A proxy consumer is similar to a normal consumer, + but includes an additional method for connecting a supplier to the proxy + consumer.

+

To get access to all definitions, e.g., exceptions, + include necessary files by using:

+

Any object that possesses an object reference that supports the ProxyPushConsumer + interface can perform the following operations:

+
+ + + connect_push_supplier(Object, PushSupplier) -> Return + Connect the push supplier to the proxy push consumer + + Object = #objref + PushSupplier = #objref of PushSupplier type + Return = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} + + +

This operation connects PushSupplier object to the ProxyPushConsumer object. + A nil object reference can be passed to this operation. If so a channel + cannot invoke the disconnect_push_supplier operation on the supplier; + the supplier may be disconnected from the channel without being + informed. If the ProxyPushConsumer is already connected to a + PushSupplier, then the + exception is raised.

+
+
+ + disconnect_push_consumer(Object) -> Return + Disconnect the ProxyPushConsumer object from the event channel. + + Object = #objref + Return = ok + + +

This operation disconnects proxy push consumer from the event channel. + Sends a notification about the loss of the connection to the push supplier + attached to it, unless nil object reference was passed at the connection + time.

+
+
+ + push(Object, Data) -> Return + Communicate event data to the consumers. + + Object = #objref + Data = any + Return = ok | {'EXCEPTION', #'CosEventComm_Disconnected'{}} + + +

This operation sends event data to all connected consumers via the + event channel. If the event communication has already been disconnected, + the is raised.

+
+
+
+ +
+ diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml new file mode 100644 index 0000000..cda162f --- /dev/null +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml @@ -0,0 +1,85 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventChannelAdmin_­ProxyPushSupplier + ..._ProxyPushSupplier + + + + + + 1997-11-13 + PA1 + CosEventChannelAdmin_ProxyPushSupplier.xml +
+ CosEventChannelAdmin_ProxyPushSupplier + This module implements a ProxyPushSupplier interface which acts as a middleman between push consumer and the event channel. + +

The ProxyPushSupplier interface defines the second step for connecting push + consumers to the event channel. A proxy supplier is similar to a normal supplier, + but includes an additional method for connecting a consumer to the proxy + supplier.

+

To get access to all definitions, e.g., exceptions, + include necessary files by using:

+

Any object that possesses an object reference that supports the ProxyPushSupplier + interface can perform the following operations:

+
+ + + connect_push_consumer(Object, PushConsumer) -> Return + Connect the push consumer to the proxy push supplier + + Object = #objref + PushConsumer = #objref of PushConsumer type + Return = ok | {'EXCEPTION', E} + E = #'CosEventChannelAdmin_AlreadyConnected'{} | #'CosEventChannelAdmin_TypeError'{} + + +

This operation connects PushConsumer object to the ProxyPushSupplier object. + If a nil object reference is passed CORBA standard exception + is raised. If the ProxyPushSupplier is already connected to a PushConsumer, + then the exception is raised. + Implementations of ProxyPushSuppliers may require additional interface + functionality; if these requirements are not met the + exception will be raised.

+
+
+ + disconnect_push_supplier(Object) -> Return + Disconnect the ProxyPushSupplier object from the event channel. + + Object = #objref + Return = ok + + +

This operation disconnects proxy push supplier from the event channel and + sends a notification about the loss of the connection to the push consumer + attached to it.

+
+
+
+ +
+ diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml new file mode 100644 index 0000000..abcd7b6 --- /dev/null +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml @@ -0,0 +1,73 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventChannelAdmin_­SupplierAdmin + ..._SupplierAdmin + + + + + + 1997-11-13 + PA1 + CosEventChannelAdmin_SupplierAdmin.xml +
+ CosEventChannelAdmin_SupplierAdmin + This module implements a SupplierAdmin interface, which allows suppliers to be connected to the event channel. + +

The SupplierAdmin interface defines the first step for connecting suppliers + to the event channel. It acts as a factory for creating proxy consumers. + Both consumer administration and supplier administration are defined as separate + objects so that the creator of the channel can control the addition of + suppliers and consumers.

+

To get access to all definitions include necessary files by using:

+
+ + + obtain_push_consumer(Object) -> Return + Create a ProxyPushConsumer object + + Object = #objref + Return = #objref + + +

This operation returns a ProxyPushConsumer object reference.

+
+
+ + obtain_pull_consumer(Object) -> Return + Create a ProxyPullConsumer object + + Object = #objref + Return = #objref + + +

This operation returns a ProxyPullConsumer object reference.

+
+
+
+ +
+ diff --git a/lib/cosEvent/doc/src/Makefile b/lib/cosEvent/doc/src/Makefile new file mode 100644 index 0000000..5136c7c --- /dev/null +++ b/lib/cosEvent/doc/src/Makefile @@ -0,0 +1,230 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(COSEVENT_VSN) +APPLICATION=cosEvent +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + CosEventChannelAdmin.xml \ + CosEventChannelAdmin_ConsumerAdmin.xml \ + CosEventChannelAdmin_SupplierAdmin.xml \ + CosEventChannelAdmin_EventChannel.xml \ + CosEventChannelAdmin_ProxyPullConsumer.xml \ + CosEventChannelAdmin_ProxyPullSupplier.xml \ + CosEventChannelAdmin_ProxyPushConsumer.xml \ + CosEventChannelAdmin_ProxyPushSupplier.xml \ + cosEventApp.xml + +XML_PART_FILES = \ + part.xml \ + part_notes.xml +XML_CHAPTER_FILES = \ + ch_contents.xml \ + ch_introduction.xml \ + ch_event_service.xml \ + notes.xml + +BOOK_FILES = book.xml + +TECHNICAL_DESCR_FILES = + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif \ + e_s_components.gif \ + e_s_models.gif + + +PS_FILES = + + +# ---------------------------------------------------- + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf + +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + rm -f $(JD_HTML) $(JD_PACK) + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(INTERNAL_HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTML_FILES) $(MAN3_FILES) + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) +endif + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +$(INDEX_TARGET): $(INDEX_SRC) + sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 + +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + +release_spec: + diff --git a/lib/cosEvent/doc/src/book.gif b/lib/cosEvent/doc/src/book.gif new file mode 100644 index 0000000000000000000000000000000000000000..94b38687920c5386f0d90df2cfc962d66f52fbce GIT binary patch literal 1081 zcmV-91jhSENk%v~VJrYQ0K@U3Z&d%1>*52OU z=jZ3|@9+2b_W%F@EC2ui04xAE000I5ARvxpX`Uh%Eez$Ma2!{|XMe{g?|T;9x5JA^ zG%bL@N^vRj5RkV9bLkO4ZPIBmas5oR#mf&V1Q#(0YhcjmXe*9~d=7a)?vMy(=-KE* z8yQRzT~`AL3l4P-3kL!Lf=d(yg_TGJLq#4K5D7Jwg%4&P850c&1Y@8d0)H_S5pFPj z7ZR$K4m$^o4iXXx39coCpaZff8wUU$784g63O)Mnh1d zM*Ony;LwB#3?8W4Fn~dfDxggNp6C!kf(B*{AQb3^!o#OZ2{2Ij__0FI3O->S0!o2G zg@f-96evKTsnY>a2Pj~$%K;+++!`!k(;yCksSK!^1M@%uPY44fe1t$i?MDI+c2ZbC za|F=4KrQICaN${m0^A%h5YV8o0a~3adU`fEQr`1qssBIw;^v!UF;k;yW-v@4+eo>JYd}fHVVU z5gLf*p9x%mVi^DlSTI8WPNw|_zy%J@^^O%t7;wu6|1F@62n+%+n+O+(7C~JYKp}tz zPXIAiOdhnDfD0a6fWQkLNGO6;!$2WQfj6jx)&W2YPymny2!Ox=N)36z-FBgSXr4c6dN%+LI-06;0gjrH4CDHEr=iiO;mnh?Fk3i5Wq1C#9AnbqG>3C zxFaCoE>b2iV1odev}UfA7}V< + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEvent + + + 1998-04-25 + 1.0 + book.xml +
+ + + cosEvent + + + + + + + + + + + + + + +
+ diff --git a/lib/cosEvent/doc/src/ch_contents.xml b/lib/cosEvent/doc/src/ch_contents.xml new file mode 100644 index 0000000..bc2838b --- /dev/null +++ b/lib/cosEvent/doc/src/ch_contents.xml @@ -0,0 +1,70 @@ + + + + +
+ + 1999 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + The cosEvent Application + Niclas Eklund + + 1999-09-17 + B + ch_contents.xml +
+ +
+ Content Overview +

The cosEvent documentation is divided into three sections: +

+ + +

PART ONE - The User's Guide +

Description of the cosEvent Application including + services and a small tutorial demonstrating + the development of a simple service.

+
+ +

PART TWO - Release Notes +

A concise history of cosEvent.

+
+ +

PART THREE - The Reference Manual +

A quick reference guide, including a + brief description, to all the functions available in cosEvent.

+
+
+
+ +
+ Brief Description of the User's Guide +

The User's Guide contains the following parts:

+ + +

CosEvent overview

+
+ +

CosEvent installation and examples

+
+
+
+
+ diff --git a/lib/cosEvent/doc/src/ch_event_service.xml b/lib/cosEvent/doc/src/ch_event_service.xml new file mode 100644 index 0000000..c65f676 --- /dev/null +++ b/lib/cosEvent/doc/src/ch_event_service.xml @@ -0,0 +1,221 @@ + + + + +
+ + 19972009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Event Service + + + 97-11-19 + A + ch_es_intro.xml +
+ +
+ Overview of the CosEvent Service +

The Event service allows programmers to subscribe to + information channels. Suppliers can generate events without knowing the + consumer identities and the consumer can receive events without knowing + the supplier identity. Both push and pull event delivery are supported. + The Event service will queue information and processes. +

+

The CORBA Event service provides a flexible model for + asynchronous, decoupled communication between objects. This + chapter outlines communication models and the roles and + relationships of key components in the CosEvent service. It + shows a simple example on use of this service.

+
+ +
+ Event Service Components +

There are five components in the OMG CosEvent service architecture. These + are described below:

+ + + +Figure 1: Event service Components + + + Suppliers and consumers: Consumers are the ultimate targets of + events generated by suppliers. Consumers and suppliers can both play active + and + passive roles. There could be two types of consumers and suppliers: push + or pull. A PushSupplier object can actively push an event to a passive + PushConsumer object. Likewise, a PullSupplier object can passively + wait for a PullConsumer object to actively pull an event from it. + EventChannel: The central abstraction in the CosEvent service is the + EventChannel which plays the role of a mediator between consumers and + suppliers. Consumers and suppliers register their interest with the + EventChannel. It can provide many-to-many communication. The channel + consumes events from one or more suppliers, and supplies events to one + or more consumers. An EventChannel can support consumers and suppliers + using different communication models. + ProxySuppliers and ProxyConsumers: ProxySuppliers act as middlemen + between consumers and the EventChannel. A ProxySupplier is similar to + a normal supplier, but includes an additional method for connecting a + consumer to the ProxySupplier. Likewise, ProxyConsumers act as + middlemen between suppliers and the EventChannel. A ProxyConsumer is + similar to a normal consumer, but includes an additional method for + connecting a supplier to the ProxyConsumer. + Supplier and consumer administrations: Consumer administration acts as + a factory for creating ProxySuppliers. Supplier administration acts as + a factory for creating ProxyConsumers. + +
+ +
+ Event Service Communication Models +

There are four general models of component collaboration in the OMG CosEvent service + architecture. The following describes these models: + (Please note that proxies are not shown in the diagrams for simplicity).

+ + + +Figure 2: Event service Communication Models + + + The Canonical Push Model: The Canonical push model shown in figure 2(A) allows + the suppliers of events to initiate the transfer of event data to consumers. + In this model, suppliers are active initiators and consumers are the passive + targets of the requests. EventChannels play the role of . + Thus, active suppliers use EventChannels to push data to passive consumers that + have registered with the EventChannels. + The Canonical Pull Model:The Canonical pull model shown + in figure 2(B) + allows consumers to request events from suppliers. In this model, + Consumers are + active initiators and suppliers are the passive targets of the pull + requests. + EventChannel plays the role of since it procures + events + on behalf of consumers. Thus, active consumers can explicitly pull + data + from passive suppliers via the EventChannels. + The Hybrid Push/Pull Model: The push/pull model shown in figure 2(C) is a + hybrid that allows consumers to request events queued at an EventChannel + by suppliers. In this model, both suppliers and consumers are active + initiators of the requests. EventChannels play the role of . + Thus, active consumers can explicitly pull data deposited by active + suppliers via the EventChannels. + The Hybrid Pull/Push Model: The pull/push model shown in figure 2(D) is another + hybrid that allows the channel to pull events from suppliers and push them + to consumers. In this model, suppliers are passive targets of pull requests + and consumers are passive targets of pushes. EventChannels play the role of + . Thus, active EventChannels can pull data from + passive suppliers and push that data to passive consumers. + +
+ +
+ A Tutorial on How to Create a Simple Service +

To be able to use the cosEvent application supplier and consumer objects + must be implemented, which must inherit from the appropriate interface + defined in the CosEventComm.idl specification.

+

We start by creating an interface which inherits from the correct interface, + e.g., CosEventComm::PushConsumer. Hence, we must also implement all + operations defined in the PushConsumer interface. The IDL-file could look like: +

+ + +module myClientImpl { + + interface ownInterface:CosEventComm::PushConsumer { + + void ownFunctions(in any NeededArguments) + raises(OwnExceptions); + + }; +}; + +#endif + ]]> +

Run the IDL compiler on this file by calling the function. + This will produce the API named . + After generating the API stubs and the server skeletons it is time to + implement the servers and if no special options are sent + to the IDl compiler the file name is .

+
+ +
+ How to Run Everything +

Below is a short transcript on how to run cosEvent.

+ +

The example above, exemplifies a event system, i.e., the Canonical Push Model, where the Supplier client in some way generates event + and pushes them to the proxy. The push supplier proxies will eventually + push the events to each Consumer client.

+
+
+ diff --git a/lib/cosEvent/doc/src/ch_introduction.xml b/lib/cosEvent/doc/src/ch_introduction.xml new file mode 100644 index 0000000..8f948a5 --- /dev/null +++ b/lib/cosEvent/doc/src/ch_introduction.xml @@ -0,0 +1,56 @@ + + + + +
+ + 1999 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + Introduction to cosEvent + Niclas Eklund + + 1999-09-17 + + ch_introduction.xml +
+ +
+ Overview +

The cosEvent application is a Event Service compliant with the OMG + Event Service CosEvent. +

+ +
+ Purpose and Dependencies +

CosEvent is dependent on Orber, which provides CORBA functionality in an Erlang environment.

+
+ +
+ Prerequisites +

To fully understand the concepts presented in the + documentation, it is recommended that the user is familiar + with distributed programming and CORBA. +

+

Recommended reading includes CORBA, Fundamentals and Programming - Jon Siegel and Open Telecom Platform Documentation Set. It is also helpful to have read + Concurrent Programming in Erlang.

+
+
+
+ diff --git a/lib/cosEvent/doc/src/cosEventApp.xml b/lib/cosEvent/doc/src/cosEventApp.xml new file mode 100644 index 0000000..d83f44a --- /dev/null +++ b/lib/cosEvent/doc/src/cosEventApp.xml @@ -0,0 +1,168 @@ + + + + +
+ + 2001 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + cosEventApp + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-01-31 + PA1 + cosEventApp.xml +
+ cosEventApp + The main module of the cosEvent application. + +

To get access to the record definitions for the structures use:

+

This module contains the functions for starting and stopping the application.

+
+ + + install() -> Return + Install the cosEvent application + + Return = ok | {'EXCEPTION', E} | {'EXIT', R} + + +

This operation installs the cosEvent application.

+
+
+ + uninstall() -> Return + Uninstall the cosEvent application + + Return = ok | {'EXCEPTION', E} | {'EXIT', R} + + +

This operation uninstalls the cosEvent application.

+
+
+ + start() -> Return + Start the cosEvent application + + Return = ok | {error, Reason} + + +

This operation starts the cosEvent application.

+
+
+ + stop() -> Return + Stop the cosEvent application + + Return = ok | {error, Reason} + + +

This operation stops the cosEvent application.

+
+
+ + start_channel() -> Channel + Start a channel with default settings + + Channel = #objref + + +

This operation creates a new instance of a + Event Channel + using the default settings.

+
+
+ + start_channel(Options) -> Channel + Start a channel with settings defined by the given options + + Options = [Option] + Option = {pull_interval, Seconds} | {typecheck, Boolean} | {maxEvents, Integer} | {blocking, Boolean} + Channel = #objref + + +

This operation creates a new instance of a + Event Channel

+

+ + - determine how often Proxy Pull + Consumers will check for new events with the client application. The + default value is 20 seconds. + - if this option is set to true the + proxies will check if the supplied client object is of correct type. + The default value is false. + - this option determine how many events + the will store before discarding events. + If the limit is reached events will be discarded in any order. + The default value is 300. + - this option determine the behavior of + the channel when handling events internally. If set to the + risk of a single event supplier floods the system is reduced, but + the performance may also be reduced. + The default value is . + +
+
+ + start_channel_link() -> Channel + Start a channel, which is linked to the invoking process, with default settings + + Channel = #objref + + +

This operation creates a new instance of a + Event Channel, + which is linked to the invoking process, using the default settings.

+
+
+ + start_channel_link(Options) -> Channel + Start a channel, which is linked to the invoking process, with settings defined by the given options + + Options = [Option] + Option = {pull_interval, Seconds} | {typecheck, Boolean} | {maxEvents, Integer} | {blocking, Boolean} + Channel = #objref + + +

This operation creates a new instance of a + Event Channel, + which is linked to the invoking process, with settings defined by the + given options. Allowed options are the same as for + .

+
+
+ + stop_channel(Channel) -> Reply + Terminate the target object + + Channel = #objref + Reply = ok | {'EXCEPTION', E} + + +

This operation stop the target event channel.

+
+
+
+ +
+ diff --git a/lib/cosEvent/doc/src/e_s_components.gif b/lib/cosEvent/doc/src/e_s_components.gif new file mode 100644 index 0000000000000000000000000000000000000000..a448c14ce0d787da689e059c2663560bb5401f78 GIT binary patch literal 4458 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 literal 0 HcmV?d00001 diff --git a/lib/cosEvent/doc/src/e_s_models.gif b/lib/cosEvent/doc/src/e_s_models.gif new file mode 100644 index 0000000000000000000000000000000000000000..329b0858d11d1447a28ff685ea2e01dd8190b448 GIT binary patch literal 10354 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 h!oHmTzP!!8g7>~+Xs{{i1B_S*me literal 0 HcmV?d00001 diff --git a/lib/cosEvent/doc/src/e_s_models.ps b/lib/cosEvent/doc/src/e_s_models.ps new file mode 100644 index 0000000000000000000000000000000000000000..3e2a8dd9a256a55c7d5548dfb3310cedec3ec4d0 GIT binary patch literal 49664 zcmeHQU6129c76A+P#zjdfXtL_*^)JHna%D)o(9>)B0vx<^g;C)s4f@mn%S8I`R_UR z^83?r+X!Y6s~Z+Ykw=G@SLEd-#rpJjKm75Vf1XZ*_-6aG<&~ zzN=owSJ9ux{vuvZAMY=($Kl+ckK*!jIuGLfGM&bk%Xxeef4ThS%V`p?mv7%M$o;#s z=s!;9@2Y?QbMYJ(>ey#rX^y6Fg{kflB z#jnWz{pqK->G<~f`_nJqRZX>No2pswt6jIp%^&*D;sOW+|K&9P^hLaV{NeQWarq7r zzki#4cltt6!~$18oKLT(&nuM;xsY%5sXB`<;tL8;ozBP4$G85qx_tB>VufNIKXb6U z^goMg5;G+qemcHRRbPFGFYhM^;MZz8jvpu#f~)PCuc|=+iBcoe@l62nj3QJYr|QQO z=e~^n+biz;{iXWr>HP6yb(*WG|L9jQ@5f)NcCT}&hiaJjeiYSwI#(l#Lcec6ONm}q zFQ3o-ua|1ybxz)@`cz#^CQ4D^$*-cKXRlt~@UYiQ1=1+n%lY$ge4BnzmmvRo`YXip zD&`M7>HH?nD=GhvbN_aEB^e>n<@jHM*dM>3E~#E*#->&N|LQIHdbwp*6dR&Y&s5D3^E9y)C{!UW-(nFfRtp0;; zuJP|1O2LT#xmx}A_|y4}I-idyCCL)nH~lDnQ8n;>djFplQ(esuIvxxp9*p;ZQc6Zo zV#`JOl-P1v$&^otJtdZrz=IpaXFHaWb0YfrRwjf}jCx9}D4xVkEwOR^m}B)AnDv^0 zYO$IUq`xK#1?|2jUzCR>Hav+%g2_faC6*OU=EhTE8Np_#UbB;6^Y#f^&|#q-6Z_K6^XH?*RC$uVvbOG(Tcg9=OsE;f|}Ru zT-O7^9o9@~L^g9UF{Uag*iQ2hp-C%~vuNedK?w;x4D&Fcka;MV*un6zA*mQl zI7dvZrHI$mh$vzfz=jw~U1o?mP!2H%VzyzH7#=Owjo3Ezejwqy@)xF2qmU$Kv(G-1 z;L12`hC?^>kbfS^5*v-Ys7?;_Lx&_rA`_coKWsx{mKUXv#PU!Fr6q@EiivqpD=IIW z)}G4Gv%VCN6^cBpYkOeBbTP%D9KM2saPf%sR~ zmLsuwXzP&J=wv}~Bw__9EwL0aA8Iw@nuvuxoO*p!RZ^kFjH(QY;T83cRXcYDD5+!g z#8_fJ6iV1KF;BzjSt^~B7)6ZjxNf$4yysT=HGR6z$EusV5|nx^HuHM3Y3V)JHG?Kn zV@M#f1|Tt#<3Vz1WeSypiD@lCBEKCouo`qF_`S(OxsUhTu>cAZLlsG4Ek9ppb&2W6 z;_SElD9Xkw>1uB2g%QT>+DT2yTyv4M!iQ0q0R zcGql%rkSWkAx1SiZSIVNAKXX(2u6f9A4E59x_&>SK&zRFMNmjC8^i#K`Y{lL5(Q8z z2uBk`JJksEtstj}O@14WSaX0d!i^a*-bCPSwMa7xGDxSR=Y=8XELjM2wX`gennRH>3>#)C$7U#Ok5hHXR@*lGsG4 z52m5;Y$4)CA`sN1wUD#e6EPG>y_GSPGC?S32*tt-p@WZy^ zde+?uVJl&F^j6NK0Q&=op+NLjCZX0lnGe4Kl&qEz$`F(N2o+i$WUHboi6R|rZ5;F! zB0A{4fY~^sPabz`vEOW46bKEh>XHJe1L{g1A=JpS522uA+`y_%+@j%;HNAQgOuYm` zU4k+xY!~(;u*c9P$rdJnI_M%tPzNFwL7}EDO{+==8B)`# z1+1hoQzxE;npAToZ&Gp%MGuLgKumVx=%Y0_ok`wQa@pw`L6PRtZGMNS_GRP9QS`%R zPX~rWLMqoCYLRMmaJiW(`9c^xAp{@`k*~m&TP!ym>--|F8d15z0T_J`7 zr6^Dl`rBl?RWzV!9MlkQi)R-4-u^x=O5_q|6446?Jo2$4#52St525)HPzG zuFC=Tm66z25xWiQ8nJqwhQnbL-3Da(wwvm{tsy;

NnbVg)GQYG>(RA%@0htT6(@ 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 + + + + + User's Guide + + + Reference Manual + + + Release Notes + + + Off-Print + + + diff --git a/lib/cosEvent/doc/src/make.dep b/lib/cosEvent/doc/src/make.dep new file mode 100644 index 0000000..b8a95c2 --- /dev/null +++ b/lib/cosEvent/doc/src/make.dep @@ -0,0 +1,34 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: CosEventChannelAdmin.tex CosEventChannelAdmin_ConsumerAdmin.tex \ + CosEventChannelAdmin_EventChannel.tex CosEventChannelAdmin_ProxyPullConsumer.tex \ + CosEventChannelAdmin_ProxyPullSupplier.tex \ + CosEventChannelAdmin_ProxyPushConsumer.tex \ + CosEventChannelAdmin_ProxyPushSupplier.tex \ + CosEventChannelAdmin_SupplierAdmin.tex book.tex \ + ch_contents.tex ch_event_service.tex ch_introduction.tex \ + cosEventApp.tex part.tex ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +CosEventChannelAdmin.tex: ../../src/CosEventChannelAdmin.idl + +book.tex: ref_man.xml + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: e_s_components.ps e_s_models.ps + diff --git a/lib/cosEvent/doc/src/notes.gif b/lib/cosEvent/doc/src/notes.gif new file mode 100644 index 0000000000000000000000000000000000000000..e000cca26a383722eca87f4d87a5841292b0b8ea GIT binary patch literal 2005 zcmc(e`(I0c1HeD$>})&L($>wE%9*B;E}M!dPv>-9341YwWX&zf>scU1zfBrl=I{N9;r;i^$ ze)#ZVWMt(1`}gnOy?gui?eOsMn>TM>zkWS5H1z7#tHHs+fq?;|(fIP^%NH+RJb(WD z*|TR)pFVx^ogEz=?d|P)y}qrjt+lnarKLru(`mKZ=H_ONMx$1%@7%d_`}XZyw{G3MdGp4N z8%<43jg5^B4Gq_?U%z(k+SRL9>+9>UT)9$LS65qGTT@eW`SRsUmo8nrc=5u83+KckWzORn^(EXDcf!&zw1P`t<2jr%qK=RFs#Ot5m9!Cr_R@apL&#<7H)K$BrF4 zdi1DLsXTJzNNH(lNl8g@aq;29hl`4e3JVJr3dNyAhYlV*SWr-qpP!$XmzSHHo0F3x zm&-FUGSbu2Wir|R{rmUr+qZY`-n6u|)YR0Jl$1St_9Q1K@7}$8*REYVckbM=V@Fa_ zl0+iezI}UQV&b-K+Y%BIwr<_JdGqE?n>KCSxN*aV4Pvo4E-p?a60KjqJ~lRX-MV!# zF)?e`u3fWc&Fa;wSFKvLa^=buD^>`F!ez^r2?T=0ix)>lMMXwNMnpvL`TX$k@UXD3 zkdTnz;NYO3Ac7zQ0|OT>TD_t~>&yScf|nl;PS)z!tt#o5`J!{InNIkDMn48x{RpYG`B=-}XBZ*Mm zJ0_E9VPQd|(M(NEQ52<8sT2wYK@bv&1j8@{LE!(5`#%Ezya3Qi0HOB$8kHskwQ`Hm z*OY4y(48X7__Y-+c}(wwXZqSxZHKVn+_d2V9bX<;)o5v8$jlB{tz6vnwfvQAiMw6t z0IXVSedvhT17nJCGJ_XCYT%)5*?chw5R9s25QXlX!e_sd7hr)!eyKroJ4zhgi|iRe z9BRcDRXkmj&PH5Z1EswZP1Yik}bX?KQfDMotrhur?Z`l6 z9SHWUks6^bPWsX|jEswdY)vps%VI@IAvY7W9?a_N?~xI!M!5pm(Ry5JJ;$6wSb!Kw z1Ofz-ES$>6ni1O}ScWTvR$Wsm*pF-~}^QqIoOkG6>BJ?$;+XE5N4m%cOVTgl$q1H6Cj2CRZ#Cwk*Z+A1}6-ZGIOnZ zriKR6JwuHEr#89IP&lU0d>}f|iQ2(xTebl}Km=JKc>w~{On}kI=M0e4E*aE>B!t(` zz!7B(z}xLdevm2fNGl*)VFk@hhEN1isQ4%eVdfhlo64C^B-c26^Z?T#Tc$&!YL-EE zsr_sc%})?_z}$saj#x(bLnO=CUH5f1>6}R!!dMZ|W9GTgpb9n@*5fiBqnDrne~DCT zx&%mdn3ma=CO4$ZCjP+)Zks2RB*+Tt`QEtb2g6+n+RKF1oJqVMUCo0mdGDTz#3Q^?T4648gGi%gvvJ#j{AlN2b z`m?E;VM>mcPQBC_Y6=8kn9B=CL=o-QgXt_x2k`|YJusL&`b=Pj%+?u4tr>8h24sDX + + + +

+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEvent Release Notes + Niclas Eklund + Niclas Eklund + + + + 99-02-12 + A + notes.xml +
+ +
+ cosEvent 2.1.7 + +
+ Improvements and New Features + + +

+ The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.

+

+ Own Id: OTP-8201 Aux Id:

+
+
+
+
+ +
+ cosEvent 2.1.6 + +
+ Improvements and New Features + + +

Obsolete guards, e.g. record vs is_record, has been changed + to avoid compiler warnings.

+

Own id: OTP-7987

+
+
+
+
+ +
+ cosEvent 2.1.5 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7837

+
+
+
+
+ +
+ cosEvent 2.1.4 + +
+ Improvements and New Features + + +

Documentation source included in open source releases.

+

Own id: OTP-7595

+
+
+
+
+ +
+ cosEvent 2.1.3 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7011

+
+
+
+
+ +
+ cosEvent 2.1.2 + +
+ Improvements and New Features + + +

The documentation source has been converted from SGML to XML.

+

Own id: OTP-6754

+
+
+
+
+ +
+ cosEvent 2.1.1 + +
+ Improvements and New Features + + +

Minor Makefile changes.

+

Own id: OTP-6701

+
+
+
+
+ +
+ cosEvent 2.1 + +
+ Improvements and New Features + + +

The stub/skeleton-files generated by IC have been improved, + i.e., depending on the IDL-files, reduced the size of the + erl- and beam-files and decreased dependencies off Orber's + Interface Repository. It is necessary to re-compile all IDL-files + and use COS-applications, including Orber, compiled with + IC-4.2.

+

Own id: OTP-4576

+
+
+
+
+ +
+ cosEvent 2.0 + +
+ Fixed Bugs and Malfunctions + + +

This version is a completely new version of the cosEvent + application; older versions was not compliant with the OMG + specification. The have been changed + to be more uniform with the other COS-services.

+
+
+
+
+ + diff --git a/lib/cosEvent/doc/src/part.xml b/lib/cosEvent/doc/src/part.xml new file mode 100644 index 0000000..a17821c --- /dev/null +++ b/lib/cosEvent/doc/src/part.xml @@ -0,0 +1,39 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEvent User's Guide + + + 1998-04-26 + 1.0 + part.xml +
+ +

The cosEvent application is an Erlang implementation of a + CORBA Service CosEvent.

+
+ + + +
+ diff --git a/lib/cosEvent/doc/src/part_notes.xml b/lib/cosEvent/doc/src/part_notes.xml new file mode 100644 index 0000000..92324ce --- /dev/null +++ b/lib/cosEvent/doc/src/part_notes.xml @@ -0,0 +1,37 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEvent Release Notes + + + 1999-04-20 + 1.0 + part_notes.xml +
+ +

The cosEvent Application is an Erlang implementation of a CORBA Service + CosEvent.

+
+ +
+ diff --git a/lib/cosEvent/doc/src/ref_man.gif b/lib/cosEvent/doc/src/ref_man.gif new file mode 100644 index 0000000000000000000000000000000000000000..b13c4efd53ff30209e94a832b9b141aefa01373e GIT binary patch literal 1530 zcmdVZdppw$0KoB|UD(ZKjLpudxl|bD5*~BdW(#wPxjQR!4XwvDQJz|2?rd%yODG+} zTS?d`8$ziw@9efjcbb8~ZJV`F`NeQj-Rb#--RW#!YS zPs_{8OG`^1KYmEb&dp9*T_4@VeSFc{Z zeEIUlix(;Hhy1Lrh+M1f0n>TM(S67S0;;O2u%F4=$ii+~`^0Klrkw{chQc_%8TvSw4P*9Mc zpP!ePmz$fLlanJ52(q)YuU)&AnVEUz%9YEPFK1+AT)K4W;>C;U>FH@{X%{YBNKH*W zfBt+*N=kBaa#B)KVq#)KLPC6e{JC@Ics$E-3+>FMd= z;o5R+g5Q78Vv{ zGTGeR+|10()YOzjBAJ+&7#kZK85t3YL|t879UUD4fq=*3wY9ZzI2;y>)zZ?^)YQaa zFd7;fYHDh#s;Vj~D$2^rC=?2bL?RFfI2;ax!IYGg6crVrP$&cf0fWIH5J*8m0r;Os z`p^I03jpi@P=FC!+v{kk6S6LO_!Iu)95sCwBtcqW%*9y*G+T7kk6cw&i6X!~u9ub^ z(;p_fv9U$vWTl#^q0-1BITpV6n#M{a{we|K$qn8tF1dhi2#U)iChGwf%c>!EMdamI z$h@1HHE$AU0uQ06DJaKq=RDnzU^TZiOigaDbX?9sbbG2Mo zru2uhl#`IQgUVf0v!Xj-d%-$1xRm>;TQmHNwcAfcM=qjwu=nh zQh;0;RMT@!2!f)5xXw7CWD^X8atslf08f~GlvPC&!u3CIvJ6wy=4qhoBAlk74dDIc za5tv{OoL_(_?n6N^K=DFVPbx|J4#5`n`9n$heG9OfAim6K_sx=yuqZzUrzW~%(8B5(t!Xl{Hb0?L6-vF=+wDe8$ zTT`s`Dq0fpfEZM3+{q@m}*YWuf-$-b$k$LLWEZK;Ee|dK!!GAvHA;V z*1da#TyGWrnurc+>Z42^g}P$+dV8CLlZ-G3$5&lvmrHi*;me*Y^_v!=AL*c_d4sqi z`SWVr{)P|6KptK|>YQR5CUyjEppnvPJ-9YQBBMdn(+)quWG#%To7OvoyB^9=`#bkY st1M+qtZTt#!ZD6_9%~hW^bvUb7(Sl{bx5FV=!1r@;+Z6>KNX<-3tg&0LjV8( literal 0 HcmV?d00001 diff --git a/lib/cosEvent/doc/src/ref_man.xml b/lib/cosEvent/doc/src/ref_man.xml new file mode 100644 index 0000000..7088c2e --- /dev/null +++ b/lib/cosEvent/doc/src/ref_man.xml @@ -0,0 +1,45 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEvent Reference Manual + + + 1998-05-05 + 2.0 + ref_man.xml +
+ +

The cosEvent application is an Erlang implementation of + a CORBA Service CosEvent.

+
+ + + + + + + + + +
+ diff --git a/lib/cosEvent/doc/src/summary.html.src b/lib/cosEvent/doc/src/summary.html.src new file mode 100644 index 0000000..6196223 --- /dev/null +++ b/lib/cosEvent/doc/src/summary.html.src @@ -0,0 +1 @@ +Orber OMG Event Service \ No newline at end of file diff --git a/lib/cosEvent/doc/src/user_guide.gif b/lib/cosEvent/doc/src/user_guide.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6275a803db46bc56df2b31240f80e68a4eb28b5 GIT binary patch literal 1581 zcmd6mi9gc|0Kk8njctY*W^QwCJ{HX#%4V)-y(i>aMOY|Iy@!%dZA6YGb49u7IpPyu zxpLn_avvd{2!$L^&hlRW#rysR-_Q5+`C8dn8X8V>k`j;wKQ1gR%+Jry&CSiu&d$utOixe0fB$}JYHD(Fa$;g)e0+Rt zY;1INbYx^?czAedXlQV7@ZGz20|Nv7{r!D?eZ9TCJRYy7r>DESyQ{0Kv$M0KqocjO zy{)aSwY9aSrKP#Kxv8nCv9YnCq2bM&H}&=Pb#-;MwY4=hHPzMCuV25es;a82tgNW0 zc=_^WSy|bO7cWXnOG`>hii?Yjii!#g3kwPg^7Hfa^73+Xb8~WXva_?Zva&KWGoL+s z_Vnq~jEs!*^z{(M&Qxg*t zV`JkpXU-TI85tTH>g((4>FMd}>gwp|kVqtLZEYmX?x|!eX(Kl9CtEE3!%>OGRc>9)Rn&SYM zj~Y~*8(l`PO4G;6R;FqaD@X#~VMifcR)pt=DvF{Q3(>@Ud>(7)(V4{v)PmxVK~kPo zjj~AEyr<1v8vx#~Tk98U5_J`0L}~fU>RjhaAKM=MUf{g5m?T z)+IHOf7l%`QALwKCeyDj6SLD45WBagBU?Fw4{df%%9E4Y2u)Wk*W$nyCUXV^5gf*w zJcTmdm_5ACzSYODr)n2;x_FnPc`B(M`LXIbz9g71J`3n))Gq$bQK+sRivkPkZkj>F zXejb80{#?f()6mQl&jOcTB0m7HQ)B0eJ!3!3LG1z5Dy4!8UDX&qmZHiEZH4hCN$qe z4*)g+{|y}64a+3k1Ar7VS%DkXnyczs>8pr>ch^qPgriJZarAD;X*)P0t_Uea!m)bj zekgBBW+6d2l7{g|`zZIq7r_Y&symb`GN>UKUQ)c!TxUa0r_Gumy9Jeti%E)uL##a# zMGizq*jB%VA7Ip@(A3hq9YH69qL7NjkWRA2q5;hU`xYmEN)bB>aqrz!?T?Ynv*X-7 zk5PfTmt$8kTF6UOKy_o?XHYzxtkg%ZbG*StHxDNDsyD5c2a>x5vWvVCApVgu@XNF$})`XD-pCH3`9zE-Lj6@!*TS9lwVaP}h|-H2`m~ItYQE$0z|a zt4=D`BBR~(5MZ;L{+LQk#4$5Kz`eloKZBK-7eFm?OlZCy;GH~%L;($J;|e#tww(~b et1Zl|+ha7@T8X2%4FJEoWS?mjDfbqXtih~yb literal 0 HcmV?d00001 diff --git a/lib/cosEvent/ebin/.gitignore b/lib/cosEvent/ebin/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEvent/example/.gitignore b/lib/cosEvent/example/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEvent/include/.gitignore b/lib/cosEvent/include/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEvent/info b/lib/cosEvent/info new file mode 100644 index 0000000..dc9f7b7 --- /dev/null +++ b/lib/cosEvent/info @@ -0,0 +1,2 @@ +group: orb +short: Orber OMG Event Service diff --git a/lib/cosEvent/src/CosEventChannelAdmin.cfg b/lib/cosEvent/src/CosEventChannelAdmin.cfg new file mode 100644 index 0000000..0de579b --- /dev/null +++ b/lib/cosEvent/src/CosEventChannelAdmin.cfg @@ -0,0 +1,6 @@ +{this, "CosEventChannelAdmin::SupplierAdmin"}. +{{handle_info, "CosEventChannelAdmin::SupplierAdmin"}, true}. +{this, "CosEventChannelAdmin::ProxyPushConsumer"}. +{{handle_info, "CosEventChannelAdmin::ProxyPushConsumer"}, true}. +{this, "CosEventChannelAdmin::ProxyPullConsumer"}. +{{handle_info, "CosEventChannelAdmin::ProxyPullConsumer"}, true}. diff --git a/lib/cosEvent/src/CosEventChannelAdmin.idl b/lib/cosEvent/src/CosEventChannelAdmin.idl new file mode 100644 index 0000000..d5cb92c --- /dev/null +++ b/lib/cosEvent/src/CosEventChannelAdmin.idl @@ -0,0 +1,66 @@ +#ifndef _COSEVENTCHANELADMIN_IDL +#define _COSEVENTCHANELADMIN_IDL + +#include "CosEventComm.idl" + +#pragma prefix "omg.org" + +module CosEventChannelAdmin +{ + exception AlreadyConnected{}; + exception TypeError{}; + + interface ProxyPushConsumer: CosEventComm::PushConsumer + { + void connect_push_supplier(in CosEventComm:: + PushSupplier push_supplier) + raises (AlreadyConnected); + }; + + interface ProxyPullSupplier: CosEventComm::PullSupplier + { + void connect_pull_consumer(in CosEventComm:: + PullConsumer pull_consumer) + raises (AlreadyConnected); + }; + + interface ProxyPullConsumer: CosEventComm::PullConsumer + { + void connect_pull_supplier(in CosEventComm:: + PullSupplier pull_supplier) + raises (AlreadyConnected, TypeError); + }; + + interface ProxyPushSupplier: CosEventComm::PushSupplier + { + void connect_push_consumer(in CosEventComm:: + PushConsumer push_consumer) + raises (AlreadyConnected, TypeError); + }; + + interface ConsumerAdmin + { + ProxyPushSupplier obtain_push_supplier(); + ProxyPullSupplier obtain_pull_supplier(); + }; + + interface SupplierAdmin + { + ProxyPushConsumer obtain_push_consumer(); + ProxyPullConsumer obtain_pull_consumer(); + }; + + interface EventChannel + { + ConsumerAdmin for_consumers(); + SupplierAdmin for_suppliers(); + void destroy(); + }; + +}; + +#endif + + + + diff --git a/lib/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer_impl.erl b/lib/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer_impl.erl new file mode 100644 index 0000000..26269ad --- /dev/null +++ b/lib/cosEvent/src/CosEventChannelAdmin_ProxyPullConsumer_impl.erl @@ -0,0 +1,205 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosEventChannelAdmin_ProxyPullConsumer_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosEventChannelAdmin_ProxyPullConsumer_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include("CosEventChannelAdmin.hrl"). +-include("CosEventComm.hrl"). +-include("cosEventApp.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +%% Mandatory +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%% Interface functions +-export([connect_pull_supplier/3]). + +%% Exports from "CosEventComm::PullConsumer" +-export([disconnect_pull_consumer/2]). + + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {admin, admin_pid, channel, client, + typecheck, pull_interval, timer_ref}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([Admin, AdminPid, Channel, TypeCheck, PullInterval]) -> + process_flag(trap_exit, true), + Secs = timer:seconds(PullInterval), + timer:start(), + {ok, #state{admin = Admin, admin_pid = AdminPid, channel = Channel, + typecheck = TypeCheck, pull_interval = Secs}}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, #state{client = undefined}) -> + ?DBG("Terminating ~p; no client connected.~n", [_Reason]), + ok; +terminate(_Reason, #state{client = Client} = State) -> + stop_timer(State), + ?DBG("Terminating ~p~n", [_Reason]), + cosEventApp:disconnect('CosEventComm_PullSupplier', + disconnect_pull_supplier, Client), + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% function : handle_info +%% Arguments: +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Effect : If the Parent Admin or the Channel terminates so must this object. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, Reason}, #state{admin_pid = Pid} = State) -> + ?DBG("Parent Admin terminated ~p~n", [Reason]), + orber:dbg("[~p] CosEventChannelAdmin_ProxyPullConsumer:handle_info(~p);~n" + "My Admin terminated and so will I.", [?LINE, Reason], ?DEBUG_LEVEL), + {stop, Reason, State}; +handle_info(try_pull_event, State) -> + try_pull_event(State); +handle_info(_Info, State) -> + ?DBG("Unknown Info ~p~n", [_Info]), + {noreply, State}. + +%%---------------------------------------------------------------------- +%% Function : connect_pull_supplier +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +connect_pull_supplier(_OE_This, #state{client = undefined, + typecheck = TypeCheck} = State, NewClient) -> + case corba_object:is_nil(NewClient) of + true -> + ?DBG("A NIL client supplied.~n", []), + orber:dbg("[~p] CosEventChannelAdmin_ProxyPullConsumer:connect_pull_supplier(..);~n" + "Supplied a NIL reference which is not allowed.", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}); + false -> + cosEventApp:type_check(NewClient, 'CosEventComm_PullSupplier', TypeCheck), + NewState = start_timer(State), + {reply, ok, NewState#state{client = NewClient}} + end; +connect_pull_supplier(_, _, _) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}). + + +%%---------------------------------------------------------------------- +%% Function : disconnect_pull_consumer +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +disconnect_pull_consumer(_OE_This, State) -> + NewState = stop_timer(State), + ?DBG("Disconnect invoked ~p~n", [NewState]), + {stop, normal, ok, NewState#state{client = undefined}}. + +%%====================================================================== +%% Internal functions +%%====================================================================== +%% Start timer which send a message each time we should pull for new events. +start_timer(State) -> + case catch timer:send_interval(State#state.pull_interval, try_pull_event) of + {ok,PullTRef} -> + ?DBG("Started timer: ~p~n", [State#state.pull_interval]), + State#state{timer_ref = PullTRef}; + _ -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. +stop_timer(#state{timer_ref = undefined} = State) -> + ?DBG("No timer to stop~n",[]), + State; +stop_timer(State) -> + ?DBG("Stopped timer~n",[]), + timer:cancel(State#state.timer_ref), + State#state{timer_ref = undefined}. + + +try_pull_event(State) -> + case catch 'CosEventComm_PullSupplier':try_pull(State#state.client) of + {_,false} -> + ?DBG("Client did not supply event~n", []), + {noreply, State}; + {Any, true} -> + 'oe_CosEventComm_Channel':send_sync(State#state.channel, Any), + ?DBG("Received Event ~p and forwarded it successfully.~n", [Any]), + {noreply, State}; + {'EXCEPTION', #'CosEventComm_Disconnected'{}} -> + ?DBG("Client claims we are disconnectedwhen trying to pull event.~n", []), + orber:dbg("[~p] CosEventChannelAdmin_ProxyPullConsumer:try_pull_event();~n" + "Client claims we are disconnected when trying to pull event so I terminate.", + [?LINE], ?DEBUG_LEVEL), + {stop, normal, State#state{client = undefined}}; + What -> + orber:dbg("[~p] CosEventChannelAdmin_ProxyPullConsumer:try_pull_event(~p);~n" + "My Client behaves badly so I terminate.", + [?LINE, What], ?DEBUG_LEVEL), + {stop, normal, State} + end. + + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer_impl.erl b/lib/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer_impl.erl new file mode 100644 index 0000000..969beb1 --- /dev/null +++ b/lib/cosEvent/src/CosEventChannelAdmin_ProxyPushConsumer_impl.erl @@ -0,0 +1,169 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosEventChannelAdmin_ProxyPushConsumer_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosEventChannelAdmin_ProxyPushConsumer_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include("CosEventChannelAdmin.hrl"). +-include("CosEventComm.hrl"). +-include("cosEventApp.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +%% Mandatory +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%% Exports from "CosEventChannelAdmin::ProxyPushConsumer" +-export([connect_push_supplier/3]). + +%% Exports from "CosEventComm::PushConsumer" +-export([push/3, + disconnect_push_consumer/2]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {admin, admin_pid, channel, client, typecheck}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([Admin, AdminPid, Channel, TypeCheck]) -> + process_flag(trap_exit, true), + {ok, #state{admin = Admin, admin_pid = AdminPid, channel = Channel, + typecheck = TypeCheck}}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, #state{client = undefined}) -> + ?DBG("Terminating ~p; no client connected.~n", [_Reason]), + ok; +terminate(_Reason, #state{client = Client} = _State) -> + ?DBG("Terminating ~p~n", [_Reason]), + cosEventApp:disconnect('CosEventComm_PushSupplier', + disconnect_push_supplier, Client), + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% function : handle_info +%% Arguments: +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Effect : If the Parnet Admin or the Channel terminates so must this object. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, Reason}, #state{admin_pid = Pid} = State) -> + ?DBG("Parent Admin terminated ~p~n", [Reason]), + orber:dbg("[~p] CosEventChannelAdmin_ProxyPushConsumer:handle_info(~p);~n" + "My Admin terminated and so will I.", + [?LINE, Reason], ?DEBUG_LEVEL), + {stop, Reason, State}; +handle_info(_Info, State) -> + ?DBG("Unknown Info ~p~n", [_Info]), + {noreply, State}. + +%%---------------------------------------------------------------------- +%% Function : connect_push_supplier +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +connect_push_supplier(_OE_This, #state{client = undefined, + typecheck = TypeCheck} = State, NewClient) -> + case corba_object:is_nil(NewClient) of + true -> + ?DBG("A NIL client supplied.~n", []), + {reply, ok, State}; + false -> + cosEventApp:type_check(NewClient, 'CosEventComm_PushSupplier', TypeCheck), + ?DBG("Connected to client.~n", []), + {reply, ok, State#state{client = NewClient}} + end; +connect_push_supplier(_, _, _) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}). + + +%%---------------------------------------------------------------------- +%% Function : push +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +push(_OE_This, State, Any) -> + %% We should not use corba:reply here since if we block incoming + %% events this will prevent producers to flood the system. + ?DBG("Received Event ~p and forwarded it successfully.~n", [Any]), + 'oe_CosEventComm_Channel':send_sync(State#state.channel, Any), + {reply, ok, State}. + +%%---------------------------------------------------------------------- +%% Function : disconnect_push_consumer +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +disconnect_push_consumer(_OE_This, State) -> + ?DBG("Disconnect invoked ~p~n", [State]), + {stop, normal, ok, State#state{client = undefined}}. + +%%====================================================================== +%% Internal functions +%%====================================================================== + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosEvent/src/CosEventChannelAdmin_SupplierAdmin_impl.erl b/lib/cosEvent/src/CosEventChannelAdmin_SupplierAdmin_impl.erl new file mode 100644 index 0000000..c7cf0bd --- /dev/null +++ b/lib/cosEvent/src/CosEventChannelAdmin_SupplierAdmin_impl.erl @@ -0,0 +1,159 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosEventChannelAdmin_SupplierAdmin_impl.erl +%% Created : 21 Mar 2001 +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosEventChannelAdmin_SupplierAdmin_impl'). + + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include("cosEventApp.hrl"). + + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +%% Mandatory +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%% Exports from "CosEventChannelAdmin::SupplierAdmin" +-export([obtain_push_consumer/2, + obtain_pull_consumer/2]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {channel, channel_pid, typecheck, pull_interval, server_options}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([Channel, ChannelPid, TypeCheck, PullInterval, ServerOpts]) -> + process_flag(trap_exit, true), + {ok, #state{channel = Channel, channel_pid = ChannelPid, typecheck = TypeCheck, + pull_interval = PullInterval, server_options = ServerOpts}}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ?DBG("Terminating ~p~n", [_Reason]), + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% function : handle_info +%% Arguments: +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Effect : Functions demanded by the gen_server module. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, Reason}, #state{channel_pid = Pid} = State) -> + ?DBG("Parent Channel terminated ~p~n", [Reason]), + orber:dbg("[~p] CosEventChannelAdmin_SupplierAdmin:handle_info(~p);~n" + "My Channel terminated and so will I.", + [?LINE, Reason], ?DEBUG_LEVEL), + {stop, Reason, State}; +handle_info(_Info, State) -> + ?DBG("Unknown Info ~p~n", [_Info]), + {noreply, State}. + + +%%---------------------------------------------------------------------- +%% Function : obtain_push_consumer +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +obtain_push_consumer(OE_This, #state{channel = Channel, + channel_pid = _ChannelPid, + typecheck = TypeCheck, + server_options = ServerOpts} = State) -> + ?DBG("Starting a new CosEventChannelAdmin_ProxyPushConsumer.~n", []), + {reply, + 'CosEventChannelAdmin_ProxyPushConsumer':oe_create_link([OE_This, + self(), + Channel, + TypeCheck], + ServerOpts), + State}. + +%%---------------------------------------------------------------------- +%% Function : obtain_pull_consumer +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +obtain_pull_consumer(OE_This, #state{channel = Channel, + channel_pid = _ChannelPid, + typecheck = TypeCheck, + pull_interval= PullInterval, + server_options = ServerOpts} = State) -> + ?DBG("Starting a new CosEventChannelAdmin_ProxyPullConsumer.~n", []), + {reply, + 'CosEventChannelAdmin_ProxyPullConsumer':oe_create_link([OE_This, + self(), + Channel, + TypeCheck, + PullInterval], + ServerOpts), + State}. + +%%====================================================================== +%% Internal functions +%%====================================================================== + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosEvent/src/CosEventComm.idl b/lib/cosEvent/src/CosEventComm.idl new file mode 100644 index 0000000..bb0c107 --- /dev/null +++ b/lib/cosEvent/src/CosEventComm.idl @@ -0,0 +1,37 @@ + +#ifndef _COSEVENTCOMM_IDL +#define _COSEVENTCOMM_IDL + +#pragma prefix "omg.org" + +module CosEventComm +{ + exception Disconnected{}; + + interface PushConsumer + { + void push(in any data) raises (Disconnected); + void disconnect_push_consumer(); + }; + + + interface PushSupplier + { + void disconnect_push_supplier(); + }; + + interface PullSupplier + { + any pull() raises(Disconnected); + any try_pull(out boolean has_event) raises(Disconnected); + void disconnect_pull_supplier(); + }; + + interface PullConsumer + { + void disconnect_pull_consumer(); + }; +}; + +#endif + diff --git a/lib/cosEvent/src/Makefile b/lib/cosEvent/src/Makefile new file mode 100644 index 0000000..a62d47c --- /dev/null +++ b/lib/cosEvent/src/Makefile @@ -0,0 +1,214 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug -W +endif +EBIN=../ebin +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(COSEVENT_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/cosEvent-$(VSN) +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + CosEventChannelAdmin_ProxyPullConsumer_impl \ + CosEventChannelAdmin_ProxyPushConsumer_impl \ + CosEventChannelAdmin_SupplierAdmin_impl \ + oe_CosEventComm_CAdmin_impl \ + oe_CosEventComm_Channel_impl \ + oe_CosEventComm_PullerS_impl \ + oe_CosEventComm_PusherS_impl \ + cosEventApp + + + +ERL_FILES = $(MODULES:%=%.erl) +HRL_FILES = cosEventApp.hrl + + +GEN_ERL_FILES1 = \ + oe_CosEventChannelAdmin.erl \ + CosEventChannelAdmin_ConsumerAdmin.erl \ + CosEventChannelAdmin_EventChannel.erl \ + CosEventChannelAdmin_ProxyPullConsumer.erl \ + CosEventChannelAdmin_ProxyPullSupplier.erl \ + CosEventChannelAdmin_ProxyPushConsumer.erl \ + CosEventChannelAdmin_ProxyPushSupplier.erl \ + CosEventChannelAdmin_SupplierAdmin.erl \ + CosEventChannelAdmin_AlreadyConnected.erl \ + CosEventChannelAdmin_TypeError.erl + +GEN_ERL_FILES2 = \ + oe_CosEventComm_CAdmin.erl \ + oe_CosEventComm_Channel.erl \ + oe_CosEventComm_Event.erl \ + oe_CosEventComm_PullerS.erl \ + oe_CosEventComm_PusherS.erl \ + oe_cosEventApp.erl + +GEN_ERL_FILES3 = \ + oe_CosEventComm.erl \ + CosEventComm_Disconnected.erl \ + CosEventComm_PullConsumer.erl \ + CosEventComm_PullSupplier.erl \ + CosEventComm_PushConsumer.erl \ + CosEventComm_PushSupplier.erl + +GEN_ERL_FILES = \ + $(GEN_ERL_FILES1) $(GEN_ERL_FILES2) $(GEN_ERL_FILES3) + +EXTERNAL_INC_PATH = ../include + +GEN_HRL_FILES1 = \ + oe_CosEventChannelAdmin.hrl \ + CosEventChannelAdmin.hrl \ + CosEventChannelAdmin_ConsumerAdmin.hrl \ + CosEventChannelAdmin_EventChannel.hrl \ + CosEventChannelAdmin_ProxyPullConsumer.hrl \ + CosEventChannelAdmin_ProxyPullSupplier.hrl \ + CosEventChannelAdmin_ProxyPushConsumer.hrl \ + CosEventChannelAdmin_ProxyPushSupplier.hrl \ + CosEventChannelAdmin_SupplierAdmin.hrl + +EXTERNAL_GEN_HRL_FILES1 = $(GEN_HRL_FILES1:%=$(EXTERNAL_INC_PATH)/%) + +GEN_HRL_FILES2 = \ + oe_CosEventComm_PullerS.hrl \ + oe_CosEventComm_CAdmin.hrl \ + oe_CosEventComm_PusherS.hrl \ + oe_CosEventComm_Channel.hrl \ + oe_cosEventApp.hrl \ + oe_CosEventComm_Event.hrl + +GEN_HRL_FILES3 = \ + oe_CosEventComm.hrl \ + CosEventComm.hrl \ + CosEventComm_PullConsumer.hrl \ + CosEventComm_PullSupplier.hrl \ + CosEventComm_PushConsumer.hrl \ + CosEventComm_PushSupplier.hrl + +EXTERNAL_GEN_HRL_FILES3 = $(GEN_HRL_FILES3:%=$(EXTERNAL_INC_PATH)/%) + +GEN_HRL_FILES = \ + $(EXTERNAL_GEN_HRL_FILES1) $(GEN_HRL_FILES2) $(EXTERNAL_GEN_HRL_FILES3) + +TARGET_FILES = \ + $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +GEN_FILES = $(GEN_HRL_FILES) $(GEN_ERL_FILES) + +IDL_FILES = \ + CosEventChannelAdmin.idl \ + CosEventComm.idl \ + cosEventApp.idl + +APPUP_FILE = cosEvent.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + +APP_FILE = cosEvent.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosEvent/ebin -pa $(ERL_TOP)/lib/ic/ebin +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -I$(ERL_TOP)/lib/orber/include \ + -I$(ERL_TOP)/lib/cosEvent/include \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,"cosEvent_$(COSEVENT_VSN)"}' + +YRL_FLAGS = + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + +debug: + @${MAKE} TYPE=debug opt + +clean: + rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) + sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET) +$(APPUP_TARGET): $(APPUP_SRC) + sed -e 's;%VSN%;$(VSN);' $(APPUP_SRC) > $(APPUP_TARGET) + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +$(GEN_ERL_FILES1) $(EXTERNAL_GEN_HRL_FILES1): CosEventChannelAdmin.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventChannelAdmin.cfg"}' CosEventChannelAdmin.idl + mv $(GEN_HRL_FILES1) $(EXTERNAL_INC_PATH) + +$(GEN_ERL_FILES2) $(GEN_HRL_FILES2): cosEventApp.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosEventApp.cfg"}' cosEventApp.idl + +$(GEN_ERL_FILES3) $(EXTERNAL_GEN_HRL_FILES3): CosEventComm.idl + erlc $(ERL_IDL_FLAGS) CosEventComm.idl + mv $(GEN_HRL_FILES3) $(EXTERNAL_INC_PATH) + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) ../info $(RELSYSDIR) + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include + + +release_docs_spec: + + + + + + diff --git a/lib/cosEvent/src/cosEvent.app.src b/lib/cosEvent/src/cosEvent.app.src new file mode 100644 index 0000000..c1cb9e0 --- /dev/null +++ b/lib/cosEvent/src/cosEvent.app.src @@ -0,0 +1,45 @@ +{application, cosEvent, + [{description, "The Erlang CosEvent application"}, + {vsn, "%VSN%"}, + {modules, + [ + 'CosEventChannelAdmin_ProxyPullConsumer_impl', + 'CosEventChannelAdmin_ProxyPushConsumer_impl', + 'CosEventChannelAdmin_SupplierAdmin_impl', + 'oe_CosEventComm_CAdmin_impl', + 'oe_CosEventComm_Channel_impl', + 'oe_CosEventComm_PullerS_impl', + 'oe_CosEventComm_PusherS_impl', + 'cosEventApp', + 'oe_CosEventChannelAdmin', + 'CosEventChannelAdmin_AlreadyConnected', + 'CosEventChannelAdmin_ConsumerAdmin', + 'CosEventChannelAdmin_EventChannel', + 'CosEventChannelAdmin_ProxyPullConsumer', + 'CosEventChannelAdmin_ProxyPullSupplier', + 'CosEventChannelAdmin_ProxyPushConsumer', + 'CosEventChannelAdmin_ProxyPushSupplier', + 'CosEventChannelAdmin_SupplierAdmin', + 'CosEventChannelAdmin_TypeError', + 'oe_CosEventComm_CAdmin', + 'oe_CosEventComm_Channel', + 'oe_CosEventComm_Event', + 'oe_CosEventComm_PullerS', + 'oe_CosEventComm_PusherS', + 'oe_cosEventApp', + 'oe_CosEventComm', + 'CosEventComm_PushSupplier', + 'CosEventComm_PushConsumer', + 'CosEventComm_PullSupplier', + 'CosEventComm_PullConsumer', + 'CosEventComm_Disconnected' + ] + }, + {registered, []}, + {applications, [orber, stdlib, kernel]}, + {env, []}, + {mod, {cosEventApp, []}} +]}. + + + diff --git a/lib/cosEvent/src/cosEvent.appup.src b/lib/cosEvent/src/cosEvent.appup.src new file mode 100644 index 0000000..d69b2ef --- /dev/null +++ b/lib/cosEvent/src/cosEvent.appup.src @@ -0,0 +1,6 @@ +{"%VSN%", + [ + ], + [ + ] +} diff --git a/lib/cosEvent/src/cosEventApp.cfg b/lib/cosEvent/src/cosEventApp.cfg new file mode 100644 index 0000000..bbacd13 --- /dev/null +++ b/lib/cosEvent/src/cosEventApp.cfg @@ -0,0 +1,15 @@ +{this, "oe_CosEventComm::Event"}. +{from, "oe_CosEventComm::Event"}. +{{handle_info, "oe_CosEventComm::Event"}, true}. +{this, "oe_CosEventComm::Channel"}. +{from, "oe_CosEventComm::Channel"}. +{{handle_info, "oe_CosEventComm::Channel"}, true}. +{this, "oe_CosEventComm::CAdmin"}. +{from, "oe_CosEventComm::CAdmin"}. +{{handle_info, "oe_CosEventComm::CAdmin"}, true}. +{this, "oe_CosEventComm::PullerS"}. +{from, "oe_CosEventComm::PullerS"}. +{{handle_info, "oe_CosEventComm::PullerS"}, true}. +{this, "oe_CosEventComm::PusherS"}. +{from, "oe_CosEventComm::PusherS"}. +{{handle_info, "oe_CosEventComm::PusherS"}, true}. diff --git a/lib/cosEvent/src/cosEventApp.erl b/lib/cosEvent/src/cosEventApp.erl new file mode 100644 index 0000000..084490f --- /dev/null +++ b/lib/cosEvent/src/cosEventApp.erl @@ -0,0 +1,290 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosEventApp.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module(cosEventApp). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include("cosEventApp.hrl"). + + +%%--------------- EXPORTS------------------------------------- +%% cosEvent API external +-export([start/0, stop/0, install/0, uninstall/0, start_channel/0, start_channel/1, + start_channel_link/0, start_channel_link/1, stop_channel/1]). + +%% cosEvent API internal +-export([create_link/3, get_option/2, type_check/3, disconnect/3, do_disconnect/3]). + +%% Application callbacks +-export([start/2, init/1, stop/1]). + +%%--------------- DEFINES ------------------------------------ +-define(IDL_MODULES, ['oe_CosEventComm', + 'oe_CosEventChannelAdmin', + 'oe_cosEventApp']). + +-define(SUPERVISOR_NAME, oe_cosEventSup). +-define(SUP_FLAG, {simple_one_for_one,50,10}). + +-define(SUP_SPEC(Name, Args), + ['CosEventChannel_EventChannel',Args, + [{sup_child, true}, {regname, {global, Name}}]]). +-define(SUP_CHILD, + {"oe_EventChild", + {cosEventApp,create_link, []}, + transient,100000,worker, + ['CosEventChannel_EventChannel']}). + + +%%-----------------------------------------------------------% +%% function : install +%% Arguments: - +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ +install() -> + install_loop(?IDL_MODULES, []). + +install_loop([], _) -> + ok; +install_loop([H|T], Accum) -> + case catch H:'oe_register'() of + {'EXIT',{unregistered,App}} -> + ?write_ErrorMsg("Unable to register '~p'; application ~p not registered. +Trying to unregister ~p~n", [H,App,Accum]), + uninstall_loop(Accum, {exit, register}); + {'EXCEPTION',_} -> + ?write_ErrorMsg("Unable to register '~p'; propably already registered. +You are adviced to confirm this. +Trying to unregister ~p~n", [H,Accum]), + uninstall_loop(Accum, {exit, register}); + ok -> + install_loop(T, [H|Accum]); + _ -> + ?write_ErrorMsg("Unable to register '~p'; reason unknown. +Trying to unregister ~p~n", [H,Accum]), + uninstall_loop(Accum, {exit, register}) + end. + +%%-----------------------------------------------------------% +%% function : uninstall +%% Arguments: - +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosEvent from the IFR DB +%%------------------------------------------------------------ +uninstall() -> + uninstall_loop(lists:reverse(?IDL_MODULES), ok). + +uninstall_loop([],ok) -> + ok; +uninstall_loop([],{exit, register}) -> + exit({?MODULE, "oe_register failed"}); +uninstall_loop([],{exit, unregister}) -> + exit({?MODULE, "oe_unregister failed"}); +uninstall_loop([],{exit, both}) -> + exit({?MODULE, "oe_register and, for some of those already registered, oe_unregister failed"}); +uninstall_loop([H|T], Status) -> + case catch H:'oe_unregister'() of + ok -> + uninstall_loop(T, Status); + _ when Status == ok -> + ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered. +You are adviced to confirm this.~n",[H]), + uninstall_loop(T, {exit, unregister}); + _ -> + ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered. +You are adviced to confirm this.~n",[H]), + uninstall_loop(T, {exit, both}) + end. + +%%-----------------------------------------------------------% +%% function : start/stop +%% Arguments: +%% Returns : +%% Effect : Starts or stops the cosTime application. +%%------------------------------------------------------------ + +start() -> + application:start(cosEvent). +stop() -> + application:stop(cosEvent). + +%%-----------------------------------------------------------% +%% function : start +%% Arguments: Type - see module application +%% Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +start(_, _) -> + supervisor:start_link({local, ?SUPERVISOR_NAME}, cosEventApp, app_init). + + +%%-----------------------------------------------------------% +%% function : stop +%% Arguments: Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +stop(_) -> + ok. + +%%-----------------------------------------------------------% +%% function : start_channel +%% Arguments: - +%% Returns : +%% Effect : +%%------------------------------------------------------------ +start_channel() -> + start_channel(?DEFAULT_OPTIONS). + +start_channel(Options) when is_list(Options) -> + ServerOpts = get_option(?SERVER, Options), + 'oe_CosEventComm_Channel':oe_create([Options, ServerOpts], ServerOpts); +start_channel(Options) -> + orber:dbg("[~p] cosEventApp:start_channel(~p);~n" + "Options not correct.", [?LINE, Options], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%-----------------------------------------------------------% +%% function : start_channel +%% Arguments: - +%% Returns : +%% Effect : +%%------------------------------------------------------------ +start_channel_link() -> + start_channel_link(?DEFAULT_OPTIONS). + +start_channel_link(Options) when is_list(Options) -> + ServerOpts = get_option(?SERVER, Options), + 'oe_CosEventComm_Channel':oe_create_link([Options, ServerOpts], ServerOpts); +start_channel_link(Options) -> + orber:dbg("[~p] cosEventApp:start_channel_link(~p);~n" + "Options not correct.", [?LINE, Options], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%-----------------------------------------------------------% +%% function : stop_factory +%% Arguments: ChannelObj +%% Returns : +%% Effect : +%%------------------------------------------------------------ +stop_channel(ChannelObj) -> + corba:dispose(ChannelObj). + +%%-----------------------------------------------------------% +%% function : init +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%% Starting using create_factory/X +init(own_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}; +%% When starting as an application. +init(app_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}. + +%%-----------------------------------------------------------% +%% function : create_link +%% Arguments: Module - which Module to call +%% Env/ArgList - ordinary oe_create arguments. +%% Returns : +%% Exception: +%% Effect : Necessary since we want the supervisor to be a +%% 'simple_one_for_one'. Otherwise, using for example, +%% 'one_for_one', we have to call supervisor:delete_child +%% to remove the childs startspecification from the +%% supervisors internal state. +%%------------------------------------------------------------ +create_link(Module, Env, ArgList) -> + Module:oe_create_link(Env, ArgList). + + +%%-----------------------------------------------------------% +%% function : get_option +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +get_option(Key, OptionList) -> + case lists:keysearch(Key, 1, OptionList) of + {value,{Key,Value}} -> + Value; + _ -> + case lists:keysearch(Key, 1, ?DEFAULT_OPTIONS) of + {value,{Key,Value}} -> + Value; + _-> + {error, "Invalid option"} + end + end. + +%%-----------------------------------------------------------% +%% function : type_check +%% Arguments: Obj - objectrefernce to test. +%% Mod - Module which contains typeID/0. +%% Returns : 'ok' or raises exception. +%% Effect : +%%------------------------------------------------------------ +type_check(_Obj, _Mod, false) -> + ok; +type_check(Obj, Mod, _) -> + case catch corba_object:is_a(Obj, Mod:typeID()) of + true -> + ok; + _ -> + orber:dbg("[~p] cosEventApp:type_check(~p) failed; Should be ~p", + [?LINE, Obj, Mod], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end. + +%%-----------------------------------------------------------% +%% function : disconnect +%% Arguments: Module - one of the interfaces defined in CosEventComm. +%% Function - the appropriate disconnect function. +%% Object - the client object reference. +%% Returns : ok +%% Exception: +%% Effect : If the process would try to diconnect itself it could +%% result in a deadlock. Hence, we spawn a new process to do it. +%%------------------------------------------------------------ +disconnect(Module, Function, Object) -> + spawn(cosEventApp, do_disconnect, [Module, Function, Object]), + ok. + +do_disconnect(Module, Function, Object) -> + catch Module:Function(Object), + ?DBG("Disconnect ~p:~p(..).~n", [Module, Function]), + ok. + +%%--------------- END OF MODULE ------------------------------ + + diff --git a/lib/cosEvent/src/cosEventApp.hrl b/lib/cosEvent/src/cosEventApp.hrl new file mode 100644 index 0000000..ef72277 --- /dev/null +++ b/lib/cosEvent/src/cosEventApp.hrl @@ -0,0 +1,62 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosEventApp.hrl +%% Description : +%% +%%---------------------------------------------------------------------- + +%%--------------- INCLUDES ----------------------------------- +%% External +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). + +-define(write_ErrorMsg(Txt, Arg), +error_logger:error_msg("================ CosEvent =================~n" + Txt + "===========================================~n", + Arg)). + + +-define(PULL_INTERVAL, pull_interval). +-define(TYPECHECK, typecheck). +-define(MAXEVENTS, maxEvents). +-define(BLOCKING, blocking). +-define(SERVER, server_options). +-define(DEFAULT_OPTIONS, [{?PULL_INTERVAL, 20}, + {?BLOCKING, true}, + {?TYPECHECK, false}, + {?MAXEVENTS, 300}, + {?SERVER, []}]). + +-define(DEBUG_LEVEL, 3). + +-ifdef(debug). +-define(DBG(F,A), + io:format("[~p (~p)] "++F,[?MODULE, ?LINE]++A)). +-else. +-define(DBG(F,A), ok). +-endif. + + + + +%%--------------- END OF MODULE ---------------------------------------- diff --git a/lib/cosEvent/src/cosEventApp.idl b/lib/cosEvent/src/cosEventApp.idl new file mode 100644 index 0000000..e5a1346 --- /dev/null +++ b/lib/cosEvent/src/cosEventApp.idl @@ -0,0 +1,26 @@ +#ifndef _COS_EVENT_APP_IDL_ +#define _COS_EVENT_APP_IDL_ + +#include + + +module oe_CosEventComm { + + + interface Event { + oneway void send(in any event); + void send_sync(in any event); + }; + + interface Channel : CosEventChannelAdmin::EventChannel, Event {}; + + interface CAdmin : CosEventChannelAdmin::ConsumerAdmin, Event {}; + + interface PullerS : CosEventChannelAdmin::ProxyPullSupplier, Event {}; + + interface PusherS : CosEventChannelAdmin::ProxyPushSupplier, Event {}; + +}; + + +#endif diff --git a/lib/cosEvent/src/oe_CosEventComm_CAdmin_impl.erl b/lib/cosEvent/src/oe_CosEventComm_CAdmin_impl.erl new file mode 100644 index 0000000..976c6db --- /dev/null +++ b/lib/cosEvent/src/oe_CosEventComm_CAdmin_impl.erl @@ -0,0 +1,233 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : oe_CosEventComm_CAdmin_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module(oe_CosEventComm_CAdmin_impl). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include("cosEventApp.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%% Exports from "CosEventChannelAdmin::ConsumerAdmin" +-export([obtain_push_supplier/3, + obtain_pull_supplier/3]). + + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +%% Exports from "oe_CosEventComm::Event" +-export([send/3, send_sync/4]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {channel_pid, typecheck, maxevents, proxies = [], + server_options}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([ChannelPid, TypeCheck, MaxEvents, ServerOpts]) -> + process_flag(trap_exit, true), + {ok, #state{channel_pid = ChannelPid, typecheck = TypeCheck, + maxevents = MaxEvents, server_options = ServerOpts}}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ?DBG("Terminating ~p~n", [_Reason]), + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% function : handle_info +%% Arguments: +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Effect : Functions demanded by the gen_server module. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, Reason}, #state{channel_pid = Pid} = State) -> + ?DBG("Parent Channel terminated ~p~n", [Reason]), + orber:dbg("[~p] oe_CosEventComm_PullerS_impl:handle_info(~p);~n" + "My Channel terminated and so will I which will cause" + " my children to do the same thing.", + [?LINE, Reason], ?DEBUG_LEVEL), + {stop, Reason, State}; +handle_info({'EXIT', Pid, _Reason}, #state{proxies = Proxies} = State) -> + %% A child terminated which is normal. Hence, no logging. + ?DBG("Probably a child terminated ~p~n", [_Reason]), + {noreply, State#state{proxies = lists:keydelete(Pid, 2, Proxies)}}; +handle_info(_Info, State) -> + ?DBG("Unknown Info ~p~n", [_Info]), + {noreply, State}. + +%%---------------------------------------------------------------------- +%% Function : obtain_push_supplier +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +obtain_push_supplier(_, _, #state{server_options = ServerOpts} = State) -> + case catch 'oe_CosEventComm_PusherS':oe_create_link([self(), + State#state.typecheck], + [{sup_child, true}|ServerOpts]) of + {ok, Pid, Proxy} -> + ?DBG("Started a new oe_CosEventComm_PusherS.~n", []), + {reply, Proxy, State#state{proxies = [{Proxy, Pid}|State#state.proxies]}}; + Other -> + orber:dbg("[~p] oe_CosEventComm_CAdmin:obtain_push_supplier();~nError: ~p", + [?LINE, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------- +%% Function : obtain_pull_supplier +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +obtain_pull_supplier(_, _, #state{server_options = ServerOpts} = State) -> + case catch 'oe_CosEventComm_PullerS':oe_create_link([self(), + State#state.typecheck, + State#state.maxevents], + [{sup_child, true}|ServerOpts]) of + {ok, Pid, Proxy} -> + ?DBG("Started a new oe_CosEventComm_PullerS.~n", []), + {reply, Proxy, State#state{proxies = [{Proxy, Pid}|State#state.proxies]}}; + Other -> + orber:dbg("[~p] oe_CosEventComm_CAdmin:obtain_pull_supplier();~nError: ~p", + [?LINE, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + + +%%---------------------------------------------------------------------- +%% Function : send +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +send(_, #state{proxies = Proxies} = State, Any) -> + ?DBG("Received Event ~p~n", [Any]), + case send_helper(Proxies, Any, [], false) of + ok -> + ?DBG("Received Event and forwarded it successfully.~n", []), + {noreply, State}; + {error, Dropped} -> + ?DBG("Received Event but forward failed to: ~p~n", [Dropped]), + RemainingProxies = delete_proxies(Dropped, Proxies), + {noreply, State#state{proxies = RemainingProxies}} + end. + +%%---------------------------------------------------------------------- +%% Function : send_sync +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +send_sync(_, OE_From, #state{proxies = Proxies} = State, Any) -> + ?DBG("Received Event ~p~n", [Any]), + corba:reply(OE_From, ok), + case send_helper(Proxies, Any, [], true) of + ok -> + ?DBG("Received Event and forwarded (sync) it successfully.~n", []), + {noreply, State}; + {error, Dropped} -> + ?DBG("Received Event but forward (sync) failed to: ~p~n", [Dropped]), + RemainingProxies = delete_proxies(Dropped, Proxies), + {noreply, State#state{proxies = RemainingProxies}} + end. + + +%%====================================================================== +%% Internal functions +%%====================================================================== +send_helper([], _, [], _) -> + ok; +send_helper([], _, Dropped, _) -> + {error, Dropped}; +send_helper([{ObjRef, Pid}|T], Event, Dropped, false) -> + case catch 'oe_CosEventComm_Event':send(ObjRef, Event) of + ok -> + send_helper(T, Event, Dropped, false); + What -> + orber:dbg("[~p] oe_CosEventComm_CAdmin:send_helper(~p, ~p);~n" + "Bad return value ~p. Closing connection.", + [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL), + send_helper(T, Event, [{ObjRef, Pid}|Dropped], false) + end; +send_helper([{ObjRef, Pid}|T], Event, Dropped, Sync) -> + case catch 'oe_CosEventComm_Event':send_sync(ObjRef, Event) of + ok -> + send_helper(T, Event, Dropped, Sync); + What -> + orber:dbg("[~p] oe_CosEventComm_CAdmin:send_helper(~p, ~p);~n" + "Bad return value ~p. Closing connection.", + [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL), + send_helper(T, Event, [{ObjRef, Pid}|Dropped], Sync) + end. + +delete_proxies([], RemainingProxies) -> + RemainingProxies; +delete_proxies([{_,Pid}|T], Proxies) -> + Rest = lists:keydelete(Pid, 2, Proxies), + delete_proxies(T, Rest). + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosEvent/src/oe_CosEventComm_Channel_impl.erl b/lib/cosEvent/src/oe_CosEventComm_Channel_impl.erl new file mode 100644 index 0000000..531edaa --- /dev/null +++ b/lib/cosEvent/src/oe_CosEventComm_Channel_impl.erl @@ -0,0 +1,246 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : oe_CosEventComm_Channel_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module(oe_CosEventComm_Channel_impl). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include("cosEventApp.hrl"). + + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +%% Mandatory +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%% Exports from "CosEventChannelAdmin::EventChannel" +-export([for_consumers/3, + for_suppliers/3, + destroy/3]). + + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +%% Exports from "oe_CosEventComm::Event" +-export([send/3, send_sync/4]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {typecheck, pull_interval, maxevents, blocking, cadmins = [], + server_options}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([Options, ServerOpts]) -> + process_flag(trap_exit, true), + PullI = cosEventApp:get_option(?PULL_INTERVAL, Options), + TC = cosEventApp:get_option(?TYPECHECK, Options), + Max = cosEventApp:get_option(?MAXEVENTS, Options), + Blocking = cosEventApp:get_option(?BLOCKING, Options), + {ok, #state{typecheck = TC, pull_interval = PullI, maxevents = Max, + blocking = Blocking, server_options = ServerOpts}}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ?DBG("Terminating ~p~n", [_Reason]), + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% function : handle_info +%% Arguments: +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Effect : Functions demanded by the gen_server module. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, _Reason}, #state{cadmins = CAdmins} = State) -> + ?DBG("Probably a child terminated with Reason: ~p~n", [_Reason]), + {noreply, State#state{cadmins = lists:keydelete(Pid, 2, CAdmins)}}; +handle_info(_Info, State) -> + ?DBG("Unknown Info ~p~n", [_Info]), + {noreply, State}. + + +%%---------------------------------------------------------------------- +%% Function : for_consumers +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +for_consumers(_, _, #state{server_options = ServerOpts} = State) -> + case catch 'oe_CosEventComm_CAdmin':oe_create_link([self(), + State#state.typecheck, + State#state.maxevents, + ServerOpts], + [{sup_child, true}|ServerOpts]) of + {ok, Pid, AdminCo} -> + ?DBG("Created a new oe_CosEventComm_CAdmin.~n", []), + {reply, AdminCo, + State#state{cadmins = [{AdminCo, Pid}|State#state.cadmins]}}; + Other -> + orber:dbg("[~p] oe_CosEventComm_Channel:for_consumers(); Error: ~p", + [?LINE, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------- +%% Function : for_suppliers +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +for_suppliers(OE_This, _, #state{server_options = ServerOpts} = State) -> + case catch 'CosEventChannelAdmin_SupplierAdmin':oe_create_link([OE_This, self(), + State#state.typecheck, + State#state.pull_interval, + ServerOpts], + [{sup_child, true}|ServerOpts]) of + {ok, _Pid, AdminSu} -> + ?DBG("Created a new CosEventChannelAdmin_SupplierAdmin.~n", []), + {reply, AdminSu, State}; + Other -> + orber:dbg("[~p] oe_CosEventComm_Channel:for_suppliers();~nError: ~p", + [?LINE, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------- +%% Function : destroy +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +destroy(_, _, State) -> + ?DBG("Destroy invoked.", []), + {stop, normal, ok, State}. + +%%---------------------------------------------------------------------- +%% Function : send +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +send(_OE_This, #state{cadmins = CAdmins} = State, Any) -> + ?DBG("Received Event ~p~n", [Any]), + case send_helper(CAdmins, Any, [], false) of + ok -> + ?DBG("Received Event and forwarded it successfully.~n", []), + {noreply, State}; + {error, Dropped} -> + ?DBG("Received Event but forward failed for: ~p~n", [Dropped]), + RemainingAdmins = delete_cadmin(Dropped, CAdmins), + {noreply, State#state{cadmins = RemainingAdmins}} + end. + +%%---------------------------------------------------------------------- +%% Function : send_sync +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +send_sync(_OE_This, OE_From, #state{cadmins = CAdmins, blocking = BL} = State, Any) -> + ?DBG("Received Event ~p~n", [Any]), + corba:reply(OE_From, ok), + case send_helper(CAdmins, Any, [], BL) of + ok -> + ?DBG("Received Event and forwarded (sync) it successfully.~n", []), + {reply, ok, State}; + {error, Dropped} -> + ?DBG("Received Event but forward (sync) failed for: ~p~n", [Dropped]), + RemainingAdmins = delete_cadmin(Dropped, CAdmins), + {reply, ok, State#state{cadmins = RemainingAdmins}} + end. + + +%%====================================================================== +%% Internal functions +%%====================================================================== +send_helper([], _, [], _) -> + ok; +send_helper([], _, Dropped, _) -> + {error, Dropped}; +send_helper([{ObjRef, Pid}|T], Event, Dropped, false) -> + case catch 'oe_CosEventComm_CAdmin':send(ObjRef, Event) of + ok -> + send_helper(T, Event, Dropped, false); + What -> + orber:dbg("[~p] oe_CosEventComm_Channel:send_helper(~p, ~p);~n" + "Bad return value ~p. Closing connection.", + [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL), + send_helper(T, Event, [{ObjRef, Pid}|Dropped], false) + end; +send_helper([{ObjRef, Pid}|T], Event, Dropped, Sync) -> + case catch 'oe_CosEventComm_CAdmin':send_sync(ObjRef, Event) of + ok -> + send_helper(T, Event, Dropped, Sync); + What -> + orber:dbg("[~p] oe_CosEventComm_Channel:send_helper(~p, ~p);~n" + "Bad return value ~p. Closing connection.", + [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL), + send_helper(T, Event, [{ObjRef, Pid}|Dropped], Sync) + end. + + +delete_cadmin([], RemainingAdmins) -> + RemainingAdmins; +delete_cadmin([{_,Pid}|T], CAdmins) -> + Rest = lists:keydelete(Pid, 2, CAdmins), + delete_cadmin(T, Rest). + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosEvent/src/oe_CosEventComm_PullerS_impl.erl b/lib/cosEvent/src/oe_CosEventComm_PullerS_impl.erl new file mode 100644 index 0000000..5f2733e --- /dev/null +++ b/lib/cosEvent/src/oe_CosEventComm_PullerS_impl.erl @@ -0,0 +1,280 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : oe_CosEventComm_PullerS_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module(oe_CosEventComm_PullerS_impl). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include("CosEventChannelAdmin.hrl"). +-include("CosEventComm.hrl"). +-include("cosEventApp.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). +%% Exports from "CosEventChannelAdmin::ProxyPullSupplier" +-export([connect_pull_consumer/4]). + +%% Exports from "CosEventComm::PullSupplier" +-export([pull/3, + try_pull/3, + disconnect_pull_supplier/3]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +%% Exports from "oe_CosEventComm::Event +-export([send/3, send_sync/4]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {admin_pid, client, db, respond_to, typecheck, maxevents}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([AdminPid, TypeCheck, MaxEvents]) -> + process_flag(trap_exit, true), + {ok, #state{admin_pid = AdminPid, + db = ets:new(oe_ets, [set, private, ordered_set]), + typecheck = TypeCheck, maxevents = MaxEvents}}. + +%%---------------------------------------------------------------------% +%% function : handle_info +%% Arguments: +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Effect : Functions demanded by the gen_server module. +%% The CosEvent specification states: +%% "A nil object reference may be passed to the connect_pull_consumer operation; +%% if so a channel cannot invoke a disconnect_pull_consumer operation on the +%% consumer; the consumer may be disconnected from the channel without being +%% informed." +%% If we would invoke the disconnect_pull_consumer operation +%% at the same time as the client tries to pull an event it +%% would cause a dead-lock. We can solve this by spawning a process +%% but as is the client will discover that the object no longer exists +%% the next time it tries to pull an event. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, Reason}, #state{admin_pid = Pid} = State) -> + orber:dbg("[~p] oe_CosEventComm_PullerS_impl:handle_info(~p);~n" + "My Admin terminated and so will I.", + [?LINE, Reason], ?DEBUG_LEVEL), + {stop, Reason, State}; +handle_info(_Info, State) -> + ?DBG("Unknown Info ~p~n", [_Info]), + {noreply, State}. + +%%---------------------------------------------------------------------% +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, #state{client = undefined, respond_to = undefined, db = DB}) -> + ?DBG("Terminating ~p; no client connected and no pending pull's.~n", [_Reason]), + ets:delete(DB), + ok; +terminate(_Reason, #state{client = undefined, respond_to = ReplyTo, db = DB}) -> + ?DBG("Terminating ~p; no client connected but a pending pull.~n", [_Reason]), + corba:reply(ReplyTo, {'EXCEPTION', #'CosEventComm_Disconnected'{}}), + ets:delete(DB), + ok; +terminate(_Reason, #state{client = Client, respond_to = undefined, db = DB}) -> + ?DBG("Terminating ~p; no pending pull~n", [_Reason]), + cosEventApp:disconnect('CosEventComm_PullConsumer', + disconnect_pull_consumer, Client), + ets:delete(DB), + ok; +terminate(_Reason, #state{client = Client, respond_to = ReplyTo, db = DB}) -> + ?DBG("Terminating ~p; pending pull~n", [_Reason]), + corba:reply(ReplyTo, {'EXCEPTION', #'CosEventComm_Disconnected'{}}), + cosEventApp:disconnect('CosEventComm_PullConsumer', + disconnect_pull_consumer, Client), + ets:delete(DB), + ok. + +%%---------------------------------------------------------------------% +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_pull_consumer +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +connect_pull_consumer(_OE_This, _OE_From, #state{client = undefined, + typecheck = TypeCheck} = State, + NewClient) -> + case corba_object:is_nil(NewClient) of + true -> + ?DBG("A NIL client supplied.~n", []), + {reply, ok, State}; + false -> + cosEventApp:type_check(NewClient, 'CosEventComm_PullConsumer', TypeCheck), + ?DBG("Connected to client.~n", []), + {reply, ok, State#state{client = NewClient}} + end; +connect_pull_consumer(_, _, _, _) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}). + + +%%---------------------------------------------------------------------% +%% Function : pull +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +pull(_OE_This, OE_From, State) -> + case get_event(State#state.db) of + false -> + ?DBG("pull invoked but no event stored; put the client on hold.~n", []), + {noreply, State#state{respond_to = OE_From}}; + Event -> + ?DBG("pull invoked and returned: ~p~n", [Event]), + {reply, Event, State} + end. + +%%---------------------------------------------------------------------% +%% Function : try_pull +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +try_pull(_OE_This, _OE_From, State) -> + case get_event(State#state.db) of + false -> + ?DBG("try_pull invoked but no event stored.~n", []), + {reply, {any:create(orber_tc:long(), 0), false}, State}; + Event -> + ?DBG("try_pull invoked and returned: ~p~n", [Event]), + {reply, {Event, true}, State} + end. + +%%---------------------------------------------------------------------% +%% Function : disconnect_pull_supplier +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +disconnect_pull_supplier(_OE_This, _OE_From, State) -> + ?DBG("Disconnect invoked ~p ~n", [State]), + {stop, normal, ok, State#state{client = undefined}}. + + +%%====================================================================== +%% Internal functions +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : send +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +send(_OE_This, #state{respond_to = undefined} = State, Any) -> + ?DBG("Received event ~p and stored it.~n", [Any]), + store_event(State#state.db, State#state.maxevents, Any), + {noreply, State}; +send(_OE_This, State, Any) -> + ?DBG("Received event ~p and sent it to pending client.~n", [Any]), + corba:reply(State#state.respond_to, Any), + {noreply, State#state{respond_to = undefined}}. + +%%---------------------------------------------------------------------% +%% Function : send_sync +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +send_sync(_OE_This, _OE_From, #state{respond_to = undefined} = State, Any) -> + ?DBG("Received event ~p and stored it (sync).~n", [Any]), + store_event(State#state.db, State#state.maxevents, Any), + {reply, ok, State}; +send_sync(_OE_This, _OE_From, State, Any) -> + ?DBG("Received event ~p and sent it to pending client (sync).~n", [Any]), + corba:reply(State#state.respond_to, Any), + {reply, ok, State#state{respond_to = undefined}}. + + +%%---------------------------------------------------------------------% +%% Function : store_event +%% Arguments : DB - ets reference +%% Event - CORBA::Any +%% Returns : true +%% Description: Insert the event in FIFO order. +%%---------------------------------------------------------------------- +store_event(DB, Max, Event) -> + case ets:info(DB, size) of + CurrentSize when CurrentSize < Max -> + ets:insert(DB, {now(), Event}); + _ -> + orber:dbg("[~p] oe_CosEventComm_PullerS:store_event(~p); DB full drop event.", + [?LINE, Event], ?DEBUG_LEVEL), + true + end. + +%%---------------------------------------------------------------------% +%% Function : get_event +%% Arguments : DB - ets reference +%% Event - CORBA::Any +%% Returns : false | Event (CORBA::Any) +%% Description: Lookup event in FIFO order; return false if no event exists. +%%---------------------------------------------------------------------- +get_event(DB) -> + case ets:first(DB) of + '$end_of_table' -> + false; + Key -> + [{_, Event}] = ets:lookup(DB, Key), + ets:delete(DB, Key), + Event + end. + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosEvent/src/oe_CosEventComm_PusherS_impl.erl b/lib/cosEvent/src/oe_CosEventComm_PusherS_impl.erl new file mode 100644 index 0000000..c64b01e --- /dev/null +++ b/lib/cosEvent/src/oe_CosEventComm_PusherS_impl.erl @@ -0,0 +1,217 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : oe_CosEventComm_PusherS_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module(oe_CosEventComm_PusherS_impl). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include("CosEventChannelAdmin.hrl"). +-include("CosEventComm.hrl"). +-include("cosEventApp.hrl"). + + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%% Exports from "CosEventChannelAdmin::ProxyPushSupplier" +-export([connect_push_consumer/4]). + +%% Exports from "CosEventComm::PushSupplier" +-export([disconnect_push_supplier/3]). + + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +%% Exports from "oe_CosEventComm::Event" +-export([send/3, send_sync/4]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {admin_pid, client, typecheck}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([AdminPid, TypeCheck]) -> + process_flag(trap_exit, true), + {ok, #state{admin_pid = AdminPid, typecheck = TypeCheck}}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, #state{client = undefined}) -> + ?DBG("Terminating ~p; no client connected.~n", [_Reason]), + ok; +terminate(_Reason, #state{client = Client} = _State) -> + ?DBG("Terminating ~p~n", [_Reason]), + cosEventApp:disconnect('CosEventComm_PushConsumer', + disconnect_push_consumer, Client), + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% function : handle_info +%% Arguments: +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Effect : Functions demanded by the gen_server module. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, Reason}, #state{admin_pid = Pid} = State) -> + ?DBG("Parent Admin terminated ~p~n", [Reason]), + orber:dbg("[~p] oe_CosEventComm_PusherS_impl:handle_info(~p);~n" + "My Admin terminated and so will I.", + [?LINE, Reason], ?DEBUG_LEVEL), + {stop, Reason, State}; +handle_info(_Info, State) -> + ?DBG("Unknown Info ~p~n", [_Info]), + {noreply, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_push_consumer +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +connect_push_consumer(_OE_This, _, #state{client = undefined, + typecheck = TypeCheck} = State, NewClient) -> + case corba_object:is_nil(NewClient) of + true -> + orber:dbg("[~p] oe_CosEventComm_PusherS_impl:connect_push_consumer(..);~n" + "Supplied a NIL reference which is not allowed.", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}); + false -> + cosEventApp:type_check(NewClient, 'CosEventComm_PushConsumer', TypeCheck), + ?DBG("Connected to client.~n", []), + {reply, ok, State#state{client = NewClient}} + end; +connect_push_consumer(_, _, _, _) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}). + + +%%---------------------------------------------------------------------% +%% Function : disconnect_push_supplier +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +disconnect_push_supplier(_OE_This, _, State) -> + ?DBG("Disconnect invoked ~p ~n", [State]), + {stop, normal, ok, State#state{client = undefined}}. + +%%====================================================================== +%% Internal functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : send +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +send(_OE_This, #state{client = undefined} = State, _Any) -> + %% No consumer connected. + ?DBG("Received event ~p but have no client.~n", [_Any]), + {noreply, State}; +send(_OE_This, #state{client = Client} = State, Any) -> + %% Push Data + case catch 'CosEventComm_PushConsumer':push(Client, Any) of + ok -> + ?DBG("Received event ~p and delivered it client.~n", [Any]), + {noreply, State}; + {'EXCEPTION', #'CosEventComm_Disconnected'{}} -> + ?DBG("Received event ~p but failed to deliver it since the client claims we are disconnected.~n", [Any]), + {stop, normal, State#state{client = undefined}}; + Other -> + ?DBG("Received event ~p but failed to deliver it to client.~n", [Any]), + orber:dbg("[~p] oe_CosEventComm_PusherS_impl:send(~p);~n" + "My Client behaves badly, returned ~p, so I will terminate.", + [?LINE, Any, Other], ?DEBUG_LEVEL), + {stop, normal, State} + end. + + +%%---------------------------------------------------------------------- +%% Function : send_sync +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +send_sync(_OE_This, _OE_From, #state{client = undefined} = State, _Any) -> + %% No consumer connected. + ?DBG("Received event ~p but have no client.~n", [_Any]), + {reply, ok, State}; +send_sync(_OE_This, OE_From, #state{client = Client} = State, Any) -> + corba:reply(OE_From, ok), + %% Push Data + case catch 'CosEventComm_PushConsumer':push(Client, Any) of + ok -> + ?DBG("Received event ~p and delivered (sync) it client.~n", [Any]), + {noreply, State}; + {'EXCEPTION', #'CosEventComm_Disconnected'{}} -> + ?DBG("Received event ~p but failed to deliver (sync) it since the client claims we are disconnected.~n", [Any]), + {stop, normal, State#state{client = undefined}}; + Other -> + ?DBG("Received event ~p but failed to deliver (sync) it to client.~n", [Any]), + orber:dbg("[~p] oe_CosEventComm_PusherS_impl:send_sync(~p);~n" + "My Client behaves badly, returned ~p, so I will terminate.", + [?LINE, Any, Other], ?DEBUG_LEVEL), + {stop, normal, State} + end. + + +%%====================================================================== +%% END OF MODULE +%%====================================================================== + diff --git a/lib/cosEvent/vsn.mk b/lib/cosEvent/vsn.mk new file mode 100644 index 0000000..953e5fc --- /dev/null +++ b/lib/cosEvent/vsn.mk @@ -0,0 +1,10 @@ + +COSEVENT_VSN = 2.1.7 + +TICKETS = OTP-8201 + +TICKETS_2.1.6 = OTP-7987 + +TICKETS_2.1.5 = OTP-7837 + +TICKETS_2.1.4 = OTP-7595 diff --git a/lib/cosEventDomain/AUTHORS b/lib/cosEventDomain/AUTHORS new file mode 100644 index 0000000..6d03df4 --- /dev/null +++ b/lib/cosEventDomain/AUTHORS @@ -0,0 +1,4 @@ +Original Authors: +Niclas Eklund + +Contributors: diff --git a/lib/cosEventDomain/Makefile b/lib/cosEventDomain/Makefile new file mode 100644 index 0000000..566141c --- /dev/null +++ b/lib/cosEventDomain/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(COSEVENTDOMAIN_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk + diff --git a/lib/cosEventDomain/doc/html/.gitignore b/lib/cosEventDomain/doc/html/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEventDomain/doc/man3/.gitignore b/lib/cosEventDomain/doc/man3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEventDomain/doc/man6/.gitignore b/lib/cosEventDomain/doc/man6/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEventDomain/doc/pdf/.gitignore b/lib/cosEventDomain/doc/pdf/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEventDomain/doc/src/CosEventDomainAdmin.xml b/lib/cosEventDomain/doc/src/CosEventDomainAdmin.xml new file mode 100644 index 0000000..d0aac96 --- /dev/null +++ b/lib/cosEventDomain/doc/src/CosEventDomainAdmin.xml @@ -0,0 +1,92 @@ + + + + +
+ + 2002 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventDomainAdmin + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2001-08-20 + PA1 +
+ CosEventDomainAdmin + This module export functions which return QoS and Admin Properties constants. + +

To get access to all definitions include necessary files by using:

+
+ + + 'CycleDetection'() -> string() + Return the CycleDetection identifier required when defining QoS Properties + +

This function returns the CycleDetection identifier; required when + defining QoS Properties.

+
+
+ + 'AuthorizeCycles'() -> short() + Return the AuthorizeCycles value; required when defining QoS Properties + +

This function returns the AuthorizeCycles value; required when + defining QoS Properties.

+
+
+ + 'ForbidCycles'() -> short() + Return the ForbidCycles value; required when defining QoS Properties + +

This function returns the ForbidCycles value; required when + defining QoS Properties.

+
+
+ + 'DiamondDetection'() -> string() + Return the DiamondDetection identifier required when defining QoS Properties + +

This function returns the DiamondDetection identifier; required when + defining QoS Properties.

+
+
+ + 'AuthorizeDiamonds'() -> short() + Return the AuthorizeDiamonds value; required when defining QoS Properties + +

This function returns the AuthorizeDiamonds value; required when + defining QoS Properties.

+
+
+ + 'ForbidDiamonds'() -> short() + Return the ForbidDiamonds value; required when defining QoS Properties + +

This function returns the ForbidDiamonds value; required when + defining QoS Properties.

+
+
+
+ +
+ diff --git a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml new file mode 100644 index 0000000..cf1cdab --- /dev/null +++ b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml @@ -0,0 +1,627 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosEventDomainAdmin_­EventDomain + ..._EventDomain + + + Niclas Eklund + + 2001-08-20 + PA1 +
+ CosEventDomainAdmin_EventDomain + This module implements the Event Domain interface. + +

To get access to all definitions include necessary files by using:

+

This module also exports the functions described in:

+ + CosNotification_QoSAdmin + CosNotification_AdminPropertiesAdmin + +
+ + + add_channel(EventDomain, Channel) -> MemberID + Add a new channel to the EventDomain + + EventDomain = Channel = #objref + MemberID = long() + + +

Adds the given channel to the target domain. The channel + must be a .

+
+
+ + get_all_channels(EventDomain) -> MemberIDSeq + Return all channel id's associated with target object + + EventDomain = #objref + MemberIDSeq = [long()] + + +

Returns a a sequence of all channels associated with + the target object.

+
+
+ + get_channel(EventDomain, MemberID) -> Reply + Return the channel associated with the given id + + EventDomain = #objref + MemberID = long() + Reply = Channel | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + Channel = #objref + + +

If the target domain have a + represented by the given id this channel is returned. Otherwise, + an exception is raised.

+
+
+ + remove_channel(EventDomain, MemberID) -> Reply + Remove the channel associated with the given id and remove all connections of that channel + + EventDomain = #objref + MemberID = long() + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a with the + exists it will removed and all its + terminated. Otherwise an exception is raised.

+
+
+ + add_connection(EventDomain, Connection) -> Reply + If possible, setup a connection described by the struct + + EventDomain = #objref + Connection = 'CosEventDomainAdmin_Connection'{supplier_id=MemberID, consumer_id=MemberID, ctype=Type, notification_style=Style} + MemberID = long() + Type = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' + Style = 'Pull' | 'Push' + Reply = ConnectionID | {'EXCEPTION', Exc} + ConnectionID = long() + Exc = #'CosNotifyChannelAdmin_ChannelNotFound'{} | #'CosNotifyChannelAdmin_TypeError'{} | #'CosEventDomainAdmin_AlreadyExists'{} | #'CosEventDomainAdmin_DiamondCreationForbidden'{diam=RouteSeq} | #'CosEventDomainAdmin_CycleCreationForbidden'{cyc=MemberIDSeq} + RouteSeq = [MemberIDSeq] + MemberIDSeq = [long()] + + +

The Connection parameter must contain valid data to enable + the target domain to setup a connection between two channels. + The struct members and + determines which channel should produce and consume events. + which type of events and if the supplier should push or the + consumer pull events is determined by and + respectively.

+

If the target domain is not able to setup the connection + the appropriate exception is raised.

+
+
+ + get_all_connections(EventDomain) -> ConnectionIDSeq + Return a sequence of all connections within the target domain + + EventDomain = #objref + ConnectionIDSeq = [long()] + + +

This operation returns a sequence of all connections within + the target domain.

+
+
+ + get_connection(EventDomain, ConnectionID) -> Reply + Return a struct describing the connection associated with the given id within the target domain + + EventDomain = #objref + ConnectionID = long() + Reply = Connection | {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} + Connection = 'CosEventDomainAdmin_Connection'{supplier_id=MemberID, consumer_id=MemberID, ctype=Type, notification_style=Style} + MemberID = long() + Type = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' + Style = 'Pull' | 'Push' + + +

If a connection identified by the given id exists within the + target domain, a which + describe the connection is returned. Otherwise, an exception + is raised.

+
+
+ + remove_connection(EventDomain, ConnectionID) -> Reply + Remove the connection identified by the given id from the target domain + + EventDomain = #objref + ConnectionID = long() + Reply = ok | {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} + + +

If the supplied connection id exists, the connection the + id represents is terminated. Otherwise, an exception is raised.

+
+
+ + get_offer_channels(EventDomain, MemberID) -> Reply + Return all id's of the channels which produce events received by the channel identified by the given id + + EventDomain = #objref + MemberID = long() + Reply = MemberIDSeq | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

This operation returns a sequence, containing the member id's + of all channels within the target domain which will supply events + to the channel identified by the given id. But, if no such + id exists in this domain, an exception is raised.

+
+
+ + get_subscription_channels(EventDomain, MemberID) -> Reply + Return all id's of the channels which consume events supplied by the channel identified by the given id + + EventDomain = #objref + Reply = MemberIDSeq | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

This operations behaves like ; + the difference is that the id's returned identifies channels + which will consume events supplied by the channel associated + with the given id.

+
+
+ + destroy(EventDomain) -> ok + Destroy the event domain and all connections within it + + EventDomain = #objref + + +

Calling this operation will terminate all connections + within the target domain. The domain will terminate but + all channels will not be affected.

+
+
+ + get_cycles(EventDomain) -> RouteSeq + Return a list of all cycles which exists within the target domain + + EventDomain = #objref + RouteSeq = [MemberIDSeq] + MemberIDSeq = [long()] + + +

Returns a list of all cycles within the target domain.

+
+
+ + get_diamonds(EventDomain) -> DiamondSeq + Return a list of all diamonds which exists within the target domain + + EventDomain = #objref + DiamondSeq = [RouteSeq] + RouteSeq = [MemberIDSeq] + MemberIDSeq = [long()] + + +

Returns a list of all diamonds within the target domain

+
+
+ + set_default_consumer_channel(EventDomain, MemberID) -> Reply + Set the channel represented by the given id as default for supplier clients + + EventDomain = #objref + Reply = MemberID | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + MemberID = long() + + +

If the given id represents a channel within the target domain, + this channel will be used when connection a supplier client + without specifying a certain channel. If no such channel exists + an exceptions is raised.

+
+
+ + set_default_supplier_channel(EventDomain, MemberID) -> Reply + Set the channel represented by the given id as default for supplier clients + + EventDomain = #objref + Reply = MemberID | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + MemberID = long() + + +

If the given id represents a channel within the target domain, + this channel will be used when connection a consumer client + without specifying a certain channel. If no such channel exists + an exceptions is raised.

+
+
+ + connect_push_consumer(EventDomain, Consumer) -> Reply + Connect the PushConsumer to the default Channel + + EventDomain = #objref + Consumer = CosEventComm::PushConsumer + Reply = CosNotifyChannelAdmin::ProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + PushConsumer to it. Otherwise, the + exception is raised.

+
+
+ + connect_pull_consumer(EventDomain, Consumer) -> Reply + Connect the PullConsumer to the default Channel + + EventDomain = #objref + Consumer = CosEventComm::PullConsumer + Reply = CosNotifyChannelAdmin::ProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + PullConsumer to it. Otherwise, the + exception is raised.

+
+
+ + connect_push_supplier(EventDomain, Supplier) -> Reply + Connect the PushSupplier to the default Channel + + EventDomain = #objref + Supplier = CosEventComm::PushSupplier + Reply = CosNotifyChannelAdmin::ProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + PushSupplier to it. Otherwise, the + exception is raised.

+
+
+ + connect_pull_supplier(EventDomain, Supplier) -> Reply + Connect the PullSupplier to the default Channel + + EventDomain = #objref + Supplier = CosEventComm::PullSupplier + Reply = CosNotifyChannelAdmin::ProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + PullSupplier to it. Otherwise, the + exception is raised.

+
+
+ + connect_structured_push_consumer(EventDomain, Consumer) -> Reply + Connect the StructuredPushConsumer to the default Channel + + EventDomain = #objref + Consumer = CosNotifyComm::StructuredPushConsumer + Reply = CosNotifyChannelAdmin::StructuredProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + StructuredPushConsumer to it. Otherwise, the + exception is raised.

+
+
+ + connect_structured_pull_consumer(EventDomain, Consumer) -> Reply + Connect the StructuredPullConsumer to the default Channel + + EventDomain = #objref + Consumer = CosNotifyComm::StructuredPullConsumer + Reply = CosNotifyChannelAdmin::StructuredProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + StructuredPullConsumer to it. Otherwise, the + exception is raised.

+
+
+ + connect_structured_push_supplier(EventDomain, Supplier) -> Reply + Connect the StructuredPushSupplier to the default Channel + + EventDomain = #objref + Supplier = CosNotifyComm::StructuredPushSupplier + Reply = CosNotifyChannelAdmin::StructuredProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + StructuredPushSupplier to it. Otherwise, the + exception is raised.

+
+
+ + connect_structured_pull_supplier(EventDomain, Supplier) -> Reply + Connect the StructuredPullSupplier to the default Channel + + EventDomain = #objref + Supplier = CosNotifyComm::StructuredPullSupplier + Reply = CosNotifyChannelAdmin::StructuredProxyPullConsume | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + StructuredPullSupplier to it. Otherwise, the + exception is raised.

+
+
+ + connect_sequence_push_consumer(EventDomain, Consumer) -> Reply + Connect the SequencePushConsumer to the default Channel + + EventDomain = #objref + Consumer = CosNotifyComm::SequencePushConsumer + Reply = CosNotifyChannelAdmin::SequenceProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + SequencePushConsumer to it. Otherwise, the + exception is raised.

+
+
+ + connect_sequence_pull_consumer(EventDomain, Consumer) -> Reply + Connect the SequencePullConsumer to the default Channel + + EventDomain = #objref + Consumer = CosNotifyComm::SequencePullConsumer + Reply = CosNotifyChannelAdmin::SequenceProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + SequencePullConsumer to it. Otherwise, the + exception is raised.

+
+
+ + connect_sequence_push_supplier(EventDomain, Supplier) -> Reply + Connect the SequencePushSupplier to the default Channel + + EventDomain = #objref + Supplier = CosNotifyComm::SequencePushSupplier + Reply = CosNotifyChannelAdmin::SequenceProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + SequencePushSupplier to it. Otherwise, the + exception is raised.

+
+
+ + connect_sequence_pull_supplier(EventDomain, Supplier) -> Reply + Connect the SequencePullSupplier to the default Channel + + EventDomain = #objref + Supplier = CosNotifyComm::SequencePullSupplier + Reply = CosNotifyChannelAdmin::SequenceProxyPullConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a default Channel have been set, this operation connects the given + SequencePullSupplier to it. Otherwise, the + exception is raised.

+
+
+ + connect_push_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply + Connect the PushConsumer to the Channel with the given MemberID + + EventDomain = #objref + Consumer = CosEventComm::PushConsumer + MemberID = long() + Reply = CosNotifyChannelAdmin::ProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given PushConsumer + to it. Otherwise, the + exception is raised.

+
+
+ + connect_pull_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply + Connect the PullConsumer to the Channel with the given MemberID + + EventDomain = #objref + Consumer = CosEventComm::PullConsumer + MemberID = long() + Reply = CosNotifyChannelAdmin::ProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given PullConsumer + to it. Otherwise, the + exception is raised.

+
+
+ + connect_push_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply + Connect the PushSupplier to the Channel with the given MemberID + + EventDomain = #objref + Supplier = CosEventComm::PushSupplier + MemberID = long() + Reply = CosNotifyChannelAdmin::ProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given PushSupplier + to it. Otherwise, the + exception is raised.

+
+
+ + connect_pull_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply + Connect the PullSupplier to the Channel with the given MemberID + + EventDomain = #objref + Supplier = CosEventComm::PullSupplier + MemberID = long() + Reply = CosNotifyChannelAdmin::ProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given PullSupplier + to it. Otherwise, the + exception is raised.

+
+
+ + connect_structured_push_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply + Connect the StructuredPushConsumer to the Channel with the given MemberID + + EventDomain = #objref + Consumer = CosNotifyComm::StructuredPushConsumer + MemberID = long() + Reply = CosNotifyChannelAdmin::StructuredProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given StructuredPushConsumer + to it. Otherwise, the + exception is raised.

+
+
+ + connect_structured_pull_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply + Connect the StructuredPullConsumer to the Channel with the given MemberID + + EventDomain = #objref + Consumer = CosNotifyComm::StructuredPullConsumer + MemberID = long() + Reply = CosNotifyChannelAdmin::StructuredProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given StructuredPullConsumer + to it. Otherwise, the + exception is raised.

+
+
+ + connect_structured_push_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply + Connect the StructuredPushSupplier to the Channel with the given MemberID + + EventDomain = #objref + Supplier = CosNotifyComm::StructuredPushSupplier + MemberID = long() + Reply = CosNotifyChannelAdmin::StructuredProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given StructuredPushSupplier + to it. Otherwise, the + exception is raised.

+
+
+ + connect_structured_pull_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply + Connect the StructuredPullSupplier to the Channel with the given MemberID + + EventDomain = #objref + Supplier = CosNotifyComm::StructuredPullSupplier + MemberID = long() + Reply = CosNotifyChannelAdmin::StructuredProxyPullConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given StructuredPullSupplier + to it. Otherwise, the + exception is raised.

+
+
+ + connect_sequence_push_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply + Connect the SequencePushConsumer to the Channel with the given MemberID + + EventDomain = #objref + Consumer = CosNotifyComm::SequencePushConsumer + MemberID = long() + Reply = CosNotifyChannelAdmin::SequenceProxyPushSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given SequencePushConsumer + to it. Otherwise, the + exception is raised.

+
+
+ + connect_sequence_pull_consumer_with_id(EventDomain, Consumer, MemberID) -> Reply + Connect the SequencePullConsumer to the Channel with the given MemberID + + EventDomain = #objref + Consumer = CosNotifyComm::SequencePullConsumer + MemberID = long() + Reply = CosNotifyChannelAdmin::SequenceProxyPullSupplier | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given SequencePullConsumer + to it. Otherwise, the + exception is raised.

+
+
+ + connect_sequence_push_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply + Connect the SequencePushSupplier to the Channel with the given MemberID + + EventDomain = #objref + Supplier = CosNotifyComm::SequencePushSupplier + MemberID = long() + Reply = CosNotifyChannelAdmin::SequenceProxyPushConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given SequencePushSupplier + to it. Otherwise, the + exception is raised.

+
+
+ + connect_sequence_pull_supplier_with_id(EventDomain, Supplier, MemberID) -> Reply + Connect the SequencePullSupplier to the Channel with the given MemberID + + EventDomain = #objref + Supplier = CosNotifyComm::SequencePullSupplier + MemberID = long() + Reply = CosNotifyChannelAdmin::SequenceProxyPullConsumer | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + + +

If a Channel associated with the given MemberID exists within the + target Domain, this operation connects the given SequencePullSupplier + to it. Otherwise, the + exception is raised.

+
+
+
+ +
+ diff --git a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml new file mode 100644 index 0000000..0720a4b --- /dev/null +++ b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml @@ -0,0 +1,88 @@ + + + + +
+ + 2001 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosEventDomainAdmin_­EventDomainFactory + ..._EventChannel + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2001-08-20 + PA1 +
+ CosEventDomainAdmin_EventDomainFactory + This module implements an Event Domain Factory interface, which is used to create new Event Domain instances. + +

To get access to all definitions include necessary files by using:

+
+ + + create_event_domain(Factory, QoS, Admin) -> Reply + Create a new ConsumerAdmin object + + Factory = #objref + QoS = CosNotification::QoSProperties + Admin = CosNotification::AdminProperties + Reply = {EventDomain, DomainID} | {'EXCEPTION', #'CosNotification_UnsupportedQoS'{}} | {'EXCEPTION', #'CosNotification_UnsupportedAdmin'{}} + EventDomain = #objref + + +

To create a new EventDomain this operation is used. If it is not + possible to support the given or + an exception is raised, which list the properties not supported. For more + information see the user's guide.

+
+
+ + get_all_domains(Factory) -> DomainIDSeq + Return a DomainID sequence of all domains associated with the target object + + Factory = #objref + DomainIDSeq = [long()] + + +

This function returns a DomainID sequence of all domains associated with the + target object.

+
+
+ + get_event_domain(Factory, DomainID) -> Reply + Return the domain associated with the given id + + Factory = #objref + DomainID = long() + Reply = EventDomain | {'EXCEPTION', #'CosEventDomainAdmin_DomainNotFound'{}} + EventDomain = #objref + + +

This operation returns the EventDomain object associated with the + given DomainID. If no such binding exists an exception is raised.

+
+
+
+ +
+ diff --git a/lib/cosEventDomain/doc/src/Makefile b/lib/cosEventDomain/doc/src/Makefile new file mode 100644 index 0000000..465b726 --- /dev/null +++ b/lib/cosEventDomain/doc/src/Makefile @@ -0,0 +1,227 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(COSEVENTDOMAIN_VSN) +APPLICATION=cosEventDomain + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + CosEventDomainAdmin_EventDomainFactory.xml \ + CosEventDomainAdmin_EventDomain.xml \ + CosEventDomainAdmin.xml \ + cosEventDomainApp.xml + +XML_PART_FILES = \ + part.xml \ + part_notes.xml +XML_CHAPTER_FILES = \ + ch_contents.xml \ + ch_introduction.xml \ + ch_QoS.xml \ + ch_event_domain_service.xml \ + notes.xml + +BOOK_FILES = book.xml + +TECHNICAL_DESCR_FILES = + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif + + +PS_FILES = + + +# ---------------------------------------------------- + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf + +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + rm -f $(JD_HTML) $(JD_PACK) + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(INTERNAL_HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTML_FILES) $(MAN3_FILES) + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) + +endif + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +$(INDEX_TARGET): $(INDEX_SRC) + sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + +release_spec: + diff --git a/lib/cosEventDomain/doc/src/book.gif b/lib/cosEventDomain/doc/src/book.gif new file mode 100644 index 0000000000000000000000000000000000000000..94b38687920c5386f0d90df2cfc962d66f52fbce GIT binary patch literal 1081 zcmV-91jhSENk%v~VJrYQ0K@U3Z&d%1>*52OU z=jZ3|@9+2b_W%F@EC2ui04xAE000I5ARvxpX`Uh%Eez$Ma2!{|XMe{g?|T;9x5JA^ zG%bL@N^vRj5RkV9bLkO4ZPIBmas5oR#mf&V1Q#(0YhcjmXe*9~d=7a)?vMy(=-KE* z8yQRzT~`AL3l4P-3kL!Lf=d(yg_TGJLq#4K5D7Jwg%4&P850c&1Y@8d0)H_S5pFPj z7ZR$K4m$^o4iXXx39coCpaZff8wUU$784g63O)Mnh1d zM*Ony;LwB#3?8W4Fn~dfDxggNp6C!kf(B*{AQb3^!o#OZ2{2Ij__0FI3O->S0!o2G zg@f-96evKTsnY>a2Pj~$%K;+++!`!k(;yCksSK!^1M@%uPY44fe1t$i?MDI+c2ZbC za|F=4KrQICaN${m0^A%h5YV8o0a~3adU`fEQr`1qssBIw;^v!UF;k;yW-v@4+eo>JYd}fHVVU z5gLf*p9x%mVi^DlSTI8WPNw|_zy%J@^^O%t7;wu6|1F@62n+%+n+O+(7C~JYKp}tz zPXIAiOdhnDfD0a6fWQkLNGO6;!$2WQfj6jx)&W2YPymny2!Ox=N)36z-FBgSXr4c6dN%+LI-06;0gjrH4CDHEr=iiO;mnh?Fk3i5Wq1C#9AnbqG>3C zxFaCoE>b2iV1odev}UfA7}V< + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEventDomain + Niclas Eklund + + 2001-08-20 + 1.0 +
+ + + cosEventDomain + + + + + + + + + + + + + + +
+ diff --git a/lib/cosEventDomain/doc/src/ch_QoS.xml b/lib/cosEventDomain/doc/src/ch_QoS.xml new file mode 100644 index 0000000..232cc40 --- /dev/null +++ b/lib/cosEventDomain/doc/src/ch_QoS.xml @@ -0,0 +1,117 @@ + + + + +
+ + 20022009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Quality Of Service and Admin Properties + + + 2000-05-29 + + ch_QoS.xml +
+ +
+ Quality Of Service and Admin Properties +

This chapter explains the allowed properties it is possible to set for this + application.

+ +
+ Quality Of Service +

The cosEventDomain application supports the following QoS settings:

+ + + QoS + Range + Default + + + CycleDetection + AuthorizeCycles/ForbidCycles + ForbidCycles + + + DiamondDetection + AuthorizeDiamonds/ForbidDiamonds + ForbidDiamonds + + Supported QoS settings +
+







Comments on the table 'Supported QoS Settings':

+ + CycleDetection + If a cycle is created, the user must be aware of the fact + that unless they set timeout on events, events that are not filtered + will loop endlessly through the topology. + DiamondDetection + A Diamond in this context, means that the same + event may reach a point in the graph by more than one route + (i.e. transitive). Hence, it is possible that multiple copies + are delivered. + +
+ +
+ Setting Quality Of Service +

Assume we have a Consumer Admin object which we want to change + the current Quality of Service. Typical usage:

+ +

If it is not possible to set the requested QoS the + exception is raised, which includes a sequence of 's + describing which QoS, possible range and why is not allowed. The error + codes are:

+ + UNSUPPORTED_PROPERTY - QoS not supported for this type of target object. + UNAVAILABLE_PROPERTY - due to current QoS settings the given property + is not allowed. + UNSUPPORTED_VALUE - property value out of range; valid range is returned. + UNAVAILABLE_VALUE - due to current QoS settings the given value is + not allowed; valid range is returned. + BAD_PROPERTY - unrecognized property. + BAD_TYPE - type of supplied property is incorrect. + BAD_VALUE - illegal value. + +

The CosEventDomainAdmin_EventDomain interface also supports an operation + called . The purpose of this operations is to check + if a QoS setting is supported by the target object and if so, the operation + returns additional properties which could be optionally added as well.

+
+ +
+ Admin Properties +

The OMG specification do not contain any definitions of Admin Properties. + Hence, the cosEventDomain application currently does not support any Admin + Properties.

+
+
+
+ diff --git a/lib/cosEventDomain/doc/src/ch_contents.xml b/lib/cosEventDomain/doc/src/ch_contents.xml new file mode 100644 index 0000000..bdb9515 --- /dev/null +++ b/lib/cosEventDomain/doc/src/ch_contents.xml @@ -0,0 +1,68 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The cosEventDomain Application + Niclas Eklund + + 2001-08-20 + B + ch_contents.xml +
+ +
+ Content Overview +

The cosEventDomain documentation is divided into three sections: +

+ + +

PART ONE - The User's Guide +

Description of the cosEventDomain Application including + services and a small tutorial demonstrating + the development of a simple service.

+
+ +

PART TWO - Release Notes +

A concise history of cosEventDomain.

+
+ +

PART THREE - The Reference Manual +

A quick reference guide, including a + brief description, to all the functions available in cosEventDomain.

+
+
+
+ +
+ Brief Description of the User's Guide +

The User's Guide contains the following parts:

+ + +

CosEventDomain overview

+
+ +

CosEventDomain installation and examples

+
+
+
+
+ diff --git a/lib/cosEventDomain/doc/src/ch_event_domain_service.xml b/lib/cosEventDomain/doc/src/ch_event_domain_service.xml new file mode 100644 index 0000000..62378ca --- /dev/null +++ b/lib/cosEventDomain/doc/src/ch_event_domain_service.xml @@ -0,0 +1,110 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Event Domain Service + Niclas Eklund + + 2001-08-20 + A + ch_event_domain_service.xml +
+ +
+ Overview of the CosEventDomain Service +

The Event Domain service allows programmers to manage a cluster + of information channels.

+ +
+ Event Domain Service Components +

There are two components in the OMG CosEventDomainAdmin service architecture:

+ + EventDomainFactory: a factory for creating EventDomains. + EventDomain: supplies a tool, which makes it easy to create + topologies of interconnected channels (i.e. a directed graph). + +
+ +
+ A Tutorial on How to Create a Simple Service +

To be able to use the cosEventDomain application, the cosNotification + and, possibly, the cosTime application must be installed.

+
+ +
+ How to Run Everything +

Below is a short transcript on how to run cosEventDomain.

+ +
+
+
+ diff --git a/lib/cosEventDomain/doc/src/ch_introduction.xml b/lib/cosEventDomain/doc/src/ch_introduction.xml new file mode 100644 index 0000000..8a85fc0 --- /dev/null +++ b/lib/cosEventDomain/doc/src/ch_introduction.xml @@ -0,0 +1,52 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Introduction to cosEventDomain + Niclas Eklund + + 2001-08-20 + + ch_introduction.xml +
+ +
+ Overview +

The cosEventDomain application is a Event Domain Service compliant with the OMG + Service CosEventDomainAdmin. +

+ +
+ Purpose and Dependencies +

CosEventDomain is dependent on Orber, which provides CORBA functionality in an Erlang environment.

+
+ +
+ Prerequisites +

To fully understand the concepts presented in the + documentation, it is recommended that the user is familiar + with distributed programming and CORBA. +

+
+
+
+ diff --git a/lib/cosEventDomain/doc/src/cosEventDomainApp.xml b/lib/cosEventDomain/doc/src/cosEventDomainApp.xml new file mode 100644 index 0000000..fe8df55 --- /dev/null +++ b/lib/cosEventDomain/doc/src/cosEventDomainApp.xml @@ -0,0 +1,149 @@ + + + + +
+ + 2001 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + cosEventDomainApp + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2001-08-20 + PA1 +
+ cosEventDomainApp + The main module of the cosEventDomain application. + +

To get access to the record definitions for the structures use:

+

This module contains the functions for starting and stopping the application.

+
+ + + install() -> Return + Install the cosEventDomain application + + Return = ok | {'EXCEPTION', E} | {'EXIT', R} + + +

This operation installs the cosEventDomain application.

+
+
+ + uninstall() -> Return + Uninstall the cosEventDomain application + + Return = ok | {'EXCEPTION', E} | {'EXIT', R} + + +

This operation uninstalls the cosEventDomain application.

+
+
+ + start() -> Return + Start the cosEventDomain application + + Return = ok | {error, Reason} + + +

This operation starts the cosEventDomain application.

+
+
+ + stop() -> Return + Stop the cosEventDomain application + + Return = ok | {error, Reason} + + +

This operation stops the cosEventDomain application.

+
+
+ + start_factory() -> Factory + Start a factory with default settings + + Factory = #objref + + +

This operation creates a new instance of a + Event Domain Factory + using the default settings.

+
+
+ + start_factory(Options) -> Factory + Start a factory with settings defined by the given options + + Options = [Option] + Option = currently no options defined. + Factory = #objref + + +

This operation creates a new instance of a + Event Domain Factory

+
+
+ + start_factory_link() -> Factory + Start a factory, which is linked to the invoking process, with default settings + + Factory = #objref + + +

This operation creates a new instance of a + Event Domain Factory, + which is linked to the invoking process, using the default settings.

+
+
+ + start_factory_link(Options) -> Factory + Start a factory, which is linked to the invoking process, with settings defined by the given options + + Options = [Option] + Option = currently no options defined. + Factory = #objref + + +

This operation creates a new instance of a + Event Domain Factory, + which is linked to the invoking process, with settings defined by the + given options. Allowed options are the same as for + .

+
+
+ + stop_factory(Factory) -> Reply + Terminate the target object + + Factory = #objref + Reply = ok | {'EXCEPTION', E} + + +

This operation stop the target factory.

+
+
+
+ +
+ diff --git a/lib/cosEventDomain/doc/src/fascicules.xml b/lib/cosEventDomain/doc/src/fascicules.xml new file mode 100644 index 0000000..0678195 --- /dev/null +++ b/lib/cosEventDomain/doc/src/fascicules.xml @@ -0,0 +1,18 @@ + + + + + + User's Guide + + + Reference Manual + + + Release Notes + + + Off-Print + + + diff --git a/lib/cosEventDomain/doc/src/make.dep b/lib/cosEventDomain/doc/src/make.dep new file mode 100644 index 0000000..2f3f1ae --- /dev/null +++ b/lib/cosEventDomain/doc/src/make.dep @@ -0,0 +1,23 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: CosEventDomainAdmin.tex CosEventDomainAdmin_EventDomain.tex \ + CosEventDomainAdmin_EventDomainFactory.tex \ + book.tex ch_QoS.tex ch_contents.tex ch_event_domain_service.tex \ + ch_introduction.tex cosEventDomainApp.tex \ + part.tex ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + diff --git a/lib/cosEventDomain/doc/src/notes.gif b/lib/cosEventDomain/doc/src/notes.gif new file mode 100644 index 0000000000000000000000000000000000000000..e000cca26a383722eca87f4d87a5841292b0b8ea GIT binary patch literal 2005 zcmc(e`(I0c1HeD$>})&L($>wE%9*B;E}M!dPv>-9341YwWX&zf>scU1zfBrl=I{N9;r;i^$ ze)#ZVWMt(1`}gnOy?gui?eOsMn>TM>zkWS5H1z7#tHHs+fq?;|(fIP^%NH+RJb(WD z*|TR)pFVx^ogEz=?d|P)y}qrjt+lnarKLru(`mKZ=H_ONMx$1%@7%d_`}XZyw{G3MdGp4N z8%<43jg5^B4Gq_?U%z(k+SRL9>+9>UT)9$LS65qGTT@eW`SRsUmo8nrc=5u83+KckWzORn^(EXDcf!&zw1P`t<2jr%qK=RFs#Ot5m9!Cr_R@apL&#<7H)K$BrF4 zdi1DLsXTJzNNH(lNl8g@aq;29hl`4e3JVJr3dNyAhYlV*SWr-qpP!$XmzSHHo0F3x zm&-FUGSbu2Wir|R{rmUr+qZY`-n6u|)YR0Jl$1St_9Q1K@7}$8*REYVckbM=V@Fa_ zl0+iezI}UQV&b-K+Y%BIwr<_JdGqE?n>KCSxN*aV4Pvo4E-p?a60KjqJ~lRX-MV!# zF)?e`u3fWc&Fa;wSFKvLa^=buD^>`F!ez^r2?T=0ix)>lMMXwNMnpvL`TX$k@UXD3 zkdTnz;NYO3Ac7zQ0|OT>TD_t~>&yScf|nl;PS)z!tt#o5`J!{InNIkDMn48x{RpYG`B=-}XBZ*Mm zJ0_E9VPQd|(M(NEQ52<8sT2wYK@bv&1j8@{LE!(5`#%Ezya3Qi0HOB$8kHskwQ`Hm z*OY4y(48X7__Y-+c}(wwXZqSxZHKVn+_d2V9bX<;)o5v8$jlB{tz6vnwfvQAiMw6t z0IXVSedvhT17nJCGJ_XCYT%)5*?chw5R9s25QXlX!e_sd7hr)!eyKroJ4zhgi|iRe z9BRcDRXkmj&PH5Z1EswZP1Yik}bX?KQfDMotrhur?Z`l6 z9SHWUks6^bPWsX|jEswdY)vps%VI@IAvY7W9?a_N?~xI!M!5pm(Ry5JJ;$6wSb!Kw z1Ofz-ES$>6ni1O}ScWTvR$Wsm*pF-~}^QqIoOkG6>BJ?$;+XE5N4m%cOVTgl$q1H6Cj2CRZ#Cwk*Z+A1}6-ZGIOnZ zriKR6JwuHEr#89IP&lU0d>}f|iQ2(xTebl}Km=JKc>w~{On}kI=M0e4E*aE>B!t(` zz!7B(z}xLdevm2fNGl*)VFk@hhEN1isQ4%eVdfhlo64C^B-c26^Z?T#Tc$&!YL-EE zsr_sc%})?_z}$saj#x(bLnO=CUH5f1>6}R!!dMZ|W9GTgpb9n@*5fiBqnDrne~DCT zx&%mdn3ma=CO4$ZCjP+)Zks2RB*+Tt`QEtb2g6+n+RKF1oJqVMUCo0mdGDTz#3Q^?T4648gGi%gvvJ#j{AlN2b z`m?E;VM>mcPQBC_Y6=8kn9B=CL=o-QgXt_x2k`|YJusL&`b=Pj%+?u4tr>8h24sDX + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEventDomain Release Notes + Niclas Eklund + + + + 2001-08-20 + A + notes.xml +
+ +
+ cosEventDomain 1.1.7 + +
+ Improvements and New Features + + +

+ The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.

+

+ Own Id: OTP-8201 Aux Id:

+
+
+
+
+ +
+ cosEventDomain 1.1.6 + +
+ Improvements and New Features + + +

Obsolete guards, e.g. record vs is_record, has been changed + to avoid compiler warnings.

+

Own id: OTP-7987

+
+
+
+
+ +
+ cosEventDomain 1.1.5 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7837

+
+
+
+
+ +
+ cosEventDomain 1.1.4 + +
+ Improvements and New Features + + +

Documentation source included in open source releases.

+

Own id: OTP-7595

+
+
+
+
+ +
+ cosEventDomain 1.1.3 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7011

+
+
+
+
+ +
+ cosEventDomain 1.1.2 + +
+ Improvements and New Features + + +

The documentation source has been converted from SGML to XML.

+

Own id: OTP-6754

+
+
+
+
+ +
+ cosEventDomain 1.1.1 + +
+ Improvements and New Features + + +

Minor Makefile changes.

+

Own id: OTP-6701

+
+
+
+
+ +
+ cosEventDomain 1.1 + +
+ Improvements and New Features + + +

The stub/skeleton-files generated by IC have been improved, + i.e., depending on the IDL-files, reduced the size of the + erl- and beam-files and decreased dependencies off Orber's + Interface Repository. It is necessary to re-compile all IDL-files + and use COS-applications, including Orber, compiled with + IC-4.2.

+

Own id: OTP-4576

+
+
+
+
+ +
+ cosEventDomain 1.0 + +
+ Improvements and New Features + + +

First release of the cosEventDomain application.

+
+
+
+
+
+ diff --git a/lib/cosEventDomain/doc/src/part.xml b/lib/cosEventDomain/doc/src/part.xml new file mode 100644 index 0000000..720a4d3 --- /dev/null +++ b/lib/cosEventDomain/doc/src/part.xml @@ -0,0 +1,39 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEventDomain User's Guide + Niclas Eklund + + 2001-08-20 + 1.0 +
+ +

The cosEventDomain application is an Erlang implementation of a + CORBA Service CosEventDomainAdmin.

+
+ + + + +
+ diff --git a/lib/cosEventDomain/doc/src/part_notes.xml b/lib/cosEventDomain/doc/src/part_notes.xml new file mode 100644 index 0000000..0979d6e --- /dev/null +++ b/lib/cosEventDomain/doc/src/part_notes.xml @@ -0,0 +1,36 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEventDomain Release Notes + Niclas Eklund + + 2001-08-20 + 1.0 +
+ +

The cosEventDomain Application is an Erlang implementation of a CORBA Service + CosEventDomainAdmin.

+
+ +
+ diff --git a/lib/cosEventDomain/doc/src/ref_man.gif b/lib/cosEventDomain/doc/src/ref_man.gif new file mode 100644 index 0000000000000000000000000000000000000000..b13c4efd53ff30209e94a832b9b141aefa01373e GIT binary patch literal 1530 zcmdVZdppw$0KoB|UD(ZKjLpudxl|bD5*~BdW(#wPxjQR!4XwvDQJz|2?rd%yODG+} zTS?d`8$ziw@9efjcbb8~ZJV`F`NeQj-Rb#--RW#!YS zPs_{8OG`^1KYmEb&dp9*T_4@VeSFc{Z zeEIUlix(;Hhy1Lrh+M1f0n>TM(S67S0;;O2u%F4=$ii+~`^0Klrkw{chQc_%8TvSw4P*9Mc zpP!ePmz$fLlanJ52(q)YuU)&AnVEUz%9YEPFK1+AT)K4W;>C;U>FH@{X%{YBNKH*W zfBt+*N=kBaa#B)KVq#)KLPC6e{JC@Ics$E-3+>FMd= z;o5R+g5Q78Vv{ zGTGeR+|10()YOzjBAJ+&7#kZK85t3YL|t879UUD4fq=*3wY9ZzI2;y>)zZ?^)YQaa zFd7;fYHDh#s;Vj~D$2^rC=?2bL?RFfI2;ax!IYGg6crVrP$&cf0fWIH5J*8m0r;Os z`p^I03jpi@P=FC!+v{kk6S6LO_!Iu)95sCwBtcqW%*9y*G+T7kk6cw&i6X!~u9ub^ z(;p_fv9U$vWTl#^q0-1BITpV6n#M{a{we|K$qn8tF1dhi2#U)iChGwf%c>!EMdamI z$h@1HHE$AU0uQ06DJaKq=RDnzU^TZiOigaDbX?9sbbG2Mo zru2uhl#`IQgUVf0v!Xj-d%-$1xRm>;TQmHNwcAfcM=qjwu=nh zQh;0;RMT@!2!f)5xXw7CWD^X8atslf08f~GlvPC&!u3CIvJ6wy=4qhoBAlk74dDIc za5tv{OoL_(_?n6N^K=DFVPbx|J4#5`n`9n$heG9OfAim6K_sx=yuqZzUrzW~%(8B5(t!Xl{Hb0?L6-vF=+wDe8$ zTT`s`Dq0fpfEZM3+{q@m}*YWuf-$-b$k$LLWEZK;Ee|dK!!GAvHA;V z*1da#TyGWrnurc+>Z42^g}P$+dV8CLlZ-G3$5&lvmrHi*;me*Y^_v!=AL*c_d4sqi z`SWVr{)P|6KptK|>YQR5CUyjEppnvPJ-9YQBBMdn(+)quWG#%To7OvoyB^9=`#bkY st1M+qtZTt#!ZD6_9%~hW^bvUb7(Sl{bx5FV=!1r@;+Z6>KNX<-3tg&0LjV8( literal 0 HcmV?d00001 diff --git a/lib/cosEventDomain/doc/src/ref_man.xml b/lib/cosEventDomain/doc/src/ref_man.xml new file mode 100644 index 0000000..ddb836e --- /dev/null +++ b/lib/cosEventDomain/doc/src/ref_man.xml @@ -0,0 +1,39 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosEventDomain Reference Manual + Niclas Eklund + + 2001-08-20 + 1.0 +
+ +

The cosEventDomain application is an Erlang implementation of + a CORBA Service CosEventDomainAdmin.

+
+ + + + +
+ diff --git a/lib/cosEventDomain/doc/src/summary.html.src b/lib/cosEventDomain/doc/src/summary.html.src new file mode 100644 index 0000000..922c956 --- /dev/null +++ b/lib/cosEventDomain/doc/src/summary.html.src @@ -0,0 +1 @@ +Orber OMG Event Domain Service \ No newline at end of file diff --git a/lib/cosEventDomain/doc/src/user_guide.gif b/lib/cosEventDomain/doc/src/user_guide.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6275a803db46bc56df2b31240f80e68a4eb28b5 GIT binary patch literal 1581 zcmd6mi9gc|0Kk8njctY*W^QwCJ{HX#%4V)-y(i>aMOY|Iy@!%dZA6YGb49u7IpPyu zxpLn_avvd{2!$L^&hlRW#rysR-_Q5+`C8dn8X8V>k`j;wKQ1gR%+Jry&CSiu&d$utOixe0fB$}JYHD(Fa$;g)e0+Rt zY;1INbYx^?czAedXlQV7@ZGz20|Nv7{r!D?eZ9TCJRYy7r>DESyQ{0Kv$M0KqocjO zy{)aSwY9aSrKP#Kxv8nCv9YnCq2bM&H}&=Pb#-;MwY4=hHPzMCuV25es;a82tgNW0 zc=_^WSy|bO7cWXnOG`>hii?Yjii!#g3kwPg^7Hfa^73+Xb8~WXva_?Zva&KWGoL+s z_Vnq~jEs!*^z{(M&Qxg*t zV`JkpXU-TI85tTH>g((4>FMd}>gwp|kVqtLZEYmX?x|!eX(Kl9CtEE3!%>OGRc>9)Rn&SYM zj~Y~*8(l`PO4G;6R;FqaD@X#~VMifcR)pt=DvF{Q3(>@Ud>(7)(V4{v)PmxVK~kPo zjj~AEyr<1v8vx#~Tk98U5_J`0L}~fU>RjhaAKM=MUf{g5m?T z)+IHOf7l%`QALwKCeyDj6SLD45WBagBU?Fw4{df%%9E4Y2u)Wk*W$nyCUXV^5gf*w zJcTmdm_5ACzSYODr)n2;x_FnPc`B(M`LXIbz9g71J`3n))Gq$bQK+sRivkPkZkj>F zXejb80{#?f()6mQl&jOcTB0m7HQ)B0eJ!3!3LG1z5Dy4!8UDX&qmZHiEZH4hCN$qe z4*)g+{|y}64a+3k1Ar7VS%DkXnyczs>8pr>ch^qPgriJZarAD;X*)P0t_Uea!m)bj zekgBBW+6d2l7{g|`zZIq7r_Y&symb`GN>UKUQ)c!TxUa0r_Gumy9Jeti%E)uL##a# zMGizq*jB%VA7Ip@(A3hq9YH69qL7NjkWRA2q5;hU`xYmEN)bB>aqrz!?T?Ynv*X-7 zk5PfTmt$8kTF6UOKy_o?XHYzxtkg%ZbG*StHxDNDsyD5c2a>x5vWvVCApVgu@XNF$})`XD-pCH3`9zE-Lj6@!*TS9lwVaP}h|-H2`m~ItYQE$0z|a zt4=D`BBR~(5MZ;L{+LQk#4$5Kz`eloKZBK-7eFm?OlZCy;GH~%L;($J;|e#tww(~b et1Zl|+ha7@T8X2%4FJEoWS?mjDfbqXtih~yb literal 0 HcmV?d00001 diff --git a/lib/cosEventDomain/ebin/.gitignore b/lib/cosEventDomain/ebin/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEventDomain/example/.gitignore b/lib/cosEventDomain/example/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEventDomain/include/.gitignore b/lib/cosEventDomain/include/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosEventDomain/info b/lib/cosEventDomain/info new file mode 100644 index 0000000..46ecf95 --- /dev/null +++ b/lib/cosEventDomain/info @@ -0,0 +1,2 @@ +group: orb +short: Orber OMG Event Domain Service diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin.cfg b/lib/cosEventDomain/src/CosEventDomainAdmin.cfg new file mode 100644 index 0000000..75a2720 --- /dev/null +++ b/lib/cosEventDomain/src/CosEventDomainAdmin.cfg @@ -0,0 +1,4 @@ +{this, "CosEventDomainAdmin::EventDomain"}. +{{handle_info, "CosEventDomainAdmin::EventDomain"}, true}. +{this, "CosEventDomainAdmin::EventDomainFactory"}. +{{handle_info, "CosEventDomainAdmin::EventDomainFactory"}, true}. diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin.idl b/lib/cosEventDomain/src/CosEventDomainAdmin.idl new file mode 100644 index 0000000..2ecd935 --- /dev/null +++ b/lib/cosEventDomain/src/CosEventDomainAdmin.idl @@ -0,0 +1,280 @@ +#ifndef _COS_EVENT_DOMAIN_ADMIN_IDL_ +#define _COS_EVENT_DOMAIN_ADMIN_IDL_ + +#pragma prefix "omg.org" + +// Event Domain Interface +#include "CosNotification.idl" +#include "CosEventComm.idl" +#include "CosNotifyComm.idl" +#include "CosNotifyChannelAdmin.idl" + + +module CosEventDomainAdmin { + + // The following constant declarations define the Event Domain + // QoS property names and the associated values each property can + // take on. The name/value pairs for each Event Domain property + // are grouped, beginning with a string constant defined for the + // property name, followed by the values the property can take on. + + const string CycleDetection = "CycleDetection"; + const short AuthorizeCycles = 0; // Default value + const short ForbidCycles = 1; + + const string DiamondDetection = "DiamondDetection"; + const short AuthorizeDiamonds = 0; // Default value + const short ForbidDiamonds = 1; + + + // The following enum declaration defines the types that a channel + // can be of. It is used to specify channel types while externalizing + // and instantiating topologies. + enum ChannelType + { + CHANNEL, + TYPED_CHANNEL, + LOG_CHANNEL, + TYPED_LOG_CHANNEL + }; + + enum NotificationStyle { + Push, + Pull + }; + + typedef long MemberID; + typedef sequence MemberIDSeq; + typedef long ConnectionID; + typedef sequence ConnectionIDSeq; + + struct Connection { + MemberID supplier_id; + MemberID consumer_id; + CosNotifyChannelAdmin::ClientType ctype; + NotificationStyle notification_style; + }; + + + typedef MemberIDSeq Route; + typedef sequence RouteSeq; + + typedef Route Cycle; + typedef sequence CycleSeq; + + typedef RouteSeq Diamond; + typedef sequence DiamondSeq; + + exception CycleCreationForbidden + { + Cycle cyc; + }; + + exception DiamondCreationForbidden + { + Diamond diam; + }; + + // Forward declarations + interface ConsumerAdmin; + interface SupplierAdmin; + + + typedef long DomainID; + typedef sequence DomainIDSeq; + typedef long ItemID; + + + // EventDomain administrates EventChannels that reside in the same + // administrative domain + exception ConnectionNotFound {}; + exception AlreadyExists {}; + + + interface EventDomain : + CosNotification::QoSAdmin , + CosNotification::AdminPropertiesAdmin { + + MemberID add_channel ( in CosNotifyChannelAdmin::EventChannel channel ); + + MemberIDSeq get_all_channels (); + + CosNotifyChannelAdmin::EventChannel get_channel ( in MemberID channel ) + raises ( CosNotifyChannelAdmin::ChannelNotFound ); + + void remove_channel ( in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + ConnectionID add_connection ( in Connection connection) + raises (CosNotifyChannelAdmin::ChannelNotFound, + CosEventChannelAdmin::TypeError, + AlreadyExists, + CycleCreationForbidden, + DiamondCreationForbidden); + + ConnectionIDSeq get_all_connections (); + + Connection get_connection ( in ConnectionID connection ) + raises ( ConnectionNotFound ); + + void remove_connection ( in ConnectionID connection ) + raises ( ConnectionNotFound ); + + CosNotifyChannelAdmin::ChannelIDSeq get_offer_channels ( in MemberID channel ) + raises ( CosNotifyChannelAdmin::ChannelNotFound ); + + CosNotifyChannelAdmin::ChannelIDSeq get_subscription_channels ( in MemberID channel ) + raises ( CosNotifyChannelAdmin::ChannelNotFound ); + + void destroy(); + + // Cycle and diamond configurations listing + CycleSeq get_cycles(); + + DiamondSeq get_diamonds(); + + + // Connection of clients to the domain + // - using no specific information + // - for any clients + void set_default_consumer_channel(in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + void set_default_supplier_channel(in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::ProxyPushSupplier + connect_push_consumer(in CosEventComm::PushConsumer client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::ProxyPullSupplier + connect_pull_consumer(in CosEventComm::PullConsumer client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::ProxyPushConsumer + connect_push_supplier(in CosEventComm::PushSupplier client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::ProxyPullConsumer + connect_pull_supplier(in CosEventComm::PullSupplier client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + // - for structured clients + CosNotifyChannelAdmin::StructuredProxyPushSupplier + connect_structured_push_consumer(in CosNotifyComm::StructuredPushConsumer client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::StructuredProxyPullSupplier + connect_structured_pull_consumer(in CosNotifyComm::StructuredPullConsumer client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::StructuredProxyPushConsumer + connect_structured_push_supplier(in CosNotifyComm::StructuredPushSupplier client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::StructuredProxyPullConsumer + connect_structured_pull_supplier(in CosNotifyComm::StructuredPullSupplier client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + // - for sequence clients + CosNotifyChannelAdmin::SequenceProxyPushSupplier + connect_sequence_push_consumer(in CosNotifyComm::SequencePushConsumer client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::SequenceProxyPullSupplier + connect_sequence_pull_consumer(in CosNotifyComm::SequencePullConsumer client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::SequenceProxyPushConsumer + connect_sequence_push_supplier(in CosNotifyComm::SequencePushSupplier client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::SequenceProxyPullConsumer + connect_sequence_pull_supplier(in CosNotifyComm::SequencePullSupplier client) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + // - using a channel id + // - for any clients + CosNotifyChannelAdmin::ProxyPushSupplier + connect_push_consumer_with_id(in CosEventComm::PushConsumer client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::ProxyPullSupplier + connect_pull_consumer_with_id(in CosEventComm::PullConsumer client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::ProxyPushConsumer + connect_push_supplier_with_id(in CosEventComm::PushSupplier client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::ProxyPullConsumer + connect_pull_supplier_with_id(in CosEventComm::PullSupplier client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + // - for structured clients + CosNotifyChannelAdmin::StructuredProxyPushSupplier + connect_structured_push_consumer_with_id(in CosNotifyComm::StructuredPushConsumer client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::StructuredProxyPullSupplier + connect_structured_pull_consumer_with_id(in CosNotifyComm::StructuredPullConsumer client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::StructuredProxyPushConsumer + connect_structured_push_supplier_with_id(in CosNotifyComm::StructuredPushSupplier client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::StructuredProxyPullConsumer + connect_structured_pull_supplier_with_id(in CosNotifyComm::StructuredPullSupplier client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + // - for sequence clients + CosNotifyChannelAdmin::SequenceProxyPushSupplier + connect_sequence_push_consumer_with_id(in CosNotifyComm::SequencePushConsumer client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::SequenceProxyPullSupplier + connect_sequence_pull_consumer_with_id(in CosNotifyComm::SequencePullConsumer client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::SequenceProxyPushConsumer + connect_sequence_push_supplier_with_id(in CosNotifyComm::SequencePushSupplier client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + + CosNotifyChannelAdmin::SequenceProxyPullConsumer + connect_sequence_pull_supplier_with_id(in CosNotifyComm::SequencePullSupplier client, + in MemberID channel) + raises (CosNotifyChannelAdmin::ChannelNotFound); + }; + + exception DomainNotFound {}; + + interface EventDomainFactory { + + EventDomain create_event_domain( in CosNotification::QoSProperties initialQoS , + in CosNotification::AdminProperties initialAdmin, + out DomainID id ) + raises ( CosNotification::UnsupportedQoS, + CosNotification::UnsupportedAdmin ); + + DomainIDSeq get_all_domains (); + + EventDomain get_event_domain ( + in DomainID id ) + raises ( DomainNotFound ); + }; +}; + +#endif // _COS_EVENT_DOMAIN_ADMIN_IDL_ + diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory_impl.erl b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory_impl.erl new file mode 100644 index 0000000..1729402 --- /dev/null +++ b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomainFactory_impl.erl @@ -0,0 +1,182 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosEventDomainAdmin_EventDomainFactory_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosEventDomainAdmin_EventDomainFactory_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +-include_lib("cosNotification/include/CosNotification.hrl"). + +-include("CosEventDomainAdmin.hrl"). +-include("cosEventDomainApp.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +-export([create_event_domain/4, + get_all_domains/2, + get_event_domain/3]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {current_id = -1, domains = []}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([]) -> + process_flag(trap_exit, true), + {ok, #state{}}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------- +%% Function : handle_info/2 +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Description: Handle, for example, exit signals. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, _Reason}, State) -> + {noreply, State#state{domains=delete_domain(State#state.domains, Pid, [])}}; +handle_info(_Info, State) -> + {noreply, State}. + + +%%---------------------------------------------------------------------- +%% Function : create_event_domain +%% Arguments : InitialQoS - CosNotification::QoSProperties +%% InitialAdmin - CosNotification::AdminProperties +%% Returns : CosEventDomainAdmin::EventDomain | +%% {'EXCEPTION', #'CosNotification_UnsupportedQoS'{}} | +%% {'EXCEPTION', #'CosNotification_UnsupportedAdmin'{}} | +%% Description: +%%---------------------------------------------------------------------- +create_event_domain(_OE_This, State, InitialQoS, InitialAdmin) -> + Id = cosEventDomainApp:create_id(State#state.current_id), + Admin = cosEventDomainApp:get_admin(InitialAdmin), + QoS = cosEventDomainApp:get_qos(InitialQoS), + case catch 'CosEventDomainAdmin_EventDomain':oe_create_link([self(), Id, + QoS, Admin], + [{sup_child, true}]) of + {ok, Pid, ED} -> + {reply, {ED, Id}, State#state{current_id = Id, + domains = [{Id, ED, Pid}|State#state.domains]}}; + What -> + orber:dbg("[~p] CosEventDomainAdmin_EventDomainFactory:" + "create_event_domain();~n" + "Failed creatin a new EventDomain due to: ~p", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------- +%% Function : get_all_domains +%% Arguments : - +%% Returns : CosEventDomainAdmin::DomainIDSeq - [long()] +%% Description: +%%---------------------------------------------------------------------- +get_all_domains(_OE_This, State) -> + {reply, get_all_domains_helper(State#state.domains, []), State}. + +get_all_domains_helper([], Acc) -> + Acc; +get_all_domains_helper([{Id, _, _}|T], Acc) -> + get_all_domains_helper(T, [Id|Acc]). + + +%%---------------------------------------------------------------------- +%% Function : get_event_domain +%% Arguments : CosEventDomainAdmin::DomainID - long() +%% Returns : CosEventDomainAdmin::EventDomain | +%% {'EXCEPTION', #'CosEventDomainAdmin_DomainNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +get_event_domain(_OE_This, State, DomainID) -> + {reply, get_event_domain_helper(State#state.domains, DomainID), State}. + +get_event_domain_helper([], _) -> + corba:raise(#'CosEventDomainAdmin_DomainNotFound'{}); +get_event_domain_helper([{Id, ED, _}|_], Id) -> + ED; +get_event_domain_helper([_|T], Id) -> + get_event_domain_helper(T, Id). + +%%====================================================================== +%% Internal functions +%%====================================================================== +delete_domain([], _, Acc) -> + %% The domain didn't exist. + Acc; +delete_domain([{_Id, _, Pid}], Pid, Acc) -> + Acc; +delete_domain([{_Id, _, Pid}|T], Pid, Acc) -> + T++Acc; +delete_domain([H|T], Pid, Acc) -> + delete_domain(T, Pid, [H|Acc]). + +%%====================================================================== +%% END OF MODULE +%%====================================================================== + diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl new file mode 100644 index 0000000..0b73100 --- /dev/null +++ b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl @@ -0,0 +1,1415 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosEventDomainAdmin_EventDomain_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosEventDomainAdmin_EventDomain_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +-include_lib("cosNotification/include/CosNotifyChannelAdmin.hrl"). +-include_lib("cosNotification/include/CosNotification.hrl"). + +-include("cosEventDomainApp.hrl"). +-include("CosEventDomainAdmin.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%%------------------ CosEventDomainAdmin::EventDomain ------------------ +-export([add_channel/3, + get_all_channels/2, + get_channel/3, + remove_channel/3, + add_connection/3, + get_all_connections/2, + get_connection/3, + remove_connection/3, + get_offer_channels/3, + get_subscription_channels/3, + destroy/2, + get_cycles/2, + get_diamonds/2, + set_default_consumer_channel/3, + set_default_supplier_channel/3, + connect_push_consumer/3, + connect_pull_consumer/3, + connect_push_supplier/3, + connect_pull_supplier/3, + connect_structured_push_consumer/3, + connect_structured_pull_consumer/3, + connect_structured_push_supplier/3, + connect_structured_pull_supplier/3, + connect_sequence_push_consumer/3, + connect_sequence_pull_consumer/3, + connect_sequence_push_supplier/3, + connect_sequence_pull_supplier/3, + connect_push_consumer_with_id/4, + connect_pull_consumer_with_id/4, + connect_push_supplier_with_id/4, + connect_pull_supplier_with_id/4, + connect_structured_push_consumer_with_id/4, + connect_structured_pull_consumer_with_id/4, + connect_structured_push_supplier_with_id/4, + connect_structured_pull_supplier_with_id/4, + connect_sequence_push_consumer_with_id/4, + connect_sequence_pull_consumer_with_id/4, + connect_sequence_push_supplier_with_id/4, + connect_sequence_pull_supplier_with_id/4]). + +%%------------------ CosNotification::QoSAdmin ------------------------- +-export([get_qos/2, + set_qos/3, + validate_qos/3]). + +%%------------------ CosNotification::AdminPropertiesAdmin ------------- +-export([get_admin/2, + set_admin/3]). + + + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {parent_pid, id, graph, ch_counter=-1, + co_counter=-1, def_supplier, def_consumer, diamonds, cyclic}). + +-record(connection, {supplier, consumer, data}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([ParentPid, MyId, QoS, _Admin]) -> + process_flag(trap_exit, true), + Diamonds = case lists:keysearch(?DiamondDetection, 1, QoS) of + false -> + ?ForbidDiamonds; + {value, {_, Value}} -> + Value + end, + case lists:keysearch(?CycleDetection, 1, QoS) of + {value, {_, ?AuthorizeCycles}} -> + {ok, #state{parent_pid = ParentPid, id = MyId, + graph = digraph:new([private]), + diamonds = Diamonds, cyclic = ?AuthorizeCycles}}; + _ -> + {ok, #state{parent_pid = ParentPid, id = MyId, + graph = digraph:new([acyclic, private]), + diamonds = Diamonds, cyclic = ?ForbidCycles}} + end. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, #state{graph = DG} = _State) -> + Connections = digraph:edges(DG), + close_connections(DG, Connections), + digraph:delete(DG), + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------- +%% Function : handle_info/2 +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Description: Handle, for example, exit signals. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, Reason}, #state{parent_pid = Pid} = State) -> + {stop, Reason, State}; +handle_info(_Info, State) -> + {noreply, State}. + +%%---------------------------------------------------------------------- +%%------------------ CosEventDomainAdmin::EventDomain ------------------ +%%---------------------------------------------------------------------% +%% Function : add_channel +%% Arguments : Channel - CosNotifyChannelAdmin::EventChannel +%% Returns : MemberId - long() +%% Description: +%%---------------------------------------------------------------------- +add_channel(_OE_This, #state{ch_counter=C, graph = DG} = State, Channel) -> + type_check(Channel, 'CosNotifyChannelAdmin_EventChannel'), + Id = cosEventDomainApp:create_id(C), + digraph:add_vertex(DG, Id, Channel), + {reply, Id, State#state{ch_counter=Id}}. + +%%---------------------------------------------------------------------% +%% Function : get_all_channels +%% Arguments : - +%% Returns : CosEventDomainAdmin::MemberIDSeq ([long()]) +%% Description: +%%---------------------------------------------------------------------- +get_all_channels(_OE_This, #state{graph = DG} = State) -> + {reply, digraph:vertices(DG), State}. + +%%---------------------------------------------------------------------% +%% Function : get_channel +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::EventChannel | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} +%% Description: +%%---------------------------------------------------------------------- +get_channel(_OE_This, #state{graph = DG} = State, Id) -> + {reply, lookup_channel(DG, Id), State}. + +%%---------------------------------------------------------------------% +%% Function : remove_channel +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} +%% Description: +%%---------------------------------------------------------------------- +remove_channel(_OE_This, #state{graph = DG} = State, Id) -> + lookup_channel(DG, Id), + close_connections(DG, digraph:edges(DG, Id)), + digraph:del_vertex(DG, Id), + {reply, ok, State}. + +%%---------------------------------------------------------------------% +%% Function : add_connection +%% Arguments : Connection - CosEventDomainAdmin::Connection +%% Returns : ConnectionID | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_TypeError'{}} | +%% {'EXCEPTION', #'CosEventDomainAdmin_AlreadyExists'{}} | +%% {'EXCEPTION', #'CosEventDomainAdmin_CycleCreationForbidden'{cyc}} | +%% {'EXCEPTION', #'CosEventDomainAdmin_DiamondCreationForbidden'{diam}} +%% Description: +%%---------------------------------------------------------------------- +add_connection(_OE_This, #state{graph = DG, co_counter = C} = State, + Connection) when is_record(Connection, + 'CosEventDomainAdmin_Connection') -> + SId = Connection#'CosEventDomainAdmin_Connection'.supplier_id, + SChannel = lookup_channel(DG, SId), + CId = Connection#'CosEventDomainAdmin_Connection'.consumer_id, + CChannel = lookup_channel(DG, CId), + case lists:member(CId, digraph:out_neighbours(DG, SId)) of + false -> + Id = cosEventDomainApp:create_id(C), + %% Try to insert the new connection before we actually setup a connection. + %% Note that #connection is NOT complete, hence, we must update it later. + case digraph:add_edge(DG, Id, SId, CId, #connection{data=Connection}) of + {error, {bad_edge, Path}} -> + corba:raise(#'CosEventDomainAdmin_CycleCreationForbidden'{cyc=Path}); + Id when State#state.diamonds == ?AuthorizeDiamonds -> + case catch setup_connection(Connection, SChannel, CChannel) of + {ok, SProxy, CProxy} -> + %% Now we can update the connection with complete data. + digraph:add_edge(DG, Id, SId, CId, #connection{supplier=SProxy, + consumer=CProxy, + data=Connection}), + {reply, Id, State#state{co_counter = Id}}; + {'EXCEPTION', E} -> + digraph:del_edge(DG, Id), + corba:raise(E); + What -> + digraph:del_edge(DG, Id), + orber:dbg("[~p] CosEventDomainAdmin_EventDomain:" + "add_connection(~p);~nFailed setting up" + " connection due to: ~p", + [?LINE, Connection, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_MAYBE}) + end; + Id -> + case get_diamonds_helper(State, false, SId) of + [] -> + case catch setup_connection(Connection, SChannel, CChannel) of + {ok, SProxy, CProxy} -> + %% Now we can update the connection with complete data. + digraph:add_edge(DG, Id, SId, CId, #connection{supplier=SProxy, + consumer=CProxy, + data=Connection}), + {reply, Id, State#state{co_counter = Id}}; + {'EXCEPTION', E} -> + digraph:del_edge(DG, Id), + corba:raise(E); + What -> + digraph:del_edge(DG, Id), + orber:dbg("[~p] CosEventDomainAdmin_EventDomain:" + "add_connection(~p);~nFailed setting" + " up connection due to: ~p", + [?LINE, Connection, What], + ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_MAYBE}) + end; + Diamond -> + %% Since no diamonds should exist the returned list can + %% only describe the diamond we just created. + digraph:del_edge(DG, Id), + corba:raise(#'CosEventDomainAdmin_DiamondCreationForbidden' + {diam=Diamond}) + end + end; + true -> + corba:raise(#'CosEventDomainAdmin_AlreadyExists'{}) + end. + + +%%---------------------------------------------------------------------% +%% Function : get_all_connections +%% Arguments : - +%% Returns : CosEventDomainAdmin::ConnectionIDSeq - [long()] +%% Description: +%%---------------------------------------------------------------------- +get_all_connections(_OE_This, #state{graph = DG} = State) -> + {reply, digraph:edges(DG), State}. + +%%---------------------------------------------------------------------% +%% Function : get_connection +%% Arguments : Id - CosEventDomainAdmin::ConnectionID (long()) +%% Returns : CosEventDomainAdmin::Connection | +%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +get_connection(_OE_This, #state{graph = DG} = State, Id) -> + {reply, lookup_connection_data(DG, Id), State}. + +%%---------------------------------------------------------------------% +%% Function : remove_connection +%% Arguments : Id - CosEventDomainAdmin::ConnectionID (long()) +%% Returns : ok | +%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +remove_connection(_OE_This, #state{graph = DG} = State, Id) -> + #connection{supplier=S, consumer=C, data=Connection} = + lookup_connection(DG, Id), + close_connection(Connection, S, C), + digraph:del_edge(DG, Id), + {reply, ok, State}. + + +%%---------------------------------------------------------------------% +%% Function : get_offer_channels +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ChannelIDSeq | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +get_offer_channels(_OE_This, #state{graph = DG, cyclic = Cyclic} = State, Id) -> + lookup_channel(DG, Id), + case digraph:vertex(DG, Id) of + {Id, _Channel} when Cyclic == ?ForbidCycles -> + {reply, digraph_utils:reaching_neighbours([Id], DG), State}; + {Id, _Channel} -> + %% If cyclic graphs is allowed 'Id' will appear in the returned list. + %% Hence, we must delete it. + {reply,lists:delete(Id, digraph_utils:reaching_neighbours([Id], DG)), + State}; + false -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}) + end. + +%%---------------------------------------------------------------------% +%% Function : get_subscription_channels +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ChannelIDSeq | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +get_subscription_channels(_OE_This, #state{graph = DG, cyclic = Cyclic} = State, Id) -> + lookup_channel(DG, Id), + case digraph:vertex(DG, Id) of + {Id, _Channel} when Cyclic == ?ForbidCycles -> + {reply, digraph_utils:reachable_neighbours([Id], DG), State}; + {Id, _Channel} -> + %% If cyclic graphs is allowed 'Id' will appear in the returned list. + %% Hence, we must delete it. + {reply, lists:delete(Id, digraph_utils:reachable_neighbours([Id], DG)), + State}; + false -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}) + end. + +%%---------------------------------------------------------------------% +%% Function : destroy +%% Arguments : - +%% Returns : ok +%% Description: +%%---------------------------------------------------------------------- +destroy(_OE_This, #state{graph = _DG} = State) -> + {stop, normal, ok, State}. + +%%---------------------------------------------------------------------% +%% Function : get_cycles +%% Arguments : - +%% Returns : CosEventDomainAdmin::CycleSeq +%% Description: +%%---------------------------------------------------------------------- +get_cycles(_OE_This, #state{cyclic = ?ForbidCycles} = State) -> + {reply, [], State}; +get_cycles(_OE_This, #state{graph = DG} = State) -> + {reply, digraph_utils:cyclic_strong_components(DG), State}. + +%%---------------------------------------------------------------------- +%% Function : get_diamonds +%% Arguments : - +%% Returns : CosEventDomainAdmin::DiamondSeq +%% Description: +%%---------------------------------------------------------------------- +get_diamonds(_OE_This, #state{diamonds = ?ForbidDiamonds} = State) -> + {reply, [], State}; +get_diamonds(_OE_This, State) -> + {reply, get_diamonds_helper(State, true), State}. + +get_diamonds_helper(#state{graph = DG} = _State, FindAll) -> + case find_candidates(DG) of + {[], _, _} -> + []; + {_, [], _} -> + []; + {COut, CIn, Max} -> + %% In this case we cannot tell if a diamond exists. Got to + %% check the paths between the candidates. + evaluate_candidates(DG, COut, CIn, [], Max, FindAll) + end. + +get_diamonds_helper(#state{graph = DG} = _State, FindAll, Vertex) -> + case find_candidates(DG, Vertex) of + {[], _, _} -> + []; + {_, [], _} -> + []; + {COut, CIn, Max} -> + %% In this case we cannot tell if a diamond exists. Got to + %% check the paths between the candidates. + evaluate_candidates(DG, COut, CIn, [], Max, FindAll) + end. + +%%---------------------------------------------------------------------% +%% Function : set_default_consumer_channel +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +set_default_consumer_channel(_OE_This, #state{graph = DG} = State, Id) -> + lookup_channel(DG, Id), + {reply, ok, State#state{def_consumer=Id}}. + +%%---------------------------------------------------------------------% +%% Function : set_default_supplier_channel +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +set_default_supplier_channel(_OE_This, #state{graph = DG} = State, Id) -> + lookup_channel(DG, Id), + {reply, ok, State#state{def_supplier=Id}}. + +%%---------------------------------------------------------------------% +%% Function : connect_push_consumer +%% Arguments : PC - CosEventComm::PushConsumer +%% Returns : CosNotifyChannelAdmin::ProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_push_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + type_check(PC, 'CosEventComm_PushConsumer'), + Proxy = connect_a_push_consumer(Ch, PC, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_pull_consumer +%% Arguments : PC - CosEventComm::PullConsumer +%% Returns : CosNotifyChannelAdmin::ProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_pull_consumer(_OE_This, #state{def_consumer = Ch} = State, PC) -> + Proxy = connect_a_pull_consumer(Ch, PC, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_push_supplier +%% Arguments : PS - CosEventComm::PushSupplier +%% Returns : CosNotifyChannelAdmin::ProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_push_supplier(_OE_This, #state{def_supplier = Ch} = State, PS) -> + Proxy = connect_a_push_supplier(Ch, PS, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_pull_supplier +%% Arguments : PS - CosEventComm::PullSupplier +%% Returns : CosNotifyChannelAdmin::ProxyPullConsumer +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_pull_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + type_check(PS, 'CosEventComm_PullSupplier'), + Proxy = connect_a_pull_supplier(Ch, PS, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_push_consumer +%% Arguments : PC - CosNotifyComm::StructuredPushConsumer +%% Returns : CosNotifyChannelAdmin::StructuredProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_push_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + type_check(PC, 'CosNotifyComm_StructuredPushConsumer'), + Proxy = connect_a_push_consumer(Ch, PC, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_pull_consumer +%% Arguments : PC - CosNotifyComm::StructuredPullConsumer +%% Returns : CosNotifyChannelAdmin::StructuredProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_pull_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + Proxy = connect_a_pull_consumer(Ch, PC, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_push_supplier +%% Arguments : PS - CosNotifyComm::StructuredPushSupplier +%% Returns : CosNotifyChannelAdmin::StructuredProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_push_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + Proxy = connect_a_push_supplier(Ch, PS, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_pull_supplier +%% Arguments : PS - CosNotifyComm::StructuredPullSupplier +%% Returns : CosNotifyChannelAdmin::StructuredProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_pull_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + type_check(PS, 'CosNotifyComm_StructuredPullSupplier'), + Proxy = connect_a_pull_supplier(Ch, PS, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_push_consumer +%% Arguments : PC - CosNotifyComm::SequencePushConsumer +%% Returns : CosNotifyChannelAdmin::SequenceProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_push_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + type_check(PC, 'CosNotifyComm_SequencePushConsumer'), + Proxy = connect_a_push_consumer(Ch, PC, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_pull_consumer +%% Arguments : PC - CosNotifyComm::SequencePullConsumer +%% Returns : CosNotifyChannelAdmin::SequenceProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_pull_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + Proxy = connect_a_pull_consumer(Ch, PC, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_push_supplier +%% Arguments : PS - CosNotifyComm::SequencePushSupplier +%% Returns : CosNotifyChannelAdmin::SequenceProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_push_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + Proxy = connect_a_push_supplier(Ch, PS, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_pull_supplier +%% Arguments : PS - CosNotifyComm::SequencePullSupplier +%% Returns : CosNotifyChannelAdmin::SequenceProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_pull_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + type_check(PS, 'CosNotifyComm_SequencePullSupplier'), + Proxy = connect_a_pull_supplier(Ch, PS, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_push_consumer_with_id +%% Arguments : PC - CosEventComm::PushConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_push_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + type_check(PC, 'CosEventComm_PushConsumer'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_consumer(Channel, PC, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_pull_consumer_with_id +%% Arguments : PC - CosEventComm::PullConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_pull_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_consumer(Channel, PC, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_push_supplier_with_id +%% Arguments : PS - CosEventComm::PushSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_push_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_supplier(Channel, PS, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_pull_supplier_with_id +%% Arguments : PS - CosEventComm::PullSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_pull_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + type_check(PS, 'CosEventComm_PullSupplier'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_supplier(Channel, PS, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_push_consumer_with_id +%% Arguments : PC - CosNotifyComm::StructuredPushConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::StructuredProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_push_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + type_check(PC, 'CosNotifyComm_StructuredPushConsumer'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_consumer(Channel, PC, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_pull_consumer_with_id +%% Arguments : PC - CosNotifyComm::StructuredPullConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::StructuredProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_pull_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_consumer(Channel, PC, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_push_supplier_with_id +%% Arguments : PS - CosNotifyComm::StructuredPushSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::StructuredProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_push_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_supplier(Channel, PS, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_pull_supplier_with_id +%% Arguments : PS - CosNotifyComm::StructuredPullSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::StructuredProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_pull_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + type_check(PS, 'CosNotifyComm_StructuredPullSupplier'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_supplier(Channel, PS, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_push_consumer_with_id +%% Arguments : PC - CosNotifyComm::SequencePushConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::SequenceProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_push_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + type_check(PC, 'CosNotifyComm_SequencePushConsumer'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_consumer(Channel, PC, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_pull_consumer_with_id +%% Arguments : PC - CosNotifyComm::SequencePullConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::SequenceProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_pull_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_consumer(Channel, PC, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_push_supplier_with_id +%% Arguments : PS - CosNotifyComm::SequencePushSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::SequenceProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_push_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_supplier(Channel, PS, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_pull_supplier_with_id +%% Arguments : PS - CosNotifyComm::SequencePullSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::SequenceProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_pull_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + type_check(PS, 'CosNotifyComm_SequencePullSupplier'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_supplier(Channel, PS, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + + +%%---------------------------------------------------------------------- +%%------------------ CosNotification::QoSAdmin ------------------------- +%%---------------------------------------------------------------------% +%% Function : get_qos +%% Arguments : - +%% Returns : CosNotification::QoSProperties +%% Description: +%%---------------------------------------------------------------------- +get_qos(_OE_This, #state{cyclic = Cyclic, diamonds = Diamonds} = State) -> + {reply, [#'CosNotification_Property' + {name = ?DiamondDetection, + value = any:create(orber_tc:short(), Diamonds)}, + #'CosNotification_Property' + {name = ?CycleDetection, + value = any:create(orber_tc:short(), Cyclic)}], State}. + +%%---------------------------------------------------------------------% +%% Function : set_qos +%% Arguments : NewQoS - CosNotification::QoSProperties +%% Returns : ok | +%% {'EXCEPTION', #'CosNotification_UnsupportedQoS{}} +%% Description: +%%---------------------------------------------------------------------- +set_qos(_OE_This, State, NewQoS) -> + QoS = cosEventDomainApp:get_qos(NewQoS), + set_qos_helper(QoS, State, []). + +set_qos_helper([], State, []) -> + {reply, ok, State}; +set_qos_helper([], _, Errors) -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors}); +set_qos_helper([{?DiamondDetection, Diamonds}|T], #state{diamonds = Diamonds} = State, + Errors) -> + set_qos_helper(T, State, Errors); +set_qos_helper([{?CycleDetection, Cyclic}|T], #state{cyclic = Cyclic} = State, + Errors) -> + set_qos_helper(T, State, Errors); +set_qos_helper([{?DiamondDetection, ?AuthorizeDiamonds}|T], State, Errors) -> + %% Diamonds have not been allowed so far so it's safe to allow it. + set_qos_helper(T, State#state{diamonds = ?AuthorizeDiamonds}, Errors); +set_qos_helper([{?DiamondDetection, ?ForbidDiamonds}|T], State, Errors) -> + %% If any diamonds already exists we cannot allow this. Hence, now we must check + %% if we can update the QoS. + case get_diamonds_helper(State, false) of + [] -> + set_qos_helper(T, State#state{diamonds = ?ForbidDiamonds}, Errors); + _ -> + set_qos_helper(T, State, + [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', + name = ?DiamondDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds), + high_val=any:create(orber_tc:short(), ?AuthorizeDiamonds)}}|Errors]) + end; +set_qos_helper([{?CycleDetection, _}|T], #state{cyclic = Cyclic} = State, Errors) -> + %% Currently we do not support changing the Cycle schema. If we want to, + %% we must copy the graph to a new instance of the correct type. + set_qos_helper(T, State, + [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', + name = ?CycleDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), Cyclic), + high_val=any:create(orber_tc:short(), Cyclic)}}|Errors]). + +%%---------------------------------------------------------------------% +%% Function : validate_qos +%% Arguments : WantedQoS - CosNotification::QoSProperties +%% Returns : {ok, CosNotification::NamedPropertyRangeSeq} | +%% {'EXCEPTION', #'CosNotification_UnsupportedQoS{}} +%% Description: NamedPropertyRangeSeq is of out-type +%%---------------------------------------------------------------------- +validate_qos(_OE_This, State, WantedQoS) -> + QoS = cosEventDomainApp:get_qos(WantedQoS), + {reply, {ok, validate_qos_helper(QoS, State, [], [])}, State}. + +validate_qos_helper([], _, Properties, []) -> + Properties; +validate_qos_helper([], _, _, Errors) -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors}); +validate_qos_helper([{?DiamondDetection, ?ForbidDiamonds}|T], State, Properties, + Errors) -> + case get_diamonds_helper(State, false) of + [] -> + Property = + #'CosNotification_NamedPropertyRange' + {name = ?DiamondDetection, + range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds), + high_val=any:create(orber_tc:short(), ?ForbidDiamonds)}}, + validate_qos_helper(T, State, [Property|Properties], Errors); + _ -> + Error = + #'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', + name = ?DiamondDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds), + high_val=any:create(orber_tc:short(), ?AuthorizeDiamonds)}}, + validate_qos_helper(T, State, Properties, [Error|Errors]) + end; +validate_qos_helper([{?DiamondDetection, ?AuthorizeDiamonds}|T], State, Properties, + Errors) -> + Property = + #'CosNotification_NamedPropertyRange' + {name = ?DiamondDetection, + range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds), + high_val=any:create(orber_tc:short(), ?ForbidDiamonds)}}, + validate_qos_helper(T, State, [Property|Properties], Errors); +validate_qos_helper([{?CycleDetection, Cyclic}|T], #state{cyclic = Cyclic} = State, + Properties, Errors) -> + validate_qos_helper(T, State, Properties, Errors); +validate_qos_helper([{?CycleDetection, _}|T], #state{cyclic = Cyclic} = State, + Properties, Errors) -> + Error = + #'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', + name = ?CycleDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), Cyclic), + high_val=any:create(orber_tc:short(), Cyclic)}}, + validate_qos_helper(T, State, Properties, [Error|Errors]). + + +%%---------------------------------------------------------------------- +%%------------------ CosNotification::AdminPropertiesAdmin ------------- +%%---------------------------------------------------------------------% +%% Function : get_admin +%% Arguments : - +%% Returns : CosNotification::AdminProperties +%% Description: No Admins currently supported +%%---------------------------------------------------------------------- +get_admin(_OE_This, State) -> + {reply, [], State}. + +%%---------------------------------------------------------------------% +%% Function : set_admin +%% Arguments : NewAdmins - CosNotification::AdminProperties +%% Returns : ok | +%% {'EXCEPTION', #'CosNotification_UnsupportedAdmin{}} +%% Description: No Admins currently supported +%%---------------------------------------------------------------------- +set_admin(_OE_This, State, NewAdmins) -> + cosEventDomainApp:get_admin(NewAdmins), + {reply, ok, State}. + + +%%====================================================================== +%% Internal functions +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : find_candidates +%% Arguments : Digraph reference +%% (Vertex - if we're interested in a specific vertex. +%% Returns : {[SourceVertices], [SinkVertices], Max} +%% SourceVertices - {Vertice, [ReachableVertices]} +%% SinkVertices - {Vertice, [ReachingVertices]} +%% Max - number of edges in the graph. +%% Description: To be a part of a diamond ("transitive" relation xRy, yRz => xRz; +%% in comparison with discrete mathematics we do not require that the +%% entire graph is transitive) a vertex must have more than one +%% outgoing and/or incoming. Hence, a digraph must contain at least +%% one vertex with more than one outgoing edges and at least +%% one with more than one incoming edges for a diamond to exist. +%% Hence, the purpose of this function is to find vertices that +%% look like: +%% +%% Vout->V1 V6->Vin +%% \ and ^ +%% +->V2 | +%% V8--+ +%%---------------------------------------------------------------------- +find_candidates(DG) -> + Edges = digraph:edges(DG), + {COut, CIn, Max} = find_candidates_helper(Edges, [], [], DG, 0), + {filter_candidates(COut), filter_candidates(CIn), Max}. + + +find_candidates(DG, _Vertex) -> + %% We should use the fact that we know one of the vertices. + Edges = digraph:edges(DG), + {COut, CIn, Max} = find_candidates_helper(Edges, [], [], DG, 0), + {filter_candidates(COut), filter_candidates(CIn), Max}. + +find_candidates_helper([], AccOut, AccIn, _, Counter) -> + {lists:sort(AccOut), lists:sort(AccIn), Counter}; +find_candidates_helper([H|T], AccOut, AccIn, DG, Counter) -> + {H, V1, V2, _Label} = digraph:edge(DG, H), + find_candidates_helper(T, [{V1, V2}|AccOut], [{V2,V1}|AccIn], DG, Counter+1). + +filter_candidates([]) -> + []; +filter_candidates([{V1, V2}|T]) -> + filter_candidates([{V1, V2}|T], V1, [], []). +filter_candidates([], _V, [_Acc1], Acc2) -> + %% Only one in/out connection. Hence, cannot be start- or end-point + %% of a diamond. + lists:reverse(Acc2); +filter_candidates([], V, Acc1, Acc2) -> + lists:reverse([{V, lists:reverse(Acc1)}|Acc2]); +filter_candidates([{V1, V2}|T], V1, Acc1, Acc2) -> + filter_candidates(T, V1, [V2|Acc1], Acc2); +filter_candidates([{V1, V2}|T], _V, [_Acc1], Acc2) -> + %% Only one in/out connection. Hence, cannot be start- or end-point + %% of a diamond. + filter_candidates(T, V1, [V2], Acc2); +filter_candidates([{V1, V2}|T], V, Acc1, Acc2) -> + filter_candidates(T, V1, [V2], [{V, lists:reverse(Acc1)}|Acc2]). + +%%---------------------------------------------------------------------% +%% Function : evaluate_candidates +%% Arguments : - +%% Returns : [Diamond] +%% Description: There are several scenarios but they can be categorized as: +%% (1) (2) (3) (4) +%% 2 2 2-..-56 +%% / \ / \ / \ +%% 1---4 1---4 1---4 1 4 +%% \ / \ / \ / +%% 3 3 3-..-11 +%% +%% The purpose of this function is to find these in the cheapest +%% way possible. For complex diamonds (may also include cycles) +%% duplicates may be generated. For example, #2/#3 is a sub-set of #1 +%% but they are as well diamonds. +%%---------------------------------------------------------------------- +evaluate_candidates(_DG, [], _, Acc, _Max, _) -> + Acc; +evaluate_candidates(DG, [{V, OutV}|T], CIn, Acc, Max, FindAll) -> + case evaluate_candidates_helper(DG, V, OutV, CIn, [], FindAll) of + [] -> + evaluate_candidates(DG, T, CIn, Acc, Max, FindAll); + Diamonds when FindAll == true -> + %% May be more than one diamond. + evaluate_candidates(DG, T, CIn, Diamonds ++ Acc, Max, FindAll); + Diamond -> + Diamond + end. + +evaluate_candidates_helper(_, _, _, _, [Diamond], false) -> + Diamond; +evaluate_candidates_helper(_, _, _, [], Diamonds, _) -> + Diamonds; +evaluate_candidates_helper(DG, V1, OutV, [{V1, _InV}|T], Diamonds, FindAll) -> + evaluate_candidates_helper(DG, V1, OutV, T, Diamonds, FindAll); +evaluate_candidates_helper(DG, V1, OutV, [{V2, InV}|T], Diamonds, FindAll) -> + case double_match(OutV, InV, [], V1, V2) of + [] -> + case is_member(InV, V1) of + true -> + %% At this point we know that we have: + %% x -> y + %% For this pair to be a part of a diamond we have two options: + %% (1) x - y (2) x ---- y + %% \ / or \ / or a additional path besides z1-zN, + %% z z1-zN + case double_match_exclude(OutV, InV, [], V1, V2) of + [] -> + %% Nope it's not #1. + case digraph_match(OutV, V2, V1, DG, 1) of + false -> + evaluate_candidates_helper(DG, V1, OutV, T, + Diamonds, FindAll); + Diamond -> + evaluate_candidates_helper(DG, V1, OutV, T, + [[[V1, V2]|Diamond]|Diamonds], + FindAll) + end; + Diamond -> + %% We've found a diamond looking like: + %% x - y xRy, yRz => xRz + %% \ / + %% z + evaluate_candidates_helper(DG, V1, OutV, T, + [[[V1, V2]|Diamond]|Diamonds], + FindAll) + end; + false -> + case digraph_match(OutV, V2, V1, DG) of + false -> + evaluate_candidates_helper(DG, V1, OutV, T, + Diamonds, FindAll); + Diamond -> + evaluate_candidates_helper(DG, V1, OutV, T, + [Diamond|Diamonds], FindAll) + end + end; + Diamond -> + %% We've found a diamond looking something like: + %% 2 + %% / \ + %% 1-5-4 V1 eq. 1, V2 eq 4. + %% \ / + %% 3 + evaluate_candidates_helper(DG, V1, OutV, T, [Diamond|Diamonds], + FindAll) + end. + +is_member([], _) -> + false; +is_member([H|_], H) -> + true; +is_member([H|_], H2) when H > H2 -> + %% Since it's a sorted list no need to look any further. + false; +is_member([_|T], H) -> + is_member(T, H). + +double_match([], _, [_Matched], _, _) -> + []; +double_match([], _, Matched, _, _) -> + Matched; +double_match(_, [], [_Matched], _, _) -> + []; +double_match(_, [], Matched, _, _) -> + Matched; +double_match([H|T1], [H|T2], Matched, V1, V2) -> + double_match(T1, T2, [[V1,H,V2] | Matched], V1, V2); +double_match([H1|T1], [H2|T2], Matched, V1, V2) when H1 > H2 -> + double_match([H1|T1], T2, Matched, V1, V2); +double_match([_H1|T1], [H2|T2], Matched, V1, V2) -> + double_match(T1, [H2|T2], Matched, V1, V2). + +double_match_exclude([], _, Matched, _, _) -> + Matched; +double_match_exclude(_, [], Matched, _, _) -> + Matched; +%% exclude it +double_match_exclude([V2|T1], CIn, Matched, V1, V2) -> + double_match_exclude(T1, CIn, Matched, V1, V2); +%% exclude it +double_match_exclude(COut, [V1|T2], Matched, V1, V2) -> + double_match_exclude(COut, T2, Matched, V1, V2); +%% Found match +double_match_exclude([H|T1], [H|T2], Matched, V1, V2) -> + double_match_exclude(T1, T2, [[V1,H,V2] | Matched], V1, V2); +double_match_exclude([H1|T1], [H2|T2], Matched, V1, V2) when H1 > H2 -> + double_match_exclude([H1|T1], T2, Matched, V1, V2); +double_match_exclude([_H1|T1], [H2|T2], Matched, V1, V2) -> + double_match_exclude(T1, [H2|T2], Matched, V1, V2). + + +digraph_match(OutV, V2, V1, DG) -> + digraph_match(OutV, V2, V1, DG, [], 0). + +digraph_match(OutV, V2, V1, DG, Counter) -> + digraph_match(OutV, V2, V1, DG, [], Counter). + +digraph_match([], _, _, _, _, Counter) when Counter < 2 -> + false; +digraph_match([], _, _, _, Acc, _) -> + Acc; +digraph_match([Vin|T], Vin, Vout, DG, Acc, Counter) -> + digraph_match(T, Vin, Vout, DG, Acc, Counter); +digraph_match([H|T], Vin, Vout, DG, Acc, Counter) -> + case get_path(DG, H, Vin, H, Vout) of + false -> + digraph_match(T, Vin, Vout, DG, Acc, Counter); + Path -> + %% Found one path; now me must se if there are one more. + digraph_match(T, Vin, Vout, DG, [[Vout|lists:reverse(Path)] | Acc], + Counter+1) + end. + +get_path(G, V1, V2, E1, E2) -> + one_path(digraph:out_neighbours(G, V1), V2, [], [V1], [V1], G, E1, E2). + +one_path([E1|_Vs], W, Cont, Xs, Ps, G, E1, E2) -> + one_path([], W, Cont, Xs, Ps, G, E1, E2); +one_path([E2|_Vs], W, Cont, Xs, Ps, G, E1, E2) -> + one_path([], W, Cont, Xs, Ps, G, E1, E2); +one_path([W|_Ws], W, _Cont, _Xs, Ps, _G, _E1, _E2) -> + [W|Ps]; +one_path([V|Vs], W, Cont, Xs, Ps, G, E1, E2) -> + case lists:member(V, Xs) of + true -> one_path(Vs, W, Cont, Xs, Ps, G, E1, E2); + false -> one_path(digraph:out_neighbours(G, V), W, + [{Vs,Ps} | Cont], [V|Xs], [V|Ps], G, E1, E2) + end; +one_path([], W, [{Vs,Ps}|Cont], Xs, _, G, E1, E2) -> + one_path(Vs, W, Cont, Xs, Ps, G, E1, E2); +one_path([], _, [], _, _, _, _, _) -> false. + +%%---------------------------------------------------------------------% +%% function : type_check +%% Arguments: Obj - objectrefernce to test. +%% Mod - Module which contains typeID/0. +%% Returns : 'ok' or raises exception. +%% Effect : +%%---------------------------------------------------------------------- +type_check(Obj, Mod) -> + case catch corba_object:is_a(Obj,Mod:typeID()) of + true -> + ok; + What -> + orber:dbg("[~p] CosEventDomainAdmin:type_check();~n" + "Object of incorrect type supplied; should be: ~p~n" + "Failed due to: ~p", [?LINE, Mod, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{minor=507, completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------% +%% function : lookup_channel +%% Arguments: DG - digraph reference +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::EventChannel | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} +%% Effect : +%%---------------------------------------------------------------------- +lookup_channel(DG, Id) -> + case digraph:vertex(DG, Id) of + {Id, Channel} -> + Channel; + false -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}) + end. + + +%%---------------------------------------------------------------------% +%% function : lookup_connection +%% Arguments: DG - digraph reference +%% Id - CosEventDomainAdmin::ConnectionID (long()) +%% Returns : #connectio{} | +%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} +%% Effect : +%%---------------------------------------------------------------------- +lookup_connection(DG, Id) -> + case digraph:edge(DG, Id) of + {Id, _SId, _CId, Connection} -> + Connection; + false -> + corba:raise(#'CosEventDomainAdmin_ConnectionNotFound'{}) + end. + +%%---------------------------------------------------------------------% +%% function : lookup_connection_data +%% Arguments: DG - digraph reference +%% Id - CosEventDomainAdmin::ConnectionID (long()) +%% Returns : CosEventDomainAdmin::Connection | +%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} +%% Effect : +%%---------------------------------------------------------------------- +lookup_connection_data(DG, Id) -> + case digraph:edge(DG, Id) of + {Id, _SId, _CId, #connection{data = Connection}} -> + Connection; + false -> + corba:raise(#'CosEventDomainAdmin_ConnectionNotFound'{}) + end. + +%%---------------------------------------------------------------------% +%% function : close_connections +%% Arguments: DG -digraph reference +%% [CosEventDomainAdmin::ConnectionID] - [long()] +%% Returns : ok +%% Effect : +%%---------------------------------------------------------------------- +close_connections(_DG, []) -> + ok; +close_connections(DG, [H|T]) -> + #connection{supplier=S, consumer=C, data=Connection} = + lookup_connection(DG, H), + close_connection(Connection, S, C), + digraph:del_edge(DG, H), + close_connections(DG, T). + +%%---------------------------------------------------------------------% +%% function : close_connection +%% Arguments: CosEventDomainAdmin::Connection +%% S - SupplierProxy +%% C - ConsumerProxy +%% Returns : ok +%% Effect : +%%---------------------------------------------------------------------- +close_connection(#'CosEventDomainAdmin_Connection'{ctype=Type, + notification_style = Style}, + S, C) -> + case {Type, Style} of + {'ANY_EVENT', 'Push'} -> + catch 'CosNotifyChannelAdmin_ProxyPushSupplier':disconnect_push_supplier(S), + catch 'CosNotifyChannelAdmin_ProxyPushConsumer':disconnect_push_consumer(C); + {'ANY_EVENT', 'Pull'} -> + catch 'CosNotifyChannelAdmin_ProxyPullSupplier':disconnect_pull_supplier(S), + catch 'CosNotifyChannelAdmin_ProxyPullConsumer':disconnect_pull_consumer(C); + {'STRUCTURED_EVENT', 'Push'} -> + catch 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':disconnect_structured_push_supplier(S), + catch 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':disconnect_structured_push_consumer(C); + {'STRUCTURED_EVENT', 'Pull'} -> + catch 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':disconnect_structured_pull_supplier(S), + catch 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':disconnect_structured_pull_consumer(C); + {'SEQUENCE_EVENT', 'Push'} -> + catch 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':disconnect_sequence_push_supplier(S), + catch 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':disconnect_sequence_push_consumer(C); + {'SEQUENCE_EVENT', 'Pull'}-> + catch 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':disconnect_sequence_pull_supplier(S), + catch 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':disconnect_sequence_pull_consumer(C) + end, + ok. + +%%---------------------------------------------------------------------% +%% function : setup_connection +%% Arguments: CosEventDomainAdmin::Connection +%% S - SupplierProxy +%% C - ConsumerProxy +%% Returns : {ok, SupplierProxy, ConsumerProxy}; +%% Effect : +%%---------------------------------------------------------------------- +setup_connection(#'CosEventDomainAdmin_Connection'{ctype=Type, + notification_style = Style}, + S, C) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_consumer_admin'(S), + case Style of + 'Push' -> + {Proxy, _Id} = + 'CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_push_supplier(Admin, Type), + CProxy = connect_a_push_supplier(C, Proxy, Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPushSupplier': + connect_any_push_consumer(Proxy, CProxy); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPushSupplier': + connect_structured_push_consumer(Proxy, CProxy); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPushSupplier': + connect_sequence_push_consumer(Proxy, CProxy) + end, + {ok, Proxy, CProxy}; + 'Pull' -> + {Proxy, _Id} = + 'CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_pull_supplier(Admin, Type), + CProxy = connect_a_pull_supplier(C, Proxy, Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPullSupplier': + connect_any_pull_consumer(Proxy, CProxy); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPullSupplier': + connect_structured_pull_consumer(Proxy, CProxy); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPullSupplier': + connect_sequence_pull_consumer(Proxy, CProxy) + end, + {ok, Proxy, CProxy} + end. + +%%---------------------------------------------------------------------% +%% function : connect_a_pull_consumer +%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined +%% PC - a PullConsumer +%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +connect_a_pull_consumer(undefined, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}); +connect_a_pull_consumer(Channel, PC, Type) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_consumer_admin'(Channel), + {Proxy, _Id} = + 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_pull_supplier(Admin, + Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPullSupplier':connect_any_pull_consumer(Proxy, PC); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':connect_structured_pull_consumer(Proxy, PC); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':connect_sequence_pull_consumer(Proxy, PC) + end, + Proxy. + +%%---------------------------------------------------------------------% +%% function : connect_a_push_consumer +%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined +%% PC - a PushConsumer +%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +connect_a_push_consumer(undefined, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}); +connect_a_push_consumer(Channel, PC, Type) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_consumer_admin'(Channel), + {Proxy, _Id} = + 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(Admin, + Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPushSupplier':connect_any_push_consumer(Proxy, PC); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':connect_structured_push_consumer(Proxy, PC); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':connect_sequence_push_consumer(Proxy, PC) + end, + Proxy. + +%%---------------------------------------------------------------------% +%% function : connect_a_pull_supplier +%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined +%% PC - a PullSupplier +%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +connect_a_pull_supplier(undefined, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}); +connect_a_pull_supplier(Channel, PS, Type) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_supplier_admin'(Channel), + {Proxy, _Id} = + 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_pull_consumer(Admin, + Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPullConsumer':connect_any_pull_supplier(Proxy, PS); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':connect_structured_pull_supplier(Proxy, PS); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':connect_sequence_pull_supplier(Proxy, PS) + end, + Proxy. + +%%---------------------------------------------------------------------% +%% function : connect_a_push_supplier +%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined +%% PC - a PushSupplier +%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +connect_a_push_supplier(undefined, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}); +connect_a_push_supplier(Channel, PS, Type) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_supplier_admin'(Channel), + {Proxy, _Id} = + 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(Admin, + Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPushConsumer':connect_any_push_supplier(Proxy, PS); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':connect_structured_push_supplier(Proxy, PS); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':connect_sequence_push_supplier(Proxy, PS) + end, + Proxy. + + +%%====================================================================== +%% END OF MODULE +%%====================================================================== + diff --git a/lib/cosEventDomain/src/Makefile b/lib/cosEventDomain/src/Makefile new file mode 100644 index 0000000..56a67cd --- /dev/null +++ b/lib/cosEventDomain/src/Makefile @@ -0,0 +1,179 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug -W +endif +EBIN=../ebin +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(COSEVENTDOMAIN_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/cosEventDomain-$(VSN) +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + CosEventDomainAdmin_EventDomainFactory_impl \ + CosEventDomainAdmin_EventDomain_impl \ + cosEventDomainApp + +ERL_FILES = $(MODULES:%=%.erl) +HRL_FILES = cosEventDomainApp.hrl + +EXTERNAL_INC_PATH = ../include + +GEN_ERL_FILES = \ + oe_CosEventDomainAdmin.erl \ + CosEventDomainAdmin.erl \ + CosEventDomainAdmin_DiamondSeq.erl \ + CosEventDomainAdmin_AlreadyExists.erl \ + CosEventDomainAdmin_DomainIDSeq.erl \ + CosEventDomainAdmin_Connection.erl \ + CosEventDomainAdmin_ConnectionIDSeq.erl \ + CosEventDomainAdmin_ConnectionNotFound.erl \ + CosEventDomainAdmin_CycleCreationForbidden.erl \ + CosEventDomainAdmin_CycleSeq.erl \ + CosEventDomainAdmin_DiamondCreationForbidden.erl \ + CosEventDomainAdmin_DomainNotFound.erl \ + CosEventDomainAdmin_EventDomain.erl \ + CosEventDomainAdmin_EventDomainFactory.erl \ + CosEventDomainAdmin_MemberIDSeq.erl \ + CosEventDomainAdmin_RouteSeq.erl + + + +GEN_HRL_FILES = \ + oe_CosEventDomainAdmin.hrl \ + CosEventDomainAdmin.hrl \ + CosEventDomainAdmin_EventDomainFactory.hrl \ + CosEventDomainAdmin_EventDomain.hrl + +EXTERNAL_GEN_HRL_FILES = \ + $(GEN_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + + +TARGET_FILES = \ + $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +GEN_FILES = $(GEN_HRL_FILES) $(GEN_ERL_FILES) + +IDL_FILES = \ + CosEventDomainAdmin.idl + +APPUP_FILE = cosEventDomain.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + +APP_FILE = cosEventDomain.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += \ + -pa $(ERL_TOP)/lib/cosEventDomain/ebin \ + -pa $(ERL_TOP)/lib/cosEventDomain/include \ + -pa $(ERL_TOP)/lib/cosNotification/include \ + -pa $(ERL_TOP)/lib/cosNotification/ebin \ + -pa $(ERL_TOP)/lib/ic/ebin \ + -I$(ERL_TOP)/lib/cosNotification/include \ + -I$(ERL_TOP)/lib/cosNotification/ebin \ + -I$(ERL_TOP)/lib/cosNotification/src \ + -I$(ERL_TOP)/lib/cosEvent/src \ + -I$(ERL_TOP)/lib/cosEventDomain/include +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -pa $(ERL_TOP)/lib/cosEventDomain/include \ + -pa $(ERL_TOP)/lib/cosNotification/ebin \ + -pa $(ERL_TOP)/lib/cosNotification/include \ + -pa $(ERL_TOP)/lib/cosNotification/src \ + -I$(ERL_TOP)/lib/cosEventDomain/include \ + -I$(ERL_TOP)/lib/cosNotification/ebin \ + -I$(ERL_TOP)/lib/cosNotification/include \ + -I$(ERL_TOP)/lib/cosNotification/src \ + -I$(ERL_TOP)/lib/cosEvent/src \ + -I$(ERL_TOP)/lib/cosEvent/include \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,"cosEventDomain_$(COSEVENTDOMAIN_VSN)"}' + +YRL_FLAGS = + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + +debug: + @${MAKE} TYPE=debug opt + +clean: + rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) + sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET) +$(APPUP_TARGET): $(APPUP_SRC) + sed -e 's;%VSN%;$(VSN);' $(APPUP_SRC) > $(APPUP_TARGET) + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +$(GEN_ERL_FILES) $(EXTERNAL_GEN_HRL_FILES): CosEventDomainAdmin.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventDomainAdmin.cfg"}' CosEventDomainAdmin.idl + mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH) + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) ../info $(RELSYSDIR) + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DATA) $(EXTERNAL_GEN_HRL_FILES) $(RELSYSDIR)/include + + +release_docs_spec: + + + + + diff --git a/lib/cosEventDomain/src/cosEventDomain.app.src b/lib/cosEventDomain/src/cosEventDomain.app.src new file mode 100644 index 0000000..e4307e1 --- /dev/null +++ b/lib/cosEventDomain/src/cosEventDomain.app.src @@ -0,0 +1,31 @@ +{application, cosEventDomain, + [{description, "The Erlang CosEventDomain application"}, + {vsn, "%VSN%"}, + {modules, + [ + 'CosEventDomainAdmin_EventDomainFactory_impl', + 'CosEventDomainAdmin_EventDomain_impl', + 'cosEventDomainApp', + 'oe_CosEventDomainAdmin', + 'CosEventDomainAdmin', + 'CosEventDomainAdmin_DiamondSeq', + 'CosEventDomainAdmin_AlreadyExists', + 'CosEventDomainAdmin_DomainIDSeq', + 'CosEventDomainAdmin_Connection', + 'CosEventDomainAdmin_ConnectionIDSeq', + 'CosEventDomainAdmin_ConnectionNotFound', + 'CosEventDomainAdmin_CycleCreationForbidden', + 'CosEventDomainAdmin_CycleSeq', + 'CosEventDomainAdmin_DiamondCreationForbidden', + 'CosEventDomainAdmin_DomainNotFound', + 'CosEventDomainAdmin_EventDomain', + 'CosEventDomainAdmin_EventDomainFactory', + 'CosEventDomainAdmin_MemberIDSeq', + 'CosEventDomainAdmin_RouteSeq' + ] + }, + {registered, []}, + {applications, [orber, stdlib, kernel]}, + {env, []}, + {mod, {cosEventDomainApp, []}} +]}. diff --git a/lib/cosEventDomain/src/cosEventDomain.appup.src b/lib/cosEventDomain/src/cosEventDomain.appup.src new file mode 100644 index 0000000..d69b2ef --- /dev/null +++ b/lib/cosEventDomain/src/cosEventDomain.appup.src @@ -0,0 +1,6 @@ +{"%VSN%", + [ + ], + [ + ] +} diff --git a/lib/cosEventDomain/src/cosEventDomainApp.erl b/lib/cosEventDomain/src/cosEventDomainApp.erl new file mode 100644 index 0000000..d57f514 --- /dev/null +++ b/lib/cosEventDomain/src/cosEventDomainApp.erl @@ -0,0 +1,363 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%-------------------------------------------------------------------- +%% File : cosEventDomainApp.erl +%% Purpose : +%%-------------------------------------------------------------------- + +-module(cosEventDomainApp). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +-include_lib("cosNotification/include/CosNotification.hrl"). +%% Application files +-include("cosEventDomainApp.hrl"). +-include("CosEventDomainAdmin.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%% External MISC +-export([get_option/3, + create_name/2, + create_name/1, + create_id/0, + create_id/1, + is_debug_compiled/0, + install/0, + uninstall/0, + start_factory/0, + start_factory/1, + start_factory_link/0, + start_factory_link/1, + stop_factory/1, + start/0, + stop/0, + create_link/3, + get_qos/1, + get_admin/1]). + +%% Application callbacks +-export([start/2, init/1, stop/1]). + +%%--------------- DEFINES ------------------------------------ + +-define(SUPERVISOR_NAME, oe_cosEventDomainSup). +-define(SUP_FLAG, {simple_one_for_one,50,10}). + +-define(SUP_SPEC(Name, Args), + ['CosEventDomainAdmin_EventDomain',Args, + [{sup_child, true}, {regname, {global, Name}}]]). +-define(SUP_CHILD, + {"oe_EventDomainChild", + {cosEventDomainApp,create_link, []}, + transient,100000,worker, + ['CosEventDomainAdmin_EventDomain']}). + + +-define(DEFAULT_OPTIONS, []). + +%%--------------- DEFINITIONS OF CONSTANTS ------------------- +%%--------------- EXTERNAL MISC FUNCTIONS -------------------- +%%-----------------------------------------------------------% +%% function : install +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +install() -> + oe_CosEventDomainAdmin:oe_register(). + +%%-----------------------------------------------------------% +%% function : uninstall +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +uninstall() -> + oe_CosEventDomainAdmin:oe_unregister(). + +%%-----------------------------------------------------------% +%% function : start/stop +%% Arguments: +%% Returns : +%% Effect : Starts or stops the cosTime application. +%%------------------------------------------------------------ + +start() -> + application:start(cosEventDomain). +stop() -> + application:stop(cosEventDomain). + +%%-----------------------------------------------------------% +%% function : start +%% Arguments: Type - see module application +%% Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +start(_, _) -> + supervisor:start_link({local, ?SUPERVISOR_NAME}, cosEventDomainApp, app_init). + + +%%-----------------------------------------------------------% +%% function : stop +%% Arguments: Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +stop(_) -> + ok. + +%%-----------------------------------------------------------% +%% function : start_channel +%% Arguments: - +%% Returns : +%% Effect : +%%------------------------------------------------------------ +start_factory() -> + start_factory(?DEFAULT_OPTIONS). + +start_factory(Options) when is_list(Options) -> + 'CosEventDomainAdmin_EventDomainFactory':oe_create(Options); +start_factory(Options) -> + orber:dbg("[~p] cosEventDomainApp:start_factory(~p);~n" + "Options not correct.", + [?LINE, Options], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%-----------------------------------------------------------% +%% function : start_channel +%% Arguments: - +%% Returns : +%% Effect : +%%------------------------------------------------------------ +start_factory_link() -> + start_factory_link(?DEFAULT_OPTIONS). + +start_factory_link(Options) when is_list(Options) -> + 'CosEventDomainAdmin_EventDomainFactory':oe_create_link(Options); +start_factory_link(Options) -> + orber:dbg("[~p] cosEventDomainApp:start_factory_link(~p);~n" + "Options not correct.", + [?LINE, Options], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%-----------------------------------------------------------% +%% function : stop_factory +%% Arguments: ChannelObj +%% Returns : +%% Effect : +%%------------------------------------------------------------ +stop_factory(ChannelObj) -> + corba:dispose(ChannelObj). + +%%-----------------------------------------------------------% +%% function : init +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%% Starting using create_factory/X +init(own_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}; +%% When starting as an application. +init(app_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}. + + +%%------------------------------------------------------------ +%% function : create_link +%% Arguments: Module - which Module to call +%% Env/ArgList - ordinary oe_create arguments. +%% Returns : +%% Exception: +%% Effect : Necessary since we want the supervisor to be a +%% 'simple_one_for_one'. Otherwise, using for example, +%% 'one_for_one', we have to call supervisor:delete_child +%% to remove the childs startspecification from the +%% supervisors internal state. +%%------------------------------------------------------------ +create_link(Module, Env, ArgList) -> + Module:oe_create_link(Env, ArgList). + +%%-----------------------------------------------------------% +%% function : get_option +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +get_option(Key, OptionList, DefaultList) -> + case lists:keysearch(Key, 1, OptionList) of + {value,{Key,Value}} -> + Value; + _ -> + case lists:keysearch(Key, 1, DefaultList) of + {value,{Key,Value}} -> + Value; + _-> + {error, "Invalid option"} + end + end. +%%-----------------------------------------------------------% +%% function : create_name/2 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_name(Name,Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',Name,'_',MSec, '_', Sec, '_', USec]). + +%%-----------------------------------------------------------% +%% function : create_name/1 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_name(Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',MSec, '_', Sec, '_', USec]). + +%%------------------------------------------------------------ +%% function : create_id/0 +%% Arguments: - +%% Returns : CosEventDomainAdmin::DomainID (long) +%% Exception: +%% Purpose : +%%------------------------------------------------------------ +create_id(2147483647) -> + -2147483648; +create_id(OldID) -> + OldID+1. + + +create_id() -> + {_A,_B,C}=now(), + C. +%%------------------------------------------------------------ +%% function : get_qos +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +get_qos([]) -> + []; +get_qos(Properties) -> + get_qos(Properties, [], []). + +get_qos([], Supported, []) -> + Supported; +get_qos([], _, Unsupported) -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupported}); +get_qos([#'CosNotification_Property'{name = ?CycleDetection, + value= #any{value = ?AuthorizeCycles}}|T], + Supported, Unsupported) -> + get_qos(T, [{?CycleDetection, ?AuthorizeCycles}|Supported], Unsupported); +get_qos([#'CosNotification_Property'{name = ?CycleDetection, + value= #any{value = ?ForbidCycles}}|T], + Supported, Unsupported) -> + get_qos(T, [{?CycleDetection, ?ForbidCycles}|Supported], Unsupported); +get_qos([#'CosNotification_Property'{name = ?CycleDetection}|T], + Supported, Unsupported) -> + %% Illegal value supplied. + get_qos(T, Supported, + [#'CosNotification_PropertyError' + {code = 'UNSUPPORTED_VALUE', + name = ?CycleDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeCycles), + high_val=any:create(orber_tc:short(), ?ForbidCycles)}}|Unsupported]); +get_qos([#'CosNotification_Property'{name = ?DiamondDetection, + value= #any{value = ?AuthorizeDiamonds}}|T], + Supported, Unsupported) -> + get_qos(T, [{?DiamondDetection, ?AuthorizeDiamonds}|Supported], Unsupported); +get_qos([#'CosNotification_Property'{name = ?DiamondDetection, + value= #any{value = ?ForbidDiamonds}}|T], + Supported, Unsupported) -> + get_qos(T, [{?DiamondDetection, ?ForbidDiamonds}|Supported], Unsupported); +get_qos([#'CosNotification_Property'{name = ?DiamondDetection}|T], + Supported, Unsupported) -> + %% Illegal value supplied. + get_qos(T, Supported, + [#'CosNotification_PropertyError' + {code = 'UNSUPPORTED_VALUE', + name = ?DiamondDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds), + high_val=any:create(orber_tc:short(), ?ForbidDiamonds) + }} | Unsupported]); +get_qos([#'CosNotification_Property'{name = Name}|T], Supported, Unsupported) -> + %% Unknown QoS supplied. + get_qos(T, Supported, + [#'CosNotification_PropertyError' + {code = 'BAD_PROPERTY', + name = Name, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null)}} | Unsupported]). + +%%------------------------------------------------------------ +%% function : get_admin +%% Arguments: +%% Returns : {"EXCEPTION', #'CosNotification_PropertyError'{}} +%% Exception: +%% Effect : No Admin supported. +%%------------------------------------------------------------ +get_admin([]) -> + []; +get_admin(Properties) -> + get_admin(Properties, []). + +get_admin([], Unsupported) -> + corba:raise(#'CosNotification_UnsupportedAdmin'{admin_err = Unsupported}); +get_admin([#'CosNotification_Property'{name = Name}|T], Unsupported) -> + %% Unknown QoS supplied. + get_admin(T, [#'CosNotification_PropertyError' + {code = 'BAD_PROPERTY', + name = Name, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null)}} | Unsupported]). + + +%%------------------------------------------------------------ +%% function : is_debug_compiled +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +-ifdef(debug). + is_debug_compiled() -> true. +-else. + is_debug_compiled() -> false. +-endif. + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosEventDomain/src/cosEventDomainApp.hrl b/lib/cosEventDomain/src/cosEventDomainApp.hrl new file mode 100644 index 0000000..340bbc5 --- /dev/null +++ b/lib/cosEventDomain/src/cosEventDomainApp.hrl @@ -0,0 +1,69 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosEventDomainApp.hrl +%% Purpose : +%%---------------------------------------------------------------------- + + +%%--------------- INCLUDES ----------------------------------- +%% External + +%% Local + +-define(write_ErrorMsg(Txt, Arg), +error_logger:error_msg("============== CosEventDomain =============~n" + Txt + "===========================================~n", + Arg)). + +-define(DEBUG_LEVEL, 3). + +-ifdef(debug). +-define(DBG(F,A), + io:format("[LINE: ~p MODULE: ~p] "++F,[?LINE, ?MODULE]++A)). +-else. +-define(DBG(F,A), ok). +-endif. + +%%%%%% WARNING! These definitions are defined in the CosEventDomainAdmin.idl +%%%%%% file. If the specification is changed so must the definitions!! +%%%%%% We use this approach to be able to use them as guards. + +%%%% Constant: 'CycleDetection' +-define(CycleDetection, "CycleDetection"). + +%%%% Constant: 'AuthorizeCycles' +-define(AuthorizeCycles, 0). + +%%%% Constant: 'ForbidCycles' +-define(ForbidCycles, 1). + +%%%% Constant: 'DiamondDetection' +-define(DiamondDetection, "DiamondDetection"). + +%%%% Constant: 'AuthorizeDiamonds' +-define(AuthorizeDiamonds, 0). + +%%%% Constant: 'ForbidDiamonds' +-define(ForbidDiamonds, 1). + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosEventDomain/vsn.mk b/lib/cosEventDomain/vsn.mk new file mode 100644 index 0000000..81c0b49 --- /dev/null +++ b/lib/cosEventDomain/vsn.mk @@ -0,0 +1,10 @@ + +COSEVENTDOMAIN_VSN = 1.1.7 + +TICKETS = OTP-8201 + +TICKETS_1.1.6 = OTP-7987 + +TICKETS_1.1.5 = OTP-7837 + +TICKETS_1.1.4 = OTP-7595 diff --git a/lib/cosFileTransfer/AUTHORS b/lib/cosFileTransfer/AUTHORS new file mode 100644 index 0000000..55d8059 --- /dev/null +++ b/lib/cosFileTransfer/AUTHORS @@ -0,0 +1,4 @@ +Original Authors: +Niclas Eklund + +Contributors: diff --git a/lib/cosFileTransfer/Makefile b/lib/cosFileTransfer/Makefile new file mode 100644 index 0000000..02df603 --- /dev/null +++ b/lib/cosFileTransfer/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(COSFILETRANSFER_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- +# SUB_DIRECTORIES = src test examples doc/src +# At the moment we don't have any example programs. +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/cosFileTransfer/doc/html/.gitignore b/lib/cosFileTransfer/doc/html/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosFileTransfer/doc/man3/.gitignore b/lib/cosFileTransfer/doc/man3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosFileTransfer/doc/man6/.gitignore b/lib/cosFileTransfer/doc/man6/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosFileTransfer/doc/pdf/.gitignore b/lib/cosFileTransfer/doc/pdf/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer.gif b/lib/cosFileTransfer/doc/src/CosFileTransfer.gif new file mode 100644 index 0000000000000000000000000000000000000000..16970ad5ad7dd05d34185b023c12c4b52f8442b0 GIT binary patch literal 10889 zcmeHs)mxPhu=R_AG>SokC?XA_Al=>FozflBNOw25>F%ygH=7MecXxNQ-|u(6|KZ%7 zbvHM&o@cF@i!~!AAB8UU{V@Dczo0Pq|D&j9cg08aq$7yyp|@DKnG0B|1w_W*Dg0Cxaz8vwTea1#JG z0B{`u*Z%AIpBw*&|1AYRA&8W0O`Ti~985ULWz3BnY#skA$>mH<&5cX|`v0N*pG^VK z5CA?piFj33mp|G&TJ6EA?4IB^6p|U@)j56P1V1d62CH)iqREBANF-|VhT^G}O0^<-|8m9SX?2F{iYE)@b0z;u)|X6|s@Ga9 z57(E@R_gbJkxDg`&DWYumgvA5$`>2$Hi!R8HC8OQ{=Pg|hBa2McKE);B$IBcTJH&Y zN2fc|RJ}P6Lm>r`Zm!verTnm58ELNF9m^65CzENZ+n+2_D%FLz)E~}P8NnbjtqsSE zP1rBy;H{0eKr=o_Hp;~=u`w9`l5JG2*>QD*nKv_v`$79)E?dj>j>Pcx*rEgB=!%2T zcZk}Bg{xG=^4uLzte39Rf=16vy(&AIw$6N#U_CZ!yzi3;N|rbBaFV_>CSHoNKa)UF zS^ySeXU%_M-q^sB_+V;1P|zzRJ|sVO&mf5W#@JAn&O7L{JW~O?p{;P=o<=zB0(Gu5 z=fjkdDPOmEu0h}Qhb=iV*`zOVLKqx>1>fU1eN1STxHojaVhuHjO=BR;N#Zt09#24y zZG4mbIW06XS=zykFkP>uIX(r=pg29v`Q)oF5S|xGrK11yLy@r^jtaHZ+_78XUz4z3 z5QrzDpom}Y1!qxK@=uqd?9_<_>deTN#-gI=7gDV?)o{jhmiH!fXi^$#!2ai`*y1MS+zixLalj_MpCu1k)W(4D?EHMg88|-=HM~_ye zvfYTN9C5>x{3?mXyy+t`tD>6Rw2QWF>$0zIb+Aluwd4fJYCCf&nvzysCBc|8DgnPf-XQnqxPSx9z#Il2(DWzOse&-s+|z!2W9 zWf!lhOI`dtWOp@<)P1^^ZFi)7jnE z0gv>t!s#dV)z$m{yRBqf#Qk2Ot@k-$pwHv}gst8|?M%3A^XU$!Ir}4qYcv^ffSCoL z4D#*2eOp1IBz)W73F1?I3e ztQW;Cj=R$wqwq0d*PM2r171+nFG9FE%m&ft#SefDr9KfeiYPx@Et$e~(M( z*B7d+x%$>eseKu1Elj=c^=qNef+;+CA#on$xc)`m-vsPkP{nhJW(WI!wwy=WX>a1~ zy5hevjqy|>k^O+=+eh!-8})WSXQFJXHD~)+HqW0tPgS*_10EY-ACdQks<>Z_u_P*q zWQ@$7ou7CkHrk5>5Fh=GE8sV(&gi(*AoGVbs6m>e*ue%3bG55Q-)SU3uyLUa}UyuBBt3!3mfydwMlv0lO<=|={F zWrw+gP{@R~#^aoOkxQ$XYnR!H;-%Mn;>*2^$ehbC;8>3rmq^whFCiuSJtaO(IY|y6=uNrJNOcac6iT0CS(4n9#$U&zevr0`R4~{~s`}|uAmjaxtBNN9D z3q*6i4S`mME^ja=Ascb^u};TYNVHlN(t9W?Uf8iq-rkMEjo|g*DW3SZyg|n3TCgG3fAZ=+$m!8wox3K zi=AyKDY;jF&ZuPzl~}d#I;Kp zxeX~5<#v2DBibkZF1>$+#=VE;^{~R{C{g<9TS}6)Xv^okS1B3YBQcE#m3(`+wXL1( zM~oN_@4BUUO8H&6T0f!I4jSlEBVv9yhzE^~#Gsr1NQ4w`s9^|?)_T}SQ1So4&~~-c zEnrGUFEtX3XKf^)yi9_MD!!)r@UKPZhv->Z40PVn$)%zWgGOfm@*;8AhvB zGU%zuu@{x&U22#u8HhDr$Mc>rD)^SirsJrLsWRT6eCu2>zMQKX@ouP{=2^EIa2W}) zsH-1CH>6O)`>yu)!mr2L3d@-Pr9JCyq{8yHBR8RhEr{1`HZC6*mQNu+d(aQ;EQLJtC}idPm}M{1EVZXLPuNjk zVL12?FlQGta&%Kb)&r$9lWY3dVU-*M%bn}{xKaL7+vLF<>O9>}Swf@-`lwt>NUwhn z`jg#Mq4HjJz4pF)N&ezfh`^hiH$m*kpWkMO&>IV2YOM+4L(fpY1qfgnkqZ%y*u7%O z6Tr6A7b0Hr4fsNBfG%z3_YMLCQi~g4C>QyCsPGLWUL!~4oI`r;zUKcC_=G0--z0?T z2T&w*B2)1TU?^9;z^m&-Ve;*Q_Z{0}Tlv1^S~VF%_3q26^w{&!zDG8XSWe<{-t2cPQLEcdKq8%ssS#3ppROMgJj=s*C1J1grE{0+*rok>211>hGt`1_ZF2Szu1Fqhv zzx~912L=BQ8~7cC>J}&FmK5xkHsA(9b!o8E~&a^{5f^XbARbDYWega%{Wx zAQ?v@J42H1<@khZ{Zij^G{|$v)hT5oh->N($XyqKxI zS=7DRLcBSfyb(Nm-uwhULgGH6zkMW%e5B`maeAQEYweHLx8|*n|eGS-y z$k&8T_Z7A{QzY z_cRy(^IJg&TpUm?2~@3wYyE99#0DTg<$u_oBV#{E#>z{M2Ix%tFwcBf{ol#`Z#RIU?iKV`t4m z37aF+=3-a(LUpL4a;W2Ws9#XLVWZNJde;<&s%A%!^5@L#TeZ5@4;pEc`5?B`@IF-F zsVQFjCYqNf;*WStzj_E-aYX1~%;;Rm8=A;i@z@#lP=eyf)WO)5xzKLBC@g}wJn=XR z{uj2FiH3=BzX()MQp|qQuxCmLS`H;Kx`hu1#@llww-F?}5Jvd2$MlJZpr%HIG{wLN zLtYa`#<0gui-+Q;My52yE)Rx&ybr`-Pt}%qfffVoyfRLox3Q;5(i2U}Pjy&}PqN@h zLq$v{*`!9>HAj^+2e;3~SJ1@tvWL71jR-D^8EFc^L63~4j-6r;#S4v0E{a`h3ME62 zdU_Q%z!5jpoH0@?RCSp_h5r}s;yGn*3o+-OL)T@UC0^POo2K-eYK-P=PCJ}S^D%=6 zG$+?KLqyS2n$R<)G*a3$GUba?x{EVa?o*!4Gq#!%6KS$A##vFq!U}`3zBUG7T7)xk z2xSjx;c}9^dx&cKoz0ON?8E_CbWN^wg9r{K*9}3$2veE~Go{T_+RZZ+np1k3GgZ-3 z5gfS*#Tn=^0ES&IeM0U*QBc`k?(JOGEJvRBtzD&ao|AjpYBTZrP`sQbgugf$QBw>N zxleAqhe%4KKqWHeQd7E8GnMyKvhZ>@ixPiXw(;w#NEz`e{Ot@7~zINzvTOhClZrG}MSB;i;T z;ssWXW>*yqRe8}Szs4;6Lt9-XQLRjy6OvZCUy@IKP}K2Ip?{E*@DQpiUc(YrKvh~s z^9ZbT*X+HjVtRCp5zYPqlU;B#^>nH#56hM=$!_h+UMH$kBFYI4E8R=Wr&=g#Kd8`K z$cdLM(=abnPA_{{0B9{mUNorNmgMSqWX%!fO+JKu4=tRsmql}GkQxqOX~|v-OSZwx z334yp4a@&JT-3Hup*x%t$60nsRPUu#;}c%Unp_7?<)ZNu#o344|lOaakzQNGXG0SQEN+uc1cbQQQ0|d!8gvD+4SPO zma+th5*!t61*R`K>hyqm1Moy&BGllM$Dt9;~F}u;lo$oDZ{OK&zD0vszTDG3OEb za9AzV+E^T(NFC8O*wRf;V#o;1C1{AE)9C!6t;tH_#a8CTQ6~F=1ez4yC4Z0|K--I_ zRp&_DGMe5&3afJuZ<)sIl%wx_>0W-L+P8kFr@j=0aF;HbnQv;Mf5;&2T#(w`qTU4NE$O?(A(B($?(Pkt~LZ+4df|vj(9kytSXPYD$IEpqh-X8 zzE)>Rs1gen8j)u-(%x{?6P*Fu7`u=alf1*9$d+%VJ&>l0b{-_9;8Of;KVe?i-wYX(t9&y_fW{sRjV(k4WW%0

4 zuwsJ0|A@+^*!qdr4(rRM%YS^HXugmjwH5-($7rm(kiB3GJk_>~&CJhTqEG!P^dkrK z|EMBHc;MaI(0|m;Q~dc#qSj1LPg2nJF^{Q9%+lIU7+m2P{_1!_g{MP!sXqy8WDn~f z?;3eJVnI}0( zm16v!T!+goyMao!r4HG~;N3d5vJzccb#R_hSXn3xnd-?gHDcV(?#5MVAK|Uowj`Wz z$xiqVE@|a9Y6rqI@2xtv;yFIksl7EWh3)AvB|Z*#!LPg6<3~4MeqrXl9dy!4ByhP! zcKLnv_>=9$`^?K8gL4a)y>(Jsa$9oYQ`+DE^gB;TBwuH9Mr){54)Tnd$@wtoMJE}o zs_ zz#AIf-V}w+{;=0P-Vt{STRkxp=yt-XirbP=WEu^1>JA1yek|`K>+UB$N&MyULLh5? z|23Ze&U#0fsJ37N!Whac!r|~mwwT;Cj2m6$P_;zpkGoEb(vEZi7VN-jSmk&j(>(j) zh&JhHu32xr#zadcPrgku-?Wdoi9tOx06vT@#m4-v)sK|##J!tvOfg#_px+#iUoK_gwKG(GMt zVWzH@8D83));lsZA931~Pp3v_3&l`KHEdm?`#O4}cnOUT`cl$6qS&Y z=8tV9v1K^%$Zy5=zHlAS@vpF zwztku({zMGT^F4HL?(;6JeM}=`3{lJsTkcp%Pf0|j5N@GK+(lp^8Eyno3=-XyfX;G zm2EOmqzS^C4;82&FxnL5{jJl5pumS~^Qzn2ekGffk#B`{4?TWK~4wnW%m>s?8| zS}@H)ff1Um5|CXny~JlEQb~1_;nvKM^s6W^&@A(lH*L(tbx982-*}vz)B`b~}@;?cO;X%rH8r#8-bhQcA6XWx` zp8eI~b-NnO=Y79h*x~(ns+RHl>2?=fYIinzoK2WEXxT5zKPHVRfph?e8x*06v;1T`QMA(a zr1-kuBq8E55pU08G9teA~>WKU(`A^Ipr|2&Zp`= zTqO68;4p`3NSP(U;*wdmXjA8!)~*KK zhAj);{)GuobIyiJD4k$J$gberscK`!EAKLYOcnBG(v0UnDTSv7m~o0+(`RnWx?tr; zabRYR_%p(y(90#oB54LFy5nf ze{US>IpAK#5052&s+dMji3lcrpqwUoOd~Jy89)+u{-XTXOkQt+GScP>BCbNMEJ7q6 z!l{zMBT_2KTeawQ@qy~`q>2u$OQyF@i2*6?B*}eHjW3*Do4Hiuu$QHp zmk^-h3!mv1ysXasVm-p`s5x1X#HySaW}<;fHcRIGJzRvw(w1&`Nz}evInc&QiB5fW zg0@Ae{KU?ndwzBSwRvdz$bph@eu7u6<)6-=Gn{TYRC2a_e%i)7yi`WStFb}rL*>VG z%ff3&W6MEbna^Un1`?F59W#x|3*T68Ge|83T&l!<3B?64dpo9C&urH{^ttSBV`k7T zl@lNJt$@1Fneqrr1X2!<|yW@7KfjkJxLY}(YfsPCgSrE@8iUZQo~A6B2KNU9w) zIk!56$WhJyeS`^HjyYhnE%=W$QpZfHR50+Xr zF5*0LV6~gSq|&PqLl~^i9FsCtqY2m+(c|QpVsm%cJ-!tFm+v z`(8Z`znqsBB^p{#Moztn-HSh(P$?I3+r3{{Tr2c;OumJmT@baX0*ZTC;F%;-&ml zm|y1KdsBJ0(A2w|nLnqr&z@hSJLo1=u~FOvuPV1?K3()o%WeJQbFXey)apR8>gXXR zue?N?N=JLpLVs#SLvzYRVDg_`GMv@E0a*BvGPn&FA;1XF@gW(CHvd&PKl&Eh`vkNP z+L@&-90)BQtOQ)_BYqqb-WN`#2|}H@mt=1(?GHh09A_X4)--E)`~uY@c6?D-~&+tCgAafo~9rn&#mYV)kUMUAhMh_3Y zkc>nJE^;sHyIxs}UTouDd?y_3+@7@`twZM-Q~SaS0lm|jQ9u1->Na^|QoE%+S()jC zzp}6g@OP2d_9*uJyf)&AFD+q+5T4N&G5y!KZ<(yF-SaY?o{dCMwYN_~J4^&ih&d07 zDVJIfSrq>rkL8qrW;U4#OP3pQk7lnBK}H8YSHDFa?Q3q{b1spi^a`Zj7AtN}XDu>& zng(NGR|yNK_QBRv=0dy!8OLg^7hT`&nX7Ge3P@=WC6EE2KUp0fJyl3$&M z)))JbHite?z-lsvsDxmcPzj7Yv63TZ)H=p8C|UWExTXGnTn95i|M)l24Fr3HIP1$v@VG?!C;1qQu#+PUu9`BA*L>6sTcA5w}K-~PlLr@ zSlNUc5T~&t{hN}Q>2+U`M`~F3tGPukAIjIMr9ULViAlu!p9EJE;-~1-)So!UFpF@B zC1AaR%?ZNW(jgsRWNM)Bqd^(xDcCP4+hiU*d|3K`V)V35%*>#BvNg(1O#QNR>}hK3d20-DH3lM&1MsnKi>x@OQFi0eK7P47?lJh2 zC{3$Gz28{T`#y|m*}|#8$M@sd+v7Of@-KMEUvkO+TEfw;8+uhgu4g>r-&65VyYYfc z@TOL-^g_tve4MyXfdob2>4?#XylfSR5R=nH+cRk+q$li!-#?@d@svOUi?DG;L z8OaOn=?aV1nv9NtQvTqdPMHi{-4J@dd}}Q{ik*Q}8}?kw8G$u~9l(gS%+P=Y&|hOS zlq-%`P13Uhv{-qJ*8}*Gz2CeP=aDA6wnPnk;cPOB{E;jlttT#}C)bQ5|E4N2EX)6? zQkL#h2A8H}rvFK9Px1_Z6H`$VOP6G}{!aBYBxoIR?Vuo8T1F)!DNd>M(pe6zWQymn zqRzI8-1e9(e3}?#CgDh_X{-0{i};Z>W17bS>j>>1C8dd&sqsq!5UQNxwEx7A~wRsMXKHE5G!Y*Teo znG60f5oDqfZLi_%l`ayfg6TOsSvD^UR~5*akh-4tIabSrD`fqZ)~B8S7});ZOCs-j z!iuhc%xd9h{x~d7l5gO#%wREMnBJzJ2r2|^t5x=qAm7Z^!B1WcHX$Lz$LUPfoH%%sS7dK*4l_&ha5N+ zPoXm1S^J$iZ(HoanZyx@1OB`?@DhON7wuk*fqWzSi6n@6w5m}v?{ z=T=8|?*rq3jNYons&U;iXWueixi-)C5)`&dl)vg9zIw;=8u=vWd0L~~TK^b#{!9dl z&Pce7E$=g}Yu~pJo4Xf-VN#k98RybWfMb) zmmzx61_Q(pjv|lSzH!{P@OfwB`^j5cRfA|WBjyuT>Ytlzj0`NQ8z5XC&t)UZ*@%6{ z2(x;PsbZ70-H6nsp6Bb<*8XO>&L-YhLk;>ZQC$pHCcsUYUsXZ_$qGe8n;TE^ETByUkKDA(Mn5kkq2CYVt}bsrYqH5^sm$>yG%(9V5|g<0KPZ$d>8K+OHtfABgog2qTOBZOfn?lL`!* z8B^n%9kN%uT6n+szV13Cty`UJJN2(So9@2j-6aXy{f%hYapT=^cUkwaF%+Ho<(OnD ze6tHl-1RNc_eO;H{oL~u-E)yOG&MD&<=G1!<#L7WghuJhHJCB>oB7S`*_`YNs+zIl zn8%Xs^Dypf;_U0on)g2LDcG3%dhes_?yI){O0L*1Z{4>pF#Wq?{x^Kzhu1s-$0C}{ zEOo{#i`OFPa6iZNpun`Tkaxc*$-*S}Ahlwzlx#QzXSbxlyu!sIlkp&E$E;e`tcLN> zciEz@K>94evdGb_5pvMfaQJb_phebFM%4(leKKnMuwzHP1IH?V;*c6K+xyC@??kWv z#KHwO_glH;TK#D_a_w(F8uvc>7iHChup(=>+=ytN`nf(m zGtl62%%KHeC@7!bFo$Mu@ z>=&FIG@KmvpB&Ac9PgZ*+?<@gIz7WXJ^y-o@$>Xj^z=&g^xE|FM)c4Z0J#1iQHM>A literal 0 HcmV?d00001 diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer.ps b/lib/cosFileTransfer/doc/src/CosFileTransfer.ps new file mode 100644 index 0000000000000000000000000000000000000000..2345f2b904b538b919bdb3bd1d1dab34ea30a00f GIT binary patch literal 1281353 zcmeFaU9TKTlBRb({1vH-LhVB8F4i||07+1fb_T1f!R%-uK+pw?JnSZhMHWa_f9zoX zyWGPfj=vse<{yy}Cn6)?Gnh;ZbNAQG9`}e$>q8d5_@Dmyzy0q2c>Uq$hu?kk`{$Sc z^3VV6AEWW?i!c85?dNw7e}DPv)w_q6A78!v^zhY(&%b{4?(NSXUw(Z1@ad~pA3pu# z+jkHD`tjxaPj4PRe)amptFJzNeD&2oeEIs_!{5U4 zKYaM@{p+{y|M-Uwe+_fLyL|KY50~$MdU5&w#~;GzKfnCr!>8a6=KuNO)o;H%y#M@< zAKrid^!LH>U*5m|hY!C*S4<;Z{qx5U?>_wT*|;pM3hSPIaryZ0%fl}}KYYA=`1tmZ zZ{NRsclq@B<>!ZIU&ZUeynK53=ZDMdhc|Kh&%eEW_xkek^7-MHUq1vOf4jVX`|5M3 zDwxl{c|KfSetrl_aduer_WeUp{1|GueEx9x(}!X8r&llEzY8N@e!BeS!^h8mx_o$Z zdHwS9%V%Hx`u4AvuYdghn`zA$b`tva<*SFwn-3o^uR<~L_5Gg(>ZfO4{qf_=zkRxV z|KdAXd%1jZ`SiFb&bWlw?;b8O`m?Xzhj8ycT|(NSy01R|@#nYiU;lNy4C%l7@RtDQ z-NT#DA=1b94}tj-u@D{;U{flpZ|I<(3Jb!-q_J`-ce;$7%Bf$0LP~0H*<>hS<{(O1+ z>HU|VN1U%i%**9J$*j*GVo_gSUcP^Q`SO>CkAHml_2Y+EpS}zMe+i^Me)#3`*T1~} zCZ5Hx=yLh<+n1NWh9y7$=V##{2ZoaMU;gy)@gWR{E&Fi!%fsd0-hcSZ<>k*Ge*1jE zZ2tFWm&?Cje*N(4LZkQidgnf&L=koB^ z0Qyt7+hQeQVc6(*VH19hMT~R49M?=s-aWkkV>o`_Uf#Zb`{zk-JQYc98b}9Zh%&mL zhg)e}^7ZA@Z$DrDeH^%4;z>wHqT>k6jf4%(v`+vIp z&zIkS`}M!Xx36FP;W18N`)EJjKT~Pn4tj{{KjOVRE)X`)Cv<_p+xMRzKK}XTyJ5nA zT;k0*+?d1l7nlG0^V@fCKmY9#5BS6D-@-0GJ_zIxe+YM7eAxbeT=1`ddix1xe}4II z51%fd|MDUEK1~O9ToImkul{Ygmxfy@%>L8EFX0Gu7f|E?B9M3507}jM#s08-+g@vk722Bm@tlH)55yZ{e3uEFn_*2Y}YvP<;VDF zd-dnPj@L!!{^P1@Nx3xo0soC zJzT#1@-pn&``4ewl>U8qD#`u-AD6^-93FOhupxmjxx z#*eXIUWSjezdrl-SHFGy7(QO#gzo~E_^}l}>0kfp;jiO|U8wj!o{dF@hw=2JefI3l zNAaEaS7c;S$$ey$^RTYSC{ZDc#KN=4$Rm^dWRzHV78!YD zlAnwc3(q1Wk4*BDQDWg)WaN=aelkidJd2DxGRaRyiG^p8kw+%^yBT#aNU?H@LOBoX zii|8OxsQx;9@Z5ZSyXZ#8Ra~zD>AaEoL&6&YDnavvGxJgh4+vZ&-fGRk>aS7c;S$$ey$^RTYS z$fA<_$SCJwU6GMRCHIk0&cnJQqeO))5)02FBack-lTl*fS!CpqNq#a)EIf;hJTl2o zMu~-Ik&#Cx`N=4;@GLU&$Rs}*B^I7VMjn~u?`G7!AjQfp3gtYkD>AaE}UMjn~u zC!@r|v&hIJll)|qSa=p0d1R8Gj1mjaA|sDX@{>_w;aOzlkx70sN-R8!j65>Q-_59d zL5h`I6v}y6S7c;S$$ey$^RTYS$fA<_$SCJwU6GMRCHIk0&cnJQBa2GzBcq&$bwx%N zmE1>0IS=cKj1m>HNGv>yj65>QPezG_XOWRdCi%%IvG6Q1^2j7V86_5;MMfT(xzslD!Gr0avs(d86_%Ykyv;Z8F^%qpNtX<&mtp_O!AXa zV&Pe2bD<1u0f;Q7GqOU6GMR zCHIk0&cnJQBa2GzBcq&$bwx%NmE1>0IS=cKj4Ud-kBo92))g69RB|5~xzslD!Gr0avs(d8Cg_v z9~tF5tSd6IsN_B}%6V80IS=cKj4Ud- zkBo92))g69RB|5~xzslD!Gr0avs(d8Cg_v9~tF5tSd6IsN_B}%6V8@pUXWtt7KL&i))g69RB|5~_w;aOzlkx70sN-R8! zj65>QPezG_XOWRdCi%%IvG6Q1^2j7V86_5;MMfT()shXZ}@rEFvp#O;O`wavhZv&^2j7V86_5;MMfT( zbUpU_RuW-kl$S2Dt>+QxjF zGQtJgmH<~}ggH_OY1lRy*<8>|Mo7c9$;jq{UNS-&woOKJF8X8gs!v*!-v+i$xZPuv zh6%UZ+mzNGU(aMln#tTlMu`YnBo>}^a7OLVJw5Z_rQwd~ggN$4>j{{`%h{83<$VKxw@U)D|AB{4aeL(63kC|7Er!7s=(fOjMQkqPy))gk~ zQCc}KW>n@AN69ELB8$YrvyQ|_o=r^;Fnr?OLTQp?H*72u?Fu80i1v49q$L)XMj?+t z-OpVkqdI~544xx0suQTs*!~>hhhK|5en8e!ug%!Lv|0vfTnevz_G>yxAh(WGnqX1~^}_f!w#lf4Kz$Bx5i+V1 zNHg>Yk$AEOFHP^acpz68?KPqwWP>Yzlc~l0RdFj|Yq4>N9wb$f!=BKI3W6k@pdV{-@2TPUzhK z6Bv^B?0aX_Qh&=Fp6oiMZbsb;yc{UxkxBlnRp8?yfdT6n=Lk2)-8IO%$vj4Bm?|?u z8n#VFHW&1g5z?@2GP1d#_Z}JHM~!FSJ0q;W#op!|dAoytFS~6r@}jl)nNgk62^gKA z1aF^?RGK^k*eZB?mHbEAHOb1|HQCgZdd)guX|pP+CHNxQtLZ2s*^eaqZ5?i?bF_+;TbKfZ$Ns%mVzS;WvfQ*)XX52(+I>}|81MXUTA?5wO>C(y&SX!A+9Nmx6 zevv&YH=Pmha&KE({WrAz<;~Uw-%x2f`LgFGN-OV|H){Oa-J5z9BTrQOSAZ>|9i_v?U7Y(MtVWnlQGg6wR_x*+9fKbQRtDtkzmXD%FYoUxyPIvjU$yNDKn$A zb-1%=kK3OnF0}}|PL7NcBeF;=JgdS8?_+JFXhjI8mTd}^`NYwuWu!MAJ(BIyW>hEi z)QtAd2zR92cE6cviE@GN_G_WCXN4~d5}>0rFQe5?wvmy>>1BcbN=7)f#daC#?8+W@ z`^(GpD1|hWx#t*+@O&BPXr6T2^)X7rT$vHlh&FD#*xB~ar}tbFcAXX(B}QbCSa_Dp zNZ-fk(Q>Yko?7-$sLUsh?!gGRU)y_RROWPF8R;Eq@nj#(YTR8GZLU{ht)ll99}GGis5*ITc18VC{D^(o@SG3YGc9(Y+br2@-oeNA=We zGxjb`=f{jRljO;^AJ0Xa(qj>Jofa7-Mr4s#c$UEkZ&Yn}2zgV>ej}su0&kQ;9+~9t zW~2{<%GsU&{W2`jPKm>%5H8aB;hBWTc~&Jrc|iYR>{^u5hxA zj5JP+>DjXCnY?KV-ZIbM#7KwH9%K9Uq!tf_>Xi0i2>g8MPrFS1AF;2B+WqaM68Z%11EENxCnAC&C7;(U6~HDT9j8I1If zw0N>zD=*L;3Fet)R2C|a8W~}n7Fz-sLgmQb=qS_@*_&fzq;Y!j(a#3YLp=9q2Xa2x zbA9hZc>J_2B=4P3%XvCKBYis1Lq;tG>T}M2j_M4i8Due$@ZU#9cq^jqFPx7M_MC{m zJ|!bLF2?t1U4M(`l#HbCElb0jw%s;%&0DNH65P$KG*6<%?`DM2%C>}Yg<7(}Ihjy7 zvK}>r5Tw|$45xbb9u1!4qDwPK>+Kt zG$j|z6k&^GtsU|*tHW{fJWB#bL0!y?z6QF|7W5e67DLXaqjQ$1VeU)A7=gaoKC z!YnXTge`Wq{d&0FL!mmWEg9jKYun3h%Z$93Wj`}2^NFL|GtwsrJvzhfGtx239%fYL z6G!)Bv|nV8$}uv+yDa;R_tI|hAEPwPlo=rn+unu|9x$}+9CGhA8Raqhu5KbD#N2LY zcYk@Ae8cy?=Z}oa5_%N74Hr3$gId z5_|mmGN0IgP1tp2_r*vbHu01>-4~-W3vaZ-2)~Sr?QMnIyl4sZ=)A^^yg1sAa+qV5 zk+)38M~|#(67sUZz?l#(z?hzG2ze4X)w5;o+6|tldNIZCWi5qQ4x~p%`zfTE%sp!} zDsTKex^=yFMpleIA2X`+dRj&;r|fAnsuSAtw^LqrWR%E|MPlLIUu2XRc@`OYWRl-y z@@?u$8|tn6fa^|$y5 zyH1IWY(_kgHW$y!bCk&3FAKbD&`xY7>wXzc1nTc(v??P!kZ4N~!d?}&h#_XQv#)qw z=TXn+@oO+@Yr7>tw*9z3+g@H0I4i9^7dBo5aM%g|ikA>%FMjn~uKLI1}pq`+#v`@LUUuiCE9Pm1iya@Zs_-ICHv0DOUjBtV2 zcJ$mU!73S{v@F;88bW$m9y?uWxv?+vB=iF9k+o|#csh>ucv(xq*{&r9{T7Al%oZ}z zd%93aXGkH1P2}xNY`JSK85yu!mbJ{;yEL8Sei>=Z;>k{S`8&KW2R)gP7p*103XF`> zyo_4>S!pdL2p27Vj0O+$%1XllZI=sQVb_Ejh48Mj?QTYTH^tK}Wasnv`+IM=-Or5b ztj^5HJE?Ul`HV9&$}3%dbpl2wD8bu5qqJo=hau#}Ec>?<@=7cFJHEc$oKSf$+DEtC zwU#V2_;J@-7MJJjU7F5rzl=0y@npA1`8&KW2R)gPj)u}=<6^W|U}Ti0Givu_rC}kM zwzhQuHh7xS+_S>=izJ022Ym>|LqpRo^o+`k&Uf|_$aG}%R3Rqy=qqeSX*tNE)Wzk~@A%ue;Nbf!> z`=!9_OJ{jOdGwTwq~z|>@a&+S!7hJ?ufRrCZKJfhZ3@+i?Z;@p$R3roGs1(9wijRf*Um^s==B&G%}Z9rIFJ&ul9A5Q^Nd1Rg4kt7 zT8<4~nOGcMVf!V>{R-)WCms#|1dP05*S`C`IPLz!W~9$WuV>412(aDOPSBR!ATJJn{O~VN1i*vCQcAdodgxN^6^n%d~wAA%t)fyB0zA{}>;H z{UUM2nHlvG!Lx&Q1{+(L-T;{pMnJozFIr*OBxF-Yn4M>5eOWsrEtd&tzf2kJvHkXI z*yWtI&!`+#Kh05l4!iwWt=KyGvgfd+mD6q+?JiBz6i;@Gl)uB5^U8$0XcC|zR32^_ zHA?d`D*GkhtS@URL2}g6nUF3-FVLPWqh%5(TG=&;hOauLc)AZHg**avzY80;7Hv<` z74jB%{{4jVGUJteTL>AYi)-vt3JJCG?)Nse-M{_zOTzlq%W?aRyvUxP8F^%qznf9_ zf)p#ajwF=boOtB(lv}TkRGQ>$WHc|+YVdH5%ScaZ@l?JCwMcYi6e-jSyvGJl5VoFc z{ss?8c}Fxm*)8AXQ55Y=$crWcaGAC( zK5F%L_IjRb`*E|y_A-5{jJ){T&x|yaxu=^^_kwxE>H0`Q+09u#=2QBm_al`ic^Vnv zogF9D`X8Ay2w77-3D3X1P;Y_fZ}8$?$j39Xk=>NB+N*JnYD?_#6A0xD(^b|^wS1Ge z35746Nz=Dl0vJMGOwTU~7($pC=2EsReVNVz!-y>bDnfdh_GCgWkv)k_s9e8{>R{-} zVBk*sjdo{*g=04tgyPWkucs6eYU54o?M1u4d)GYa ziV$u#+FGt6q!)M|3VCFbe?Lb1MNZY{)>RqdnZB=2RIEG#wYoMvXMk-@^&~w1_Ch*& zoeR#n-v&=8L^`#ftL`-vKYG>1EnOA?Di>#H)tlYOH%=ft7(ZZN{i z<5H_@({lzPYpN&V`L`F+$?IHj&b>5vk%D|kWA(D9GUmS;=g6O28aaVbPA^?$T@dy; zB_7sTCY1DZt0h21$cjDpNzjT=OD-bZz5RL7@hWTZ=IKt?dYSfAg!BUK!NRlBZ~*No zztX!4yR^s}%QCViwEFHvNN;c}p~9c_Y?qLk`@zQYv6~AS#i8q8PbnnS#+$bOm-$}= zj-{VHwjVcMY|L$nSre`+^m2*Mq?(N5t#g<@|Uj^!A+EWqI3$zCd?=B6wpk3KD$pRO6_Ieq45qkXx z&q!}@dw~Zpt)&nwAG^6wS{%YxoZ4yHbpu1(JwgsiEagy-L0NGGpz!8!NU;6)blDTNGVXJyQKHO`SW zt?oO4P|ht~W#2mRtACwJK4WB*lxtSLJYLC)EF%=b?8Md*;;9J9Fv@vC;_u#m%o>B; zON003%@03m29sxH*q&VXuHBr_1T?*SC3yZ5FiOSe-CQUw4&f_KZMWU$QM-i9d|Dwa zT-#Yjx7pyynbw;i{u7++6W_F}m3D${)+czpIXy_d{+nQg6k>r^*QVzTrCC!w3D3X1 zkWOCbf^*p5B^r^G^>Y&^+e*Cd>n<(P%B}2MM|;nsGaNI@)t6jl8KD4XcRLLpW_@1` zUTE`P#E0(>-{US$wmw1P=|0)_D>R`@?;Z=!-wiv3$}RV%&8O9`Dnhytl*C3Rlop5Z z)ticQv~39KNiCl3h1v_0nImjAc=}j9db)3s$CWdKLNg%7WjCYl1xC=pwVx2)v|>w+ z`(?BTBcu@HTV0!;GcdBIdJ>+0dm){?&IRY(V}loo$R{b1ko}dh{Pn(Wk-YZ#RZc8j zWnZYU8JP>zu1DBOd8w6Ugd&(78@xzB?+NnqY~;A!ErQYHH+b0K1^YXkG1yt?=7&qw0Xek+P!I~39auHAzdH}W1AI9i$nP8O~pCdHiYz~7SHxV?FGur z5%#$nys>>d7o5WeFVTpkte-6pq!q93+b^R;E4Q*QRQT1uUQ9kCD=m-Fca>!% zOEE98^Vst%S!D=eCMY@=$gi`~@*(@m3v<7}!IK6ryncghCL1Ys!^XvEpIK-Em)^1R zcDtKV3Yhm!K`0Jg|7r;3G3UkQqbZ51P?}oK+7K!)@J6>6@>uAMWabGPJUI?n_*mNf zoGiT#ySB~`h3Xu;8Fer4a@a#ipIXdrkBl(Bwztd(S;WXz*QVzT8Cg?33D3X1kWOCb zf^+V-!HZnv6AO9BF3Z^Ty5)hKV)VW5mr>3tU1eQRd(WfG&Pq%A{Z^KdEXTZVy1~=f z(9^<7%6B`(c8O64<6mQEyA~R`@OSXS>*F8M#0D?eUt4)f`0N~AmC-eeaqW>Z5^fo6 zabd#kc6VvkzD1vrkvFyM&xG`2UYCY)*vN#^;t;-iQ*n;A4Iw?L#k0Lodx0`@gni4u z!IJ}lg=eMd^U~|-zD2wM6!ORbD<1u0f;?IEO3E#|aGMi^h)TV{kTVq~jp({qN5 ztf`)a=igpPC$DqCIc)HdMzkZZ{AbGpnMZ29+ApIyt?4@ZLWPY~Ye~~QqqHeT-+Pvk zEXBOUo}$|CvdR#`Oi16(~$k{g{cVPGS8N*Ptf4KdGr174SZhcxNA1p9&ZJ9 zyVQ|{gjRO4+Y8Y%yGxtz)^wd^G&z^NXF}38p^PpeAB|VCDwLKkETQ?Rp6?2IQ_FrM zqw)f8)D?;)O+VgZ@yo0c_U$)#axA9O@pUXWtt*3$~% zNktoTdfJRIvS)9Z(VT+SwdpxSM%L6=LXUrYA)UO=5$CYMLmJ7(!@1>w#5nEteiP^Kt+BSsr zq!!QiLhS|0%n>#lJbkPlJx99xkM}&|wzDr`pb z<@GB!qZF&nax;?b>X}T(A`{ZF+lzHe)45<68O1OaAzbX)B6qR|FSL0-$6NRN@CQ4M zUDKFbJQdh25;Er)LU6|h@f>NW+M~}7dO~UI{9Gl3e8$bn-eEoWllB_#l&LNAL7woTF)|@BIWqb57HB_Cbiv zNFSj>H$6paeIGNzT+nXGOG0I(>FDjE9ovs#BvTAi5yHiuEplgW@Is##{_39oY1w$3 zQ-O_B%l0vZ5XgA4%W1cac9(`(VA~Lc;?VW4h7iWood=F$_=*rtE!&1rd4V^&y^zO3 zXCyPnbEKhaPx&;3($@J|K`1LtF0RRKg^VOTh3ebT&8T~Um%~#D;Vp``&g-c%(vdyS zmKn`iSY4Z*Gh}2w-?gM>l|?o8$98IOp+bP3O$Dmx4&+AvfH!3nO9|$^&EJC zHb!f)D;bG&+9Au5Ib-vJxrp781DuRkEn$<~oQ&w8bK5qkYsWi$bZ?`-f=2ZCI% zkqNNl5Wad-agMePAw8+Zv%OGzfijZ~Ui}un>ZV0`3Ly>K?q<}zz>fQL-xcu|6?^ZD zy!hI`C2ZspBU{~>o-<@*P4y%^|Mo&Ud7TT+VS^X>$PaQ6Tl`xd$SHQ;`!O=YZ~JSv zQ)M0)*|XQq$cuyia@GrXO$X=@!o}LYmj*Aid0qcXI__f!Y+R=8y@mASjSU_fyu5dn z1`|(8x#g6Z_tN0umjZo%mpyym{W?2ll$hKc3%o_k$MWV%OS@9DjM9)xTyAx3dd?tZ zP4y%^|Mo&Ud7TT+VS^X>$PaQ6Tl~g3nwIpvpG*iFhPB(NGFXi4*+xcXQEznIH7^eO zJqhtI+2(aUJg$s)P5|VDkG1G_HUUHa*2_xu1(JwGP0(65}tp1A)UO=1?RBAi+tnU|l4N{qZ`fF%WVv@nn$>z4;Z3;OAJLTG;7NlQUd?|c9q)K7 zaJ|w{^%{F&Mo3odg+e;_ZXwJC+lC+%hpvA$gfQmR)}?nG#qbp&oLaUGq4EN6bbBF> zh0aK3vcc20#M~2hZJi$q)j4)E>R#aGu)Pr8oML;qh=2Qx%JKE+mKhH?K=G4}ucO1p=6(O8jwhf{3 z0&jGCA&-U5NM?@DqXg5p^l3&Q_bA>_X=y*& zETc4}6Gg19P0tyGtf`)a=igpPC$DqCIc)GEAN)Z&VjJfO7qr_8g^Y}}OFTLkZ>IP= zT7|N7htO&nQK(FyK6>z7d(s9kw0Yql(bGQ*Z(4o3>?fp)lI)I=5w;B>qnPaVuZ9p( z&>aYlV)%*>PA%JpPKwZnbuaL8*j@;4PO-gQ z#J_z;<@kDZ%Z!jtjBIsndd`rMHPw^w{M!rZ@5!@M)qvXD9m|~ zKU)>v+sW7!Cj4S$O?% zcpZ{>2!W%}5c6S(`7p$M7@`H`u;BF&V0;|{ydI=q57Ms(>DNIt2)!OuUk~NH9^_sR za`6{GZ{EBb@_jYPy&Cd;H3+>LgkBBVy$T9J=+z+cYLIv}NQA&a;^$%U&qEeJ4~u^u z;{QAp_45$^=V8^)VO0$u$RNKmqW0hhWS4Y!F~$C zg3wRHvY&=#3v7sIk2hd4hD3w|7m z`f*tB;}GV@p`0IwFh9!tA0AhJPj@ zoWx;q{Ew{2-@(H_qA9<@lLk+>d07)2PVM5KP}({_-9q84%zh-1ZXqxKZXrwu+lC+% zhpvA$gfJ!>yg0A~HrA*?T7_a0tWRxzhu?-=N$p$abFc=APBvsx7naKvvyD^e~zk4m^ zkXy_s@wf>Vcw35{3h=F)D9um5G-8y7jN;PaOY-bh&l!ZQsh))A-(E;3uXDjUZ15r< z{gW}03q7gVV;sm93CtzTXM-2M4e~d5@p;7G-~|X9{02`Nyzm-+br^2i@4~Mf^-s&K zi*pv<{U{-Jhfq1|4k4Wddb))$FKi)#P#n7c)eyp%Z14gNgOPwoQsu3XndfitRymy<<^!$%Z}fc8RfONUTv8XGK%?FU7MaWWMobCBs~B2 zLOOY!3(jGK7y0O)jFDXENxhzhCmVAKA=%)u!Q&s%jF02Z{)nd0;00IsQ=a;#{TZv_dTfvcc2m zM!2Q@9Cyv0*yA-0WXtlD$#7gt4PNbwOZvl^A+Y=Y4S%(2d>#JE6aNlg z_^QgkgBMTjZT%fQx4{bo;qL(IpO)Kr;oYyLJA}%ab_nS#(9&BC-3z=NwiLqKQfw~^ z^lzCF#%Z^=%m^99jM(7mk2>vX*}E-wttGymb5%xoP}tx_8v0mdi~@f)c%hx+e`F=L zbHju6cK;(Ql?E>ihyPlO{?X4M^j!5kS}0V`agU6o5X=i(h>%eny8hJ=!kFcU8HTS2 z;ncEi2$dIjquUE1DK880%S<+SczfD**tKb(%GTh9vMk|%nMtHkWn1E z{?!n|m~8L@4TF(@M^fdjkeO`o@UF7${q8k8AO2ZSvcc20#N5+;i_8V4YYI&y{P%7~-3z?f+X&$eDYh41`?twR$7%O$nGuqT8MSq7 zLq=^=%c92+LI`Z|N(WO&jh|n=ca|1jc(QT7f+!oj@CA?!UVI+0!3z+M(BQp!^X>3i z@@@DNy81_+1Pkx}s~#g>F8gI9kufi9Ap)Z~bp5L#gfZFR1sVn;0gt50TOl*q;OU!m z?%Ct+pXZQYGo!@g;4JWl6g#C}vkqQbE&bBCQ5uqpOWV4(L8xtNS@ak}2!Rb==>!QW zHh7Uk`8!cO+59_r{5yE(_=nEJujPh+VIBUNgy1s&h^G7o4;#E-n{A%)aa4Nt_+w2% z_>dP{3pNSqW!lp%gxO&W5rpE<^{<8y#wOrj!$Q_Hp? zR9@hXZZG7q&>6|h@nmbL+M~}7dO~UI{A?+Nbi{7SdCQDi;_ErgC^0!Wi)BYn$~$;z zX%G4>qclyb#gl!*Z&~2YIiQe!25V0XdINULGCk)=Lb8w9uIYr^Jqt_2(-eZS!DEBR ze+Mr%EKmRM;Dz7U&Hf`R-f!@v!NWH1X&)o_&=6ZcrxresRuIDMux$t##i8q84IzxF zKjUx|!&iiGYS}h~$_u>F?S(uRIwP4mo@@ z!W&X-FTVC~laY?o?%6vdq#3hjgV(Zmd+(agafOVs&#&G)YqgAK2a*jQ8$336H`w4w zpNDrd+WK+fd72(@YZB7Sw5MALv%|I_2*si6UkxFQxmtsVqGj9d@5{^d=+g?7 zw?eXGgQstaxu^RUnF~zU6q-o*@7;{L7kII^5z-FZkbDqo%-VCZb0h`IfylOBSKjVf$Ow;R2*w7F4IUf3Q#5#? z%?tl&PW@AUq%=K7T11)B00dYSfg3t@KHR0N?obp5L# zgfYtxGYoGC;c&ZsN+Ds&22bA-b5Gd*b$%#R=h)4tdx4k3HbVI565ETf{o7=u9)g+{sX-~HhW`{je z5Q;=(QJ? zHro(3cx>?aM>OMu^;Z5JJo(jKxclR8@Vp=0b7+q|aGD+?I*fi=H3{iu+S4tB** zHW}$S?VhVLLKK5g-eJWo`aOFKVNqgdeVHC^_hdps2Nyrlu3?y~wtri-oZ;td(dVf zilMarb}k0WSM4o?MTx!5r-f9G(ex8qdt_ryc8;Vd1GWq-dtJx~HzWjRgU1Gs4c;v^ zc*bKyKStX<&tz)(8H5iFvGx3g&!ZKDFgxt#LPl}u`d32;V`|tqiuN|2v>2h+K5RxB zs`lu!gP#2kBxZrOk&)gnT;SP;kTH?KW(#sDGh-ynP^djqBct}k zICFa;EU<-Cb|A|O^w~jA1{()@?Jb3nj@T{PZJAL^d_9L5B_;=FvFyl6c?T~o?LnJ` zD2CGd+qoDhUv*zXh_L*$mQmT5lbs_eN>H%DiyZV(z=IOEpZ^t2{#P{lU(pQRN&K&9 z>Yt9U!TMf94}XIf;bPCD?eILBPr@BRoStobuE|ss(qTN0k&!pG?B8Ap3-suqzvE;J zRPQx@imdXpr4Z5)yCvl&JZZCuddUVj=ak9M=WWX*@ zEstiqR-RfOHH46k*kuVBHH2E0={XeAOy-_$M%@eM5vS{Igq9sS$!VL6rh1pWUzHJ} z7=-%UxtMdl>b`^!AwI@ETlV;>UBhE?Bq2e;1}}2Z+m8n&?iw3BHh6d4;NcA+Hr_NH zUxRTO+8vKtoeMr>JB0Ky?dg7IV|Gu~ykJa(>e&V(nTkS~eAy0+;==1+w->?!Jv!*` zINAE_pr`vB;bOG66hb;;V`R_XG9xc$+0Tp;pPOL8gBLaoAq=~gw`y@q`#tw1gb495 z?%8si+{7&+skXc#gt5VESyrC2kP+q*0`TwPg>Omxcktq4jQO$vJ#)r`~Ew4cw3_FJtsT928)FEKMEX|vaR61K&w&ssYp;iBp2 zC$#p&RSW*hw6aXU9^*jb7L2fUs=c0trC}~1BpW<7cx>?YZ1C`g6k9(PwWp)OD?eB| z9wRzal`S{;M)V2!l}G;Nft)y>>g*9@(3@ zO-6BF@`(CtiuTBEUbSm@AdVq~820}B!dwC=Hh66C*x>Ec;Nh((wtgOZo~8y5pM;*> z@r2a*qG*Q@F4K0m5axw_Q4oql*S{J<7_;5p=99KPzMgrEjPRR+k&!+lEuQXk%w~tHzWjLgU1Gs4c=2Xcz6?vjnBXqyVBs5A00T_@fgurFBHOM z+V03m7Gqx6%>|)2bp2~4gwc9!qj~9-koos0q)$rO(|wLSxow2>#(VL#f18YSoOTa0 zN~~^z#j@jf6Q!k{s96YMC=DHx9YrR)<^9ah<}!b| zW~5=;6-N4NiuMTp)0`vC>GAUm584uYAtTHvgk^)r29FKi6Et{o-(^oo{q$@17!BT% zhe+2SmcU1c*cfu*^9Uux?iRwlu$v1)ap?NjY}YVauT7yku_i|P)M!ulInojf4`h>& zCgCm9{)3mM6K?mMptKt*q4yBpP-!hk4$E(P?%)E?zIUPWml)ZW)0`uH2=*?`$Vj`y zqj$=iDgKU=U6$?;S}h|Al?l{G558;RzmxgX(8#?QUcVn+zZ+h^8D77RudDtu37Xl+ zNFV=RPuAeIe3p50x}Qh7sJ)-rm=Sh!p|m)(>=i{1ezGyuUi&6WlO5Ehd1rd>1L@^8 z-fO*uXu0m2R!bb5k(Y40e?Lb1MfT{p8TB4TSICR(`Hvxl<=@1U5EE{<_bAQ#LL&#_ z7~7ABb74k$6BY_#E>|%!GSV*b=soggiofF=m8Cm`R?CP&WdillgYVjtHh3PbtS{3y zLAz(a$A~WNs^`%P4>rsQyScz94)wmGoY)6H**f8N&k0J?Cur{jS;+`?|1hz zBacAx-_Y*#9>p6fE$xS8>B5K7w7cJPf=8-Xv|Cz4Y%S7XXk;_aevYgo*X!Gok=_^2 zgISLmc~jf{rx;L^npBZ^%l7Br$_{@2t1`k7uoeF#Le1+2FPT2D9 z*Y_QIbb&|82)nt!C??zfs!J1(`?=;V@cb0=$Rz(&jPRiDcZ*;aXpb4CS|Os&UxQIw z>~;y6dDZu63`QZOVcQ2}ly1KGJ%6*mgNI?nwh1l%4W7Oe_I^U@lK0C9bHQ#dWE6+W zuejK=Z}gMaD+m22D9!sivEPBzx2t#z*xuB#|A3{H6K)?pL1{Nv0zMGL_V(-MN|Qo# zf!br-oO)7=heCBqH+qinw$Me&=uMR7eLvNHEO{(VPwMrs!K)KHU^`V$x^2dKrQuDu zNrQ(0#4eZET^inBXz%?P(S`4qktKdcG^>=6F1)$KJjNZG95#Bq!_If9K zo^+#JlQ#F zS)k`g*+X`E%xF<>K#@tIvt zyJd8n(lFKb)=pMsA4e$EYg4FBY&}N!>pY1ow`j{D#5pS*NC}^nh7o%06*7{L6sn`| zX4JjF%i(E-^sTA$dfJS1eC-)CvXhtJs`91Uob(2lJ$oET z`>aiQ?vc?H+kR(8HW&1g5z?^j12V!}aan^W3hwg=pG_^c(csxIYu;nPM!qAXTH^Kb zwM)Y!#l{A&#SR(8h1b7QsLpY1MzZDdinnO}AWkz@IFJ%PdyGu#OWs$=NWxO6j=!5x z_X016rxn5*1#QgkX*0seo;_xS2`{s=n{%0jtfEkzUd9NY%3^z)t^H4XAicscucyrj zBYQS8^2j7V86_5;bwEaVL-sa!xORLV=_gUICu{ILkS+dWz&03(tEB{Q&f2A6lFRJu z<7kUel@SJ`5Yn*iZbsb;?6~{_GNk|g*217Cu5|a%HqL;=h;ttAm?SsuW|F-o;IUAwtdBnY%b^}Bcx&5 z2V{gdWP5{$tHjRwGVgiR;va=Of+VV`-D_^7pGU!mt!V8n)fdsC$7OmkplB1^rjS#^=G>pYf=@%w|TB z8*a9?uiAc;YZAhTx!5Qnc9W1^ractWOy-_$M&1r~3(Yf`t}8-b{Aqc5uLz}yHS5em zh_j`^!}(&%qj|kYZEZJN$B(pYLMr=W-dct=Z=2GVea5c6{nuoHYu7uFsCtckf{d)g z7=2eANPMKQ!SfI&|5dP)%$2)#mCy-Fz*8%>5II3Byevelya$=6SaHX!fFce%!&PUGs#{fABBnSaYvEE3Nboog)#k@oBlj z6H;<-+O?K4k0d0#GT7p3DMZiNuQc3pv{%^v(|pn*7qm~qXte{WA1T{>is*#fJ^S5j zUXCZo=maI`vn%^`)1~3#O53M-fSt0my&o6e4WaY8>03mXgPt2IP48FPv-Y>waW!~AUOfEl z_sAswX&C84v+zLb`(dHbY8g>T6R3N-cddJYm&1NS`s|8lzl>I3lpa==b(#m5F75=S zt+4%`g!tW)?cEBVoGaul@cb0=$RxkZ$lEo~Z!~x^HN|SPTp=&A=WqI7gT2M*&oX-P zL;SzCQs%Q<*z<|C>-B`NPW&U9=to;W8^zQ8g!D>WuQV@0uYbLa5G30BWz-(o+xUgs z@5yzaBMNy0>i&hW^`Ys$Mey{a-7TbZ5f6ntGReOmqx~YM>T_#hMtF9`UMQ4j6R-9V zDnBw7J}$HV zWtA(0qAfNXJcMi88Ek3rG}`&I$GYx#9@&{p-Yrk|6r=Bb?Tj?wzI^!EZymt7uj4?@ zm*&?L%6V9SslWRc@$P|cA@A0qkVhu@_hYnQ#B_KG>=~va`h!w zS7n3&DTFj^n~ZEO=rtJO!514Bc(x(rO)dK=ROS;$M@D+5dOcYeq!*Vn!TA*-oLaUs zAuoPeLPj&8J8AHc7k;_)?8=u;lq=i!a?|RASLTAF_reHk?zPFNPHYcG<#WGBMrBUS zsLUshb~EZ;;N@@(Aw1LBmjy5F7XL9y!%UeG(y;A&VT4B>ZJSE&y%$D#)qPiMGr~Pu zW@isJEm7`^aDGJyr<}J^YiM1J77v$}o z__4tfS)AV_q_aT@v0b5Z{3fB6_!S|qQ`FMhbE7BQYwFOSHF&!6cF&D6YAMhtO&>P# zl;sSe@&a#^LLQmqC!@r|vnq_*PkBYii?96@(oE)_{TS^RdCp+EUN0kk*rynM@9SmM z7uTQ7jC?lJ$oUyvf4221jn`EFl^a=Ks~tq6Iom6mXYTHUea`Z*wUs1m%p>LI=cfhy8cW{*#|7Gz8`Hf4p^Gr zHP7Rw@ zwr})6dJP^Hd!wac37-8_rRjsWcSc@(?cauxCW0QF1$wfKa9OXN31I}ZTST+R2rfXO z7P~2mfd!F?eAq6j*_{%fhjLOTj zboWQL7r@8}r;1%JSw;<^mSuX*mO{F;mIAlTNY~%uVMcXI-Hf^ycsU$gXxU95#U8vg zZ%4FWL&&~R>EV_Kh0JLZY6)P#_Li0XMn;-Qi^s^QWtpCHl@J!2m8Rpgd#=g|!%zrm z*!IW>H*%RhZoeI+=EacNIl_UmtwS_ze_2#UvyAS%!PA(<(*)aFjQ)EU@($$b8D;kx zR$I1_7tVCgk+%RBi=Aa87kZNRcmbL+Y6;^C>0HX5ZG^CXw9C23=r$R(ME2$|Back- zcQfixo&ED20jC8KFt{e7Vj<}UVC-|#Wdg&CoQ*c8%C=AMy}-p*c+akA&J{A&zm z2;p#xErFW0zeO&~=nfk^f8Wwb6YMnIw=y)AC2G`&0J zVk@PU7h|wd2p8b6wsEG|GN&UWEs7o^BaDMn%XTHB@?soaD5Oa(6vAA@rjTYb_pHrG zZ)dM3`yPag=c!xQINue*NiB90qb4Do#0JmWK>n3*lS=MvI*_siPaN7Z+98x@Fuyv6 z5Ei&FBb2Bx(o^SD^6Tt*ln>cgUVutz-ZCAeBBU31p0$Or1hl>Q+P`*2Izq398P$n( zGwNR8<#0nnctfClg3@#eLfn4_Lw$w)6iIkYpO_GKs`b|$2U+dbVv zm^IqnLSBv(^2j9rHjHpPd+qFd5H3zh*DP7(3ZZC=Jqnehb_mH-Hh3n`Z4RUvs?m9Z zjJ(5ng3@FYu|V-$RT|2gs^6`bhGBJ_^-IEo7w6_d+3^;od@6nq+rXMkwbB;UrB2JuaI` z1?P0b#>Hr7j}aUY+sj4!-O}{bvS$S$$=xWe9N8OPAtRBdkcT+=_hYnQL{%&HwxjTc6-VuzE?787tNl8xD2DU*p-Z0BxFuS2y;YR z2dD_?1)hgO9+~9do)K<#i|w9lT$~Ed>RvF9I9;DWNZ(E4JvG&M?fcU*!g9RKJ2EQEjY2r7Y%k0R zMLh}e8z0TGxV%h{b}-V5(c=nXQE200v|S;b)M8VpPU)!_Njrnv@7eCj#sw|iQC3=e zd<-MDk&%wCmuXKXq$TRRHOX_% zBVOUC*shRXEFP4=IZZ;|;%*^a;Mq+X;bP1V?QS6yMVmrM!?sVr=maI$d$ag|>BPH9 z?D1QN7pL9-w6L)dFUO9I%5tMnc@mC_t@Em6gc5o&dNLtg=0(QEXlFt=&}$n)In5F0$i_h>)ufqV>GFwUQm zKB?jQzI36!?jw|#yduHHb9BLBs7IzEb0?%&BNETyWXv=7a zke3UE%4E{$31FX~gtQ;IbyaD2XJy|y@)&(rS7n5unuM?fu~9Vl~kVhu@_haNWTiNpn&yKdsJyNAKFTM`r zW`yzeGVRHPaB=%`cUktWLtI|W zvVRZQ_@L0)HDy$m5YbVnWh%}Q8}q7Ugo|;Rwhf{7#VBV8;c&ZcFgiv??In0K*Jk9! zY4_hyMlFXxnjM*GJdaQU?Q)M~97qo^#>W7aj4-}lraf6{xY*0f^WV_+dnI^&mgbR3 z{%siP^NOAn-LkgH$cj|=N!Hu9Q|)w~DkEXjp4U_D8fK(z+|j4X2xFFQW>n@ANB3j2 zUu2KU0W;FKoOrwvJpUf0>D)29N=D_yh7c~mVQqUeJ2KLu=*fgIn%FqCY-d8{spZk^ z+bd>NUZzLa%SdZ4^Dv_lH`!}<``eE~hmcI|?#oJLSbuG%k`eZ3Sf*!ZjBs%|FFncw zshP|@WHcwDuMI}t*%iN*5RW0`O)dM^6T(8uG0QXEjLOS&$n5SfGotNsc?U18oP2qdrIq=_ z(QZcF3%nfeOGw|A=(z<(l5h5fs-*;7T17~P^)mEe;4CAVgv0H&A%rp8?e3H94 z9@(4Ooe_mR0(Jj-u)TAk{pHpsJK1_MdQb@cV!J}POcPotq?c)rn~|RCc_iQUc1_p6 z%)^Z8+-{VScNE3X16kkrdtuaaQp&V$^cE=>buZiBLZLjTd;7Z=c=7L1sP}fgM@HUx z@%%ToeBx+#^WsT%2w|tD4`)Tli{Bwsj^81qr+OaAng`O`z2qmO z#KN<>8F|ODTWGb6DC7~S``6nw?_AV#$Y-pVQLelEiW$|}?Z;@p$R3p&&B(if#V^I) zXldR~q5pnMYuR{iKc1D6edcpiJ}KTP(vmrqz6^!R4OWwoj*kH<8I|LA2z&uvl^;H>R2nrz$+dcuK z6O>@@&4NF!x`Ghi)7mC%4{`F}5F@?8=t(6_)(w?5rQG_?((0s)&v-m9?RJxp^f~1Q zt4XLOFGHv$zLqwG^rW(f4PN~y$_(DLby8O`!h>p@?0R%-##I@iAcc^IZ7*bm8!vXY z{dTN2@4}3Qs4kjk z7^N#hIJInNLSFo`gp6iFEerGkbK54Pa?JAR{bq!_ zrfsBlzl@MV*(RehpE%mhsC$8z1BE;?$v-mEj{@yUi!6(i zjI=z3G?TgKCK&0%*5WY^BrfwBEF>iJD?%t*wlg6wepzC*jM(7eMwjfHxJ60@_+vLw zTFVWgOT3BFblNSRn<$ODHrvXZ*tJ>Cjh81V?F1!wn|1KgS{@WKM;CbT(saV@o;^w{ zZ$JZJ;LyQ8MU3EIBRW2dM~u6oZZ?Pm7}$cGNU@B6EHeK z3En>4P-*&c;d!Lk8!FA)9nb$%rFnq0|EV(ah-g1E(oE)_8)Br7T-jrELD*V}J?CLv zkBrLET1KC>#BUO6nN*&`2G81R%XdS!h?RcHchjYn&-Zxum#S|YyJ<${5?3fqHol5;+PXR@)|{#Dy#p3(tC5M)&~nY(C_@y-I##*F2ospJdkmp94{QnQfFt zp&5ajV}w1DK9J}c?|xi>_6$VfGGl}i7|pYBe%9a>0zMAmVze_M9O$*P(jLPuFep@q zMn)Sj^6opM=cq@wW^mW$R5Wq}woIBYtz8p#jS#`%R8EmY%*S>eyExgF6PN|zw_W~~m3VCFb|0+iK z49cE6IH2tm-LkIA2nF{R(uFrM!V)}t@6vQ$%t$ktd&p=`L|>DUW-|AX(VU3BCL_&c z?pcqK{-`T^=9x^_>t!@4Ui-d%MrBfZbo-2YnK7d}F)~Vw$Re@utiv+W52SXF6nogx zyuD~I&}i^H(X#*M7?sPxQI>`@Y@3X1F6bpAq+#1+WOG3;86geZHW;;kDB?^*$c|X^ z9#9DDY`1lx2P{n|xy-}T>fBDi=maHr`*e?`wLi>crqKnVgojr9SAgA=5oTAmSI9`p zq>$e3xrdDAMD#ToX(n?I8O@34YckSI=AQdyRQ^!JQTMZd4zqT>A8afKZMQU>BzC#D z{YvxlVn!aBGtNCfKEO`jM2NJCG@lMt6_dv77Vi#NS%x*YVdG^AnMWMp$eFBu^X z+a@EM3wp^2Y1sCDjP!@Kcou$S>+-fN%}c)QcT3aBmpxmSR*vkAG9!;n@{0)d|#Rbf2T{1zrvm^2j7V86_5;MMfT(0)d|#R@Enm*oj`pC&(Q{q2z3Lfo+M#=WRjnZ5)02FBack-lTl*fS!CpqNq#a) zEIf;hJTl2oMu~-Ik&#Cx`N=4;@GLS)WXK}1@GLU&$RxkZNdBW+X=2TCg=!1u;}n_` z(br_8nan+8G$*33$w)Jqd&p=`L|>DUW-|AX(VU3BCL_&c?jfT&5q*6EMkgpi?~8a? znnx!2w_&9JOUmd;(JgD6jI2nlK4w%WMMh*)Cs3ckb3{gU0`(a@M`TndP@lnbL`HQ2 z^%?t}qx~X#RG5)RCixG`2phSwor=k=!0 z)d|#R@Enm*oj`p?_c`ib;N?Iek4*BPl9BXr&vZK%>wf+mU-caEBtmcAoRX0g$kK45 zZJUg2F6bpAq+#1+WOG3;86geZCL@~*ddUcB*fts2T+mBKNW-?f8FeqPDUW-|AX(VU3BCL_&c?l}P?{n03%tS|E>wfHlkIl!Ll6TrrD zk=@7$hnLwWV}uY`8q%=s{TS^R*(Slh%;SRoJ$4PBduYeJoZ9B>GO81(&)_+_3r6^%`091MlGkT=agEJS+W9#`6#f$B>eZMWu%{b;)(f9J>8Jebb$lCcJ@fc$Wf^0=V=+WWX6o@l*ovT z>ICXDc#g=ZPM|(xzjK72eb~pb!P{Wh5cc%tCcbCiM(T0>8T*|hFDGW?kxBj&FgigA zX+Ls{rR6-VE0>Xe;!V%J)YL`6sizx+rVAYCwMU^+{3u!faZ9T&&1X<3=V4uukwqo< zkx|aWx*{WsO70`0oQHLF0!H`=$Og~aWZ&1Z{fK$`iWA@CSDWDvCdD`W@uQYTIx;HB z@DI3^>BuNyCrV_ISa{ZbF~Wx#+L4am!3~W3;qqb}HH0t=wBs`W=e~B$=TI6UqY@n% zBO@}Z6R6MNIU=Jvfiwd@>Db^UE-hBmy@r6rmZlD0gOHvUJuO+_oTiL$foD_5Ba{4O zL>7ra-8%nyu^(bR{o25&XFmRofjFAQJp}22G0>0)d|dJ z;HRFndE5LE%@@z>|2NNVy1u!SjZnqLrVi~;TAU!SdYLerIF#ORj!~(Ye2k^#Jglqz z80{C?;t+kz$Rm^d>oL*~E%C%yR{!Pshm3j_TqRV>Its_1^%#lX^{>pR&XA1As7|0h zgXf5h>ICXD_C81WNyi4SzF#uK-8IBHebI^U*vFwAgyzGt3}0K?JU64(lBRhSnn?KX zWR%#DMPlJuCu4-qCiRzym-c7_qos=@_-Sp25Eg>A?BmIH4G$+vLmIYCMm87pk`dCd zZ8EaCpqGr0hHWoogr93{@NBf&o54neXzSihdxB70qF+%+>~fozWuy~s_fV+Lii{E? zvPdjE>okn?Q)z7QV&zkZwagwET_+)d7YY?ii^|J?PP6?Q0ZY?N<{mPd6VcaXq?yb; zWHcwDugPf61V7i-Ztz48Bb5J`<~+CQ`mno(rJ=3+HO~`DiwnJ16lH@qork6GhdoD2 z3rg$uD{a5XsruYvMmZ1bs+$o$iNubwSN`*LB5@=kEK~h*GA6p@ryI5xghC#f`o;^dtifyP(Y!g~UWwa?OHvPX$CWzNcit$(rzmt*A zW*Q-*iG=^YkP&`-vBC54N((m8dij|_>ICXD zc#g=ZPGCMGeMmij&IWHzN3M~P*x_D_#`Uk=LOK^|^LY2$dxu^!LK?Q+&8T~U9hd)A zdXEeGw}GvnDea!@&obb$n08O&HA50n+q95=k>2w31N=U*x>1d zGxO|mj%F#$E>Dor2}+o4%Ht(Vdqm+H86$ik#T7mM+91@kzza|j!W_#VMB^j1JPAiV zNEsuXgt@fX9W5t@(RPPWIj@S4j_i3VLS7bH&V{X~mOT_I^NFKmL`HQ2^%*=z8#BV^ z=e;+0$ilO;kE3hayl}E(4E^dw_WWZ;*SC4R*EYV_Q2qq4Pf!Bx2-++SY1nqw1>wUf zPVed02G~6dyZ{v;%n`dYZD*zF;j#y5x#tLTX|c19o$>;Vuk8+@a+r#cj_i3VLgg%Q z)P?Ou_WTs`$Rs}*B^I7VMjn~uC!@r|v#w&4Jt5^6Z`Z$$og!+NKNMwD7kE`^DCY`c zjxBcfaiqJmc2CGC#?!AYS>T*3BM&69@NAcnx4`pL$Rm^dCt!4f64HL;7E8-{B7`}XKaR4}%2T~jA?BVV%%#Q79`fY{64`t05GseM2zl|f zzamu50!K$79ii9b?iz(236Rkv3fCYb7tP}U89kzKjjI@CPsrDPvgdKP#ADngi}E(bkXX*kepk3xz5WMM8Xc1IWV-Rty!Q@Hfr zAym$*B9wCY?sbZ8Srwsj7C4#-S&>?O3vUrEPa(}@?jfT&5q(WYn#tTlMsp%^ojoDh z;MtJCJNp!g_;iof;t2ksZi#oc2*8BaG8- zH{BvFauljlA|o=Y6R6MNIVv%dr|9^EyuQuL{)nc?;d9#inA8~_Y1cAF*q1G{LupYF zUt1VycJ7x5oT|}k&yiqDcFaic(%iEjqx~Y!8BEvAXd>aiZ^H;5T`_h~zcyslv%m{b z5yBkt*{JRDk?KQi9dTh}E-kjvym-sXtyPDR7eM?Kp>h_;uOd{=0!IxY$pWLb*zT^i zEXFw$LK?PBMm87pk`dCdZ8EaCh&Ov?v%xb_WsI;dTV{s?85QMKwDDDc>+n2H4W2AE z>w0wZ7I{SB8f28vkVRtQS@*&SA6=0}Pro)W>RI3gs0d+>-osSGtNCfKEy_^?(fJG`j{o25&XMq=>B7`~W$0&N(;2|s9&b}<@ zDXTSjD5S%n$H)j5*KgKo#=YFMQ@u;x$*4|^jL4`?pgv>0bA*q}9U45{f2>zp9b;{V zz&T)pS4+Hg{7A4RXJ%C2yZspL7ulo2j65>QzYQb&NaWpqKvrQNOwVUAO5`@KU5MRlfz5H7HzTi$JM5i3%wj~UfTkr5fy z3Djqt`5fUxbL9q4B#Ts>-ohgpa1kC)fKjzXyI5h?r6d?4$$W7`Zes&ndQ)V;vV zfkGacBYcd-qBWp9lhvv!+UhnVm)-G*A*7uG;LPqiO z`q%8^sQi7y8mBcx&5Ct!4f670Ro`{YOp02#bGi_3Q-IEoWw%v?ynGS#+Hh9RY zWH-Ss2~1-Ynn?KXWaP7%M#yL);lJM(BYd#8w|SM{;Gqx((5=mWurV+EbzR6P4qfvq z(hD0reK7Z9q;nAuGxEqJ{|OkKpoFv^xy90Q9@bUHD1ThC!5e{Pj1VI7YO&ei#kR6c z&|rkW1jWT=+ugPDGCfKm&1CK&qd5_MO-7o@+(SllBKq23gdaZGmz8Zcc#)fK0+HtU z_dIk{TlO^Vnx53+F}A;DnVv%-&1CL50izR?FyEEwnx#!7{P&CzKH1`up1)Ez2=y%R z0#t-B$MQq=7=H&3^EH|m9QJoC94Z}4<{&touRgEwvI_};Yrvo+== zg-k4&lZ-MP<^>s2%l_`MNhvrFzQ+01*iyNj`$&??VD@x+8dds1Bs-x z%?8iA+vol!*z-l!HH9oHxsQx;9@Z5ZSyXc0JuB7`}5583S5Z0$pz&)qf5rNuUWJB7>G-~}26qjoO1ukNnlq!yb(bxLGJMs))9 z89YZ-{2t;vAtVV`kQK-&|j1nWVNGv?- zUKrt1F0$z9*9JyC3%mdoAF;{ge1)PCsXj_xDM8uVH`*-MC_KXEeOTQEw2~=E6Bb?=mGRtrObUs zY4a&<*A%LABBR8JED{UPx)(k&jK$%MF?}mhpe`b(codH@(eG^ws#c8 z-*h06l(r@Om{B=e%V_0KpX&IYXB5(OTC%`7O^k4XXH&={ll)|qSa=p0d1R8Gj1mja z>R^NqS#0gZUc14QX!t?wmEifa(lB|kTlzJb6NKWD@~aMjxr^QOM>M^1(4Uot1HCqd z>cq$>F(Qk^!n5v$5kB!Ei=KXMVAQj~3s4cl9QE@UJ#6rh)!aU8gQr_N@pw0<=f9Vm z)~mn8Peyf0WJE@F0`(btoTK?eKmX&JD>Qgxr>NuL2XURvG$Uh#qUBCaj|QQ*+O&qtv=nKK_Q>bG(tub3I2V=M8dc3<-Fi?FVg7g*9JyC3%mdoA8cs*QWi(Z#n%NvovxqH*JYQZH$a+g!lnjCqzcaW;B2FPuJ@;c=+cv zMIAqmTj(cLum9|3uP5siF%Etl&-1aajX&t`b!ugQ*#4LYzG7ZtV|JeHHh5P0B_9uDiH?ks z(FTkNbpxoL``@2M<)Hh9QtZr?{bvWN`@bE(?A=U3XN>Sk7^n2~YlBeF0xv*C2y?_Iv9{UZ zA*;E)UxSwppJinS(wflfqfng`8Ie()Kz#X%e(KR*xS2HKFV=8oc^eTQhizSX6S~|KHvjElYCaNcO$HLND{KkJ%rP^{9Jg zHrr}b_t@J0{VEF)LkFEskeL~sSvP&gOcw!y4)73>H(^y$n^ER5dfH~RyB)4jp|c5{QeU>WYyaq@YGA% z```Sf?aSSH_R(ruW@JV+fjZ)C`v`xF_P-_0XPnpA9{dR&2ZiSp9RK{2(QRSQ+`8sno9CRbx}rIs+o~CvQB9zZ_>?~4-=+O;4E>zODIHd? zJX?qlwd=Y5OGMp*IpR|qGM{?y$&4B=vuG@o^(l<-6ZpnrXI}fxXlH{;PzYg-^H1yR zKbx@@W&5va-pC*Y^_GSIQ{J^Xh54!(&H3C`&B%;u0(Hb^^%4I@RlnEJ|LnO8wdXe1 z8=mwBZz^cT|5?{xzYe1aGa6CJzSl8&UFJ-nJ-MRBLRr@^!VlA1=AC)%dqq1NRDwbX zYn*>Vd%#0hz3o52Q}0&qzvf-*v+O*(qMDW&nNdxkj`-X@n*Vmi)$7M8%(h}bp`vJw z&%OTo)i@)}=p>a}d!3)>oDN2LOaC;Nh}8tU7ub0o{AItD{2U`I;?TJ#3C%-e z6_1PYOR!@zZex49B9;ixh7kTAX9Y@Ps`lq=>tR_ai zz|QmYzALV0ogXkAZ5|q{m>A=iV8>?M#`bnaED@eNh2(EqUfA`#Zos>f5neXiD0(Ms zlsImU^Q?PN?xBh>7-53f3B4{eo*!*jgfzzXHH`2jxaHlM z*S=S@vq2>&gs{f>?+*`n$f~zJ;Emrb_FnU@ah`RLE2>$23ZwqL9z82s2cyxJ=2M%| zpJ2DG`_}WmEAHpM?Z88YosP!K?7_six&%8m<2JUpD`JW8JV7Xa1HW!AQ{MnKDpGWo z7~y5JjnYqmeN@DG?(;lU5vF|JON+oBv5%u+k!-Idc!&`uc%9JeGUNHtc11{IY+u6& zUxHiSoq6qhMLQc*fn6Po`bUSHjq%jTj3K^dxNUNLW)fDzd0j( z32sI2%xm9|wzEMcD1@-ar4RW=|6Xh9*6`y(*-JtzRc;H(ieh0U=R77=q_V9fOG5LU z^HmGY`P^2`=!a*7pNGm;@7;0zYFqg6WmdFOAI;_Fs}FrwMCpMLF3)W|W;z-!C>y1b z-4g8BjN3TPc10`^9t$Zl&0jFW%Vrzzu@Gt*E9;@o#u^WyD&Kg0AcQVF`B-4&eIBDw z$BNiqsqxtrjZVGi+pcJPgQ~|uicIsrIU{}v);-Vu+*!%&0k5^z+`TJxw_FOIr%|qv_7Mk<9t(wsf&uHay65l~Q@NxZf3AK436t214e0A_!WFTIkr3F&;}6)6-8 zc=EBp$oo7-p^iney;9?|D;k}8&$nIC_6Ajtg%p|Qe{)9s60CdD$Hn?Kj@%IPfY(}U zZsCU++8*%c+-|FH{?gV5&=EeGW^=B*IV1i6Ri1e7&tu(w9!FCf!jB&pxEbxlXf8Kj z9ent&5Yiai1tYw2w(%Ydp>g(+ z_o2?l8j}#V{3vVhlR~k8C-1lF=jSns99SgVD>Xj5B7OGNmFgT1q{uY?n=|5< zVBM2GF4nhk5uU&+s+Qiwy@gDE!}5{2Rx2SOO6Y~04}uu&0jMvsM%#@H?xsT&MG-eVy&&OY)E zI(uG)T1`Sx>L}mXhoVV{Pd*kHd7sB9)Uimm@peYl+z=_|zP=eFH-tRkwbr`Ndh>?7?@+PJN2}?X(GSlEKRV|&e}_A+e`OnQMslf- z*5&XkR@leiDBy*8eomQwi?AGTKo7>Jqv4s^Mu}J*2w{-2aT}-EsE9YC$3jSBY!{5w z4Tc}@u@D+(A9+(}&-2e$2SQQsDC^93=S$0y&tnwY^Yi2Fa4q3^c10@Bx_`T(?G36H z3n?H^WRMQezctpDnTKHHG05nt#zOE<_&q@p<fV%L41rFRW)N2Ph*t*H#V{_Tpk zH>ip%q{uY?n=``K|5o(Qy!QQQI~!DjLI`X0fY(~wuiqLs}UcK|B9SCue9JJy& zV6z;0kdYF7-mR$&yZ-Hpwl}DXETqUZ|C=+y_P-UqGp~I=+Rg@*pb)|uJ>a$0y3cy^ zhP>}kvCBuR>6y_F&j>#cS8V(acU=E`+xGXMN968oNKTo)y{aSdHjE5=qau_;q4ar# zLCWUM*rpp5;WoAtBUKA;W6x4WDgpYJgg8HY4k6T@+bj{DqN2Gd-eV!8^0R;G)-W^L zSg#a{4V)Q0g%F0$?Lr8b=R&x;bp6N$H)F~HBMe=)pLhN1IV19QnN_8(NRes&YZzf` z@7jY`VOJvJH-tRkwT`&Yx~7lrt0i{1qMDu=nbApL_d^!H)*O8_m%t5Y(*9>^$VcRo zP@hFVbIQSQk@@#lJSN)5A5ZAqZ3U}9iHKN&9TL2`C3(t!_#x5^7~v7n#{6tA-5Sa% z`>2RB?0PnihP7~-;%K;;ZM?@qh%+nC($O$;2!#i0ltK}z@`t|=ns3I{LI{_`#?8uJ zde@jy$YII>Bb9URf8O=a^YH5HGIK5AaYc$u^IyXVTYJ|Yyb8M#5x*hi0k3t$ebzO7 zbYCs8%N5o1%*c#R0{4B$#+RF;kLD8Ud(c_H?PqGpN92+aW|-TYQvMcELU>HHzu16> zq$DE@3R_VNe{pLpr#z{mc}}$&(n&~VQ+||w=xC{rQ1uae>1ddllNF3&GjBr=vKv%{ zp~^;yq9P1ca_B#94Y#q)j5sD84KwW8MIWupZ3}I0P_{#8X2&+K3B!ofA=FM2?Mn$-dlPxjAZ77GftOz%+*n^5N&x##s20|onT5L!9fQ4!~14`ycRh?k7!oB7}ap}7RtTU5jw_)zFMVDmQgaE-Vcb~+kv z2pe9#^EuH2*b>xWU&w=~YEW=ySS}gN6^x!>8M(QBSFBz%K zEEJJa2+QWp;lX4Bp}7QZMtdNH%VmYMVym8C@O_8Xl}=0<tJL7#g<9to+Zrew9J_UzgbxDFU_snp;zCzTzLe<2o^!tHispQ7t7c?ICjtHdUH5#M0WV4?;1+PX8cMR zo$wx-ffe=Cs8#k~WF~z@v$=lF_DJ3I5 z$lNnH8s-ceGqYU8NTK=Wki(P%p}7QZMmr67A%V+mM+_fu>0QGbSvow&(J)ly29+i;!klVD_#+Y% z3>eKNP$=ZWlPY2f&Wu%H{6Gi~h&gc^+7aUc4-q#TNfof$rrZDU*6jZV10LTRdoV%R zOYhoB6AUWiY%89@E3&eUW4491H*n7ISV)m+{x85t&1=t|%T%6q|4~t+f3NigZcQEC zM^j{)-;5dyWtov8)BM*kntfsV`RDnUm@hWq1?m7Y_|iEi#j7E=bZfX7zks&O|DQh! z#871`iH(Xdvr2O?!ff+?389F=1OrAYCrWVQ;?_7bR)O|Fh_kKK=m8J0HXGR$u-m4s z0S~wF-LVJbkA}n|*$xTzqsIeY!#a4&+v1L8p_2VcxlD7LNC=mBqx7}*uK z#sat*?Igt8@CMn&_>FfB^P?RJ27QEi*6qP7vc4H3w}rMhU^cWZgfzzX7hvQ8Z+x{Y z-Y;X<&7BGde4)L1CXj1-yXPmJ(O3ES~Ch5g}4U#L_NewAu9WNV`$m1a=UO6FWg zds;f$yq4oDUenYT3aP3OMi{DWB@qQA*t({+qS6e$y+-EPslNZ zq3sP%%WNSFQJHDB)KRoga6>gY+ zSBqn(qv7UVJ5{ujSz$janxB7OUFfO2jQ#yN2VZLfcb3V6KGcu!-!2F{Nzi4sf;De2WP~uG5|4a?Z66irW zw$m3XT<$Yg&qqZlfmN*7vA6h!A9bJ{ro<|biZE2!N+RSEY|Oy6N)Y}5Y?PR9jv8e} zYBL@UB?dzCP^^^g4cPNai|bdL!;dG}xHUcwdYbj~rN#BHNE|{~-Xr$X z(dL+=YAH0|9JS-Y2SU3NMMan`>^Z@Wca5ddQ(XVN3S8ZIX>l9d+d|tLIA?e)q{uXX zVuX$Km!J3k|Jz=;j<%3ybFLhW@V?rW?pW#icQ*F17V3%cvl%gy-eX2R5q^GiM);}3 zHh$6K)xkG24nhg06Q0C~CD4O%Y^Rw6msMu=N3!E+yo{n)7uyk8e8t0Ukqi@H`hyW} zP_~i?xda&+9U)x;~{MY_@ZjSpDg_ ztS0qrMtEPUcjx|3>Fha$`KlSs`P^2`$c#<`_^HG;f6>C2r7u)0ai(rRQ$u0~w&!w5 zsOf8q6NKkDn%WpusLkPznBprQN<=bsz~gARLD@}*7f8`$2y zekE}TsaD+e%cEg_JSHZ<7%8MSZwReOgxpd^7=(7D!MeiUc-K&l?cx>T%*wOz(kh8` zw0RJ&zAiIXf%d0VgzZ$1D>>rX!%J4b=jrQLg!hI0x^90;XRj0CNHbz4y~m7tBK-U* zjPO&5ZT_N#G4d-O2C+l|8#l8(m)pKIP7t2sXk03K)aLLI8%{tq+8 zX1t292SOaAJeX2;HkOSW*xtT=C2#u@m>lT{Pi8V7aqnbb+@#cMmpGs`=7cGog z`lw|IW|kOX2DayNNr>~XhZBS+9Zh{dQ=7vdyEX>ArK8PrVrEtK^BBzwR+Zweum=^b zZ06fcw-yo{q&%2%AjDzMX(DnwE-$IH^^Cw2wW<2NMD%AdHsg=%VMWJWcCI^xay z2tSqB#&1kN$RxxChX*&XeH=}dI!7CFnE1}l#sh|(j>ctk zW>u*a!m>F(%MFB9Bv?BAg~*Ul2UN!l(F68;GfJq)<7iO}7rgFy-u18NOe}V{as2C! zz_t7kN5iJVIfn-+UQKfuFV8)gI0@l`s)A!8G6}8c$Hs#7Yk#wGI6!f&Q?MqhS!{S+}2e z{p&d+@^zV2rJqs}wi8YmVdE;>gLjI9Ry=76!VO%7@`OJLg-iXD)1dTmG_`r%zflp2 za&;c?)T`S3pYqbS6YpDQR5LT9O-A@}#kTrp5|K;4MU({AnQo1%K+jw*31No0jR`i6 z#@oV!HGcg8FV2jB6&I!xy9T#5mryB-hQu1##*|42uQTk}j2qaF$c^h)5{D2Me4i&B zjdQMh211GySBhy0A>54H*dFvzZ06ALV7-{;5K`NCa|m&KI$8u_o^@LuZCxTFw}rMh zsERD4$TWXqgzbbAM%cK@c4|CcUiYLa2)A(+$`k%16fX5oPJ`0N(bVR3|3*b9%GG(m zYaOht)Y&R%#c!dSk{OxNNdP~t*jC?wB68`sh>|!9xcy8G$yK0dE|-Kb!`#LM8%N`9 z;lUa=zTx9GuJ<^a%DL_z+}b>I)WQh{LL9^%P9|@SH_tsqMVuKiqx3*1HY*mmIqZnv zxPB#Z2w|y@*n^{S<`vIC2mvE6t``#&Li5c@XgxHxVZFF_>0QIkVPh>}r=!h@V1Bmc zE5f03&$iI^29@7JicIq-M%Yd`VT3(jy>obB=_JHCS3Dt_g!nkc&Bi~efCC0 zn1HK0gm6LqwM_K4Yd@`Y{ipMupBAdAnUNXQ1nP)4?<4$FVjI82@KMv(7v3D6xkQL2 zMoMT!E(vkLa}Oq7IvQ?38;`v44Ij60rN_}Q&wcjbX!Fcb3nv>0aS(biP1qqVZw)uE z*hNK{p8;cnLI^{Z9mzJXpM|hq$%qd!_dMZfQRzSk3l3Y=f`=`HSOPbrJrKfWwy|DJ zv-Gav=CCu2q`=XIG?U7u1Bwi8YmVdE;>squJu-IJyu+{RTXPxzBi zxYR#64N4zJQ=8ZQ8x^4_SLXpwy{gUsDKBk1@xEn7H8V5XWP~4AY~z<07GC--GM5O^ zbZcA%dggLThzp*3FwN4@a6{NwUD!oMD1n=~(nAP0+-DDtHqVT;V9J3IF0+kk!Vc*T zMl6aRS&_>8w4-4aVMoeO8SqvBZ@@-5+!i*&4v)Nk-hc_h#xzUs8cL|T1{HBO%&hF< z6;a#Rzb&-Afpdn(LW)fDCq~${IAMg1t85P%kAqe`X$ry(T!r$4KM93P{gcz6^l>z` zdELKJ5sGqk9`ITRD=T%j3R>}7sHS8_W^@w3k1MwMOU$|N_H*gC$Xp`iQbTeT=$XqU zAuM&p#xzSu!wq3$bz#ejaC20Lo4MXY2)Es54~{m^jJ06Ofe05;wi3*ct72ST`vHYNxg(=5GfC=r`6LD++eI2&eG zcJYd+ZS3C`+TOr9!($;uruh>iY$u#B!k(|*IlQoR65^aIo)Aq!d>r(!DAsknQ@G(i zd!r&uz||c>xPX5ZQ`zm>Pb*#j>AdHsg=%VMWJWcCI^xay2tSqB<}WdL;KA3IU5SuO zj93CaMMYTNeRd>UIvUm$HdYsQIvQ4lo5PQrF*58!2)Es54~{m^%(X<~fsm>Q6NHVT zk`V?eY4i^&;>?_%(+q?#&x##szW#u>3pijS!2xU(#oIv}CBhyEaS%$QjnYf+n%ayh z2NlIO%(h}Ly&{(gy)Lsl&Zks_jf4|M*z?sphZmMkLY#BO6QW6okAof-#k!7n3OC$m zZ&ZW{xVl3K7t~OPe(vv2>1;mvy2p%aR%T>ICjtCaVq1NQiQPvZ@iz3#C6Z7);AXbx za!=^&NICds#k4~tv~ck;!-EnS8TJxvtVr2|qs=pOEg?M+QaLdJ(n&|-Jm^u< z=szmrZ0JEzWiK5qL@__wvHB$kymT}~8@7Uqek3)3jiR^>ZIlRmAcR3EiZ+Udz4Wdr z2}~&~ip`u^d7kjWmX4W|pRD_~jod-PihBd!GMj8ucnUNyX{AScxC`&TJuPkh{ToU39>|u%U zBq0o93G`rOA;h6`&(beQtcC5OBK$ppn^j!{M!0R=K4uQJLFH%vLyS;va5P*-8>z8f z94(HFa>_1_rr5E+81OJZZ${4sBNSyj31Nm^Tf*j?bB`2?isqXmCR#z>+WcsoATf&N zU5SW)=xA8ipdwsex3`71H>g@Hq{uXXVuYV>IAMg1t8B|xfkWq>GzDQOSD`%NPeS2R z|Kv0%eH=|~UiWWQgrZ!X2fWt7%1WKBf>!(%swtU~8I1_+eu+taG~XPnqog-q62hRl zC`N`Yg*bHXIfUl<=c^kPp^&O;a5UVuZa@1==X&Odi&r*p zM$a}Ql_m*chFyCATjiYl2SQlOd~>Wud?AFQVJqpx2s5xmA*43Uw{cyAia2P+vn{l} zK~-TPMW*=^Bc3GYa|W*7IlP1fCQd@Qz@f?${v;GG^-oTN(jM?yzbGs9kqTPzTd1aF zMrKqKs3WfLqup;KgNk+~;@AVBSlE@5LN(qTaR|-xt5uX*stAQ}Gui_o+_r8PUxP8{ z+`f|$iw=&)LFiG39UKj}t=p+0l@0wNjh?WNidHi7X7r?rR^(Jn62c6-_QugvE#V*B z8rCx39IFvu2(61IMwkI5&{j1rRirkfe^3!FuiM)~+Z$9Z7E)xIKQU5s4o*85gZ6v; z3EmSb!XYr^o_91X?>;-K^Pk|g4pvs`Y!$TPw@^*VjLfJeP)B@9AK_OyWh+`sj8OC; zA+;I(OBLY;WhWs#g0h!{R1o_)P5M5~8`eD=N1KZ#p?Tw;Yh1kX(mJ3f3Qb8;J zw-rJb_+QIZHn-)QHzXIl?(xxTR%T>IHGw+9ePl*8fjYu{WJWcCI>LSQ&WwCJueu!^ z7z_$g{X)IHGw+9ePl*8 zfjYu{WJWcCI>LQqMm2#J;eKf>lywaw92j`=!Bw_B;4!h@BPT`1Irn(LQ!hsIU-ODI z{e8<7)y&MujA{aPg!{;hY65kH`^b!H0(FG@s4+5&#zI-wFv6*#A5Q*)i$C+K99}q- zJ*b_8a3Qv_hvmYPgjCRq|9YX7Lt)HO5xUf$+M%Dj>6$*`JnJ4;RI@T8GpY&H5$+>1 zstME)?jtj*3DgnpqmN+ZYkt)=rx_Trs1Qg#Kwpn$5XlMkfjV(~LBmbH$8K68fhZX*TDI8J#5jKN-InCd8Px>p2=|d0)dcDY_t6E6 z4D|x2N;1L5v5kk6`KlaVScp9+orG{9wy}rh!jptl(2D1stME)?jtj*3A70JOJkv|YZ&3cz>^QIvVHxZ z;Bii_5k1$>WteTnmKEXAln};vz*8?q^I!9dH2r1 zstME)?jtj*3DgnpqYD@r>IG1hWP*)jTR)t<=D(uJRjhmDIJGVjk=F~&!ABJs<3GVu z{oMSivzvS0vQW*;jLfJeP)E3r%%~<%N4Ss7s3uTHxQ{MiWT+QFRgwud&Ja8W%~v0q zf>8P)A*}ib62kN25zxjM4|uAdn?H4SbMIRgs+pOQ8Px>p2=|d0)dcDY_mLUZ1nLO) z(FKeQ^#Z6$GQq|f0%wb`ah2_B{)#47vF`DJ*Z;>>xCzqr^YXgKLNzNhGNYP69pOGQ zqnbb+;XX2>nm`@lJ~E@4K#Op{G#1Lbh7pc!JV@ax+gA>FoGmWHFTfTWia>45!AFXC( zMrKqKs3Y7*W>gcXBiu)3R1>Hp+(+-s$hY&V+rfc>=L}qB`Hp+(%|q6R0EHM`lzL zs3Y7*AHm4i{Hkllfq|zWTxI*3Kf&WF);-tHW$U#>p2=|d0)dcDY_mLUZ1nLO)(K|Ep z?Y!!CaBS;`lfU5N&%FB3@PgV831MAdUkI^{{=}~LabNjeVWT2P88MUIV@5p@el{a!(tEZUZExr^p3fFKN$8)65e^JEDuq2?eQ2CQ z>4$`{>aQ<^*!p2^^vrFLuAi6JJr=52nUNXQ1nLO)kr~wl>InCd8Px>p2=|d0)dX6E z`=zl^)-{Z9V8Bs{2Rw`n+kZuqiS?dmkDPc5qk*pXaW`GlN1SKfLQqMm2#t!hQ4+jC{?nx@H_0`r#!16-|uvfXA%H9uIi0>g+nNj_~J^W^=BX z(Mdx8G$YOCTrs1Qg#Kwpn$5XlMkfjV(~LBmbH$8K68h&hqwNhUw}lj$=1+`pY~vAS zzWUJcg3=EOVbxz>2(k5lS~q%b*M3^*`cLOQKP^;KGb1yq3DgnpBQvTA)Di9@GpY&H z5$+>1stL3R_e*1;tZNwIz<{Gt*tp8J|B5CP>pjmNIq?=o16}XqZn~zAIM2Gr71gZF z$c$iW!|G^iMO=Y|a%kI!WlCW~AAiD`s?(&_A~sZEsMyEu_dae`2&g z;PGhl(C~tZ9}>d4zP=D*>;JTF^xUrfw9@sT&U=1ZsHSE{W>gcXBiu)3R1>Hp+(%|q z6R0EHM`lzLXc6w0#zI-wFv5WWN2RcFm2LkOO(xcRo;`BnEsO@b-pAc^O&@Wdb&o5m zS(%X;)dcDY_mLUZ1nLO)kr~wl>InDIM=pz|M{IpO_&5X>bCQwJXkIbkhP)E3r z%%~<%N4Ss7s3y=N+%JuVvaVr-0|SmqVb50|8mCbDAt9{#>kA>a(LmSxxSOu&BhIt# zaYZ#NGcu!^Kpo*eGNYP69pOGQqnbb+;Xe8ZM!x1(T{8|0I4bdghmm3X-@#*Iz315@ zC*DFo%#EJ8ul%ktlip)SJrRC3BWBWj%%~^A&t}9-dXE|PMEKc^m`U$3qn-#qn-MeV zJ==`7H}o0LXA7Mq^v}cy2Znw)@xOz|M0PzM@N^@dE2$w*=RH3yR8un}GpY&H5$+>1 zstME)?jtj*3DgnpqjzTH+j-UPtPglR+B`J8VB&{_u&%E!gxE%ZV%Ph)ul%ktlip)S zJrRC3BWBWj%%~^A&t}9-dXE|PMEKc^m`U$3qn-#qn-MeVJ==`7H}o0LXA7Mq^v}cy z2L>FK!p2p${Z}-ZSnqlE$ceYm4|AhuZi96Fyu9wQP|eDW%%~<%N4Ss7s3uTHxR1=J zCQwJXkIbkh&?4L~jfJwVVT1!iKb-ilXflyqj|V)}&&_{LXE*(Q%N5nk%*c#t0(FG@ z$c$nm`@lJ~E@4Kpo*eGNYP6i*Ua*7RtJY5e^JEDuq2?eQ2CQ z>4$`{>aQ<^*!p2^^vvCKO&@Wdb&o5mS(%X;)dcDY_mLUZ1nLO)kr~wl>InDIM=rGwO-( zvl%gy-m}eUdqbb`e74X@LjO#RaA4qx16SGhU(sY@z317JBHqGipzD3y2I=~FdEH~7 znw1%uQB9zZa37gbO`wi&ADK~2ppI}KnNdxkMYvxY3uRry2nU9KIH{hWJ-k%;>h-T* z5#Con%#EJ8o3802&a>`uMKvokGNYP69pOGQqnbb+;XX2>nm`@lKKckozUEh5GY$;( z0F@)Y{y3G-d(YFe8R3162D;wIedTwJne-kr>WT2P88MUIV@5p@el{a!(tFIPC&JHW z#7ugR8TCZ?*^HP;@7ZRwy`j%|K3nJ{p?@YuI56zm&-*KyyO~w|XI0b>bE9W&gLM78 zyza43&B~0-s3uTHxR1=JCQwJXkIbkhP)E3r%%~>NBHS;Hg|e<;q(-F`|7VR;D?~Wv zN=BoBuJ>^_UDHRLXWiq9YF1`sMm2#t!hK{$HGw+9ePl*8fjYu{^bw4F&F^;2II6^7 zO+-)F$MB+-BZybobNoF<&af^KqH>(#oS2MP2NiM9Tw+kst^_9d){ky$&)ipj*O*D~ zF{7RcKbsLV={;uD6X9nwVkW)EjCvycY(~ta_n1*ngrCibne?7*M%x?ujOVk3P7?a( z5+j@~)Lh~LuTf$~9`JMv=9Q&}%v;7!78-LwuNfhYv28|UF6cEQq%pS5Xv_t@W`s1x zwi%7Npx2C$#@K!xqt|5~llbdjKfR(hy8L|n55=J;Y!7&ii3dFOCe{8=f7fb4{yZ|H z6#{jP-!(I;3DgnpBQvTA)DiBZk6`3$ez$9Gql*W;V8J8YoRR+oukPuH@Y`RLG9xpp z3DgnpBQvTA)Di9@GpY&H5$>apVB~9lw`<1XMcMM-cvBmc-$IH^^ZVbyd$(7luE&4y zW=1On>KOlmG^3h89pOGQqnbb+;XX2>nm~(izcd!g`u8$wlZCcCmuWWV%JUel{YO>$ zDDI|zZy#}f_P8Qu(tFIPC&JHW#7ugR8TCZ?*^HP;?=hpE2tS(#pym>NHrn)zj8z3IUljjsHSH|W>gcXBiu)3R1>Hp+(%|q z6R0EHM;9+i53F|)3r_W_8)Rq{jD@XtHt{+t&v0YJ3&y38dCQwJXkIbkh zP)E3r%%~<%N4SqZf|0NJhrH&M!DJ<7X?U?vO`z@~|7&4pv_hbc@n^Of)dcDY_mLUZ z1nLO)kr~wl>InDI1&j>!0;o#zd9dq=V=cl1Ud?HVk-Bp9Kkxcc^%2_@)%48BjA{aP zg!{;hY65kH`^b!H0(FG@=pz{Unt#Y^uE&zKh^66WMe5Uq>Mru1;F-}1fjY*Y*=AG| zs3Y7*W>gcXBiu)3R1>Hp+(#EMGSmy8D#_=;UYWU8Vm^H?dm1Bk<>-Ij^`q(|wkxXX znUNXQ1nLO)kr~wl>InCd8Px>p2=~!PF!D8j#5Jo!`uY`_<~O6pLRn^{$TYthH5SS; zBSoh9&8V?ZmKiBB&2L7Hg|f^@k!gN2YAlrXI!3R{{C+H4ks?t0-A86r6R0EHM`lzL zs3Y7*W>gcXBiu)3R1>Hp+(%|q6R0D$`)GTEs=-2vO!J#jW1%cFQe>Lnj2a7NnUNyX z{AScxD9el#ndUd6#zI+Uq{uYC88sHlG9yK%`OU~I8iCq!znD=?ppI}KnNdxkj&L8D zQB9zZa37gbO`wi&ADK~2ppI}KUBJjtFMz5f4O@|Eeluz;lx0SWO!J#jW1%cFQe>Ln zj2a7NnUNyX{AScxD9el#ndUd6#zI+U)X11cW1%cFQe>Lnj2a7NnUNyX{AScxD9el# zndUd6#zI+Uq{uYC88sHlG9yK%`OT=YP?i}fGR?ouXnRA;l`RWp9-}8S8d1qUGs-+h zPi8ctl6_{Bd5oUSXhbFZ%qa61J(Lnj2a7NnUNyX{M(GS zH?&;YvQXwRdNQLCmFzR4%wzOqMk6ZOXGWRF=*f&mRI<;EGLO-d8I7o9pBZHyqbD;O zQOQ0t$~;C-X4I&dMPs2XGg4%l-;5dyWtov8)BI-CSSZVk6q)8XqsBs6W~9h8zZo?a z$}%HGruogNu~3#7DKgE!&1ic=%att)Wgep^Ga6CJJ~PTZMo(rmqLO`PlzEJv%xFX< z`^+fw7(JQMh)VXEQRXpvGNTcd>@%axWAtQ3jfz<`7RoXsMW*@9sIgF%87VT&Z$^!U zvdl=4X?`1WvS!SfjG`|@&7RoXsMW*@9sIgF%87VT& zzs+cSL(7#d3uPXoCo>vR$v!j6JVsAuG@_DyW|Vo1p3G=OCHu@M^B6su(TGa+nNj93 zdNQLCmFzR4%wzOqMvaPDG#1J-BSoh9&8V?ZmKiBB&2L7Hg|f^@k!gN2YAlpxMv6@H zn^9w-EHhGMn%|5X3uT#+BGdfajJ7wlT-mZv<}rFQqY;(tGo#F7^khaOD%od7naAkK zj7C(l&x|sU(UTdCsAQiRWgep^Ga6CJJ~PTZMo(tcsC@hO&;R}V|NX}=fBW^@xBvL* zpa1&(A3y!~KY#oC-+ubnum9&CzyI;eAOG*C|NQMQ|N8CszyE1|`}Obtc? + + + +

+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosFileTransfer_­Directory + ..._Directory + + + + 2000-11-09 + PA1 +
+ CosFileTransfer_Directory + This module implements the OMG CosFileTransfer::Directory interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosFileTransfer/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosFileTransfer_File

+
+ +

CosPropertyService_PropertySetDef in the cosProperty application.

+
+
+
+ + + list(Directory, Max) -> Return + Return a list, of length Maxor less, containing Object References representing files or directories contained within the target Directory and a FileIteratoror a NILobject + + Directory = #objref + Return = {ok, FileList, FileIterator} + FileList = [File] + File = FileIterator = #objref + + +

This operation returns a list, of length Max or less, containing + Object References representing files or directories contained within + the target Directory. If the amount of objects found is less than Max + the returned Iterator will be a NIL object.

+
+
+
+ + + diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml new file mode 100644 index 0000000..e5050ea --- /dev/null +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml @@ -0,0 +1,94 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosFileTransfer_­File + ..._File + + + Niclas Eklund + + 2000-11-09 + PA1 +
+ CosFileTransfer_File + This module implements the OMG CosFileTransfer::File interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosFileTransfer/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosPropertyService_PropertySetDef in the cosProperty application.

+
+
+
+ + + '_get_name'(File) -> string() + Return the target object's associated name + + File = #objref + + +

This read only attribute represents the target object's associated name.

+
+
+ + '_get_complete_file_name'(File) -> string() + Return the target object's associated absolute name. + + File = #objref + + +

This read only attribute represents the target object's associated + absolute name.

+
+
+ + '_get_parent'(File) -> Directory + Return the target object's container. + + File = Directory = #objref + + +

This read only attribute represents the target object's container. + In some cases a NIL object will be returned.

+
+
+ + '_get_associated_session'(File) -> FileTransferSession + Return the target object's associated FileTransferSession + + File = FileTransferSession = #objref + + +

This read only attribute represents the target object's associated + FileTransferSession.

+
+
+
+ +
+ diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml new file mode 100644 index 0000000..c848a98 --- /dev/null +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml @@ -0,0 +1,86 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosFileTransfer_­FileIterator + ..._FileIterator + + + + 2000-11-09 + PA1 +
+ CosFileTransfer_FileIterator + This module implements the OMG CosFileTransfer::FileIterator interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosFileTransfer/include/*.hrl").

+
+ + + next_one(Iterator) -> Return + Return the next FileWrapperand a boolean which indicate whether the FileWrapperis valid or not. + + Iterator = #objref + Return = {boolean(), #'CosFileTransfer_FileWrapper'{the_file = File file_type = Type}} + File = #objref + Type = nfile | ndirectory + + +

This operation returns true if a FileWrapper exists at the + current position and the out parameter contains a valid File + reference. If false is returned the out parameter is a non-valid + FileWrapper.

+
+
+ + next_n(Iterator, Max) -> Return + Return a list, of length Maxor less, containing FileWrappersand a boolean which indicates if more FileWrappersexists + + Iterator = #objref + Max = unsigned long() + Return = {boolean(), FileList} + FileList = [#'CosFileTransfer_FileWrapper'{the_file = File file_type = Type}] + File = #objref + Type = nfile | ndirectory + + +

This operation returns true if the requested number of FileWrappers + can be delivered and there are additional FileWrappers. If false is + returned a list, of length Max or less, containing the last valid + FileWrappers associated with the target object.

+
+
+ + destroy(Iterator) -> ok + Terminate the target object + + Iterator = #objref + + +

This operation terminates the target object.

+
+
+
+ +
+ diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml new file mode 100644 index 0000000..5f45420 --- /dev/null +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml @@ -0,0 +1,191 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosFileTransfer_­FileTransferSession + ..._FileTransferSession + + + + 2000-11-09 + PA1 +
+ CosFileTransfer_FileTransferSession + This module implements the OMG CosFileTransfer::FileTransferSession interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosFileTransfer/include/*.hrl").

+
+ + + '_get_protocols_supported'(FTS) -> Return + Return the protocols supported by the target object + + FTS = #objref + Return = [#'CosFileTransfer_ProtocolSupport'{protocol_name=Type, addresses=[Address]}] + Type = Address = string() + + +

This read only attribute returns the protocols supported by the + target object.

+
+
+ + set_directory(FTS, Directory) -> Return + Change the current working directory of the target object's associated file system + + FTS = Directory = #objref + Return = ok | {'EXCEPTION, E} + + +

Invoking this operation will change the current working directory of + the target object's associated file system. If fail to do so the + appropriate exception is raised.

+
+
+ + create_file(FTS, FileNameList) -> Return + Create a FileObject representing a file which may or may not exist + + FTS = #objref + FileNameList = [string()] + Return = File | {'EXCEPTION, E} + File = #objref + + +

This operation creates a File Object representing a file which + may or may not exist. + For this operation to be independent of the working directory the + supplied FileNameList must represent the absolute name.

+
+
+ + create_directory(FTS, FileNameList) -> Return + Create a new directory in the target objects associated file systems domain + + FTS = #objref + FileNameList = [string()] + Return = Directory | {'EXCEPTION, E} + Directory = #objref + + +

This operation creates a new directory in the target objects associated + file systems domain. If fail to do so an exception is raised but, + if successful, a Directory object representing the new + directory is returned.

+
+
+ + get_file(FTS, FileNameList) -> Return + Create a FileWrapperwhich represents a file or directory + + FTS = #objref + FileNameList = [string()] + Return = FileWrapper | {'EXCEPTION, E} + FileWrapper = #'CosFileTransfer_FileWrapper'{the_file = File file_type = Type} + File = #objref + Type = nfile | ndirectory + + +

This operation, creates a FileWrapper which represents a file or directory, and + should be independent of the working Directory, + i.e., a full path name must be supplied. Furthermore, the file or + directory represented by the FileNameList must exist.

+
+
+ + delete(FTS, File) -> Return + Delete the file or directory, represented by the Fileobject, from the target objects associated file system + + FTS = File = #objref + Return = ok | {'EXCEPTION', E} + + +

This operation removes the file or directory, represented by the File + object, from the target objects associated file system. If it is a non-empty + directory or non-existing file or directory an exception is raised.

+
+
+ + transfer(FTS, SourceFile, DestinationFile) -> Return + Copy the file represented by the SourceFilefrom the target object's file system to a file in the destination FileTransferSession'sfile system + + FTS = SourceFile = DestinationFile = #objref + Return = ok | {'EXCEPTION', E} + + +

If the target object's and the DestinationFile's associated + FileTransferSession's support the same protocol(s) this operation + will copy the file represented by the SourceFile from the target + object's file system to a file in the destination + FileTransferSession's file system. The file is represented by the + DestinationFile object and may not exist. + This operation must be invoked on the FileTransferSession + associated with the SourceFile object.

+
+
+ + append(FTS, SourceFile, DestinationFile) -> Return + Append the file represented by the SourceFilefrom the target object's file system to a file in the destination FileTransferSession'sfile system + + FTS = SourceFile = DestinationFile = #objref + Return = ok | {'EXCEPTION', E} + + +

This operation behaves almost like the transfer/3 operation. The + difference is that the DestinationFile must exist since the + SourceFile will be appended to the DestinationFile.

+

Currently, it is not possible to use this operation when the target + object represents FTP.

+
+
+ + insert(FTS, SourceFile, DestinationFile, Offset) -> Return + Insert the SourceFileinto the DestinationFileOffsetbytes from the start of the file + + FTS = SourceFile = DestinationFile = #objref + Offset = long() + Return = ok | {'EXCEPTION', E} + + +

This operation behaves almost like the append/3 operation. The + difference is that the SourceFile will be inserted into the + DestinationFileOffset bytes from the start of the file.

+

Currently, it is not possible to use this operation when the target + object represents FTP.

+
+
+ + logout(FTS) -> ok + Terminate the target object and close the connection to the file system it represents + + FTS = #objref + + +

This operation terminates the target object and closes the connection + to the file system it represents.

+
+
+
+ +
+ diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml new file mode 100644 index 0000000..a43482e --- /dev/null +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml @@ -0,0 +1,83 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosFileTransfer_­VirtualFileSystem + ..._VirtualFileSystem + + + + 2000-11-09 + PA1 +
+ CosFileTransfer_VirtualFileSystem + This module implements the OMG CosFileTransfer::VirtualFileSystem interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosFileTransfer/include/*.hrl").

+
+ + + '_get_file_system_type'(VFS) -> Return + Return the target object's associated file system + + VFS = #objref + Return = 'FTP' | 'NATIVE' + + +

This read only attribute represents the target object's associated + file system.

+
+
+ + '_get_supported_content_types'(VFS) -> Return + Return the target object's supported content types. + + VFS = #objref + Return = + + +

This read only attribute represents the target object's supported + content types.

+
+
+ + login(VFS, User, Password, Account) -> Return + Create a new instance of a FileTransferSessionand a Directory + + VFS = #objref + User = Password = Account = string() + Return = {FileTransferSession, Directory} | {'EXCEPTION', E} + FileTransferSession = Directory = #objref + + +

This operation creates a new instance of a FileTransferSession + and a Directory. The later represents the current working + directory of the returned FileTransferSession.

+
+
+
+ +
+ diff --git a/lib/cosFileTransfer/doc/src/Makefile b/lib/cosFileTransfer/doc/src/Makefile new file mode 100644 index 0000000..7769d5e --- /dev/null +++ b/lib/cosFileTransfer/doc/src/Makefile @@ -0,0 +1,230 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(COSFILETRANSFER_VSN) +APPLICATION=cosFileTransfer +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + cosFileTransferApp.xml \ + CosFileTransfer_Directory.xml \ + CosFileTransfer_File.xml \ + CosFileTransfer_VirtualFileSystem.xml \ + CosFileTransfer_FileTransferSession.xml \ + CosFileTransfer_FileIterator.xml + +XML_PART_FILES = \ + part.xml \ + part_notes.xml +XML_CHAPTER_FILES = \ + ch_contents.xml \ + ch_introduction.xml \ + ch_install.xml \ + ch_system.xml \ + ch_example.xml \ + notes.xml + +BOOK_FILES = book.xml + +TECHNICAL_DESCR_FILES = + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif \ + CosFileTransfer.gif + +PS_FILES = + +# ---------------------------------------------------- + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + + +INFO_FILE = ../../info + +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf + +TOP_PS_FILE = $(APPLICATION)-$-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(INTERNAL_HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTML_FILES) $(MAN3_FILES) + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) + +endif + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +$(INDEX_TARGET): $(INDEX_SRC) + sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + +release_spec: + diff --git a/lib/cosFileTransfer/doc/src/book.gif b/lib/cosFileTransfer/doc/src/book.gif new file mode 100644 index 0000000000000000000000000000000000000000..94b38687920c5386f0d90df2cfc962d66f52fbce GIT binary patch literal 1081 zcmV-91jhSENk%v~VJrYQ0K@U3Z&d%1>*52OU z=jZ3|@9+2b_W%F@EC2ui04xAE000I5ARvxpX`Uh%Eez$Ma2!{|XMe{g?|T;9x5JA^ zG%bL@N^vRj5RkV9bLkO4ZPIBmas5oR#mf&V1Q#(0YhcjmXe*9~d=7a)?vMy(=-KE* z8yQRzT~`AL3l4P-3kL!Lf=d(yg_TGJLq#4K5D7Jwg%4&P850c&1Y@8d0)H_S5pFPj z7ZR$K4m$^o4iXXx39coCpaZff8wUU$784g63O)Mnh1d zM*Ony;LwB#3?8W4Fn~dfDxggNp6C!kf(B*{AQb3^!o#OZ2{2Ij__0FI3O->S0!o2G zg@f-96evKTsnY>a2Pj~$%K;+++!`!k(;yCksSK!^1M@%uPY44fe1t$i?MDI+c2ZbC za|F=4KrQICaN${m0^A%h5YV8o0a~3adU`fEQr`1qssBIw;^v!UF;k;yW-v@4+eo>JYd}fHVVU z5gLf*p9x%mVi^DlSTI8WPNw|_zy%J@^^O%t7;wu6|1F@62n+%+n+O+(7C~JYKp}tz zPXIAiOdhnDfD0a6fWQkLNGO6;!$2WQfj6jx)&W2YPymny2!Ox=N)36z-FBgSXr4c6dN%+LI-06;0gjrH4CDHEr=iiO;mnh?Fk3i5Wq1C#9AnbqG>3C zxFaCoE>b2iV1odev}UfA7}V< + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosFileTransfer + + + 2000-08-24 + 1.0 +
+ + + cosFileTransfer + + + + + + + + + + + + + + +
+ diff --git a/lib/cosFileTransfer/doc/src/ch_contents.xml b/lib/cosFileTransfer/doc/src/ch_contents.xml new file mode 100644 index 0000000..70094be --- /dev/null +++ b/lib/cosFileTransfer/doc/src/ch_contents.xml @@ -0,0 +1,74 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The cosFileTransfer Application + + + 2000-08-24 + 1.0 + ch_contents.xml +
+ +
+ Content Overview +

The cosFileTransfer documentation is divided into three sections: +

+ + +

PART ONE - The User's Guide +

+Description of the cosFileTransfer Application including + services and a small tutorial demonstrating + the development of a simple service.

+
+ +

PART TWO - Release Notes +

+A concise history of cosFileTransfer.

+
+ +

PART THREE - The Reference Manual +

+ A quick reference guide, including a + brief description, to all the functions available in cosFileTransfer.

+
+
+
+ +
+ Brief description of the User's Guide +

The User's Guide contains the following parts:

+ + +

cosFileTransfer overview

+
+ +

cosFileTransfer installation

+
+ +

A tutorial example

+
+
+
+
+ diff --git a/lib/cosFileTransfer/doc/src/ch_example.xml b/lib/cosFileTransfer/doc/src/ch_example.xml new file mode 100644 index 0000000..8d16371 --- /dev/null +++ b/lib/cosFileTransfer/doc/src/ch_example.xml @@ -0,0 +1,95 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosFileTransfer Examples + + + 2000-08-24 + A + ch_example.xml +
+ +
+ A tutorial on how to create a simple service + +
+ Initiate the application +

To use the complete cosFileTransfer application cosProperty + must be installed.

+
+ +
+ How to run everything +

Below is a short transcript on how to run cosFileTransfer.

+ + +%% Start Mnesia and Orber +mnesia:delete_schema([node()]), +mnesia:create_schema([node()]), +orber:install([node()]), +mnesia:start(), +orber:start(), + +%% The File Transfer Service depends on the cosProperty +%% application. Hence, we must install cosProperty first. +%% It's NOT necessary to invoke cosProperty:install_db(). +cosProperty:install(), + +%% Install File Transfer Service in the IFR. +cosFileTransfer:install(), + +%% Now start the application and necessary services. +cosFileTransfer:start(), + +%% Create two Virtual File Systems respectively representing an FTP- +%% and the local NFS file system. +VFSFTP = cosFileTransferApp:create_VFS('FTP', [], FTPHost, 21), +VFSNATIVE = cosFileTransferApp: + create_VFS({'NATIVE', 'cosFileTransferNATIVE_file'}, + [], MyLocalHost, 0), + +%% Login to each system. +{FSFTP, DirFTP} = 'CosFileTransfer_VirtualFileSystem': + login(VFSFTP, "myId", "myPwd", "myAccount"), +{FSNATIVE, DirNATIVE} = 'CosFileTransfer_VirtualFileSystem': + login(VFSNATIVE, "myId", "myPwd", "myAccount"), + +%% If we want to copy a file from the NFS to the FTP we must first +%% create a File object which contains its attributes. +Target = 'CosFileTransfer_FileTransferSession':create_file(FSFTP, + ["/", "ftp", "incoming", "targetFile"])), + + #'CosFileTransfer_FileWrapper'{the_file = Dir} = +%% Lookup the file we want to copy. +FileWrapper = 'CosFileTransfer_FileTransferSession':get_file(FSNATIVE, + ["/", "home", "myId", "sourceFile"]), +Source = FileWrapper#'CosFileTransfer_FileWrapper'.the_file, + +%% Now we are ready to transfer the file. Please note that we most +%% call the source Session object. +'CosFileTransfer_FileTransferSession':transfer(FSNATIVE, Source, Target), + +
+
+
+ diff --git a/lib/cosFileTransfer/doc/src/ch_install.xml b/lib/cosFileTransfer/doc/src/ch_install.xml new file mode 100644 index 0000000..068dceb --- /dev/null +++ b/lib/cosFileTransfer/doc/src/ch_install.xml @@ -0,0 +1,57 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Installing cosFileTransfer + + + 2000-08-24 + + ch_install.xml +
+ +
+ Installation Process +

This chapter describes how to install + cosFileTransferApp in an Erlang Environment. +

+ +
+ Preparation +

Before starting the installation process for cosFileTransfer, + the application Orber must be running and cosProperty installed by + using cosProperty:install(). Please note that it is NOT necessary + to use cosProperty:install_db() for running the cosFileTransfer application.

+
+ +
+ Configuration +

When starting the cosFileTransfer application the following configuration parameters + can be used:

+ + buffert_size - default is 64000. This option determine + how many bytes will be read at a time when transferring files. + +
+
+
+ diff --git a/lib/cosFileTransfer/doc/src/ch_introduction.xml b/lib/cosFileTransfer/doc/src/ch_introduction.xml new file mode 100644 index 0000000..d81269a --- /dev/null +++ b/lib/cosFileTransfer/doc/src/ch_introduction.xml @@ -0,0 +1,56 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Introduction to cosFileTransfer + + + 2000-08-24 + + ch_introduction.xml +
+ +
+ Overview +

The cosFileTransfer application is a FileTransfer Service compliant with the + OMG Service CosFileTransfer. +

+ +
+ Purpose and Dependencies +

If a Virtual File System is started as 'FTP', the inets-2.5.4 application, + or later, must be installed.

+

cosFileTransfer is dependent on Orber, which provides CORBA functionality in an Erlang environment, + and cosProperty.

+
+ +
+ Prerequisites +

To fully understand the concepts presented in the + documentation, it is recommended that the user is familiar + with distributed programming, CORBA, the Orber and cosProperty applications. +

+

Recommended reading includes CORBA, Fundamentals and Programming - Jon Siegel and Open Telecom Platform Documentation Set. It is also helpful to have read Concurrent Programming in Erlang.

+
+
+
+ diff --git a/lib/cosFileTransfer/doc/src/ch_system.xml b/lib/cosFileTransfer/doc/src/ch_system.xml new file mode 100644 index 0000000..51a8ac8 --- /dev/null +++ b/lib/cosFileTransfer/doc/src/ch_system.xml @@ -0,0 +1,137 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Using the File Transfer Service + + + 2001-08-07 + + ch_system.xml +
+ +
+ Overview +

This chapter describes how two File Transfer Service applications interact.

+ +
+ Components +

There are several ways the OMG File Transfer Service can be used. + Below one scenario is visualized:

+ + + Figure 1: The File Transfer Service Components. + + + Source ORB: this is the ORB we want to transfer a file from/via and it holds + an object reference to a + Virtual File System (VFS) which, + in this example, represents an FTP server. + Target ORB: the goal may be, for example, to transfer a new file or append to an + existing file placed at the location that this ORB's VFS represents. + In this scenario it is the local disk or the NFS. + Transport Protocol: initially the ORB's, i.e., target and source, communicate via + normal CORBA requests to determine whether or not they can communicate. If the + File Transfer Service's have one, or more, Transport Protocol in common the data + will be streamed using this protocol. The cosFileTransfer application currently supports + TCP/IP and SSL. + +

Which type of file system the VFS is supposed to represent is determined + by the options given when creating it, which is also how one determine which + Transport Protocol to use. Hence, the source and target VFS described above + can be started by invoking, respectively, the following operations:

+ +1> SVFS = cosFileTransferApp:create_VFS('FTP', [], Host, 21, [{protocol, tcp}]), +2> TVFS = cosFileTransferApp:create_VFS({'NATIVE', 'cosFileTransferNATIVE_file'}, + [], OtherHost, 0, [{protocol, tcp}]), + +

Naturally can any combination of VFS-types be used and it is also possible + to use own drivers, i.e., {'NATIVE', 'MyDriver'}.

+

After creating necessary VFS's we can login in and perform operations + on files and directories residing on each file system.

+
+ +
+ How To Use SSL +

To be able to use SSL as transport protocol a few configuration + parameters must be set. The required parameters depend on if Orber is + the target or/and the source ORB. However, the SSL_CERT_FILE variable + must be defined in both cases.

+

Setting of a CA certificate file with an option does not work due to + weaknesses in the SSLeay package. A work-around in the ssl application is + to set the OS environment variable SSL_CERT_FILE before SSL is started. + However, then the CA certificate file will be global for all connections + (both incoming and outgoing calls).

+ +
+ Configurations when cosFileTransfer is Used as Target +

The following three configuration variables can be used to configure + cosFileTransfer's SSL target behavior.

+ + ssl_server_certfile which is a path to a file containing a + chain of PEM encoded certificates for cosFileTransfer as target. + ssl_server_verify which specifies type of verification: + 0 = do not verify peer; 1 = verify peer, verify client once, 2 = + verify peer, verify client once, fail if no peer certificate. + The default value is 0. + ssl_server_depth which specifies verification depth, i.e. + how far in a chain of certificates the verification process shall + proceed before the verification is considered successful. The + default value is 1. + +

There also exist a number of API functions for accessing the values of + these variables:

+ + cosFileTransferApp:ssl_server_certfile/0 + cosFileTransferApp:ssl_server_verify/0 + cosFileTransferApp:ssl_server_depth/0 + +
+ +
+ Configurations when cosFileTransfer is used as Source +

Below is the list of configuration variables used when cosFileTransfer + act as the source application.

+ + ssl_client_certfile which is a path to a file containing a + chain of PEM encoded certificates used in outgoing calls. + ssl_client_verify which specifies type of verification: + 0 = do not verify peer; 1 = verify peer, verify client once, 2 = + verify peer, verify client once, fail if no peer certificate. + The default value is 0. + ssl_client_depth which specifies verification depth, i.e. + how far in a chain of certificates the verification process shall + proceed before the verification is considered successful. The + default value is 1. + +

There also exist a number of API functions for accessing the values of + these variables in the client processes:

+ + cosFileTransferApp:ssl_client_certfile/0 + cosFileTransferApp:ssl_client_verify/0 + cosFileTransferApp:ssl_client_depth/0 + +
+
+
+
+ diff --git a/lib/cosFileTransfer/doc/src/cosFileTransferApp.xml b/lib/cosFileTransfer/doc/src/cosFileTransferApp.xml new file mode 100644 index 0000000..e27bffd --- /dev/null +++ b/lib/cosFileTransfer/doc/src/cosFileTransferApp.xml @@ -0,0 +1,172 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosFileTransferApp + + + + 2000-08-24 + PA1 +
+ cosFileTransferApp + The main module of the cosFileTransfer application. + +

To get access to the record definitions for the structures use:

+-include_lib("cosFileTransfer/include/*.hrl").

+

This module contains the functions for starting and stopping the application.

+
+ + + install() -> Return + Install the cosFileTransfer application + + Return = ok | {'EXIT', Reason} + + +

This operation installs the cosFileTransfer application. Note, the + cosProperty application must be installed prior to invoking this + operation.

+
+
+ + uninstall() -> Return + Uninstall the cosFileTransfer application + + Return = ok | {'EXIT', Reason} + + +

This operation uninstalls the cosFileTransfer application.

+
+
+ + start() -> Return + Start the cosFileTransfer application + + Return = ok | {error, Reason} + + +

This operation starts the cosFileTransfer application.

+
+
+ + stop() -> Return + Stop the cosFileTransfer application + + Return = ok | {error, Reason} + + +

This operation stops the cosFileTransfer application.

+
+
+ + create_VFS(Type, Content, Host, Port [,Options]) -> Return + Create a new instance of a Virtual File System + + Type = 'FTP' | {'NATIVE', 'cosFileTransferNATIVE_file'} | {'NATIVE', MyModule} + Content = [] + Host = string(), e.g. "myHost@myServer" or "012.345.678.910" + Port = integer() + Options = [Option] + Option = {protocol, Protocol} | {connect_timeout, Seconds} + Protocol = tcp | ssl + Return = VFS | {'EXCEPTION, E} + VFS = #objref + + +

This operation creates a new instance of a Virtual File System. The + Type parameter determines which type we want the VFS to represent. + 'FTP' maps to the INETS ftp implementation, while + {'NATIVE', 'cosFileTransferNATIVE_file'} uses the file module. + It is also possible to implement own mappings which are activated by + supplying {'NATIVE', MyModule}. The MyModule module must export the same + functions and behave in the same way as the INETS ftp module, and + an operation named open(Host, Port), which shall return + {ok, Pid} or {error, Reason}.

+

If no Options are supplied the default setting will be + used, i.e., tcp and 60 seconds.

+

The Content parameter is currently ignored by must be supplied + as an empty list.

+
+
+ + ssl_server_certfile() -> string() + Display the path to the target certificate + +

This function returns a path to a file containing a chain of PEM encoded + certificates for the cosFileTransfer as target. + This is configured by setting the application variable + ssl_server_certfile.

+
+
+ + ssl_client_certfile() -> string() + Display the path to the client certificate + +

This function returns a path to a file containing a chain of PEM encoded + certificates used in outgoing calls. + The default value is configured by setting the application variable + ssl_client_certfile.

+
+
+ + ssl_server_verify() -> 0 | 1 | 2 + Display the SSL verification type for incoming calls + +

This function returns the type of verification used by SSL during authentication of the other + peer for incoming calls. + It is configured by setting the application variable + ssl_server_verify.

+
+
+ + ssl_client_verify() -> 0 | 1 | 2 + Display the SSL verification type for outgoing calls + +

This function returns the type of verification used by SSL during authentication of the other + peer for outgoing calls. + The default value is configured by setting the application variable + ssl_client_verify.

+
+
+ + ssl_server_depth() -> int() + Display the SSL verification depth for incoming calls + +

This function returns the SSL verification depth for incoming calls. + It is configured by setting the application variable + ssl_server_depth.

+
+
+ + ssl_client_depth() -> int() + Display the SSL verification depth for outgoing calls + +

This function returns the SSL verification depth for outgoing calls. + The default value is configured by setting the application variable + ssl_client_depth.

+
+
+
+ +
+ diff --git a/lib/cosFileTransfer/doc/src/fascicules.xml b/lib/cosFileTransfer/doc/src/fascicules.xml new file mode 100644 index 0000000..0678195 --- /dev/null +++ b/lib/cosFileTransfer/doc/src/fascicules.xml @@ -0,0 +1,18 @@ + + + + + + User's Guide + + + Reference Manual + + + Release Notes + + + Off-Print + + + diff --git a/lib/cosFileTransfer/doc/src/make.dep b/lib/cosFileTransfer/doc/src/make.dep new file mode 100644 index 0000000..3be0c18 --- /dev/null +++ b/lib/cosFileTransfer/doc/src/make.dep @@ -0,0 +1,30 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: CosFileTransfer_Directory.tex CosFileTransfer_File.tex \ + CosFileTransfer_FileIterator.tex CosFileTransfer_FileTransferSession.tex \ + CosFileTransfer_VirtualFileSystem.tex book.tex \ + ch_contents.tex ch_example.tex ch_install.tex \ + ch_introduction.tex ch_system.tex cosFileTransferApp.tex \ + part.tex ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: CosFileTransfer.ps + diff --git a/lib/cosFileTransfer/doc/src/notes.gif b/lib/cosFileTransfer/doc/src/notes.gif new file mode 100644 index 0000000000000000000000000000000000000000..e000cca26a383722eca87f4d87a5841292b0b8ea GIT binary patch literal 2005 zcmc(e`(I0c1HeD$>})&L($>wE%9*B;E}M!dPv>-9341YwWX&zf>scU1zfBrl=I{N9;r;i^$ ze)#ZVWMt(1`}gnOy?gui?eOsMn>TM>zkWS5H1z7#tHHs+fq?;|(fIP^%NH+RJb(WD z*|TR)pFVx^ogEz=?d|P)y}qrjt+lnarKLru(`mKZ=H_ONMx$1%@7%d_`}XZyw{G3MdGp4N z8%<43jg5^B4Gq_?U%z(k+SRL9>+9>UT)9$LS65qGTT@eW`SRsUmo8nrc=5u83+KckWzORn^(EXDcf!&zw1P`t<2jr%qK=RFs#Ot5m9!Cr_R@apL&#<7H)K$BrF4 zdi1DLsXTJzNNH(lNl8g@aq;29hl`4e3JVJr3dNyAhYlV*SWr-qpP!$XmzSHHo0F3x zm&-FUGSbu2Wir|R{rmUr+qZY`-n6u|)YR0Jl$1St_9Q1K@7}$8*REYVckbM=V@Fa_ zl0+iezI}UQV&b-K+Y%BIwr<_JdGqE?n>KCSxN*aV4Pvo4E-p?a60KjqJ~lRX-MV!# zF)?e`u3fWc&Fa;wSFKvLa^=buD^>`F!ez^r2?T=0ix)>lMMXwNMnpvL`TX$k@UXD3 zkdTnz;NYO3Ac7zQ0|OT>TD_t~>&yScf|nl;PS)z!tt#o5`J!{InNIkDMn48x{RpYG`B=-}XBZ*Mm zJ0_E9VPQd|(M(NEQ52<8sT2wYK@bv&1j8@{LE!(5`#%Ezya3Qi0HOB$8kHskwQ`Hm z*OY4y(48X7__Y-+c}(wwXZqSxZHKVn+_d2V9bX<;)o5v8$jlB{tz6vnwfvQAiMw6t z0IXVSedvhT17nJCGJ_XCYT%)5*?chw5R9s25QXlX!e_sd7hr)!eyKroJ4zhgi|iRe z9BRcDRXkmj&PH5Z1EswZP1Yik}bX?KQfDMotrhur?Z`l6 z9SHWUks6^bPWsX|jEswdY)vps%VI@IAvY7W9?a_N?~xI!M!5pm(Ry5JJ;$6wSb!Kw z1Ofz-ES$>6ni1O}ScWTvR$Wsm*pF-~}^QqIoOkG6>BJ?$;+XE5N4m%cOVTgl$q1H6Cj2CRZ#Cwk*Z+A1}6-ZGIOnZ zriKR6JwuHEr#89IP&lU0d>}f|iQ2(xTebl}Km=JKc>w~{On}kI=M0e4E*aE>B!t(` zz!7B(z}xLdevm2fNGl*)VFk@hhEN1isQ4%eVdfhlo64C^B-c26^Z?T#Tc$&!YL-EE zsr_sc%})?_z}$saj#x(bLnO=CUH5f1>6}R!!dMZ|W9GTgpb9n@*5fiBqnDrne~DCT zx&%mdn3ma=CO4$ZCjP+)Zks2RB*+Tt`QEtb2g6+n+RKF1oJqVMUCo0mdGDTz#3Q^?T4648gGi%gvvJ#j{AlN2b z`m?E;VM>mcPQBC_Y6=8kn9B=CL=o-QgXt_x2k`|YJusL&`b=Pj%+?u4tr>8h24sDX + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosFileTransfer Release Notes + + + + 2000-08-24 + A + notes.xml +
+ +
+ cosFileTransfer 1.1.9 + +
+ Improvements and New Features + + +

+ The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.

+

+ Own Id: OTP-8201 Aux Id:

+
+
+
+
+ +
+ cosFileTransfer 1.1.8 + +
+ Improvements and New Features + + +

Obsolete guards, e.g. record vs is_record, has been changed + to avoid compiler warnings.

+

Own id: OTP-7987

+
+
+
+
+ +
+ cosFileTransfer 1.1.7 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7837

+
+
+
+
+ +
+ cosFileTransfer 1.1.6 + +
+ Improvements and New Features + + +

Documentation source included in open source releases.

+

Own id: OTP-7595

+
+
+
+
+ Fixed Bugs and Malfunctions + + +

When using predefined native file copy the return values from + file operation was not handled correctly.

+

Own id: OTP-7599

+
+
+
+
+ +
+ cosFileTransfer 1.1.5 + +
+ Improvements and New Features + + +

CosFileTransfer now uses the changed Inets API.

+

Own id: OTP-7020

+
+
+
+
+ +
+ cosFileTransfer 1.1.4 + +
+ Improvements and New Features + + +

The documentation source has been converted from SGML to XML.

+

Own id: OTP-6754

+
+
+
+
+ +
+ cosFileTransfer 1.1.3 + +
+ Improvements and New Features + + +

Minor Makefile changes.

+

Own id: OTP-6701

+
+
+
+
+ +
+ cosFileTransfer 1.1.2 + +
+ Improvements and New Features + + +

Due to changed behavior of the ftp client a few changes + has been made.

+

Own id: OTP-5135

+
+
+
+
+ +
+ cosFileTransfer 1.1.1 + +
+ Fixed Bugs and Malfunctions + + +

Depending on which ftp server is used, the operation + CosFileTransfer::Directory::list could fail.

+

Own id: OTP-4954

+
+
+
+
+ +
+ cosFileTransfer 1.1 + +
+ Improvements and New Features + + +

The stub/skeleton-files generated by IC have been improved, + i.e., depending on the IDL-files, reduced the size of the + erl- and beam-files and decreased dependencies off Orber's + Interface Repository. It is necessary to re-compile all IDL-files + and use COS-applications, including Orber, compiled with + IC-4.2.

+

Own id: OTP-4576

+
+
+
+
+ +
+ cosFileTransfer 1.0.2 + +
+ Improvements and New Features + + +

First release of the cosFileTransfer application. Please note that + the OMG specification was not finalized when this version + was released. Hence, the API may be changed in way which is not + compatible with this version. Contact support if you are in doubt.

+

Own Id: -

+
+
+
+
+
+ diff --git a/lib/cosFileTransfer/doc/src/part.xml b/lib/cosFileTransfer/doc/src/part.xml new file mode 100644 index 0000000..78e4063 --- /dev/null +++ b/lib/cosFileTransfer/doc/src/part.xml @@ -0,0 +1,40 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosFileTransfer User's Guide + + + 2000-08-24 + 1.0 +
+ +

The cosFileTransfer Application is an Erlang implementation of the OMG + CORBA FileTransfer Service.

+
+ + + + + +
+ diff --git a/lib/cosFileTransfer/doc/src/part_notes.xml b/lib/cosFileTransfer/doc/src/part_notes.xml new file mode 100644 index 0000000..f3819bd --- /dev/null +++ b/lib/cosFileTransfer/doc/src/part_notes.xml @@ -0,0 +1,36 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosFileTransfer Release Notes + + + 2000-08-24 + 1.0 +
+ +

The cosFileTransfer Application is an Erlang implementation of the OMG + CORBA FileTransfer Service.

+
+ +
+ diff --git a/lib/cosFileTransfer/doc/src/ref_man.gif b/lib/cosFileTransfer/doc/src/ref_man.gif new file mode 100644 index 0000000000000000000000000000000000000000..b13c4efd53ff30209e94a832b9b141aefa01373e GIT binary patch literal 1530 zcmdVZdppw$0KoB|UD(ZKjLpudxl|bD5*~BdW(#wPxjQR!4XwvDQJz|2?rd%yODG+} zTS?d`8$ziw@9efjcbb8~ZJV`F`NeQj-Rb#--RW#!YS zPs_{8OG`^1KYmEb&dp9*T_4@VeSFc{Z zeEIUlix(;Hhy1Lrh+M1f0n>TM(S67S0;;O2u%F4=$ii+~`^0Klrkw{chQc_%8TvSw4P*9Mc zpP!ePmz$fLlanJ52(q)YuU)&AnVEUz%9YEPFK1+AT)K4W;>C;U>FH@{X%{YBNKH*W zfBt+*N=kBaa#B)KVq#)KLPC6e{JC@Ics$E-3+>FMd= z;o5R+g5Q78Vv{ zGTGeR+|10()YOzjBAJ+&7#kZK85t3YL|t879UUD4fq=*3wY9ZzI2;y>)zZ?^)YQaa zFd7;fYHDh#s;Vj~D$2^rC=?2bL?RFfI2;ax!IYGg6crVrP$&cf0fWIH5J*8m0r;Os z`p^I03jpi@P=FC!+v{kk6S6LO_!Iu)95sCwBtcqW%*9y*G+T7kk6cw&i6X!~u9ub^ z(;p_fv9U$vWTl#^q0-1BITpV6n#M{a{we|K$qn8tF1dhi2#U)iChGwf%c>!EMdamI z$h@1HHE$AU0uQ06DJaKq=RDnzU^TZiOigaDbX?9sbbG2Mo zru2uhl#`IQgUVf0v!Xj-d%-$1xRm>;TQmHNwcAfcM=qjwu=nh zQh;0;RMT@!2!f)5xXw7CWD^X8atslf08f~GlvPC&!u3CIvJ6wy=4qhoBAlk74dDIc za5tv{OoL_(_?n6N^K=DFVPbx|J4#5`n`9n$heG9OfAim6K_sx=yuqZzUrzW~%(8B5(t!Xl{Hb0?L6-vF=+wDe8$ zTT`s`Dq0fpfEZM3+{q@m}*YWuf-$-b$k$LLWEZK;Ee|dK!!GAvHA;V z*1da#TyGWrnurc+>Z42^g}P$+dV8CLlZ-G3$5&lvmrHi*;me*Y^_v!=AL*c_d4sqi z`SWVr{)P|6KptK|>YQR5CUyjEppnvPJ-9YQBBMdn(+)quWG#%To7OvoyB^9=`#bkY st1M+qtZTt#!ZD6_9%~hW^bvUb7(Sl{bx5FV=!1r@;+Z6>KNX<-3tg&0LjV8( literal 0 HcmV?d00001 diff --git a/lib/cosFileTransfer/doc/src/ref_man.xml b/lib/cosFileTransfer/doc/src/ref_man.xml new file mode 100644 index 0000000..088ec49 --- /dev/null +++ b/lib/cosFileTransfer/doc/src/ref_man.xml @@ -0,0 +1,41 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosFileTransfer Reference Manual + + + 2000-08-24 + 1.0 +
+ +

The cosFileTransfer Application is an Erlang implementation of the OMG + CORBA File Transfer Service.

+
+ > + > + > + > + > + > +
+ diff --git a/lib/cosFileTransfer/doc/src/summary.html.src b/lib/cosFileTransfer/doc/src/summary.html.src new file mode 100644 index 0000000..4c66e14 --- /dev/null +++ b/lib/cosFileTransfer/doc/src/summary.html.src @@ -0,0 +1 @@ +Orber OMG File Transfer Service. diff --git a/lib/cosFileTransfer/doc/src/user_guide.gif b/lib/cosFileTransfer/doc/src/user_guide.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6275a803db46bc56df2b31240f80e68a4eb28b5 GIT binary patch literal 1581 zcmd6mi9gc|0Kk8njctY*W^QwCJ{HX#%4V)-y(i>aMOY|Iy@!%dZA6YGb49u7IpPyu zxpLn_avvd{2!$L^&hlRW#rysR-_Q5+`C8dn8X8V>k`j;wKQ1gR%+Jry&CSiu&d$utOixe0fB$}JYHD(Fa$;g)e0+Rt zY;1INbYx^?czAedXlQV7@ZGz20|Nv7{r!D?eZ9TCJRYy7r>DESyQ{0Kv$M0KqocjO zy{)aSwY9aSrKP#Kxv8nCv9YnCq2bM&H}&=Pb#-;MwY4=hHPzMCuV25es;a82tgNW0 zc=_^WSy|bO7cWXnOG`>hii?Yjii!#g3kwPg^7Hfa^73+Xb8~WXva_?Zva&KWGoL+s z_Vnq~jEs!*^z{(M&Qxg*t zV`JkpXU-TI85tTH>g((4>FMd}>gwp|kVqtLZEYmX?x|!eX(Kl9CtEE3!%>OGRc>9)Rn&SYM zj~Y~*8(l`PO4G;6R;FqaD@X#~VMifcR)pt=DvF{Q3(>@Ud>(7)(V4{v)PmxVK~kPo zjj~AEyr<1v8vx#~Tk98U5_J`0L}~fU>RjhaAKM=MUf{g5m?T z)+IHOf7l%`QALwKCeyDj6SLD45WBagBU?Fw4{df%%9E4Y2u)Wk*W$nyCUXV^5gf*w zJcTmdm_5ACzSYODr)n2;x_FnPc`B(M`LXIbz9g71J`3n))Gq$bQK+sRivkPkZkj>F zXejb80{#?f()6mQl&jOcTB0m7HQ)B0eJ!3!3LG1z5Dy4!8UDX&qmZHiEZH4hCN$qe z4*)g+{|y}64a+3k1Ar7VS%DkXnyczs>8pr>ch^qPgriJZarAD;X*)P0t_Uea!m)bj zekgBBW+6d2l7{g|`zZIq7r_Y&symb`GN>UKUQ)c!TxUa0r_Gumy9Jeti%E)uL##a# zMGizq*jB%VA7Ip@(A3hq9YH69qL7NjkWRA2q5;hU`xYmEN)bB>aqrz!?T?Ynv*X-7 zk5PfTmt$8kTF6UOKy_o?XHYzxtkg%ZbG*StHxDNDsyD5c2a>x5vWvVCApVgu@XNF$})`XD-pCH3`9zE-Lj6@!*TS9lwVaP}h|-H2`m~ItYQE$0z|a zt4=D`BBR~(5MZ;L{+LQk#4$5Kz`eloKZBK-7eFm?OlZCy;GH~%L;($J;|e#tww(~b et1Zl|+ha7@T8X2%4FJEoWS?mjDfbqXtih~yb literal 0 HcmV?d00001 diff --git a/lib/cosFileTransfer/ebin/.gitignore b/lib/cosFileTransfer/ebin/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosFileTransfer/examples/.gitignore b/lib/cosFileTransfer/examples/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosFileTransfer/include/.gitignore b/lib/cosFileTransfer/include/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosFileTransfer/info b/lib/cosFileTransfer/info new file mode 100644 index 0000000..e5ca860 --- /dev/null +++ b/lib/cosFileTransfer/info @@ -0,0 +1,3 @@ +group: orb +short: Orber OMG File Transfer Service + diff --git a/lib/cosFileTransfer/priv/.gitignore b/lib/cosFileTransfer/priv/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosFileTransfer/src/CosFileTransfer.cfg b/lib/cosFileTransfer/src/CosFileTransfer.cfg new file mode 100644 index 0000000..a98f102 --- /dev/null +++ b/lib/cosFileTransfer/src/CosFileTransfer.cfg @@ -0,0 +1,10 @@ +{this, "CosFileTransfer::Directory"}. +{{handle_info, "CosFileTransfer::Directory"}, true}. +{this, "CosFileTransfer::File"}. +{{handle_info, "CosFileTransfer::File"}, true}. +{this, "CosFileTransfer::VirtualFileSystem"}. +{{handle_info, "CosFileTransfer::VirtualFileSystem"}, true}. +{this, "CosFileTransfer::FileTransferSession"}. +{{handle_info, "CosFileTransfer::FileTransferSession"}, true}. +{this, "CosFileTransfer::FileIterator"}. +{{handle_info, "CosFileTransfer::FileIterator"}, true}. diff --git a/lib/cosFileTransfer/src/CosFileTransfer.idl b/lib/cosFileTransfer/src/CosFileTransfer.idl new file mode 100644 index 0000000..2eb3104 --- /dev/null +++ b/lib/cosFileTransfer/src/CosFileTransfer.idl @@ -0,0 +1,157 @@ +//File: CosFileTransfer.idl +#ifndef _COS_FILE_TRANSFER_IDL_ +#define _COS_FILE_TRANSFER_IDL_ + +#include +#pragma prefix "omg.org" + +module CosFileTransfer { + + typedef string Istring; + typedef Istring ProtocolAddress; + typedef long ContentType; + + const ContentType FTAM_1 = 1; + const ContentType FTAM_2 = 2; + const ContentType FTAM_3 = 3; + const ContentType FTAM_4 = 4; + const ContentType FTAM_5 = 5; + const ContentType NBS_9 = 6; + const ContentType INTAP_1 = 7; + + exception CommandNotImplementedException { Istring reason; }; + exception SessionException { Istring reason; }; + exception TransferException { Istring reason; }; + exception FileNotFoundException { Istring reason; }; + exception RequestFailureException { Istring reason; }; + exception IllegalOperationException { Istring reason; }; + + interface VirtualFileSystem; + + struct AccessLevel { + boolean read; + boolean insert; + boolean replace; + boolean extend; + boolean erase; + boolean read_attr; + boolean change_attr; + boolean delete; + }; + + typedef sequence ProtocolAddressList; + + struct ProtocolSupport { + Istring protocol_name; + ProtocolAddressList addresses; + }; + + typedef sequence SupportedProtocolAddresses; + + interface Directory; + interface FileTransferSession; + + typedef Istring FileName; + typedef sequence FileNameList; + + interface File:CosPropertyService::PropertySetDef { + + readonly attribute FileName name; + readonly attribute FileNameList complete_file_name; + readonly attribute Directory parent; + readonly attribute FileTransferSession associated_session; + + }; + + enum FileType {nfile, ndirectory}; + + struct FileWrapper { + File the_file; + FileType file_type; + }; + + typedef sequence FileList; + + interface FileIterator; + interface Directory : File { + + void list(in unsigned long how_many, out FileList fl, out FileIterator fi); + + }; + + interface FileIterator { + + boolean next_one(out FileWrapper f); + boolean next_n(in unsigned long how_many, out FileList fl); + + void destroy(); + }; + + interface FileTransferSession { + + readonly attribute SupportedProtocolAddresses protocols_supported; + + void set_directory(in Directory new_directory) + raises(SessionException, FileNotFoundException, RequestFailureException, + IllegalOperationException); + + File create_file(in FileNameList name) + raises(SessionException, FileNotFoundException, RequestFailureException, + IllegalOperationException); + + Directory create_directory(in FileNameList name) + raises(SessionException, FileNotFoundException, RequestFailureException, + IllegalOperationException); + + FileWrapper get_file(in FileNameList complete_file_name) + raises(SessionException, FileNotFoundException, RequestFailureException, + IllegalOperationException); + + void delete(in File file) + raises(SessionException, FileNotFoundException, RequestFailureException, + IllegalOperationException); + + void transfer(in File src, in File dest) + raises(SessionException, TransferException, FileNotFoundException, + RequestFailureException, IllegalOperationException); + + void append(in File src, in File dest) + raises(CommandNotImplementedException, SessionException, TransferException, + FileNotFoundException, RequestFailureException, + IllegalOperationException); + + void insert(in File src, in File dest, in long offset) + raises(CommandNotImplementedException, SessionException, TransferException, + FileNotFoundException, RequestFailureException, + IllegalOperationException); + + void logout(); + + // WARNING!!! + // Theses are Orber specific operations and may only be used internally!! + // Maybe removed, altered and changed in any way without warning!! + Directory oe_orber_create_directory_current() + raises(SessionException, FileNotFoundException, IllegalOperationException); + FileList oe_orber_get_content(in FileNameList complete_file_name, + in Directory parent); + long oe_orber_count_children(in FileNameList complete_file_name); + + }; + + interface VirtualFileSystem { + + enum NativeFileSystemType { FTAM, FTP, NATIVE }; + + readonly attribute NativeFileSystemType file_system_type; + + typedef sequence ContentList; + + readonly attribute ContentList supported_content_types; + + FileTransferSession login(in Istring username, in Istring password, + in Istring account, out Directory root) + raises(SessionException, FileNotFoundException, IllegalOperationException); + }; +}; + +#endif //_COS_FILE_TRANSFER_IDL_ diff --git a/lib/cosFileTransfer/src/CosFileTransfer_Directory_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_Directory_impl.erl new file mode 100644 index 0000000..cecc42e --- /dev/null +++ b/lib/cosFileTransfer/src/CosFileTransfer_Directory_impl.erl @@ -0,0 +1,452 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosFileTransfer_Directory_impl +%% Description : +%% +%% Created : 12 Sept 2000 +%%---------------------------------------------------------------------- +-module('CosFileTransfer_Directory_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). + +-include_lib("cosProperty/include/CosPropertyService.hrl"). + +-include("cosFileTransferApp.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2]). + +%% Interface functions +-export([list/3]). + +%% Inherited CosFileTransfer::File +-export(['_get_name'/2, + '_get_complete_file_name'/2, + '_get_parent'/2, + '_get_associated_session'/2]). + +%% Inherited CosPropertyService::PropertySetDef +-export([get_allowed_property_types/2, + get_allowed_properties/2, + define_property_with_mode/5, + define_properties_with_modes/3, + get_property_mode/3, + get_property_modes/3, + set_property_mode/4, + set_property_modes/3]). + +%% Inherited CosPropertyService::PropertySet +-export([define_property/4, + define_properties/3, + get_number_of_properties/2, + get_all_property_names/3, + get_property_value/3, + get_properties/3, + get_all_properties/3, + delete_property/3, + delete_properties/3, + delete_all_properties/2, + is_property_defined/3]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {property, + name, + completeName, + parent, + assocSession}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +-define(create_InitState(Pr, N, C, Pa, A), + #state{property = Pr, + name = N, + completeName = C, + parent = Pa, + assocSession = A}). + +-define(get_PropertyRef(S), S#state.property). +-define(get_Name(S), S#state.name). +-define(get_CompleteName(S), S#state.completeName). +-define(get_Parent(S), S#state.parent). +-define(get_AssocSession(S), S#state.assocSession). + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([Name, CompleteName, Parent, AssocSession]) -> + PropTypes = [tk_long, tk_boolean], + %% WARNING if the order of the properties is changed so must + %% get_all_properties/3 in this module be as well! + PropDefs = [#'CosPropertyService_PropertyDef' + {property_name = "num_children", + property_value = #any{typecode=tk_long, value=0}, + property_mode = fixed_readonly}, + #'CosPropertyService_PropertyDef' + {property_name = "is_directory", + property_value = #any{typecode=tk_boolean, value=true}, + property_mode = fixed_readonly}], + Prop = cosProperty:create_static_SetDef(PropTypes, PropDefs), + {ok, ?create_InitState(Prop, Name, CompleteName, Parent, AssocSession)}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%====================================================================== +%% CosFileTransfer::Directory +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : list +%% Arguments : Max - ulong() +%% Returns : {ok, FileList, FileIterator} +%% Description: +%%---------------------------------------------------------------------- +list(OE_This, State, Max) -> + case 'CosFileTransfer_FileTransferSession': + oe_orber_get_content(?get_AssocSession(State), ?get_CompleteName(State), + OE_This) of + [] -> + {reply, {ok, [], corba:create_nil_objref()}, State}; + FileList when length(FileList) > Max -> + {reply, + {ok, lists:sublist(FileList, Max), + 'CosFileTransfer_FileIterator':oe_create([lists:nthtail(Max, + FileList)])}, + State}; + FileList -> + {reply, {ok, FileList, corba:create_nil_objref()}, State} + end. + +%%====================================================================== +%% CosFileTransfer::File +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : '_get_name' +%% Arguments : - +%% Returns : CosFileTransfer::FileName - string +%% Description: +%%---------------------------------------------------------------------- +'_get_name'(_OE_This, State) -> + {reply, ?get_Name(State), State}. + +%%---------------------------------------------------------------------% +%% Function : '_get_complete_file_name' +%% Arguments : - +%% Returns : CosFileTransfer::FileNameList - a list of strings's +%% Description: +%%---------------------------------------------------------------------- +'_get_complete_file_name'(_OE_This, State) -> + {reply, ?get_CompleteName(State), State}. + +%%---------------------------------------------------------------------% +%% Function : '_get_parent' +%% Arguments : - +%% Returns : CosFileTransfer::Directory +%% Description: +%%---------------------------------------------------------------------- +'_get_parent'(_OE_This, State) -> + {reply, ?get_Parent(State), State}. + +%%---------------------------------------------------------------------% +%% Function : '_get_associated_session' +%% Arguments : - +%% Returns : CosFileTransfer::FileTransferSession +%% Description: +%%---------------------------------------------------------------------- +'_get_associated_session'(_OE_This, State) -> + {reply, ?get_AssocSession(State), State}. + +%%====================================================================== +%% CosPropertyService::PropertySetDef +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : get_allowed_property_types +%% Arguments : - +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_allowed_property_types(_OE_This, State) -> + {reply, 'CosPropertyService_PropertySetDef': + get_allowed_property_types(?get_PropertyRef(State)), State}. + +%%---------------------------------------------------------------------% +%% Function : get_allowed_properties +%% Arguments : - +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_allowed_properties(_OE_This, State) -> + {reply, 'CosPropertyService_PropertySetDef': + get_allowed_properties(?get_PropertyRef(State)), State}. + +%%---------------------------------------------------------------------% +%% Function : define_property_with_mode +%% Arguments : Name - string() +%% Value - #any{} +%% Mode - normal | read_only | fixed_normal | fixed_readonly +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +define_property_with_mode(_OE_This, State, Name, Value, Mode) -> + {reply, 'CosPropertyService_PropertySetDef': + define_property_with_mode(?get_PropertyRef(State), Name, Value, Mode), State}. + +%%---------------------------------------------------------------------% +%% Function : define_properties_with_modes +%% Arguments : PropertyDefs - list of #'CosPropertyService_PropertyDef'{} +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +define_properties_with_modes(_OE_This, State, PropertyDefs) -> + {reply, 'CosPropertyService_PropertySetDef': + define_properties_with_modes(?get_PropertyRef(State), PropertyDefs), State}. + +%%---------------------------------------------------------------------% +%% Function : get_property_mode +%% Arguments : Name - string() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_property_mode(_OE_This, State, Name) -> + {reply, 'CosPropertyService_PropertySetDef': + get_property_mode(?get_PropertyRef(State), Name), State}. + + +%%---------------------------------------------------------------------% +%% Function : get_property_modes +%% Arguments : Names - a list of Name (i.e. string()'s). +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_property_modes(_OE_This, State, Names) -> + {reply, 'CosPropertyService_PropertySetDef': + get_property_modes(?get_PropertyRef(State), Names), State}. + +%%---------------------------------------------------------------------% +%% Function : set_property_mode +%% Arguments : Name - string() +%% Mode - normal | read_only | fixed_normal | fixed_readonly +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +set_property_mode(_OE_This, State, Name, Mode) -> + {reply, 'CosPropertyService_PropertySetDef': + set_property_mode(?get_PropertyRef(State), Name, Mode), State}. + + +%%---------------------------------------------------------------------% +%% Function : set_property_modes +%% Arguments : Modes - a list of #'CosPropertyService_PropertyModes'{} +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +set_property_modes(_OE_This, State, PropertyModes) -> + {reply, 'CosPropertyService_PropertySetDef': + set_property_modes(?get_PropertyRef(State), PropertyModes), State}. + +%%====================================================================== +%% CosPropertyService::PropertySet +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : define_property +%% Arguments : Name - string() +%% Value - #any{} +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +define_property(_OE_This, State, Name, Value) -> + {reply, 'CosPropertyService_PropertySet': + define_property(?get_PropertyRef(State), Name, Value), State}. + +%%---------------------------------------------------------------------% +%% Function : define_properties +%% Arguments : Properties - a list of #'CosPropertyService_Property'{} +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +define_properties(_OE_This, State, Properties) -> + {reply, 'CosPropertyService_PropertySet': + define_properties(?get_PropertyRef(State), Properties), State}. + + +%%---------------------------------------------------------------------% +%% Function : get_number_of_properties +%% Arguments : - +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_number_of_properties(_OE_This, State) -> + {reply, 'CosPropertyService_PropertySet': + get_number_of_properties(?get_PropertyRef(State)), State}. + +%%---------------------------------------------------------------------% +%% Function : get_all_property_names +%% Arguments : Max - ulong() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_all_property_names(_OE_This, State, Max) -> + {reply, 'CosPropertyService_PropertySet': + get_all_property_names(?get_PropertyRef(State), Max), State}. + +%%---------------------------------------------------------------------% +%% Function : get_property_value +%% Arguments : Name - string() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_property_value(_OE_This, State, "num_children") -> + Count = 'CosFileTransfer_FileTransferSession': + oe_orber_count_children(?get_AssocSession(State), ?get_CompleteName(State)), + {reply, #any{typecode=tk_long, value=Count}, State}; +get_property_value(_OE_This, State, Name) -> + {reply, 'CosPropertyService_PropertySet': + get_property_value(?get_PropertyRef(State), Name), State}. + +%%---------------------------------------------------------------------% +%% Function : get_properties +%% Arguments : Names - a list of Name (i.e. string()'s) +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_properties(_OE_This, State, Names) -> + {Bool, Props} = + 'CosPropertyService_PropertySet':get_properties(?get_PropertyRef(State), + Names), + NewProps = change_property(Props, [], State), + {reply, {Bool, NewProps}, State}. + +change_property([], Acc, _State) -> + Acc; +change_property([H|T], Acc, State) -> + NewAcc = + case H of + #'CosPropertyService_Property'{property_name = "num_children"} -> + Count = 'CosFileTransfer_FileTransferSession': + oe_orber_count_children(?get_AssocSession(State), + ?get_CompleteName(State)), + [H#'CosPropertyService_Property' + {property_value = #any{typecode=tk_long, value=Count}}|Acc]; + _ -> + [H|Acc] + end, + change_property(T, NewAcc, State). + +%%---------------------------------------------------------------------% +%% Function : get_all_properties +%% Arguments : Max - ulong() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_all_properties(_OE_This, State, 0) -> + %% WARNING if we start supporting more than 10 Properties the next line must + %% be updated! + {ok, Props, _Iterator} = + 'CosPropertyService_PropertySet':get_all_properties(?get_PropertyRef(State), + 10), + NewProps = change_property(Props, [], State), + %% WARNING if the cosProperty:start_PropertiesIterator/1 is updated + %% it must be done hear as well. + {reply, {ok, [], cosProperty:start_PropertiesIterator(NewProps)}, State}; +get_all_properties(_OE_This, State, Max) -> + {ok, Props, Iterator} = + 'CosPropertyService_PropertySet':get_all_properties(?get_PropertyRef(State), + Max), + NewProps = change_property(Props, [], State), + {reply, {ok, NewProps, Iterator}, State}. + +%%---------------------------------------------------------------------% +%% Function : delete_property +%% Arguments : Name - string() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +delete_property(_OE_This, State, Name) -> + {reply, 'CosPropertyService_PropertySet': + delete_property(?get_PropertyRef(State), Name), State}. + + +%%---------------------------------------------------------------------% +%% Function : delete_properties +%% Arguments : Names - a list of Name (i.e. string()'s) +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +delete_properties(_OE_This, State, Names) -> + {reply, 'CosPropertyService_PropertySet': + delete_properties(?get_PropertyRef(State), Names), State}. + + +%%---------------------------------------------------------------------% +%% Function : delete_all_properties +%% Arguments : - +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +delete_all_properties(_OE_This, State) -> + {reply, 'CosPropertyService_PropertySet': + delete_all_properties(?get_PropertyRef(State)), State}. + +%%---------------------------------------------------------------------% +%% Function : is_property_defined +%% Arguments : Name - string() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +is_property_defined(_OE_This, State, Name) -> + {reply, 'CosPropertyService_PropertySet': + is_property_defined(?get_PropertyRef(State), Name), State}. + +%%====================================================================== +%% Internal functions +%%====================================================================== + +%%====================================================================== +%% END OF MODULE +%%====================================================================== + diff --git a/lib/cosFileTransfer/src/CosFileTransfer_FileIterator_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_FileIterator_impl.erl new file mode 100644 index 0000000..2800c19 --- /dev/null +++ b/lib/cosFileTransfer/src/CosFileTransfer_FileIterator_impl.erl @@ -0,0 +1,157 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosFileTransfer_FileIterator_impl.erl +%% Description : +%% +%% Created : 12 Sept 2000 +%%---------------------------------------------------------------------- +-module('CosFileTransfer_FileIterator_impl'). + + + + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include("cosFileTransferApp.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%% Interface functions +-export([next_one/2, + next_n/3, + destroy/2]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([FileList]) -> + {ok, FileList}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% function : handle_info/2 +%% Arguments: +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +handle_info(Info, State) -> + case Info of + {'EXIT', _Pid, Reason} -> + {stop, Reason, State}; + _Other -> + {noreply, State} + end. + +%%====================================================================== +%% CosFileTransfer::FileIterator +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : next_one +%% Arguments : +%% Returns : {boolean(), FileWrapper} +%% Description: +%%---------------------------------------------------------------------- +next_one(_OE_This, []) -> + {reply, {false, + #'CosFileTransfer_FileWrapper'{the_file = corba:create_nil_objref(), + file_type = nfile}}, []}; +next_one(_OE_This, [FileWrapper]) -> + {reply, {true, FileWrapper}, []}; +next_one(_OE_This, [FileWrapper|Rest]) -> + {reply, {true, FileWrapper}, Rest}. + +%%---------------------------------------------------------------------% +%% Function : next_n +%% Arguments : HowMany - ulong() +%% Returns : {boolean(), FileWrapperList} +%% Description: +%%---------------------------------------------------------------------- +next_n(_OE_This, [], _) -> + {reply, {false, []}, []}; +next_n(_OE_This, FileWrapperList, HowMany) when HowMany > length(FileWrapperList) -> + {reply, {true, FileWrapperList}, []}; +next_n(_OE_This, FileWrapperList, HowMany) -> + {reply, {true, lists:sublist(FileWrapperList, HowMany)}, + lists:nthtail(HowMany, FileWrapperList)}. + +%%---------------------------------------------------------------------% +%% Function : destroy +%% Arguments : - +%% Returns : - +%% Description: +%%---------------------------------------------------------------------- +destroy(_OE_This, State) -> + {stop, normal, ok, State}. + + +%%====================================================================== +%% Internal functions +%%====================================================================== + + + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl new file mode 100644 index 0000000..e222c5b --- /dev/null +++ b/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl @@ -0,0 +1,1060 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosFileTransfer_FileTransferSession_impl.erl +%% Description : +%% +%% Created : 12 Sept 2000 +%%---------------------------------------------------------------------- +-module('CosFileTransfer_FileTransferSession_impl'). + + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). + +-include("cosFileTransferApp.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%% Interface functions +-export(['_get_protocols_supported'/2, + set_directory/3, + create_file/3, + create_directory/3, + get_file/3, + delete/3, + transfer/4, + append/4, + insert/5, + logout/2]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([oe_orber_create_directory_current/2, oe_orber_get_content/4, + oe_orber_count_children/3]). +-export([invoke_call/3]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {protocols, server, type, current, module, connection, mytype, + connection_timeout}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +-define(create_InitState(P, S, T, C, M, Co, Ty, CT), + #state{protocols=P, server=S, type=T, current=C, module=M, connection=Co, + mytype=Ty, connection_timeout=CT}). + +-define(get_Protocols(S), S#state.protocols). +-define(get_Server(S), S#state.server). +-define(get_CurrentDir(S), S#state.current). +-define(get_Module(S), S#state.module). +-define(get_Connection(S), S#state.connection). +-define(get_MyType(S), S#state.mytype). +-define(get_ConnectionTimeout(S), S#state.connection_timeout). +-define(set_CurrentDir(S, C), S#state{current=C}). + +-define(is_FTP(S), S#state.type=='FTP'). +-define(is_FTAM(S), S#state.type=='FTAM'). +-define(is_NATIVE(S), S#state.type=='NATIVE'). +-define(is_ORBER_NATIVE(S), S#state.module==cosFileTransferNATIVE_file). + + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init(['FTP', Host, Port, User, Password, _Account, Protocol, Timeout]) -> + {ok, Pid} = inets:start(ftpc, [{host, Host}, {port, Port}], stand_alone), + ok = ftp:user(Pid, User, Password), + {ok, PWD} = ftp:pwd(Pid), + {Connection, ProtocolSupport} = setup_local(Protocol), + {ok, ?create_InitState(ProtocolSupport, Pid, 'FTP', + PWD, ftp, Connection, Protocol, Timeout)}; +init([{'NATIVE', Mod}, Host, Port, User, Password, _Account, Protocol, Timeout]) -> + {ok, Pid} = Mod:open(Host, Port), + ok = Mod:user(Pid, User, Password), + {ok, PWD} = Mod:pwd(Pid), + {Connection, ProtocolSupport} = setup_local(Protocol), + {ok, ?create_InitState(ProtocolSupport, Pid, 'NATIVE', + PWD, Mod, Connection, Protocol, Timeout)}. + + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, #state{type = Type, server = Server, module = Mod} = State) -> + case ?get_MyType(State) of + ssl -> + catch ssl:close(?get_Connection(State)); + _ -> + catch gen_tcp:close(?get_Connection(State)) + end, + case Type of + 'FTP' -> + inets:stop(ftpc, Server); + 'NATIVE' -> + Mod:close(Server); + _ -> + ok + end, + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% function : handle_info/2 +%% Arguments: +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +handle_info(Info, State) -> + case Info of + {'EXIT', _Pid, Reason} -> + {stop, Reason, State}; + _Other -> + {noreply, State} + end. + +%%====================================================================== +%% CosFileTransfer::FileTransferSession +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : _get_protocols_supported +%% Arguments : +%% Returns : A list of CosFileTransfer::ProtocolSupport, i.e., +%% struct ProtocolSupport { +%% Istring protocol_name; +%% ProtocolAddressList addresses; %% eq a list of strings. +%% }; +%% Description: +%%---------------------------------------------------------------------- +'_get_protocols_supported'(_OE_This, State) -> + {reply, ?get_Protocols(State), State}. + +%%---------------------------------------------------------------------- +%% Function : set_directory +%% Arguments : Directory - CosFileTransfer::Directory +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +set_directory(_OE_This, State, Directory) when ?is_FTP(State); ?is_NATIVE(State) -> + Mod = ?get_Module(State), + Path = filename:join('CosFileTransfer_Directory': + '_get_complete_file_name'(Directory)), + case catch Mod:cd(?get_Server(State), Path) of + ok -> + {reply, ok, ?set_CurrentDir(State, Path)}; + {error, epath} -> + corba:raise(#'CosFileTransfer_FileNotFoundException' + {reason="Directory not found."}); + {error, elogin} -> + corba:raise(#'CosFileTransfer_SessionException' + {reason="User not loggen in."}); + {error, econn} -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Premature connection ending."}); + _ -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason = "Unexpected error."}) + end. + +%%---------------------------------------------------------------------- +%% Function : create_file +%% Arguments : FileNameList +%% Returns : File +%% Description: This operation creates a File Object representing a +%% file which may or may not exist. Typically used as +%% argument when invoking transfer/3. See also get_file/2. +%%---------------------------------------------------------------------- +create_file(OE_This, State, FileNameList) -> + {reply, cosFileTransferApp:create_file(OE_This, FileNameList), State}. + +%%---------------------------------------------------------------------- +%% Function : create_directory +%% Arguments : FileNameList - full path name. +%% Returns : Directory +%% Description: +%%---------------------------------------------------------------------- +create_directory(OE_This, State, FileNameList) when ?is_FTP(State); + ?is_NATIVE(State) -> + Mod = ?get_Module(State), + case Mod:mkdir(?get_Server(State), filename:join(FileNameList)) of + ok -> + {reply, cosFileTransferApp:create_dir(OE_This, FileNameList), State}; + {error, epath} -> + corba:raise(#'CosFileTransfer_FileNotFoundException' + {reason="Directory not found."}); + {error, elogin} -> + corba:raise(#'CosFileTransfer_SessionException' + {reason="User not loggen in."}); + {error, econn} -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Premature connection ending."}); + _ -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Unknown error."}) + end. + + +%%---------------------------------------------------------------------- +%% Function : get_file +%% Arguments : FileNameList +%% Returns : FileWrapper +%% Description: This operation should be independent of the working Directory, +%% i.e., a full path name must be supplied. The file or +%% directory the returned object is supposed to represent +%% MUST(!!!!) exist. +%%---------------------------------------------------------------------- +get_file(OE_This, State, FileNameList) when ?is_FTP(State); + ?is_NATIVE(State) -> + case check_type(OE_This, State, filename:join(FileNameList)) of + {ndirectory, _Listing} -> + {reply, + #'CosFileTransfer_FileWrapper'{the_file = + cosFileTransferApp: + create_dir(OE_This, + FileNameList), + file_type = ndirectory}, + State}; + nfile -> + {reply, + #'CosFileTransfer_FileWrapper'{the_file = + cosFileTransferApp: + create_file(OE_This, + FileNameList), + file_type = nfile}, + State}; + Other -> + %% If we want to return {stop, ....} + Other + end. + +%%---------------------------------------------------------------------- +%% Function : delete +%% Arguments : File +%% Returns : - +%% Description: +%%---------------------------------------------------------------------- +delete(_OE_This, State, File) when ?is_FTP(State); ?is_NATIVE(State) -> + Mod = ?get_Module(State), + Result = + case 'CosPropertyService_PropertySet': + get_property_value(File, "is_directory") of + #any{value=false} -> + Mod:delete(?get_Server(State), + filename:join('CosFileTransfer_File': + '_get_complete_file_name'(File))); + #any{value=true} -> + Mod:rmdir(?get_Server(State), + filename:join('CosFileTransfer_File': + '_get_complete_file_name'(File))); + Other -> + Other + end, + case Result of + ok -> + {reply, ok, State}; + {error, epath} -> + corba:raise(#'CosFileTransfer_FileNotFoundException' + {reason="File or Directory not found."}); + {error, elogin} -> + corba:raise(#'CosFileTransfer_SessionException' + {reason="User not loggen in."}); + {error, econn} -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Premature connection ending."}); + _ -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Unknown error."}) + end. + +%%---------------------------------------------------------------------- +%% Function : transfer +%% Arguments : SrcFile eq DestFile eq CosFileTransfer::File +%% Returns : - +%% Description: DestFile must be a newly created File object, using create_file() +%% on the Target FileTransferSession, prior to calling transfer(). +%%---------------------------------------------------------------------- +transfer(OE_This, State, SrcFile, DestFile) when ?is_ORBER_NATIVE(State) -> + case which_FTS_type(OE_This, SrcFile, DestFile) of + {source, TargetFTS} -> + %% The source FTS is supposed to be the active one, set up a connection. + Protocols = 'CosFileTransfer_FileTransferSession': + '_get_protocols_supported'(TargetFTS), + SrcName = 'CosFileTransfer_File':'_get_complete_file_name'(SrcFile), + Pid = spawn(?MODULE, invoke_call, [self(), transfer, + [TargetFTS, SrcFile, DestFile]]), + send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State), + filename:join(SrcName)), + check_reply(Pid), + {reply, ok, State}; + {target, _SourceFTS} -> + DestName = 'CosFileTransfer_File':'_get_complete_file_name'(DestFile), + receive_file(?get_MyType(State), ?get_Connection(State), + ?get_ConnectionTimeout(State), + filename:join(DestName), write), + {reply, ok, State} + end; +transfer(OE_This, State, SrcFile, DestFile) when ?is_FTP(State); ?is_NATIVE(State) -> + case which_FTS_type(OE_This, SrcFile, DestFile) of + {source, TargetFTS} -> + source_FTS_operation(State, SrcFile, DestFile, transfer, 0, TargetFTS); + {target, _SourceFTS} -> + target_FTS_operation(State, SrcFile, DestFile, send, 0) + end. + + +%%---------------------------------------------------------------------- +%% Function : append +%% Arguments : SrcFile eq DestFile eq CosFileTransfer::File +%% Returns : - +%% Description: +%%---------------------------------------------------------------------- +append(OE_This, State, SrcFile, DestFile) when ?is_ORBER_NATIVE(State) -> + case which_FTS_type(OE_This, SrcFile, DestFile) of + {source, TargetFTS} -> + SrcName = filename:join('CosFileTransfer_File': + '_get_complete_file_name'(SrcFile)), + check_type(OE_This, State, SrcName), + %% The source FTS is supposed to be the active one, set up a connection. + Protocols = 'CosFileTransfer_FileTransferSession': + '_get_protocols_supported'(TargetFTS), + Pid = spawn(?MODULE, invoke_call, [self(), append, + [TargetFTS, SrcFile, DestFile]]), + send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State), + SrcName), + check_reply(Pid), + {reply, ok, State}; + {target, _SourceFTS} -> + DestName = filename:join('CosFileTransfer_File': + '_get_complete_file_name'(DestFile)), + check_type(OE_This, State, DestName), + receive_file(?get_MyType(State), ?get_Connection(State), + ?get_ConnectionTimeout(State), DestName, append), + {reply, ok, State} + end; +append(OE_This, State, SrcFile, DestFile) when ?is_NATIVE(State) -> + case which_FTS_type(OE_This, SrcFile, DestFile) of + {source, TargetFTS} -> + source_FTS_operation(State, SrcFile, DestFile, append, 0, TargetFTS); + {target, _SourceFTS} -> + target_FTS_operation(State, SrcFile, DestFile, append, 0) + end; +append(_OE_This, _State, _SrcFile, _DestFile) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}). + + +%%---------------------------------------------------------------------- +%% Function : insert +%% Arguments : SrcFile eq DestFile eq CosFileTransfer::File +%% Offset - long +%% Returns : - +%% Description: +%%---------------------------------------------------------------------- +insert(OE_This, State, SrcFile, DestFile, Offset) when ?is_NATIVE(State) -> + case which_FTS_type(OE_This, SrcFile, DestFile) of + {source, TargetFTS} when ?is_ORBER_NATIVE(State) -> + SrcName = 'CosFileTransfer_File':'_get_complete_file_name'(SrcFile), + check_type(OE_This, State, filename:join(SrcName)), + %% The source FTS is supposed to be the active one, set up a connection. + Protocols = 'CosFileTransfer_FileTransferSession': + '_get_protocols_supported'(TargetFTS), + Pid = spawn(?MODULE, invoke_call, [self(), insert, + [TargetFTS, SrcFile, + DestFile, Offset]]), + send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State), + filename:join(SrcName)), + check_reply(Pid), + {reply, ok, State}; + {source, TargetFTS} -> + source_FTS_operation(State, SrcFile, DestFile, insert, Offset, TargetFTS); + {target, _SourceFTS} -> + target_FTS_operation(State, SrcFile, DestFile, insert, Offset) + end; +insert(_OE_This, _State, _SrcFile, _DestFile, _Offset) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}). + + +%%---------------------------------------------------------------------- +%% Function : logout +%% Arguments : - +%% Returns : - +%% Description: +%%---------------------------------------------------------------------- +logout(_OE_This, State) when ?is_FTP(State); ?is_NATIVE(State) -> + Mod = ?get_Module(State), + catch Mod:close(?get_Server(State)), + {stop, normal, ok, State}. + +%%====================================================================== +%% Internal functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : oe_orber_create_directory_current +%% Arguments : - +%% Returns : Directory +%% Description: Creates a Directory describing the working directory +%% of the remote server, e.g., an FTP-server. +%%---------------------------------------------------------------------- +oe_orber_create_directory_current(OE_This, State) when ?is_FTP(State); + ?is_NATIVE(State) -> + Mod = ?get_Module(State), + FileNameList = filename:split(?get_CurrentDir(State)), + case Mod:nlist(?get_Server(State), ?get_CurrentDir(State)) of + {ok, _Listing} -> + {reply, cosFileTransferApp:create_dir(OE_This, FileNameList), + State}; + {error, epath} -> + corba:raise(#'CosFileTransfer_FileNotFoundException' + {reason="Directory not found."}); + {error, elogin} -> + corba:raise(#'CosFileTransfer_SessionException' + {reason="User not loggen in."}); + {error, econn} -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Premature connection ending."}); + _ -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Unknown error."}) + end. +%%---------------------------------------------------------------------- +%% Function : oe_orber_get_content +%% Arguments : - +%% Returns : string +%% Description: +%%---------------------------------------------------------------------- +oe_orber_get_content(OE_This, State, FileNameList, Parent) when ?is_FTP(State); + ?is_NATIVE(State) -> + Mod = ?get_Module(State), + case Mod:nlist(?get_Server(State), filename:join(FileNameList)) of + {ok, Listing} -> + create_content(Listing, OE_This, State, Parent, FileNameList); + {error, epath} -> + {reply, [], State}; + _ -> + corba:raise(#'CosFileTransfer_FileNotFoundException' + {reason="Directory not found."}) + end. + +%%---------------------------------------------------------------------- +%% Function : oe_orber_count_children +%% Arguments : - +%% Returns : string +%% Description: +%%---------------------------------------------------------------------- +oe_orber_count_children(OE_This, State, FileNameList) when ?is_FTP(State); + ?is_NATIVE(State) -> + case catch check_type(OE_This, State, filename:join(FileNameList)) of + {ndirectory, Members} -> + {reply, length(Members), State}; + {stop, normal, _, _} -> + {stop, normal, + {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}, + State}; + _-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------- +%% Function : delete_tmp_file +%% Arguments : - +%% Returns : ok | {'EXCEPTION', E} +%% Description: +%%---------------------------------------------------------------------- +delete_tmp_file(TmpFileName, ErrorMsg) -> + case file:delete(TmpFileName) of + ok -> + ok; + _ -> + corba:raise(#'CosFileTransfer_RequestFailureException'{reason=ErrorMsg}) + end. + + +%%---------------------------------------------------------------------- +%% Function : invoke_call +%% Arguments : - +%% Returns : ok | {'EXCEPTION', E} +%% Description: +%%---------------------------------------------------------------------- +invoke_call(Pid, Op, Args) -> + Result = (catch apply('CosFileTransfer_FileTransferSession', Op, Args)), + Pid ! {transfer_result, self(), Result}, + ok. + +%%---------------------------------------------------------------------- +%% Function : check_reply +%% Arguments : Pid - the pid of the spawned process. +%% Returns : ok | {'EXCEPTION', E} +%% Description: +%%---------------------------------------------------------------------- +check_reply(Pid) -> + receive + {transfer_result, Pid, ok} -> + ok; + {transfer_result, Pid, {'EXCEPTION', E}} -> + orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:check_reply(); +Raised exception: ", [?LINE, E], ?DEBUG_LEVEL), + corba:raise(E); + {transfer_result, Pid, {'EXIT', Reason}} -> + orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:check_reply(); +Got EXIT-signal with reason: ", [?LINE, Reason], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{minor=199, + completion_status=?COMPLETED_NO}) + after infinity -> + %% Should we add an exception here or do we reuse the iiop_timeout? + %% For now keep as is. + corba:raise(#'INTERNAL'{minor=199, + completion_status=?COMPLETED_NO}) + end. + + +%%---------------------------------------------------------------------- +%% Function : which_FTS_type +%% Arguments : - +%% Returns : {source, FTS} | {target, FTS} | {'EXCEPTION', #'BAD_PARAM'{}} +%% Description: Used to determine if the target FTS is supposed to act +%% as sender or receiver and also return the counter part FTS. +%% An exception is raised if the user supplied incorrect parameters. +%%---------------------------------------------------------------------- +which_FTS_type(OE_This, SrcFile, DestFile) -> + TargetFTS = 'CosFileTransfer_File':'_get_associated_session'(DestFile), + SourceFTS = 'CosFileTransfer_File':'_get_associated_session'(SrcFile), + case corba_object:is_equivalent(OE_This, TargetFTS) of + true -> + {target, SourceFTS}; + false -> + case corba_object:is_equivalent(OE_This, SourceFTS) of + true -> + {source, TargetFTS}; + false -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end + end. + + +%%---------------------------------------------------------------------- +%% Function : setup_connection +%% Arguments : A list of #'CosFileTransfer_ProtocolSupport'{} +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +setup_connection([], Protocol, _) -> + orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:setup_connection(~p); +The Protocols listed are not supported.", [?LINE, Protocol], ?DEBUG_LEVEL), + corba:raise(#'CosFileTransfer_TransferException'{reason="Unsupported protocol"}); +setup_connection([#'CosFileTransfer_ProtocolSupport'{protocol_name="TCP/IP", + addresses=Addr}|_], + tcp, Timeout) -> + setup_connection_helper(Addr, gen_tcp, [], Timeout); +setup_connection([#'CosFileTransfer_ProtocolSupport'{protocol_name="SSL", + addresses=Addr}|_], + ssl, Timeout) -> + Options = [{certfile, cosFileTransferApp:ssl_client_certfile()}, + {verify, cosFileTransferApp:ssl_client_verify()}, + {depth, cosFileTransferApp:ssl_client_depth()}] ++ + ssl_client_cacertfile_option(), + setup_connection_helper(Addr, ssl, Options, Timeout); +setup_connection([_|T], Type, Timeout) -> + setup_connection(T, Type, Timeout). + +setup_connection_helper([], _, _, _) -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Unable to contact remote server."}); +setup_connection_helper([H|T], Driver, Options, Timeout) -> + case string:tokens(H, ":") of + [Host, Port] when Driver == gen_tcp -> + case gen_tcp:connect(Host, list_to_integer(Port), + [binary, + {packet, raw}, + {reuseaddr, true}, + {nodelay, true}|Options], Timeout) of + {ok, Sock} -> + {gen_tcp, Sock}; + _-> + %% No response. + setup_connection_helper(T, Driver, Options, Timeout) + end; + [Host, Port] when Driver == ssl -> + case ssl:connect(Host, list_to_integer(Port), + [binary, + {packet, 0}, + {active, false}|Options], Timeout) of + {ok, Sock} -> + {ssl, Sock}; + _-> + %% No response. + setup_connection_helper(T, Driver, Options, Timeout) + end; + _ -> + %% Badly configured address. + setup_connection_helper(T, Driver, Options, Timeout) + end. + +ssl_client_cacertfile_option() -> + case cosFileTransferApp:ssl_client_cacertfile() of + [] -> + []; + X when is_list(X) -> + {cacertfile, X}; + _ -> + [] + end. + +%%---------------------------------------------------------------------- +%% Function : create_content +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +create_content(Listing, OE_This, State, Parent, PathList) -> + create_content(string:tokens(Listing, ?SEPARATOR), OE_This, + State, Parent, PathList, []). + +create_content([], _OE_This, State, _Parent, _PathList, Acc) -> + {reply, Acc, State}; +create_content([H|T], OE_This, State, Parent, PathList, Acc) -> + FullPathList = PathList ++[filename:basename(H)], + case check_type(OE_This, State, filename:join(FullPathList)) of + nfile -> + create_content(T, OE_This, State, Parent, PathList, + [#'CosFileTransfer_FileWrapper' + {the_file = cosFileTransferApp:create_file(OE_This, + FullPathList, + Parent), + file_type = nfile}|Acc]); + {ndirectory, _Members} -> + create_content(T, OE_This, State, Parent, PathList, + [#'CosFileTransfer_FileWrapper' + {the_file = cosFileTransferApp:create_dir(OE_This, + FullPathList, + Parent), + file_type = ndirectory}|Acc]); + Other -> + Other + end. + + +%%---------------------------------------------------------------------- +%% Function : MISC functions +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +setup_local(tcp) -> + {ok,Socket}=gen_tcp:listen(0, [binary, + {packet, 0}, + {backlog,1}, + {active, false}]), + {ok, Port} = inet:port(Socket), + {Socket, [#'CosFileTransfer_ProtocolSupport'{protocol_name="TCP/IP", + addresses = [local_address(Port)]}]}; +setup_local(ssl) -> + Options = [{certfile, cosFileTransferApp:ssl_server_certfile()}, + {verify, cosFileTransferApp:ssl_server_verify()}, + {depth, cosFileTransferApp:ssl_server_depth()}] ++ + ssl_server_cacertfile_option(), + {ok,Socket}=ssl:listen(0, [binary, + {packet, 0}, + {backlog,1}, + {active, false}|Options]), + {ok, {_Address, Port}} = ssl:sockname(Socket), + {Socket, [#'CosFileTransfer_ProtocolSupport'{protocol_name="SSL", + addresses = [local_address(Port)]}]}. + +local_address(Port) -> + {ok, Hostname} = inet:gethostname(), + {ok, {A1, A2, A3, A4}} = inet:getaddr(Hostname, inet), + integer_to_list(A1) ++ "." ++ integer_to_list(A2) ++ "." ++ integer_to_list(A3) + ++ "." ++ integer_to_list(A4)++":"++integer_to_list(Port). + +ssl_server_cacertfile_option() -> + case cosFileTransferApp:ssl_server_cacertfile() of + [] -> + []; + X when is_list(X) -> + [{cacertfile, X}]; + _ -> + [] + end. + +%%---------------------------------------------------------------------- +%% Function : source_file_operation +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +source_FTS_operation(State, SrcFile, DestFile, Op, Offset, FTS) -> + Mod = ?get_Module(State), + %% The source FTS is supposed to be the active one, set up a connection. + Protocols = 'CosFileTransfer_FileTransferSession':'_get_protocols_supported'(FTS), + SrcName = 'CosFileTransfer_File':'_get_complete_file_name'(SrcFile), + TempName = cosFileTransferApp:create_name("TemporarySrcFile"), + case Mod:recv(?get_Server(State), filename:join(SrcName), TempName) of + ok when Op == insert -> + %% Downloaded the File, we are now ready to transmit. + Pid = spawn(?MODULE, invoke_call, [self(), insert, + [FTS, SrcFile, DestFile, Offset]]), + send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State), + TempName), + %% Delete the temporary local copy. + delete_tmp_file(TempName, + "Transfer completed but failed to remove temporary local copy."), + check_reply(Pid), + {reply, ok, State}; + ok -> + %% Downloaded the File, we are now ready to transmit. + Pid = spawn(?MODULE, invoke_call, [self(), Op, [FTS, SrcFile, DestFile]]), + send_file(Protocols, ?get_MyType(State), ?get_ConnectionTimeout(State), + TempName), + %% Delete the temporary local copy. + delete_tmp_file(TempName, + "Transfer completed but failed to remove temporary local copy."), + check_reply(Pid), + {reply, ok, State}; + {error, epath} -> + corba:raise(#'CosFileTransfer_FileNotFoundException' + {reason="File not found."}); + {error, elogin} -> + corba:raise(#'CosFileTransfer_SessionException' + {reason="User not loggen in."}); + {error, econn} -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Premature connection ending."}) + end. + +%%---------------------------------------------------------------------- +%% Function : target_file_operation +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +target_FTS_operation(State, _SrcFile, DestFile, Op, Offset) -> + Mod = ?get_Module(State), + DestName = 'CosFileTransfer_File':'_get_complete_file_name'(DestFile), + TempName = cosFileTransferApp:create_name("TemporaryDestFile"), + receive_file(?get_MyType(State), ?get_Connection(State), + ?get_ConnectionTimeout(State), TempName, write), + Result = + if + Op == insert -> + Mod:insert(?get_Server(State), TempName, filename:join(DestName), Offset); + true -> + Mod:Op(?get_Server(State), TempName, filename:join(DestName)) + end, + case Result of + ok -> + %% Delete the temporary local copy. + delete_tmp_file(TempName, + "Transfer completed but failed to remove temporary local copy."), + %% Completed the transfer succesfully. + {reply, ok, State}; + {error, epath} -> + delete_tmp_file(TempName, + "IllegalOperationException and not able to remove temporary local copy."), + corba:raise(#'CosFileTransfer_IllegalOperationException' + {reason="Not allowed by destination."}); + {error, elogin} -> + delete_tmp_file(TempName, + "SessionException and not able to remove temporary local copy."), + corba:raise(#'CosFileTransfer_SessionException' + {reason="User not logged in."}); + {error, econn} -> + delete_tmp_file(TempName, + "TransferException and not able to remove temporary local copy."), + corba:raise(#'CosFileTransfer_TransferException' + {reason="Premature connection ending."}); + {error, etnospc} -> + delete_tmp_file(TempName, + "RequestFailureException and not able to remove temporary local copy."), + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Premature connection ending."}); + {error, efnamena} -> + delete_tmp_file(TempName, + "IllegalOperationException and not able to remove temporary local copy."), + corba:raise(#'CosFileTransfer_IllegalOperationException' + {reason="Not allowed by destination."}) + end. + +%%---------------------------------------------------------------------- +%% Function : receive_file +%% Arguments : Driver - currently only gen_tcp supported. +%% LSocket - which socket to use. +%% FileName - an absolute file name representing the +%% file we want to create or append to. +%% Type - 'read', 'write', 'append'. +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +receive_file(tcp, LSock, Timeout, FileName, Type) -> + %% The Type can be the ones allowed by the file-module, i.e., + %% 'read', 'write' or 'append' + FD = file_open(FileName, Type), + case gen_tcp:accept(LSock, Timeout) of + {ok, Sock} -> + receive_file_helper(gen_tcp, Sock, FD); + {error, timeout} -> + orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n" + "gen_tcp:accept(~p) timed out", [?LINE, Timeout], ?DEBUG_LEVEL), + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="TCP accept timed out.."}); + {error, Why} -> + orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n" + "gen_tcp:accept(~p) failed: ~p", [?LINE, Timeout, Why], ?DEBUG_LEVEL), + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="TCP accept failed."}) + end; +receive_file(ssl, LSock, Timeout, FileName, Type) -> + %% The Type can be the ones allowed by the file-module, i.e., + %% 'read', 'write' or 'append' + FD = file_open(FileName, Type), + case ssl:transport_accept(LSock, Timeout) of + {ok, Sock} -> + case ssl:ssl_accept(Sock, Timeout) of + ok -> + receive_file_helper(ssl, Sock, FD); + {error, Error} -> + orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n" + "ssl:ssl_accept(~p) failed: ~p", + [?LINE, Timeout, Error], ?DEBUG_LEVEL), + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="TCP accept failed."}) + end; + {error, timeout} -> + orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n" + "ssl:transport_accept(~p) timed out", + [?LINE, Timeout], ?DEBUG_LEVEL), + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="TCP accept timed out.."}); + {error, Why} -> + orber:dbg("[~p] CosFileTransfer_FileTransferSession:receive_file();~n" + "ssl:transport_accept(~p) failed: ~p", + [?LINE, Timeout, Why], ?DEBUG_LEVEL), + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="TCP accept failed."}) + end. + +receive_file_helper(Driver, Sock, FD) -> + case Driver:recv(Sock, 0) of + {ok, Bin} -> + file:write(FD, Bin), + receive_file_helper(Driver, Sock, FD); + {error, closed} -> + file:close(FD); + What -> + orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:receive_file(~p); +Error occured when receiving data: ~p", [?LINE, Driver, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------- +%% Function : send_file +%% Arguments : Driver - currently only gen_tcp supported. +%% Sock - which socket to use. +%% FileName - an absolute file name representing the +%% file we want to send. +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +send_file(Protocols, Type, Timeout, FileName) -> + {Driver, Sock} = setup_connection(Protocols, Type, Timeout), + FD = file_open(FileName, read), + BuffSize = cosFileTransferApp:get_buffert_size(), + send_file_helper(Driver, Sock, FD, BuffSize). + +send_file_helper(Driver, Sock, FD, BuffSize) -> + case file:read(FD, BuffSize) of + eof -> + file:close(FD), + Driver:close(Sock); + {ok, Bin} -> + case Driver:send(Sock, Bin) of + ok -> + send_file_helper(Driver, Sock, FD, BuffSize); + What -> + orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:send_file_helper(~p); +Error occured when sending data: ~p", [?LINE, Driver, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end + end. + + +file_open(File, Type) -> + case file:open(File, [raw, binary, Type]) of + {ok, FD} -> + FD; + {error, What} -> + orber:debug_level_print("[~p] CosFileTransfer_FileTransferSession:file_open(~p); +Failed to open the file due to: ~p", [?LINE, File, What], ?DEBUG_LEVEL), + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Unable to open given file."}) + end. + +%%---------------------------------------------------------------------- +%% Function : check_type +%% Arguments : FullName - an absolute file name representing the +%% file or directory we want to evaluate. +%% Returns : +%% Description: +%% When communcating with FTP-servers on different platforms a variety of +%% answers can be returned. A few examples: +%% +%% ### ftp:nlist on an empty directory ### +%% {ok, ""}, {error, epath} +%% +%% ### ftp:nlist on a non-existing directory or file ### +%% {ok, "XXX: No such file or directory}, {error, epath} +%% +%% ### ftp:nlist on an existing directory with one contained item ### +%% {ok, "Item"} +%% +%% Comparing the above we see that it's virtually impossible to tell apart +%% {ok, "XXX: No such file or directory} and {ok, "Item"}. +%% Hence, it's easier to test if it's possible to do ftp:cd instead. +%% Ugly, but rather effective. If we look at the bright side, it's only +%% necessary when we try to lookup: +%% * non-existing item +%% * A directory with one member only. +%% * An empty directory. +%% +%% Furthermore, no need for traversing Listings etc. +%%---------------------------------------------------------------------- +check_type(_OE_This, State, FullName) when ?is_FTP(State); ?is_NATIVE(State) -> + Mod = ?get_Module(State), + Result = + case Mod:nlist(?get_Server(State), FullName) of + {ok, Listing} when length(Listing) > 0-> + case string:tokens(Listing, ?SEPARATOR) of + [FullName] -> + nfile; + Members when length(Members) > 1 -> + %% Must test if more than one member since sometimes + %% this operation returns for example: + %% {ok, "XXX No such file or drectory"} + {ndirectory, Members}; + Member -> + case Mod:cd(?get_Server(State), FullName) of + ok -> + case Mod:cd(?get_Server(State), + ?get_CurrentDir(State)) of + ok -> + {ndirectory, Member}; + _ -> + %% Failed, we cannot continue since the + %% FTS now pointso an incorrect Directory. + %% Hence, we must terminate. + {stop, normal, + {'EXCEPTION', + #'CosFileTransfer_RequestFailureException' + {reason="Unknown error."}}, State} + end; + {error, E} -> + {error, E}; + _ -> + nfile + end + end; + {error, epath} -> + %% Might be a file. + DirName = filename:dirname(FullName), + case Mod:nlist(?get_Server(State), DirName) of + {ok, Listing} when length(Listing) > 0-> + Members = string:tokens(Listing, ?SEPARATOR), + case lists:member(FullName, Members) of + true -> + nfile; + _ -> + BName = filename:basename(FullName), + case lists:member(BName, Members) of + true -> + nfile; + _ -> + {error, epath} + end + end; + _ -> + {error, epath} + end; + _ -> + case Mod:cd(?get_Server(State), FullName) of + ok -> + case Mod:cd(?get_Server(State), ?get_CurrentDir(State)) of + ok -> + {ndirectory, []}; + _ -> + %% Failed, we cannot continue since the + %% FTS now pointso an incorrect Directory. + %% Hence, we must terminate. + {stop, normal, + {'EXCEPTION', + #'CosFileTransfer_RequestFailureException' + {reason="Unknown error."}}, State} + end; + _ -> + {error, epath} + end + end, + case Result of + {error, epath} -> + corba:raise(#'CosFileTransfer_FileNotFoundException' + {reason="File or Directory not found."}); + {error, elogin} -> + corba:raise(#'CosFileTransfer_SessionException' + {reason="User not logged in."}); + {error, econn} -> + corba:raise(#'CosFileTransfer_RequestFailureException' + {reason="Premature connection ending."}); + Other -> + Other + end. + + + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosFileTransfer/src/CosFileTransfer_File_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_File_impl.erl new file mode 100644 index 0000000..7ee189f --- /dev/null +++ b/lib/cosFileTransfer/src/CosFileTransfer_File_impl.erl @@ -0,0 +1,384 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosFileTransfer_File_impl.erl +%% Description : +%% +%% Created : 5 Feb 2001 +%%---------------------------------------------------------------------- +-module('CosFileTransfer_File_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). + +-include_lib("cosProperty/include/CosPropertyService.hrl"). + +-include("cosFileTransferApp.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2]). + +%% Interface functions +-export(['_get_name'/2, + '_get_complete_file_name'/2, + '_get_parent'/2, + '_get_associated_session'/2]). + +%% Inherited CosPropertyService::PropertySetDef +-export([get_allowed_property_types/2, + get_allowed_properties/2, + define_property_with_mode/5, + define_properties_with_modes/3, + get_property_mode/3, + get_property_modes/3, + set_property_mode/4, + set_property_modes/3]). + +%% Inherited CosPropertyService::PropertySet +-export([define_property/4, + define_properties/3, + get_number_of_properties/2, + get_all_property_names/3, + get_property_value/3, + get_properties/3, + get_all_properties/3, + delete_property/3, + delete_properties/3, + delete_all_properties/2, + is_property_defined/3]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {property, + name, + completeName, + parent, + assocSession}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +-define(create_InitState(Pr, N, C, Pa, A), + #state{property = Pr, + name = N, + completeName = C, + parent = Pa, + assocSession = A}). + +-define(get_PropertyRef(S), S#state.property). +-define(get_Name(S), S#state.name). +-define(get_CompleteName(S), S#state.completeName). +-define(get_Parent(S), S#state.parent). +-define(get_AssocSession(S), S#state.assocSession). + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([Name, CompleteName, Parent, AssocSession]) -> + PropTypes = [tk_boolean], + PropDefs = [#'CosPropertyService_PropertyDef' + {property_name = "is_directory", + property_value = #any{typecode=tk_boolean, value=false}, + property_mode = fixed_readonly}], + Prop = cosProperty:create_static_SetDef(PropTypes, PropDefs), + {ok, ?create_InitState(Prop, Name, CompleteName, Parent, AssocSession)}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%====================================================================== +%% CosFileTransfer::File +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : '_get_name' +%% Arguments : - +%% Returns : CosFileTransfer::FileName - string +%% Description: +%%---------------------------------------------------------------------- +'_get_name'(_OE_This, State) -> + {reply, ?get_Name(State), State}. + +%%---------------------------------------------------------------------% +%% Function : '_get_complete_file_name' +%% Arguments : - +%% Returns : CosFileTransfer::FileNameList - a list of strings's +%% Description: +%%---------------------------------------------------------------------- +'_get_complete_file_name'(_OE_This, State) -> + {reply, ?get_CompleteName(State), State}. + +%%---------------------------------------------------------------------% +%% Function : '_get_parent' +%% Arguments : - +%% Returns : CosFileTransfer::Directory +%% Description: +%%---------------------------------------------------------------------- +'_get_parent'(_OE_This, State) -> + {reply, ?get_Parent(State), State}. + +%%---------------------------------------------------------------------% +%% Function : '_get_associated_session' +%% Arguments : - +%% Returns : CosFileTransfer::FileTransferSession +%% Description: +%%---------------------------------------------------------------------- +'_get_associated_session'(_OE_This, State) -> + {reply, ?get_AssocSession(State), State}. + +%%====================================================================== +%% CosPropertyService::PropertySetDef +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : get_allowed_property_types +%% Arguments : - +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_allowed_property_types(_OE_This, State) -> + {reply, 'CosPropertyService_PropertySetDef': + get_allowed_property_types(?get_PropertyRef(State)), State}. + +%%---------------------------------------------------------------------% +%% Function : get_allowed_properties +%% Arguments : - +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_allowed_properties(_OE_This, State) -> + {reply, 'CosPropertyService_PropertySetDef': + get_allowed_properties(?get_PropertyRef(State)), State}. + +%%---------------------------------------------------------------------% +%% Function : define_property_with_mode +%% Arguments : Name - string() +%% Value - #any{} +%% Mode - normal | read_only | fixed_normal | fixed_readonly +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +define_property_with_mode(_OE_This, State, Name, Value, Mode) -> + {reply, 'CosPropertyService_PropertySetDef': + define_property_with_mode(?get_PropertyRef(State), Name, Value, Mode), State}. + +%%---------------------------------------------------------------------% +%% Function : define_properties_with_modes +%% Arguments : PropertyDefs - list of #'CosPropertyService_PropertyDef'{} +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +define_properties_with_modes(_OE_This, State, PropertyDefs) -> + {reply, 'CosPropertyService_PropertySetDef': + define_properties_with_modes(?get_PropertyRef(State), PropertyDefs), State}. + +%%---------------------------------------------------------------------% +%% Function : get_property_mode +%% Arguments : Name - string() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_property_mode(_OE_This, State, Name) -> + {reply, 'CosPropertyService_PropertySetDef': + get_property_mode(?get_PropertyRef(State), Name), State}. + + +%%---------------------------------------------------------------------% +%% Function : get_property_modes +%% Arguments : Names - a list of Name (i.e. string()'s). +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_property_modes(_OE_This, State, Names) -> + {reply, 'CosPropertyService_PropertySetDef': + get_property_modes(?get_PropertyRef(State), Names), State}. + +%%---------------------------------------------------------------------% +%% Function : set_property_mode +%% Arguments : Name - string() +%% Mode - normal | read_only | fixed_normal | fixed_readonly +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +set_property_mode(_OE_This, State, Name, Mode) -> + {reply, 'CosPropertyService_PropertySetDef': + set_property_mode(?get_PropertyRef(State), Name, Mode), State}. + + +%%---------------------------------------------------------------------% +%% Function : set_property_modes +%% Arguments : Modes - a list of #'CosPropertyService_PropertyModes'{} +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +set_property_modes(_OE_This, State, PropertyModes) -> + {reply, 'CosPropertyService_PropertySetDef': + set_property_modes(?get_PropertyRef(State), PropertyModes), State}. + +%%====================================================================== +%% CosPropertyService::PropertySet +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : define_property +%% Arguments : Name - string() +%% Value - #any{} +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +define_property(_OE_This, State, Name, Value) -> + {reply, 'CosPropertyService_PropertySet': + define_property(?get_PropertyRef(State), Name, Value), State}. + +%%---------------------------------------------------------------------% +%% Function : define_properties +%% Arguments : Properties - a list of #'CosPropertyService_Property'{} +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +define_properties(_OE_This, State, Properties) -> + {reply, 'CosPropertyService_PropertySet': + define_properties(?get_PropertyRef(State), Properties), State}. + + +%%---------------------------------------------------------------------% +%% Function : get_number_of_properties +%% Arguments : - +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_number_of_properties(_OE_This, State) -> + {reply, 'CosPropertyService_PropertySet': + get_number_of_properties(?get_PropertyRef(State)), State}. + +%%---------------------------------------------------------------------% +%% Function : get_all_property_names +%% Arguments : Max - ulong() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_all_property_names(_OE_This, State, Max) -> + {reply, 'CosPropertyService_PropertySet': + get_all_property_names(?get_PropertyRef(State), Max), State}. + +%%---------------------------------------------------------------------% +%% Function : get_property_value +%% Arguments : Name - string() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_property_value(_OE_This, State, Name) -> + {reply, 'CosPropertyService_PropertySet': + get_property_value(?get_PropertyRef(State), Name), State}. + +%%---------------------------------------------------------------------% +%% Function : get_properties +%% Arguments : Names - a list of Name (i.e. string()'s) +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_properties(_OE_This, State, Names) -> + {reply, 'CosPropertyService_PropertySet': + get_properties(?get_PropertyRef(State), Names), State}. + + +%%---------------------------------------------------------------------% +%% Function : get_all_properties +%% Arguments : Max - ulong() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +get_all_properties(_OE_This, State, Max) -> + {reply, 'CosPropertyService_PropertySet': + get_all_properties(?get_PropertyRef(State), Max), State}. + + +%%---------------------------------------------------------------------% +%% Function : delete_property +%% Arguments : Name - string() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +delete_property(_OE_This, State, Name) -> + {reply, 'CosPropertyService_PropertySet': + delete_property(?get_PropertyRef(State), Name), State}. + + +%%---------------------------------------------------------------------% +%% Function : delete_properties +%% Arguments : Names - a list of Name (i.e. string()'s) +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +delete_properties(_OE_This, State, Names) -> + {reply, 'CosPropertyService_PropertySet': + delete_properties(?get_PropertyRef(State), Names), State}. + + +%%---------------------------------------------------------------------% +%% Function : delete_all_properties +%% Arguments : - +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +delete_all_properties(_OE_This, State) -> + {reply, 'CosPropertyService_PropertySet': + delete_all_properties(?get_PropertyRef(State)), State}. + +%%---------------------------------------------------------------------% +%% Function : is_property_defined +%% Arguments : Name - string() +%% Returns : See cosProperty application. +%% Description: +%%---------------------------------------------------------------------- +is_property_defined(_OE_This, State, Name) -> + {reply, 'CosPropertyService_PropertySet': + is_property_defined(?get_PropertyRef(State), Name), State}. + +%%====================================================================== +%% Internal functions +%%====================================================================== + +%%====================================================================== +%% END OF MODULE +%%====================================================================== + diff --git a/lib/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_impl.erl new file mode 100644 index 0000000..7a775f2 --- /dev/null +++ b/lib/cosFileTransfer/src/CosFileTransfer_VirtualFileSystem_impl.erl @@ -0,0 +1,216 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosFileTransfer_VirtualFileSystem_impl.erl +%% Description : +%% +%% Created : 12 Sept 2000 +%%---------------------------------------------------------------------- +-module('CosFileTransfer_VirtualFileSystem_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). + +-include_lib("cosFileTransfer/include/CosFileTransfer.hrl"). +-include("cosFileTransferApp.hrl"). + + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%% Interface functions +-export(['_get_file_system_type'/2, + '_get_supported_content_types'/2, + login/5]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {type, content, host, port, protocol, timeout, module}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +-define(create_InitState(T, C, H, P, Pr, TO), + #state{type=T, + content=C, + host=H, + port=P, + protocol=Pr, + timeout=TO}). +-define(create_NativeInitState(T, C, H, P, Pr, TO, M), + #state{type=T, + content=C, + host=H, + port=P, + protocol=Pr, + timeout=TO, + module=M}). + +-define(get_Type(S), S#state.type). +-define(get_Content(S), S#state.content). +-define(get_Host(S), S#state.host). +-define(get_Port(S), S#state.port). +-define(get_StartDir(S), S#state.startdir). +-define(get_Module(S), S#state.module). +-define(get_Protocol(S), S#state.protocol). +-define(get_Timeout(S), S#state.timeout). + +-define(is_FTP(S), S#state.type == 'FTP'). +-define(is_FTAM(S), S#state.type == 'FTAM'). +-define(is_NATIVE(S), S#state.type == 'NATIVE'). + + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([{Type, Mod}, Content, Host, Port, Options]) -> + Prot = cosFileTransferApp:get_option(protocol, Options, ?DEFAULT_CONFIG), + Time = timer:seconds(cosFileTransferApp:get_option(connect_timeout, Options, + ?DEFAULT_CONFIG)), + {ok, ?create_NativeInitState(Type, Content, Host, Port, Prot, Time, Mod)}; +init([Type, Content, Host, Port, Options]) -> + Prot = cosFileTransferApp:get_option(protocol, Options, ?DEFAULT_CONFIG), + Time = timer:seconds(cosFileTransferApp:get_option(connect_timeout, Options, + ?DEFAULT_CONFIG)), + {ok, ?create_InitState(Type, Content, Host, Port, Prot, Time)}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% function : handle_info/2 +%% Arguments: +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +handle_info(_Info, State) -> + {noreply, State}. + +%%====================================================================== +%% CosFileTransfer::VirtualFileSystem +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : '_get_file_system_type' +%% Arguments : - +%% Returns : CosFileTransfer::NativeFileSystemType, i.e., 'FTP', 'FTAM', +%% or 'NATIVE'. Currently only 'FTP' is allowed. +%% Description: +%%---------------------------------------------------------------------- +'_get_file_system_type'(_OE_This, State) -> + {reply, ?get_Type(State), State}. + +%%---------------------------------------------------------------------% +%% Function : '_get_supported_content_types' +%% Arguments : +%% Returns : +%% Description: +%%---------------------------------------------------------------------- +'_get_supported_content_types'(_OE_This, State) -> + {reply, ?get_Content(State), State}. + +%%---------------------------------------------------------------------- +%% Function : login +%% Arguments : User - string() +%% Password - string() +%% Account - string() +%% Returns : FileTransferSession object and Directory object (out-type). +%% Description: +%%---------------------------------------------------------------------- +login(_OE_This, State, User, Password, Account) when ?is_FTP(State) -> + case catch 'CosFileTransfer_FileTransferSession': + oe_create(['FTP', ?get_Host(State), ?get_Port(State), User, Password, Account, + ?get_Protocol(State), ?get_Timeout(State)], + [{sup_child, true}]) of + {ok, _Pid, FTS} -> + Dir = 'CosFileTransfer_FileTransferSession': + oe_orber_create_directory_current(FTS), + {reply, {FTS, Dir}, State}; + What -> + orber:debug_level_print("[~p] CosFileTransfer_VirtualFileSystem:login(~p ~p ~p ~p); +Unable to create a FileTransferSession: ~p", + [?LINE, ?get_Host(State), ?get_Port(State), User, + ?get_Protocol(State), What], + ?DEBUG_LEVEL), + corba:raise(#'CosFileTransfer_SessionException'{reason="Failed creating a FTS"}) + end; +login(_OE_This, State, User, Password, Account) when ?is_NATIVE(State) -> + case catch 'CosFileTransfer_FileTransferSession': + oe_create([{'NATIVE', ?get_Module(State)}, ?get_Host(State), + ?get_Port(State), User, Password, Account, + ?get_Protocol(State), ?get_Timeout(State)], + [{sup_child, true}]) of + {ok, _Pid, FTS} -> + Dir = 'CosFileTransfer_FileTransferSession': + oe_orber_create_directory_current(FTS), + {reply, {FTS, Dir}, State}; + What -> + orber:debug_level_print("[~p] CosFileTransfer_VirtualFileSystem:login(~p ~p ~p ~p); +Unable to create a FileTransferSession: ~p", + [?LINE, ?get_Host(State), ?get_Port(State), User, + ?get_Protocol(State), What], + ?DEBUG_LEVEL), + corba:raise(#'CosFileTransfer_SessionException'{reason="Failed creating a FTS"}) + end. + +%%====================================================================== +%% Internal functions +%%====================================================================== + + + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosFileTransfer/src/Makefile b/lib/cosFileTransfer/src/Makefile new file mode 100644 index 0000000..773ed7f --- /dev/null +++ b/lib/cosFileTransfer/src/Makefile @@ -0,0 +1,182 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug -W +endif + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(COSFILETRANSFER_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/cosFileTransfer-$(VSN) + +EXTERNAL_INC_PATH = ../include + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + cosFileTransferApp \ + CosFileTransfer_Directory_impl \ + CosFileTransfer_File_impl \ + CosFileTransfer_VirtualFileSystem_impl \ + CosFileTransfer_FileTransferSession_impl \ + CosFileTransfer_FileIterator_impl \ + cosFileTransferNATIVE_file \ + +ERL_FILES = $(MODULES:%=%.erl) +HRL_FILES = \ + cosFileTransferApp.hrl \ + +GEN_ERL_FILES = \ + oe_CosFileTransfer.erl \ + CosFileTransfer.erl \ + CosFileTransfer_AccessLevel.erl \ + CosFileTransfer_CommandNotImplementedException.erl \ + CosFileTransfer_Directory.erl \ + CosFileTransfer_File.erl \ + CosFileTransfer_FileIterator.erl \ + CosFileTransfer_FileList.erl \ + CosFileTransfer_FileNameList.erl \ + CosFileTransfer_FileNotFoundException.erl \ + CosFileTransfer_FileTransferSession.erl \ + CosFileTransfer_FileWrapper.erl \ + CosFileTransfer_IllegalOperationException.erl \ + CosFileTransfer_ProtocolAddressList.erl \ + CosFileTransfer_ProtocolSupport.erl \ + CosFileTransfer_RequestFailureException.erl \ + CosFileTransfer_SessionException.erl \ + CosFileTransfer_SupportedProtocolAddresses.erl \ + CosFileTransfer_TransferException.erl \ + CosFileTransfer_VirtualFileSystem.erl \ + CosFileTransfer_VirtualFileSystem_ContentList.erl \ + +LOCAL_HRL_FILES = \ + oe_CosFileTransfer.hrl \ + CosFileTransfer.hrl \ + CosFileTransfer_Directory.hrl \ + CosFileTransfer_File.hrl \ + CosFileTransfer_FileIterator.hrl \ + CosFileTransfer_FileTransferSession.hrl \ + CosFileTransfer_VirtualFileSystem.hrl \ + +GEN_HRL_FILES = $(LOCAL_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_FILES = \ + $(GEN_HRL_FILES) \ + $(GEN_ERL_FILES) + +TARGET_FILES = \ + $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +IDL_FILES = \ + CosFileTransfer.idl + +APPUP_FILE = cosFileTransfer.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + +APP_FILE = cosFileTransfer.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosFileTransfer/ebin \ + -pa $(ERL_TOP)/lib/cosProperty/ebin \ + -pa $(ERL_TOP)/lib/cosProperty/src \ + -I$(ERL_TOP)/lib/cosProperty/src \ + -pa $(ERL_TOP)/lib/ic/ebin \ + -pa $(ERL_TOP)/lib/orber/ebin + +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -pa $(ERL_TOP)/lib/orber/include \ + -pa $(ERL_TOP)/lib/cosFileTransfer/include \ + -pa $(ERL_TOP)/lib/cosProperty/include \ + -pa $(ERL_TOP)/lib/cosProperty/src \ + -I$(ERL_TOP)/lib/orber/include \ + -I$(ERL_TOP)/lib/cosFileTransfer/include \ + -I$(ERL_TOP)/lib/cosProperty/include \ + -I$(ERL_TOP)/lib/cosProperty/src \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,"cosFileTransfer_$(COSFILETRANSFER_VSN)"}' + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + +debug: + @${MAKE} TYPE=debug opt + +cleanb: + rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +clean: + rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +$(GEN_ERL_FILES) $(GEN_HRL_FILES): CosFileTransfer.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosFileTransfer.cfg"}' CosFileTransfer.idl + mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH) + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include + +release_docs_spec: diff --git a/lib/cosFileTransfer/src/cosFileTransfer.app.src b/lib/cosFileTransfer/src/cosFileTransfer.app.src new file mode 100644 index 0000000..31d94b6 --- /dev/null +++ b/lib/cosFileTransfer/src/cosFileTransfer.app.src @@ -0,0 +1,41 @@ +{application, cosFileTransfer, + [{description, "The Erlang CosFileTransfer application"}, + {vsn, "%VSN%"}, + {modules, + [ + 'cosFileTransferApp', + 'CosFileTransfer_Directory_impl', + 'CosFileTransfer_File_impl', + 'CosFileTransfer_VirtualFileSystem_impl', + 'CosFileTransfer_FileTransferSession_impl', + 'CosFileTransfer_FileIterator_impl', + 'cosFileTransferNATIVE_file', + 'oe_CosFileTransfer', + 'CosFileTransfer', + 'CosFileTransfer_AccessLevel', + 'CosFileTransfer_CommandNotImplementedException', + 'CosFileTransfer_Directory', + 'CosFileTransfer_File', + 'CosFileTransfer_FileIterator', + 'CosFileTransfer_FileList', + 'CosFileTransfer_FileNameList', + 'CosFileTransfer_FileNotFoundException', + 'CosFileTransfer_FileTransferSession', + 'CosFileTransfer_FileWrapper', + 'CosFileTransfer_IllegalOperationException', + 'CosFileTransfer_ProtocolAddressList', + 'CosFileTransfer_ProtocolSupport', + 'CosFileTransfer_RequestFailureException', + 'CosFileTransfer_SessionException', + 'CosFileTransfer_SupportedProtocolAddresses', + 'CosFileTransfer_TransferException', + 'CosFileTransfer_VirtualFileSystem', + 'CosFileTransfer_VirtualFileSystem_ContentList' + ] + }, + {registered, []}, + {applications, [orber, stdlib, kernel]}, + {env, []}, + {mod, {cosFileTransferApp, []}} +]}. + diff --git a/lib/cosFileTransfer/src/cosFileTransfer.appup.src b/lib/cosFileTransfer/src/cosFileTransfer.appup.src new file mode 100644 index 0000000..6c3b283 --- /dev/null +++ b/lib/cosFileTransfer/src/cosFileTransfer.appup.src @@ -0,0 +1,7 @@ +{"%VSN%", + [ + ], + [ + ] +}. + diff --git a/lib/cosFileTransfer/src/cosFileTransferApp.erl b/lib/cosFileTransfer/src/cosFileTransferApp.erl new file mode 100644 index 0000000..443c917 --- /dev/null +++ b/lib/cosFileTransfer/src/cosFileTransferApp.erl @@ -0,0 +1,469 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosFileTransferApp.erl +%% Purpose : +%% Created : 25 Aug 2000 +%%---------------------------------------------------------------------- +-module(cosFileTransferApp). + + +%%--------------- INCLUDES ----------------------------------- +-include("cosFileTransferApp.hrl"). + +%%--------------- EXPORTS------------------------------------- +%% cosFileTransferApp API external +-export([start/0, stop/0, install/0, uninstall/0, create_VFS/4, create_VFS/5, + get_buffert_size/0]). + +%% cosFileTransferApp API internal +-export([create_link/3, get_option/3, type_check/2, configure/2]). + +%% Application callbacks +-export([start/2, init/1, stop/1]). + +%% INTERNAL EXPORTS!! DO NOT USE THESE!! +-export([create_dir/2, create_dir/3, create_file/2, create_file/3, split_paths/1, + create_name/1]). + +-export([ssl_server_certfile/0, ssl_client_certfile/0, ssl_port/0, + ssl_server_verify/0, + ssl_client_verify/0, + ssl_server_depth/0, ssl_client_depth/0, + ssl_server_cacertfile/0, + ssl_client_cacertfile/0]). + + +%%--------------- DEFINES ------------------------------------ +-define(SUPERVISOR_NAME, oe_cosFileTransferSup). +-define(SUP_FLAG, {simple_one_for_one,50,10}). +-define(SUP_DIRECTORY_SPEC(Name, Args), + ['CosFileTransfer_Directory',Args, + [{sup_child, true}, {regname, {global, Name}}]]). +-define(SUP_CHILD, + {"oe_FileTransferChild", + {cosFileTransfer,create_link, []}, + transient,100000,worker, + []}). + +%%------------------------------------------------------------ +%% function : install +%% Arguments: - +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ +install() -> + oe_CosFileTransfer:oe_register(). + +%%------------------------------------------------------------ +%% function : uninstall +%% Arguments: - +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosFileTransfer from the IFR DB +%%------------------------------------------------------------ +uninstall() -> + oe_CosFileTransfer:oe_unregister(). + + +%%------------------------------------------------------------ +%% function : start/stop +%% Arguments: +%% Returns : +%% Effect : Starts or stops the cosFileTransfer application. +%%------------------------------------------------------------ +start() -> + application:start(cosFileTransfer). +stop() -> + application:stop(cosFileTransfer). + +%%------------------------------------------------------------ +%% function : start +%% Arguments: Type - see module application +%% Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ +start(_, _) -> + supervisor:start_link({local, ?SUPERVISOR_NAME}, cosFileTransferApp, app_init). + + +%%------------------------------------------------------------ +%% function : stop +%% Arguments: Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ +stop(_) -> + ok. + +%%-----------------------------------------------------------% +%% function : init +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +%% Starting using create_factory/X +init(own_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}; +%% When starting as an application. +init(app_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}. + +%%------------------------------------------------------------ +%% function : create_VFS +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +create_VFS(Type, Content, Host, Port) -> + create_VFS(Type, Content, Host, Port, []). + +create_VFS('FTP', Content, Host, Port, Options) + when is_list(Host) andalso is_integer(Port) andalso is_list(Options) -> + 'CosFileTransfer_VirtualFileSystem':oe_create(['FTP', Content, Host, Port, + Options], + [{pseudo, true}]); +create_VFS({'NATIVE', Mod}, Content, Host, Port, Options) + when is_list(Host) andalso is_integer(Port) andalso is_list(Options) -> + 'CosFileTransfer_VirtualFileSystem':oe_create([{'NATIVE', Mod}, Content, + Host, Port, Options], + [{pseudo, true}]); +create_VFS(_, _, _, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%-----------------------------------------------------------% +%% function : create_link +%% Arguments: Module - which Module to call +%% Env/ArgList - ordinary oe_create arguments. +%% Returns : +%% Exception: +%% Effect : Necessary since we want the supervisor to be a +%% 'simple_one_for_one'. Otherwise, using for example, +%% 'one_for_one', we have to call supervisor:delete_child +%% to remove the childs startspecification from the +%% supervisors internal state. +%%------------------------------------------------------------ +create_link(Module, Env, ArgList) -> + Module:oe_create_link(Env, ArgList). + +%%-----------------------------------------------------------% +%% function : get_option +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +get_option(Key, OptionList, DefaultList) -> + case lists:keysearch(Key, 1, OptionList) of + {value,{Key,Value}} -> + Value; + _ -> + case lists:keysearch(Key, 1, DefaultList) of + {value,{Key,Value}} -> + Value; + _-> + {error, "Invalid option"} + end + end. + +%%-----------------------------------------------------------% +%% function : type_check +%% Arguments: Obj - objectrefernce to test. +%% Mod - Module which contains typeID/0. +%% Returns : 'ok' or raises exception. +%% Effect : +%%------------------------------------------------------------ +type_check(Obj, Mod) -> + case catch corba_object:is_a(Obj,Mod:typeID()) of + true -> + ok; + _ -> + corba:raise(#'BAD_PARAM'{minor=700, completion_status=?COMPLETED_NO}) + end. + + +%%-----------------------------------------------------------% +%% function : create_name/1 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_name(Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',MSec, '_', Sec, '_', USec]). + + +%%-----------------------------------------------------------% +%% function : get_buffert_size/0 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : Lookup the configuration variable 'buffert_size' +%%------------------------------------------------------------ +get_buffert_size() -> + case application:get_env(cosFileTransfer, buffert_size) of + {ok, Size} when is_integer(Size) -> + Size; + _ -> + ?DEFAULT_BUFSIZE + end. + +%%-----------------------------------------------------------% +%% function : configure/1 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +configure(buffert_size, Value) when is_integer(Value) -> + do_configure(buffert_size, Value); +configure(ssl_port, Value) when is_integer(Value) -> + do_safe_configure(ssl_port, Value); +configure(ssl_server_certfile, Value) when is_list(Value) -> + do_safe_configure(ssl_server_certfile, Value); +configure(ssl_server_certfile, Value) when is_atom(Value) -> + do_safe_configure(ssl_server_certfile, atom_to_list(Value)); +configure(ssl_client_certfile, Value) when is_list(Value) -> + do_safe_configure(ssl_client_certfile, Value); +configure(ssl_client_certfile, Value) when is_atom(Value) -> + do_safe_configure(ssl_client_certfile, atom_to_list(Value)); +configure(ssl_server_verify, Value) when is_integer(Value) -> + do_safe_configure(ssl_server_verify, Value); +configure(ssl_client_verify, Value) when is_integer(Value) -> + do_safe_configure(ssl_client_verify, Value); +configure(ssl_server_depth, Value) when is_integer(Value) -> + do_safe_configure(ssl_server_depth, Value); +configure(ssl_client_depth, Value) when is_integer(Value) -> + do_safe_configure(ssl_client_depth, Value); +configure(ssl_server_cacertfile, Value) when is_list(Value) -> + do_safe_configure(ssl_server_cacertfile, Value); +configure(ssl_server_cacertfile, Value) when is_atom(Value) -> + do_safe_configure(ssl_server_cacertfile, atom_to_list(Value)); +configure(ssl_client_cacertfile, Value) when is_list(Value) -> + do_safe_configure(ssl_client_cacertfile, Value); +configure(ssl_client_cacertfile, Value) when is_atom(Value) -> + do_safe_configure(ssl_client_cacertfile, atom_to_list(Value)); +configure(_, _) -> + exit({error, "Bad configure parameter(s)"}). + +%% This function may be used as long as it is safe to change a value at any time. +do_configure(Key, Value) -> + case is_loaded() of + false -> + application:load(cosFileTransfer), + application_controller:set_env(cosFileTransfer, Key, Value); + true -> + application_controller:set_env(cosFileTransfer, Key, Value) + end. + + +%% This function MUST(!!) be used when we cannot change a value if cosFileTransfer +%% is running. +do_safe_configure(Key, Value) -> + case is_loaded() of + false -> + application:load(cosFileTransfer), + application_controller:set_env(cosFileTransfer, Key, Value); + true -> + case is_running() of + false -> + application_controller:set_env(cosFileTransfer, Key, Value); + true -> + exit("cosFileTransfer already running, the given key may not be updated!") + end + end. + +%%-----------------------------------------------------------% +%% function : SSL parameter access functions +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +ssl_port() -> + case application:get_env(cosFileTransfer, ssl_port) of + {ok, Port} when is_integer(Port) -> + Port; + _ -> + -1 + end. + +ssl_server_certfile() -> + case application:get_env(cosFileTransfer, ssl_server_certfile) of + {ok, V1} when is_list(V1) -> + V1; + {ok, V2} when is_atom(V2) -> + atom_to_list(V2); + _What -> + {ok, Cwd} = file:get_cwd(), + filename:join(Cwd,"ssl_server_cert.pem") + end. + + +ssl_client_certfile() -> + case application:get_env(cosFileTransfer, ssl_client_certfile) of + {ok, V1} when is_list(V1) -> + V1; + {ok, V2} when is_atom(V2) -> + atom_to_list(V2); + _ -> + {ok, Cwd} = file:get_cwd(), + filename:join(Cwd,"ssl_client_cert.pem") + end. + +ssl_server_verify() -> + Verify = case application:get_env(cosFileTransfer, ssl_server_verify) of + {ok, V} when is_integer(V) -> + V; + _ -> + 0 + end, + if + Verify =< 2, Verify >= 0 -> + Verify; + true -> + 0 + end. + +ssl_client_verify() -> + Verify = case application:get_env(cosFileTransfer, ssl_client_verify) of + {ok, V1} when is_integer(V1) -> + V1; + _ -> + 0 + end, + if + Verify =< 2, Verify >= 0 -> + Verify; + true -> + 0 + end. + +ssl_server_depth() -> + case application:get_env(cosFileTransfer, ssl_server_depth) of + {ok, V1} when is_integer(V1) -> + V1; + _ -> + 1 + end. + +ssl_client_depth() -> + case application:get_env(cosFileTransfer, ssl_client_depth) of + {ok, V1} when is_integer(V1) -> + V1; + _ -> + 1 + end. + + +ssl_server_cacertfile() -> + case application:get_env(cosFileTransfer, ssl_server_cacertfile) of + {ok, V1} when is_list(V1) -> + V1; + {ok, V2} when is_atom(V2) -> + atom_to_list(V2); + _ -> + [] + end. + +ssl_client_cacertfile() -> + case application:get_env(cosFileTransfer, ssl_client_cacertfile) of + {ok, V1} when is_list(V1) -> + V1; + {ok, V2} when is_atom(V2) -> + atom_to_list(V2); + _ -> + [] + end. + + +%%============================================================ +%% Internal functions +%%============================================================ +%%-----------------------------------------------------------% +%% function : is_loaded/0 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : Check if the application is loaded +%%------------------------------------------------------------ +is_loaded() -> + is_loaded(application:loaded_applications()). + +is_running() -> + is_loaded(application:which_applications()). + +is_loaded([]) -> + false; +is_loaded([{cosFileTransfer, _, _} |_As]) -> + true; +is_loaded([_ |As]) -> + is_loaded(As). + + + + +%%-----------------------------------------------------------% +%% function : create_dir/3/4 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_dir(Session, FileNameList) -> + create_dir(Session, FileNameList, corba:create_nil_objref()). +create_dir(Session, FileNameList, Parent) -> + 'CosFileTransfer_Directory':oe_create([lists:last(FileNameList), FileNameList, + Parent, Session], + [{pseudo, true}]). + +%%-----------------------------------------------------------% +%% function : create_file/2/3 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_file(Session, FileNameList) -> + create_file(Session, FileNameList, corba:create_nil_objref()). +create_file(Session, FileNameList, Parent) -> + 'CosFileTransfer_File':oe_create([lists:last(FileNameList), FileNameList, + Parent, Session], [{pseudo, true}]). + +%%-----------------------------------------------------------% +%% function : split_paths +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +split_paths(Listing) -> + split_paths(string:tokens(Listing, ?SEPARATOR), []). +split_paths([], Acc) -> + Acc; +split_paths([H|T], Acc) -> + split_paths(T, [filename:split(H)|Acc]). + + +%%--------------- END OF MODULE ------------------------------ + + diff --git a/lib/cosFileTransfer/src/cosFileTransferApp.hrl b/lib/cosFileTransfer/src/cosFileTransferApp.hrl new file mode 100644 index 0000000..36700a6 --- /dev/null +++ b/lib/cosFileTransfer/src/cosFileTransferApp.hrl @@ -0,0 +1,68 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosFileTransferApp.hrl +%% Purpose : +%% Created : 10 Feb 2000 +%%---------------------------------------------------------------------- + + +%%--------------- INCLUDES ----------------------------------- +%% External +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +-include_lib("cosProperty/include/CosPropertyService.hrl"). + +%% Local +-include_lib("cosFileTransfer/include/CosFileTransfer.hrl"). + +-define(write_ErrorMsg(Txt, Arg), +error_logger:error_msg("============= CosFileTransfer =============~n" + Txt + "===========================================~n", + Arg)). + +-define(FTP_PORT_INT, 21). +-define(FTP_PORT_STR, "21"). +-define(TCP_ID, "TCP"). +-define(FTP_ID, "FTP"). +-define(FTAM_ID, "FTAM"). +-define(NATIVE_ID, "NATIVE"). +-define(SUPPURTED_PROTOCOLS, ["TCP/IP", "SSL"]). + +-define(DEFAULT_CONFIG, [{protocol, tcp}, {connect_timeout, 60}]). + +-define(SEPARATOR, "\r\n"). + +-define(DEFAULT_BUFSIZE, 64000). + +-define(DEBUG_LEVEL, 3). + +-ifdef(debug). +-define(debug_print(F,A), + io:format("[LINE: ~p MODULE: ~p] "++F,[?LINE, ?MODULE]++A)). +-define(ft_TypeCheck(O,M), 'cosFileTransferApp':type_check(O,M)). +-else. +-define(debug_print(F,A), ok). +-define(ft_TypeCheck(O,I), ok). +-endif. + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosFileTransfer/src/cosFileTransferNATIVE_file.erl b/lib/cosFileTransfer/src/cosFileTransferNATIVE_file.erl new file mode 100644 index 0000000..634dfd4 --- /dev/null +++ b/lib/cosFileTransfer/src/cosFileTransferNATIVE_file.erl @@ -0,0 +1,358 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosFileTransferNATIVE_file.erl +%% Description : +%% +%% Created : 9 Nov 2000 +%%---------------------------------------------------------------------- +-module('cosFileTransferNATIVE_file'). + + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include("cosFileTransferApp.hrl"). +-include_lib("kernel/include/file.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([open/1, + open/2, + open/3, + user/3, + pwd/1, + cd/2, + mkdir/2, + rmdir/2, + nlist/1, + nlist/2, + delete/2, + recv/2, + recv/3, + send/2, + send/3, + close/1, + insert/4]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% function : open +%% Arguments: +%% Returns : {ok, Ref} | {error, ehost} for future use +%% Effect : +%%---------------------------------------------------------------------- +open(_Host) -> + {ok, 'NATIVE'}. +open(_Host, _Port) -> + {ok, 'NATIVE'}. +open(_Host, _Port, _Flags) -> + {ok, 'NATIVE'}. + +%%---------------------------------------------------------------------- +%% function : user +%% Arguments: Ref - what's returned by open/1/2 +%% User = Password = string() +%% Returns : ok | {error, euser | econn} for future use +%% Effect : +%%---------------------------------------------------------------------- +user(_Ref, _User, _Password) -> + ok. + +%%---------------------------------------------------------------------- +%% function : pwd +%% Arguments: Ref - what's returned by open/1/2 +%% Returns : {ok, string()} | {error, elogin | econn} +%% Effect : +%%---------------------------------------------------------------------- +pwd(_Ref) -> + case file:get_cwd() of + {ok, Cwd} -> + {ok, Cwd}; + _ -> + {error, econn} + end. + +%%---------------------------------------------------------------------- +%% function : cd +%% Arguments: Ref - what's returned by open/1/2 +%% Dir - string() +%% Returns : ok | {error, epath | elogin | econn} +%% Effect : +%%---------------------------------------------------------------------- +cd(_Ref, Dir) -> + case file:set_cwd(Dir) of + ok -> + ok; + {error, _} -> + {error, epath} + end. + +%%---------------------------------------------------------------------- +%% function : mkdir +%% Arguments: Ref - what's returned by open/1/2 +%% Dir - string() +%% Returns : ok | {error, epath} +%% Effect : +%%---------------------------------------------------------------------- +mkdir(_Ref, Dir) -> + case file:make_dir(Dir) of + ok -> + ok; + {error, _Reason} -> + {error, epath} + end. + +%%---------------------------------------------------------------------- +%% function : rmdir +%% Arguments: Ref - what's returned by open/1/2 +%% Dir - string() +%% Returns : ok | {error, epath} +%% Effect : +%%---------------------------------------------------------------------- +rmdir(_Ref, Dir) -> + case file:del_dir(Dir) of + ok -> + ok; + {error, _Reason} -> + {error, epath} + end. + +%%---------------------------------------------------------------------- +%% function : nlist +%% Arguments: Ref - what's returned by open/1/2 +%% Dir - string() +%% Returns : {ok, Listing} | {error, epath | elogin | econn} +%% Effect : +%%---------------------------------------------------------------------- +nlist(_Ref) -> + case file:get_cwd() of + {ok, Cwd} -> + %% Here we can assume that it's a Directory is tested. + convert_to_nlist(file:list_dir(Cwd)); + _ -> + {error, epath} + end. +nlist(_Ref, Dir) -> + case file:list_dir(Dir) of + {error, _} -> + %% Might be a File + case file:read_file_info(Dir) of + {ok, _} -> + convert_to_nlist_helper([Dir], []); + _ -> + {error, epath} + end; + {ok, Content} -> + convert_to_nlist_helper(Content, []) + end. + +convert_to_nlist({error, _}) -> + {error, epath}; +convert_to_nlist({ok, Content}) -> + convert_to_nlist_helper(Content, []). + +convert_to_nlist_helper([], Acc) -> + {ok, lists:concat(Acc)}; +convert_to_nlist_helper([H|T], Acc) -> + convert_to_nlist_helper(T, [H, "\r\n"|Acc]). + +%%---------------------------------------------------------------------- +%% function : delete +%% Arguments: Ref - what's returned by open/1/2 +%% File - string() +%% Returns : ok | {error, epath} +%% Effect : +%%---------------------------------------------------------------------- +delete(_Ref, File) -> + case file:delete(File) of + ok -> + ok; + {error, _Reason} -> + {error, epath} + end. + +%%---------------------------------------------------------------------- +%% function : recv +%% Arguments: Ref - what's returned by open/1/2 +%% Returns : ok | {error, epath | elogin | econn} +%% Effect : +%%---------------------------------------------------------------------- +recv(_Ref, _Remote) -> + ok. +recv(_Ref, Remote, Local) -> + copy_file(Remote, Local). + +%%---------------------------------------------------------------------- +%% function : send +%% Arguments: Ref - what's returned by open/1/2 +%% Returns : ok | {error, epath | elogin | econn | etnospc | epnospc | efnamena} +%% Effect : +%%---------------------------------------------------------------------- +send(_Ref, _Local) -> + ok. +send(_Ref, Local, Remote) -> + copy_file(Local, Remote). + +%%---------------------------------------------------------------------- +%% function : close +%% Arguments: Ref - what's returned by open/1/2 +%% Returns : ok +%% Effect : Currently none. +%%---------------------------------------------------------------------- +close(_) -> + ok. + + +%%---------------------------------------------------------------------- +%% function : insert +%% Arguments: Ref - what's returned by open/1/2 +%% Local - absolute file name +%% Remote - absolute file name +%% Offset - long() +%% Returns : ok +%% Effect : +%%---------------------------------------------------------------------- +insert(_Ref, Source, Target, Offset) -> + case file:open(Source, [raw, binary, read]) of + {ok, SourceDev} -> + case file:open(Target, [raw, binary, read, write]) of + {ok, TargetDev} -> + {ok, #file_info{size=SSize}} = + file:read_file_info(Source), + {ok, #file_info{size=TSize}} = + file:read_file_info(Target), + insert_file_helper(SourceDev, TargetDev, SSize, TSize, Offset); + Reason -> + file:close(SourceDev), + convert_error(Reason) + end; + Reason -> + convert_error(Reason) + end. + + +insert_file_helper(SourceDev, TargetDev, SSize, TSize, Offset) -> + BuffSize = cosFileTransferApp:get_buffert_size(), + move_data(TargetDev, TSize, SSize+TSize, TSize-Offset, BuffSize), + insert_data(SourceDev, TargetDev, 0, Offset, BuffSize), + file:close(SourceDev), + file:close(TargetDev). +move_data(_F, _RLocation, _WLocation, Counter, _BuffSize) when Counter == 0 -> + ok; +move_data(F, RLocation, WLocation, Counter, BuffSize) when Counter =< BuffSize -> + case file:pread(F, RLocation-Counter, Counter) of + {ok, Bin} -> + file:pwrite(F, WLocation-Counter, Bin); + eof -> + ok + end; +move_data(F, RLocation, WLocation, Counter, BuffSize) -> + NewRLC = RLocation-BuffSize, + NewWLC = WLocation-BuffSize, + case file:pread(F, NewRLC, BuffSize) of + {ok, Bin} -> + file:pwrite(F, NewWLC, Bin), + move_data(F, NewRLC, NewWLC, Counter-BuffSize, BuffSize); + eof -> + ok + end. + +insert_data(FSRC, FTGT, RLocation, WLocation, BuffSize) -> + case file:pread(FSRC, RLocation, BuffSize) of + {ok, Bin} -> + file:pwrite(FTGT, WLocation, Bin), + insert_data(FSRC, FTGT, RLocation+BuffSize, WLocation+BuffSize, BuffSize); + eof -> + ok + end. + + +%%====================================================================== +%% Internal functions +%%====================================================================== +copy_file(Source, Target) -> + case file:open(Source, [raw, binary, read]) of + {ok, SourceDev} -> + case file:open(Target, [raw, binary, append]) of + {ok, TargetDev} -> + BuffSize = cosFileTransferApp:get_buffert_size(), + copy_file_helper(SourceDev, TargetDev, BuffSize); + Reason -> + file:close(SourceDev), + convert_error(Reason) + end; + Reason -> + convert_error(Reason) + end. + +copy_file_helper(SourceDev, TargetDev, BuffSize) -> + case file:read(SourceDev, BuffSize) of + eof -> + file:close(SourceDev), + file:close(TargetDev); + {ok, Bin} -> + case file:write(TargetDev, Bin) of + ok -> + copy_file_helper(SourceDev, TargetDev, BuffSize); + Reason -> + file:close(SourceDev), + file:close(TargetDev), + convert_error(Reason) + end; + {error, Reason} -> + file:close(SourceDev), + file:close(TargetDev), + convert_error(Reason) + end. + +convert_error({error, eacces}) -> + {error, elogin}; +convert_error({error, enoent}) -> + {error, epath}; +convert_error({error, enotdir}) -> + {error, epath}; +convert_error({error, eidir}) -> + {error, epath}; +convert_error({error, enospc}) -> + {error, etnospc}; +convert_error(_) -> + {error, epath}. + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosFileTransfer/vsn.mk b/lib/cosFileTransfer/vsn.mk new file mode 100644 index 0000000..dd92b53 --- /dev/null +++ b/lib/cosFileTransfer/vsn.mk @@ -0,0 +1,13 @@ +COSFILETRANSFER_VSN = 1.1.9 + +TICKETS = \ + OTP-8201 + + +TICKETS_1.1.8 = OTP-7987 + +TICKETS_1.1.7 = OTP-7837 + +TICKETS_1.1.6 = \ + OTP-7595 \ + OTP-7599 \ No newline at end of file diff --git a/lib/cosNotification/AUTHORS b/lib/cosNotification/AUTHORS new file mode 100644 index 0000000..55d8059 --- /dev/null +++ b/lib/cosNotification/AUTHORS @@ -0,0 +1,4 @@ +Original Authors: +Niclas Eklund + +Contributors: diff --git a/lib/cosNotification/Makefile b/lib/cosNotification/Makefile new file mode 100644 index 0000000..980f361 --- /dev/null +++ b/lib/cosNotification/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(COSNOTIFICATION_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- +# SUB_DIRECTORIES = src test examples doc/src +# At the moment we don't have any example programs. +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/cosNotification/doc/html/.gitignore b/lib/cosNotification/doc/html/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/doc/man3/.gitignore b/lib/cosNotification/doc/man3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/doc/man6/.gitignore b/lib/cosNotification/doc/man6/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/doc/pdf/.gitignore b/lib/cosNotification/doc/pdf/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/doc/src/CosNotification.xml b/lib/cosNotification/doc/src/CosNotification.xml new file mode 100644 index 0000000..22e9bcb --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotification.xml @@ -0,0 +1,234 @@ + + + + +
+ + 2002 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotification + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2002-02-05 + PA1 +
+ CosNotification + This module export functions which return QoS and Admin Properties constants. + +

To get access to all definitions include necessary hrl files by using:

+-include_lib("cosNotification/include/*.hrl").

+
+ + + 'EventReliability'() -> string() + Return the EventReliability QoS identifier + +

This function returns the EventReliability QoS identifier

+
+
+ + 'BestEffort'() -> short() + Return the BestEffort QoS value + +

This function returns the BestEffort QoS value.

+
+
+ + 'Persistent'() -> short() + Return the Persistent QoS value + +

This function returns the Persistent QoS value.

+
+
+ + 'ConnectionReliability'() -> string() + Return the ConnectionReliability QoS identifier + +

This function returns the ConnectionReliability QoS identifier.

+
+
+ + 'Priority'() -> string() + Return the Priority QoS identifier + +

This function returns the Priority QoS identifier.

+
+
+ + 'LowestPriority'() -> short() + Return the LowestPriority QoS value + +

This function returns the LowestPriority QoS value.

+
+
+ + 'HighestPriority'() -> short() + Return the HighestPriority QoS value + +

This function returns the HighestPriority QoS value.

+
+
+ + 'DefaultPriority'() -> short() + Return the DefaultPriority QoS value + +

This function returns the DefaultPriority QoS value.

+
+
+ + 'StartTime'() -> string() + Return the StartTime QoS identifier + +

This function returns the StartTime QoS identifier.

+
+
+ + 'StopTime'() -> string() + Return the StopTime QoS identifier + +

This function returns the StopTime QoS identifier.

+
+
+ + 'Timeout'() -> string() + Return the Timeout QoS identifier + +

This function returns the Timeout QoS identifier.

+
+
+ + 'OrderPolicy'() -> string() + Return the OrderPolicy QoS identifier + +

This function returns the OrderPolicy QoS identifier.

+
+
+ + 'AnyOrder'() -> short() + Return the AnyOrder QoS value + +

This function returns the AnyOrder QoS value.

+
+
+ + 'FifoOrder'() -> short() + Return the FifoOrder QoS value + +

This function returns the FifoOrder QoS value.

+
+
+ + 'PriorityOrder'() -> short() + Return the PriorityOrder QoS value + +

This function returns the PriorityOrder QoS value.

+
+
+ + 'DeadlineOrder'() -> short() + Return the DeadlineOrder QoS value + +

This function returns the DeadlineOrder QoS value.

+
+
+ + 'DiscardPolicy'() -> string() + Return the DiscardPolicy QoS identifier + +

This function returns the DiscardPolicy QoS identifier.

+
+
+ + 'LifoOrder'() -> short() + Return the LifoOrder QoS value + +

This function returns the LifoOrder QoS value.

+
+
+ + 'RejectNewEvents'() -> short() + Return the RejectNewEvents QoS value + +

This function returns the RejectNewEvents QoS value.

+
+
+ + 'MaximumBatchSize'() -> string() + Return the MaximumBatchSize QoS identifier + +

This function returns the MaximumBatchSize QoS identifier.

+
+
+ + 'PacingInterval'() -> string() + Return the PacingInterval QoS identifier + +

This function returns the PacingInterval QoS identifier.

+
+
+ + 'StartTimeSupported'() -> string() + Return the StartTimeSupported QoS identifier + +

This function returns the StartTimeSupported QoS identifier.

+
+
+ + 'StopTimeSupported'() -> string() + Return the StopTimeSupported QoS identifier + +

This function returns the StopTimeSupported QoS identifier.

+
+
+ + 'MaxEventsPerConsumer'() -> string() + Return the MaxEventsPerConsumer QoS identifier + +

This function returns the MaxEventsPerConsumer QoS identifier.

+
+
+ + 'MaxQueueLength'() -> string() + Return the MaxQueueLength Admin identifier + +

This function returns the MaxQueueLength Admin identifier.

+
+
+ + 'MaxConsumers'() -> string() + Return the MaxConsumers Admin identifier + +

This function returns the MaxConsumers Admin identifier.

+
+
+ + 'MaxSuppliers'() -> string() + Return the MaxSuppliers Admin identifier + +

This function returns the MaxSuppliers Admin identifier.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml b/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml new file mode 100644 index 0000000..6e2a102 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml @@ -0,0 +1,79 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotification_­AdminPropertiesAdmin + ..._AdminPropertiesAdmin + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotification_AdminPropertiesAdmin + This module implements the OMG CosNotification::AdminPropertiesAdmin interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

All objects, which inherit this interface, export functions described in this module.

+
+ + + get_admin(Object) -> AdminProperties + Return a list of AdminPropertiesassociated with the target object + + Object = #objref + AdminProperties = [AdminProperty] + AdminProperty = #'CosNotification_Property'{name, value} + name = string() + value = #any + + +

This operation returns sequence of name-value pairs which encapsulates the + current administrative properties of the target object.

+
+
+ + set_admin(Object, AdminProperties) -> Reply + Update the AdminPropertiesfor the target object + + Object = #objref + AdminProperties = [AdminProperty] + AdminProperty = #'CosNotification_Property'{name, value} + name = string() + value = #any + Reply = ok | {'EXCEPTION', CosNotification_UnsupportedAdmin} + + +

As input, this operation accepts a sequence of name-value pairs encapsulating the + desired administrative settings for the target object. If it is not possible to + set the given properties the exception UnsupportedAdmin will be raised.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml b/lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml new file mode 100644 index 0000000..b7c19f6 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotification_QoSAdmin.xml @@ -0,0 +1,106 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosNotification_QoSAdmin + + + + 2000-02-01 + 1.0 +
+ CosNotification_QoSAdmin + This module implements the OMG CosNotification::QoSAdmin interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

All objects, which inherit this interface, export functions described in this module.

+
+ + + get_qos(Object) -> Reply + Return a list of name-value pairs which encapsulates the current QoS settings for the target object + + Object = #objref + Reply = [QoSProperty] + QoSProperty = #'CosNotification_Property'{name, value} + name = string() + value = #any + + +

This operation returns a list of name-value pairs which encapsulates the current QoS settings + for the target object.

+
+
+ + set_qos(Object, QoS) -> Reply + Change the QoS settings for the target object + + Object = #objref + QoS = [QoSProperty] + QoSProperty = #'CosNotification_Property'{name, value} + name = string() + value = #any + Reply = ok | {'EXCEPTION', #'CosNotification_UnsupportedQoS'{qos_err}} + qos_err = PropertyErrorSeq + PropertyErrorSeq = [PropertyError] + PropertyError = #'CosNotification_PropertyError'{code, name, available_range} + code = 'UNSUPPORTED_PROPERTY' | 'UNAVAILABLE_PROPERTY' | 'UNSUPPORTED_VALUE' | 'UNAVAILABLE_VALUE' | 'BAD_PROPERTY' | 'BAD_TYPE' | 'BAD_VALUE' + name = string() + available_range = PropertyRange + PropertyRange = #CosNotification_PropertyRange{low_val, high_val} + low_val = high_val = #any + + +

To alter the current QoS settings for the target object this function must be used. + If it is not possible to set the requested QoS the UnsupportedQoS + exception is raised, which includes a sequence of PropertyError's + describing which QoS, possible range and why is not allowed.

+
+
+ + validate_qos(Object, QoS) -> Reply + Validate if the supplied QoS properties is valid for the target object + + Object = #objref + QoS = [QoSProperty] + QoSProperty = #'Property'{name, value} + name = string() + value = #any + Reply = {ok, NamedPropertyRangeSeq} | {'EXCEPTION', CosNotification_UnsupportedQoS{}} + NamedPropertyRangeSeq = [NamedPropertyRange] + NamedPropertyRange = #CosNotification_NamedPropertyRange{name, range} + name = string() + range = #CosNotification_PropertyRange{low_val, high_val} + low_val = #any + high_val = #any + + +

The purpose of this operations is to check if a QoS setting is supported + by the target object and if so, the operation returns additional properties + which could be optionally added as well.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml new file mode 100644 index 0000000..2cdb2d5 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml @@ -0,0 +1,242 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­ConsumerAdmin + ..._ConsumerAdmin + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_ConsumerAdmin + This module implements the OMG CosNotifyChannelAdmin::ConsumerAdmin interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotification_QoSAdmin

+
+ +

CosNotifyComm_NotifySubscribe

+
+ +

CosNotifyFilter_FilterAdmin

+
+
+
+ + + _get_MyID(ConsumerAdmin) -> AdminID + Return the target object's Id + + ConsumerAdmin = #objref + AdminID = long() + + +

The ID returned by the creating channel is equal to the value encapsulated by + this readonly attribute.

+
+
+ + _get_MyChannel(ConsumerAdmin) -> Channel + Return the ancestor channel + + ConsumerAdmin = #objref + Channel = #objref + + +

The creating channel's reference is maintained by this readonly attribute.

+
+
+ + _get_MyOperator(ConsumerAdmin) -> OpType + Return the filtering schema used by the target object + + ConsumerAdmin = #objref + OpType = 'AND_OP' | 'OR_OP' + + +

When ConsumerAdmin's are created an operation type, + i.e., 'AND_OP' or 'OR_OP', is supplied, which determines + the semantics used by the target object concerning evaluation against + any associated Filter objects.

+
+
+ + _get_priority_filter(ConsumerAdmin) -> MappingFilter + Return the associated priority MappingFilter + + ConsumerAdmin = MappingFilter = #objref + + +

If set, this operation returns the associated priority MappingFilter, otherwise + a NIL object reference is returned.

+
+
+ + _set_priority_filter(ConsumerAdmin, MappingFilter) -> ok + Set the priority MappingFilter + + ConsumerAdmin = MappingFilter = #objref + + +

To associate a priority MappingFilter with the target object this operation + must be used.

+
+
+ + _get_lifetime_filter(ConsumerAdmin) -> MappingFilter + Return the associated lifetime MappingFilter + + ConsumerAdmin = MappingFilter = #objref + + +

Unless a lifetime MappingFilter have been associated with the target object + a NIL object reference is returned by this operation.

+
+
+ + _set_lifetime_filter(ConsumerAdmin, MappingFilter) -> ok + Set the lifetime MappingFilter + + ConsumerAdmin = MappingFilter = #objref + + +

This operation associate a lifetime MappingFilter with the target object.

+
+
+ + _get_pull_suppliers(ConsumerAdmin) -> ProxyIDSeq + Return a list of all associated pull supplier Id:s + + ConsumerAdmin = #objref + ProxyIDSeq = [ProxyID] + ProxyID = long() + + +

This readonly attribute maintains the Id's for all PullProxies created + by the target object and still alive.

+
+
+ + _get_push_suppliers(ConsumerAdmin) -> ProxyIDSeq + Return a list of all associated push supplier Id:s + + ConsumerAdmin = #objref + ProxyIDSeq = [ProxyID] + ProxyID = long() + + +

This attribute is similar to the _get_pull_suppliers attribute but maintains + the Id's for all PushProxies created by the target object and still alive.

+
+
+ + get_proxy_supplier(ConsumerAdmin, ProxyID) -> Reply + Return the proxy supplier with matching Id + + ConsumerAdmin = #objref + ProxyID = long() + Reply = Proxy | {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}} + Proxy = #objref + + +

If a proxy with the given Id exists the reference to the object is returned, but if + the object have terminated, or an incorrect Id is supplied, an exception is raised.

+
+
+ + obtain_notification_pull_supplier(ConsumerAdmin, ConsumerType) -> Reply + Create a supplier proxy + + ConsumerAdmin = #objref + ConsumerType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' + Reply = {Proxy, ProxyID} + Proxy = #objref + ProxyID = long() + + +

Determined by the parameter ConsumerType, a proxy which will + accept events of the defined type is created. Along with the object reference an + Id is returned.

+
+
+ + obtain_pull_supplier(ConsumerAdmin) -> Proxy + Create a supplier proxy + + ConsumerAdmin = #objref + Proxy = #objref + + +

This operation creates a new proxy which accepts #any{} events.

+
+
+ + obtain_notification_push_supplier(ConsumerAdmin, ConsumerType) -> Reply + Create a supplier proxy + + ConsumerAdmin = #objref + ConsumerType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' + Reply = {Proxy, ProxyID} + Proxy = #objref + ProxyID = long() + + +

A proxy which accepts events of the type described by the parameter ConsumerType + is created by this operation. A unique Id is returned as an out parameter.

+
+
+ + obtain_push_supplier(ConsumerAdmin) -> Proxy + Create a supplier proxy + + ConsumerAdmin = #objref + Proxy = #objref + + +

The object created by this function is a proxy which accepts #any{} events.

+
+
+ + destroy(ConsumerAdmin) -> ok + Terminate the target object and all its children + + ConsumerAdmin = #objref + + +

To terminate the target object this operation should be used. The associated + Channel will be notified.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml new file mode 100644 index 0000000..b6af2e2 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml @@ -0,0 +1,226 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosNotifyChannelAdmin_­EventChannel + ..._EventChannel + + + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_EventChannel + This module implements the OMG CosNotifyChannelAdmin::EventChannel interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotification_QoSAdmin

+
+ +

CosNotification_AdminPropertiesAdmin

+
+
+
+ + + _get_MyFactory(Channel) -> ChannelFactory + Return the factory object which created the target object + + Channel = #objref + ChannelFactory = #objref + + +

This readonly attribute maintains the reference of the event channel + factory that created the target channel.

+
+
+ + _get_default_consumer_admin(Channel) -> ConsumerAdmin + Return the default consumer admin associated with the target object + + Channel = #objref + ConsumerAdmin = #objref + + +

This is a readonly attribute which maintains a reference to a default + ConsumerAdmin object associated with the target object.

+
+
+ + _get_default_supplier_admin(Channel) -> SupplierAdmin + Return the default supplier admin associated with the target object + + Channel = #objref + SupplierAdmin = #objref + + +

This is a readonly attribute which maintains a reference to a default + SupplierAdmin object associated with the target object.

+
+
+ + _get_default_filter_factory(Channel) -> FilterFactory + Return the default filter factory associated with the target object + + Channel = #objref + FilterFactory = #objref + + +

The default FilterFactory associated with the target channel + is maintained by this readonly attribute.

+
+
+ + new_for_consumers(Channel, OpType) -> Return + Create a new ConsumerAdminobject + + Channel = #objref + OpType = 'AND_OP' | 'OR_OP' + Return = {ConsumerAdmin, AdminID} + ConsumerAdmin = #objref + AdminID = long() + + +

This operation creates a new instance of a ConsumerAdmin and supplies + an Id which may be used when invoking other operations exported by this module. + The returned object will inherit the Quality of Service properties of the + target channel.

+
+
+ + for_consumers(Channel) -> ConsumerAdmin + Create a new ConsumerAdminobject + + Channel = #objref + ConsumerAdmin = #objref + + +

A new new instance of a ConsumerAdmin object is created but no + Id is returned. The returned object's operation type, i.e., 'AND_OP' or 'OR_OP', + will be set to the value of the configuration parameter filterOp. + The target object's Quality of Service properties will be inherited by the + returned ConsumerAdmin.

+
+
+ + new_for_suppliers(Channel, OpType) -> Return + Create a new SupplierAdminobject + + Channel = #objref + OpType = 'AND_OP' | 'OR_OP' + Return = {SupplierAdmin, AdminID} + SupplierAdmin = #objref + AdminID = long() + + +

Enables us to create a new instance of a SupplierAdmin. An Id, which + may be used when invoking other operations exported by this module, is also + returned. The current Quality of Service settings associated with the target + object will be inherited by the SupplierAdmin.

+
+
+ + for_suppliers(Channel) -> SupplierAdmin + Create a new SupplierAdminobject + + Channel = #objref + SupplierAdmin = #objref + + +

To create a new SupplierAdmin with the target object's current + Quality of Service settings we can use this function. The returned object's + operation type ('AND_OP' or 'OR_OP') will be determined by the + configuration variable filterOp.

+
+
+ + get_consumeradmin(Channel, AdminID) -> ConsumerAdmin + Return the ConsumerAdminmatching AdminID + + Channel = #objref + AdminID = long() + ConsumerAdmin = #objref | {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}} + + +

If the given Id is associated with a ConsumerAdmin the object reference + is returned. If such association never existed or the ConsumerAdmin + have terminated an exception is raised.

+
+
+ + get_supplieradmin(Channel, AdminID) -> SupplierAdmin + Return the SupplierAdminmatching AdminID + + Channel = #objref + AdminID = long() + SupplierAdmin = #objref | {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}} + + +

Equal to the operation get_consumeradmin/2 but a reference to + a SupplierAdmin is returned.

+
+
+ + get_all_consumeradmins(Channel) -> Reply + Return a list of all ConsumerAdmins, currently active, Id:s + + Channel = #objref + Reply = [AdminID] + AdminID = long() + + +

To get access to all ConsumerAdmin Id's created by the target object, and still + alive, this operation could be invoked.

+
+
+ + get_all_supplieradmins(Channel) -> Reply + Return a list of all SupplierAdmins, currently active, Id:s + + Channel = #objref + Reply = [AdminID] + AdminID = long() + + +

Equal to the operation get_all_consumeradmins/1 but returns + a list of all SupplierAdmin object ID's.

+
+
+ + destroy(Channel) -> ok + Terminate the channel and all its children + + Channel = #objref + + +

The destroy operation will terminate the target channel and + all associated Admin objects.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml new file mode 100644 index 0000000..0197695 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml @@ -0,0 +1,89 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosNotifyChannelAdmin_­EventChannelFactory + ..._EventChannelFactory + + + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_EventChannelFactory + This module implements the OMG CosNotifyChannelAdmin::EventChannelFactory interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+
+ + + create_channel(ChannelFactory, InitialQoS, InitialAdmin) -> Return + Create a new channel + + ChannelFactory = #objref + InitialQoS = CosNotification::QoSProperties + InitialAdmin = CosNotification::AdminProperties + Return = {EventChannel, ChannelID} + EventChannel = #objref + ChannelID = long() + + +

This operation creates a new event channel. Along with the channel + reference an id is returned which can be used when invoking other + operations exported by this module. The Quality of Service argument + supplied will be inherited by objects created by the channel. For more + information about QoS settings see the User's Guide.

+

If no QoS- and/or Admin-properties are supplied (i.e. empty list), + the default settings will be used. For more information, see the + User's Guide.

+
+
+ + get_all_channels(ChannelFactory) -> ChannelIDSeq + Return all Id:s for channels, currently alive, created by the target object + + ChannelFactory = #objref + ChannelIDSeq = [long()] + + +

This operation returns a id sequence of all channel's created by this ChannelFactory.

+
+
+ + get_event_channel(ChannelFactory, ChannelID) -> Return + Return the channel object associated with the given Id + + ChannelFactory = #objref + ChannelID = long() + Retrurn = EventChannel | {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} + EventChannel = #objref + + +

This operation returns the EventChannel associated with the given id. If no channel is + associated with the id, i.e., never existed or have been terminated, an exception is raised.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml new file mode 100644 index 0000000..69b1e78 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml @@ -0,0 +1,128 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­ProxyConsumer + ..._ProxyConsumer + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_ProxyConsumer + This module implements the OMG CosNotifyChannelAdmin::ProxyConsumer interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+
+
+ + + _get_MyType(ProxyConsumer) -> ProxyType + Return the proxy type + + ProxyConsumer = #objref + ProxyType = 'PUSH_ANY' | 'PULL_ANY' | 'PUSH_STRUCTURED' | 'PULL_STRUCTURED' | 'PUSH_SEQUENCE' | 'PULL_SEQUENCE' + + +

This readonly attribute maintains the enumerant describing the which type the target object + is.

+
+
+ + _get_MyAdmin(ProxyConsumer) -> AdminObject + return the associated Adminobject + + ProxyConsumer = AdminObject = #objref + + +

This readonly attribute maintains the admin's reference which created the target object.

+
+
+ + obtain_subscription_types(ProxyConsumer, ObtainInfoMode) -> EventTypeSeq + Administer subscription types + + ProxyConsumer = #objref + ObtainInfoMode = 'ALL_NOW_UPDATES_OFF' | 'ALL_NOW_UPDATES_ON' | 'NONE_NOW_UPDATES_OFF' | 'NONE_NOW_UPDATES_ON' + EventTypeSeq = [EventType] + EventType = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + + +

Depending on the input parameter ObtainInfoMode, this operation may return a + sequence of the EventTypes the target object is interested in receiving. + If 'ALL_NOW_UPDATES_OFF' or 'ALL_NOW_UPDATES_ON' is given a sequence will + be returned, otherwise not. If 'ALL_NOW_UPDATES_OFF' or 'NONE_NOW_UPDATES_OFF' + are issued the target object will not inform the associated NotifySubscribe object + when an update occurs. 'ALL_NOW_UPDATES_ON' or 'NONE_NOW_UPDATES_ON' will + result in that update information will be sent.

+
+
+ + validate_event_qos(ProxyConsumer, QoSProperties) -> Reply + Check if certain Quality of Service properties can be added to events in the current context of the target object + + ProxyConsumer = #objref + QoSProperties = [QoSProperty] + QoSProperty = #'CosNotification_Property'{name, value} + name = string() + value = #any + Reply = {ok, NamedPropertyRangeSeq} | {'EXCEPTION', CosNotification_UnsupportedQoS{qos_err}} + NamedPropertyRangeSeq = [NamedPropertyRange] + NamedPropertyRange = #CosNotification_NamedPropertyRange{name, range} + name = string() + range = #CosNotification_PropertyRange{low_val, high_val} + low_val = #any + high_val = #any + qos_err = PropertyErrorSeq + PropertyErrorSeq = [PropertyError] + PropertyError = #'CosNotification_PropertyError'{code, name, available_range} + code = 'UNSUPPORTED_PROPERTY' | 'UNAVAILABLE_PROPERTY' | 'UNSUPPORTED_VALUE' | 'UNAVAILABLE_VALUE' | 'BAD_PROPERTY' | 'BAD_TYPE' | 'BAD_VALUE' + name = string() + available_range = PropertyRange + PropertyRange = #CosNotification_PropertyRange{low_val, high_val} + low_val = high_val = #any + + +

To check if certain Quality of Service properties can be added to events in + the current context of the target object this operation should be used. If we + cannot support the required settings an exception describing why will be raised.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml new file mode 100644 index 0000000..29dc598 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml @@ -0,0 +1,113 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­ProxyPullConsumer + ..._ProxyPullConsumer + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_ProxyPullConsumer + This module implements the OMG CosNotifyChannelAdmin::ProxyPullConsumer interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifyPublish

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxyConsumer

+
+
+
+ + + connect_any_pull_supplier(ProxyPullConsumer, PullSupplier) -> Reply + Connect a supplier to the proxy + + ProxyPullConsumer = #objref + PullSupplier = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}} + + +

This operation connects the given PullSupplier to the target object. + If a client is already connected the AlreadyConnected exception + will be raised. The client must support the operations pull and + try_pull, otherwise the TypeError exception is raised.

+
+
+ + suspend_connection(ProxyPullConsumer) -> Reply + Suspend the connection between the client and the proxy + + ProxyPullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

If we want to temporarily suspend the connection with the target object this + operation must be sued. If the connection already have been suspended or + no client have been connected an exception is raised.

+
+
+ + resume_connection(ProxyPullConsumer) -> Reply + Resume a previously suspended connection with the proxy + + ProxyPullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyActive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

If The connection have been suspended earlier we can invoke this operation to + reinstate the connection. If the connection already is active or no client + have been connected to the target object an exception is raised.

+
+
+ + disconnect_pull_consumer(ProxyPullConsumer) -> ok + Close the connection and terminate the proxy + + ProxyPullConsumer = #objref + + +

Invoking this operation disconnects the client from the target object which + then terminates and inform its administrative parent.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml new file mode 100644 index 0000000..daa0f3c --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml @@ -0,0 +1,112 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­ProxyPullSupplier + ..._ProxyPullSupplier + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_ProxyPullSupplier + This module implements the OMG CosNotifyChannelAdmin::ProxyPullSupplier interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifySubscribe

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxySupplier

+
+
+
+ + + connect_any_pull_consumer(ProxyPullSupplier, PullConsumer) -> Reply + Connect a consumer to the proxy + + ProxyPullSupplier = #objref + PullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} + + +

This operation connects the given PullConsumer to the target object. + If a connection already exists the AlreadyConnected exception is + raised.

+
+
+ + pull(ProxyPullSupplier) -> Reply + Pull an Any event from the proxy + + ProxyPullSupplier = #objref + Reply = #any | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}} + + +

This operation pulls next #any{} event, and blocks, if the target object + have no events to forward, until an event can be delivered. If no client have + been connected the Disconnected exception is raised.

+
+
+ + try_pull(ProxyPullSupplier) -> Reply + Try and pull an Any event from the proxy + + ProxyPullSupplier = #objref + Reply = {#any, HasEvent} | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}} + HasEvent = boolean() + + +

This operation pulls next event, but do not block if the target object + have no event to forward. If no client have + been connected the Disconnected exception is raised.

+
+
+ + disconnect_pull_supplier(ProxyPullSupplier) -> ok + Close the connection and terminate the proxy + + ProxyPullSupplier = #objref + + +

Invoking this operation will cause the target object to close the connection and terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml new file mode 100644 index 0000000..63d3f53 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml @@ -0,0 +1,98 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­ProxyPushConsumer + ..._ProxyPushConsumer + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_ProxyPushConsumer + This module implements the OMG CosNotifyChannelAdmin::ProxyPushConsumer interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifyPublish

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxyConsumer

+
+
+
+ + + connect_any_push_supplier(ProxyPushConsumer, PushSupplier) -> Reply + Connect a supplier to the proxy + + ProxyPushConsumer = #objref + PushSupplier = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} + + +

This operation connects a PushSupplier to the target object. If + a connection already exists the AlreadyConnected exception is raised.

+
+
+ + push(ProxyPushConsumer, Event) -> Reply + Push an Any event to the proxy + + ProxyPushConsumer = #objref + Event = #any + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}} + + +

This operation pushes an #any{} event to the target object. If no client + have been connected the Disconnected exception is raised.

+
+
+ + disconnect_push_consumer(ProxyPushConsumer) -> ok + Close the connection and terminate the proxy + + ProxyPushConsumer = #objref + + +

Invoking this operation will cause the target object to close the connection and + terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml new file mode 100644 index 0000000..54d100c --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml @@ -0,0 +1,110 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­ProxyPushSupplier + ..._ProxyPushSupplier + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_ProxyPushSupplier + This module implements the OMG CosNotifyChannelAdmin::ProxyPushSupplier interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifySubscribe

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmi

+
+ +

CosNotifyChannelAdmin_ProxySupplier

+
+
+
+ + + connect_any_push_consumer(ProxyPushSupplier, PushConsumer) -> Reply + Connect a consumer to the proxy + + ProxyPushSupplier = #objref + PushConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}} + + +

This operation connects a PushConsumer to the target object. If + a connection already exists or the given client does not support + the operation push an exception, AlreadyConnected and + TypeError respectively, is raised.

+
+
+ + suspend_connection(ProxyPushSupplier) -> Reply + Suspend the connection between the proxy and the client + + ProxyPushSupplier = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

This operation suspends the connection with the client object. If the connection + already is suspended or no client have been associated an exception is raised.

+
+
+ + resume_connection(ProxyPushSupplier) -> Reply + Resume a previously suspended connection with the proxy + + ProxyPullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

If a connection have been suspended earlier, calling this operation will resume the connection. + If the connection already is active or no client have been connected an exception is raised.

+
+
+ + disconnect_push_supplier(ProxyPushSupplier) -> ok + Close the connection and terminate the proxy + + ProxyPushSupplier = #objref + + +

This operation cause the target object to close the connection and terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml new file mode 100644 index 0000000..daf2aab --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml @@ -0,0 +1,175 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­ProxySupplier + ..._ProxySupplier + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_ProxySupplier + This module implements the OMG CosNotifyChannelAdmin::ProxySupplier interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+
+
+ + + _get_MyType(ProxySupplier) -> ProxyType + Return the proxy type + + ProxySupplier = #objref + ProxyType = 'PUSH_ANY' | 'PULL_ANY' | 'PUSH_STRUCTURED' | 'PULL_STRUCTURED' | 'PUSH_SEQUENCE' | 'PULL_SEQUENCE' + + +

This readonly attribute maintains the enumerant describing the which type the target object + is.

+
+
+ + _get_MyAdmin(ProxySupplier) -> AdminObject + Return the target object's associated Adminobject + + ProxySupplier = #objref + AdminObject = #objref + + +

This readonly attribute maintains the admin's reference which created the target object.

+
+
+ + _get_priority_filter(ProxySupplier) -> MappingFilter + Return the target object's associated priority MappingFilter + + ProxySupplier = #objref + MappingFilter = #objref + + +

This operation returns the associated priority MappingFilter. + If no such object exist a NIL reference is returned.

+
+
+ + _set_priority_filter(ProxySupplier, MappingFilter) -> ok + Set the target object's associated priority MappingFilter + + ProxySupplier = #objref + MappingFilter = #objref + + +

This operation associate a new priority MappingFilter with the target object.

+
+
+ + _get_lifetime_filter(ProxySupplier) -> MappingFilter + Return the target object's associated lifetime MappingFilter + + ProxySupplier = #objref + MappingFilter = #objref + + +

This operation returns the associated lifetime MappingFilter. + If no such object exist a NIL reference is returned.

+
+
+ + _set_lifetime_filter(ProxySupplier, MappingFilter) -> ok + Set the target object's associated lifetime MappingFilter + + ProxySupplier = #objref + MappingFilter = #objref + + +

This operation associate a new lifetime MappingFilter with the target object.

+
+
+ + obtain_offered_types(ProxySupplier, ObtainInfoMode) -> EventTypeSeq + Administer the type of events the proxy supplies + + ProxySupplier = #objref + ObtainInfoMode = 'ALL_NOW_UPDATES_OFF' | 'ALL_NOW_UPDATES_ON' | 'NONE_NOW_UPDATES_OFF' | 'NONE_NOW_UPDATES_ON' + EventTypeSeq = [EventType] + EventType = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + + +

Depending on the input parameter ObtainInfoMode, this operation may return a + sequence of the EventTypes the target object is interested in receiving. + If 'ALL_NOW_UPDATES_OFF' or 'ALL_NOW_UPDATES_ON' is given a sequence will + be returned, otherwise not. If 'ALL_NOW_UPDATES_OFF' or 'NONE_NOW_UPDATES_OFF' + are issued the target object will not inform the associated NotifySubscribe object + when an update occurs. 'ALL_NOW_UPDATES_ON' or 'NONE_NOW_UPDATES_ON' will + result in that update information will be sent.

+
+
+ + validate_event_qos(ProxySupplier, QoSProperties) -> Reply + Check if the QoS properties can be set + + ProxySupplier = #objref + QoSProperties = [QoSProperty] + QoSProperty = #'CosNotification_Property'{name, value} + name = string() + value = #any + Reply = {ok, NamedPropertyRangeSeq} | {'EXCEPTION', CosNotification_UnsupportedQoS{qos_err}} + NamedPropertyRangeSeq = [NamedPropertyRange] + NamedPropertyRange = #CosNotification_NamedPropertyRange{name, range} + name = string() + range = #CosNotification_PropertyRange{low_val, high_val} + low_val = #any + high_val = #any + qos_err = PropertyErrorSeq + PropertyErrorSeq = [PropertyError] + PropertyError = #'CosNotification_PropertyError'{code, name, available_range} + code = 'UNSUPPORTED_PROPERTY' | 'UNAVAILABLE_PROPERTY' | 'UNSUPPORTED_VALUE' | 'UNAVAILABLE_VALUE' | 'BAD_PROPERTY' | 'BAD_TYPE' | 'BAD_VALUE' + name = string() + available_range = PropertyRange + PropertyRange = #CosNotification_PropertyRange{low_val, high_val} + low_val = high_val = #any + + +

To check if certain Quality of Service properties can be added to events in + the current context of the target object this operation should be used. If we + cannot support the required settings an exception describing why will be raised.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml new file mode 100644 index 0000000..aa9fae4 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml @@ -0,0 +1,112 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­SequenceProxyPullConsumer + ..._SequenceProxyPullConsumer + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_SequenceProxyPullConsumer + This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPullConsumer interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifyPublish

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxyConsumer

+
+
+
+ + + connect_sequence_pull_supplier(SequenceProxyPullConsumer, PullSupplier) -> Reply + Connect a supplier to the proxy + + SequenceProxyPullConsumer = #objref + PullSupplier = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}} + + +

This operation connects a PullSupplier to the target object. If a + connection already exists or the supplied client does not support the functions + pull_structured_events and try_pull_structured_events an exception + is raised.

+
+
+ + suspend_connection(SequenceProxyPullConsumer) -> Reply + Suspend the connection with the proxy + + SequenceProxyPullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

If a connection exist, invoking this operation will suspend the connection + until instructed otherwise. Otherwise, no client have been connected or this operation + already have been invoked an exception is raised.

+
+
+ + resume_connection(SequenceProxyPullConsumer) -> Reply + Resume a previously suspended connection with the proxy + + SequenceProxyPullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

If an connection have been suspended this operation must be used to resume the + connection. If the connection already is active or no client have been connected an + exception is raised.

+
+
+ + disconnect_sequence_pull_consumer(SequenceProxyPullConsumer) -> ok + Close connection and terminate the proxy + + SequenceProxyPullConsumer = #objref + + +

This operation close the connection to the client and terminates the target object.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml new file mode 100644 index 0000000..a46c53c --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml @@ -0,0 +1,146 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­SequenceProxyPullSupplier + ..._SequenceProxyPullSupplier + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_SequenceProxyPullSupplier + This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPullSupplier interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifySubscribe

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxySupplier

+
+
+
+ + + connect_sequence_pull_consumer(SequenceProxyPullSupplier, PullConsumer) -> Reply + Connect a consumer to the proxy + + SequenceProxyPullSupplier = #objref + PullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} + + +

This operation connects a PullConsumer to the target object. If a connection + already exists an exception is raised.

+
+
+ + pull_structured_events(SequenceProxyPullSupplier, MaxEvents) -> Reply + Pull structured events from the proxy + + SequenceProxyPullSupplier = #objref + MaxEvents = long() + Reply = EventBatch | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}} + EventBatch = [StructuredEvent] + StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body} + header = EventHeader + filterable_data = [#'CosNotification_Property'{name, value}] + name = string() + value = #any + remainder_of_body = #any + EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header} + fixed_header = FixedEventHeader + variable_header = OptionalHeaderFields + FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name} + event_type = EventType + event_name = string() + EventType = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + OptionalHeaderFields = [#'CosNotification_Property'{name, value}] + + +

A client use this operation to pull next event sequence of maximum length + MaxEvents. This operation is blocking and will not reply until the + requested amount of events can be delivered or the QoS property PacingInterval + is reached. For more information see the User's Guide.

+
+
+ + try_pull_structured_events(SequenceProxyPullSupplier, MaxEvents) -> Reply + Try to pull structured events from the proxy + + SequenceProxyPullSupplier = #objref + MaxEvents = long() + Reply = {EventBatch, HasEvent} | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}} + HasEvent = boolean() + EventBatch = [StructuredEvent] + StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body} + header = EventHeader + filterable_data = [#'CosNotification_Property'{name, value}] + name = string() + value = #any + remainder_of_body = #any + EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header} + fixed_header = FixedEventHeader + variable_header = OptionalHeaderFields + FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name} + event_type = EventType + event_name = string() + EventType = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + OptionalHeaderFields = [#'CosNotification_Property'{name, value}] + + +

This operation pulls an event sequence of the maximum length MaxEvents, + but do not block if the target object have no events to forward. The outparameter, + HasEvent is true if the sequence contain any events.

+
+
+ + disconnect_sequence_pull_supplier(SequenceProxyPullSupplier) -> ok + Close the connection and terminate the proxy + + SequenceProxyPullSupplier = #objref + + +

This operation cause the target object to close the connection and terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml new file mode 100644 index 0000000..964d212 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml @@ -0,0 +1,109 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosNotifyChannelAdmin_­SequenceProxyPushConsumer + ..._SequenceProxyPushConsumer + + + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_­SequenceProxyPushConsumer + This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPushConsumer interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifyPublish

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxyConsumer

+
+
+
+ + + connect_sequence_push_supplier(SequenceProxyPushConsumer, PushSupplier) -> Reply + Connect a supplier to the proxy + + SequenceProxyPushConsumer = #objref + PushSupplier = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} + + +

This operation connects a PushSupplier to the target object. If a + connection already exists the AlreadyConnected exception is raised.

+
+
+ + push_structured_events(SequenceProxyPushConsumer, EventBatch) -> Reply + Push a structured event to the proxy + + SequenceProxyPushConsumer = #objref + EventBatch = [StructuredEvent] + StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body} + header = EventHeader + filterable_data = [#'CosNotification_Property'{name, value}] + name = string() + value = #any + remainder_of_body = #any + EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header} + fixed_header = FixedEventHeader + variable_header = OptionalHeaderFields + FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name} + event_type = EventType + event_name = string() + EventType = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + OptionalHeaderFields = [#'CosNotification_Property'{name, value}] + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}} + + +

A client must use this operation when it wishes to push a new sequence of events + to the target object. If no connection exists the Disconnected exception + is raised.

+
+
+ + disconnect_sequence_push_consumer(SequenceProxyPushConsumer) -> ok + Close connection and terminate the proxy + + SequenceProxyPushConsumer = #objref + + +

This operation cause the target object to close the connection and terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml new file mode 100644 index 0000000..60dfa2c --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml @@ -0,0 +1,111 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­SequenceProxyPushSupplier + ..._SequenceProxyPushSupplier + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_­SequenceProxyPushSupplier + This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPushSupplier interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifySubscribe

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxySupplier

+
+
+
+ + + connect_sequence_push_consumer(SequenceProxyPushSupplier, PushConsumer) -> Reply + Connect a consumer to the proxy + + SequenceProxyPushSupplier = #objref + PushConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}} + + +

This operation connects a PushConsumer to the target object. If a + connection already exists or the function psuh_structured_events + is not supported the exceptions AlreadyConnected or + TypeError will be raised respectively.

+
+
+ + suspend_connection(SequenceProxyPushSupplier) -> Reply + Suspend the connection between the client and the target object + + SequenceProxyPushSupplier = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

This operation suspends the connection between the client and the target object. + If no connection exists or the connection is already suspended an exception is raised.

+
+
+ + resume_connection(SequenceProxyPushSupplier) -> Reply + Resume a previously suspended connection with the proxy + + SequenceProxyPullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

If the connection have previously been suspended this operation must used + if we want to resume the connection. If no object have been connected or the connection + already is active an exception is raised.

+
+
+ + disconnect_sequence_push_supplier(SequenceProxyPushSupplier) -> ok + Close the connection and terminate the proxy + + SequenceProxyPushSupplier = #objref + + +

This operation cause the target object to close the connection and terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml new file mode 100644 index 0000000..070f9a3 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml @@ -0,0 +1,110 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­StructuredProxyPullConsumer + ..._StructuredProxyPullConsumer + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_­StructuredProxyPullConsumer + This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPullConsumer interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifyPublish

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxyConsumer

+
+
+
+ + + connect_structured_pull_supplier(StructuredProxyPullConsumer, PullSupplier) -> Reply + Connect a supplier to the proxy + + StructuredProxyPullConsumer = #objref + PullSupplier = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}} + + +

This operation connects a PullSupplier to the target object. If a connection + already exists or the given client object does not support the functions + pull_structured_event and try_pull_structured_event an exception is raised.

+
+
+ + suspend_connection(StructuredProxyPullConsumer) -> Reply + Suspend the connection between the target object and its client + + StructuredProxyPullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

This operation suspends the connection between the target object and its client. + If no connection exists or already suspended an exception is raised.

+
+
+ + resume_connection(StructuredProxyPullConsumer) -> Reply + Resume a previously suspended connection with the proxy + + StructuredProxyPullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

If the connection have been suspended this operation must be used if we want + to resume the connection. If the connection already are active or no connection + have been created an exception is raised.

+
+
+ + disconnect_structured_pull_consumer(StructuredProxyPullConsumer) -> ok + Close the connection and terminate the proxy + + StructuredProxyPullConsumer = #objref + + +

This operation cause the target object to close the connection and terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml new file mode 100644 index 0000000..4a454b2 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml @@ -0,0 +1,140 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­StructuredProxyPullSupplier + ..._StructuredProxyPullSupplier + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_­StructuredProxyPullSupplier + This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPullSupplier interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifySubscribe

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxySupplier

+
+
+
+ + + connect_structured_pull_consumer(StructuredProxyPullSupplier, PullConsumer) -> Reply + Connect a consumer to the proxy + + StructuredProxyPullSupplier = #objref + PullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} + + +

This operation connects a PullConsumer to the target object. If a connection + already exists the AlreadyConnected exception is raised.

+
+
+ + pull_structured_event(StructuredProxyPullSupplier) -> Reply + Pull a structured event from the proxy + + StructuredProxyPullSupplier = #objref + Reply = StructuredEvent | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}} + StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body} + header = EventHeader + filterable_data = [#'CosNotification_Property'{name, value}] + name = string() + value = #any + remainder_of_body = #any + EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header} + fixed_header = FixedEventHeader + variable_header = OptionalHeaderFields + FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name} + event_type = EventType + event_name = string() + EventType = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + OptionalHeaderFields = [#'CosNotification_Property'{name, value}] + + +

This operation pulls next event from the target object; if an event cannot + be delivered this function blocks until an event arrives.

+
+
+ + try_pull_structured_event(StructuredProxyPullSupplier) -> Reply + Try to pull a structured event from the proxy + + StructuredProxyPullSupplier = #objref + Reply = {StructuredEvent, HasEvent} | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}} + HasEvent = boolean() + StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body} + header = EventHeader + filterable_data = [#'CosNotification_Property'{name, value}] + name = string() + value = #any + remainder_of_body = #any + EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header} + fixed_header = FixedEventHeader + variable_header = OptionalHeaderFields + FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name} + event_type = EventType + event_name = string() + EventType = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + OptionalHeaderFields = [#'CosNotification_Property'{name, value}] + + +

This operation try to pull next event from the target object. If no event have arrived + an empty event is returned and the out parameter HasEvent is set to false. Otherwise, + the boolean flag is set to true and an valid event is returned.

+
+
+ + disconnect_structured_pull_supplier(StructuredProxyPullSupplier) -> ok + Close connection and terminate the proxy + + StructuredProxyPullSupplier = #objref + + +

This operation cause the target object to close the connection and terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml new file mode 100644 index 0000000..db7f1dd --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml @@ -0,0 +1,110 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­StructuredProxyPushConsumer + ..._StructuredProxyPushConsumer + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_­StructuredProxyPushConsumer + This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPushConsumer interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifyPublish

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxyConsumer

+
+
+
+ + + connect_structured_push_supplier(StructuredProxyPushConsumer, PushSupplier) -> Reply + Connect a supplier to the proxy + + StructuredProxyPushConsumer = #objref + PushSupplier = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} + + +

This operation connects a PushSupplier to the target object. If a connection + already exists an exception is raised.

+
+
+ + push_structured_event(StructuredProxyPushConsumer, StructuredEvent) -> Reply + Push a structured event to the proxy + + StructuredProxyPushConsumer = #objref + StructuredEvent = #'CosNotification_StructuredEvent'{header, filterable_data, remainder_of_body} + header = EventHeader + filterable_data = [#'CosNotification_Property'{name, value}] + name = string() + value = #any + remainder_of_body = #any + EventHeader = #'CosNotification_EventHeader'{fixed_header, variable_header} + fixed_header = FixedEventHeader + variable_header = OptionalHeaderFields + FixedEventHeader = #'CosNotification_FixedEventHeader'{event_type, event_name} + event_type = EventType + event_name = string() + EventType = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + OptionalHeaderFields = [#'CosNotification_Property'{name, value}] + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_Disconnected'{}} + + +

When a client want to push a new event to the target object this operation must be used.

+
+
+ + disconnect_structured_push_consumer(StructuredProxyPushConsumer) -> ok + Close the connection and terminate the proxy + + StructuredProxyPushConsumer = #objref + + +

This operation cause the target object to close the connection and terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml new file mode 100644 index 0000000..b2dab10 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml @@ -0,0 +1,110 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­StructuredProxyPushSupplier + ..._StructuredProxyPushSupplier + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_­StructuredProxyPushSupplier + This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPushSupplier interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotifyComm_NotifySubscribe

+
+ +

CosNotification_QoSAdmin

+
+ +

CosNotifyFilter_FilterAdmin

+
+ +

CosNotifyChannelAdmin_ProxySupplier

+
+
+
+ + + connect_structured_push_consumer(StructuredProxyPushSupplier, PushConsumer) -> Reply + Connect a consumer to the proxy + + StructuredProxyPushSupplier = #objref + PushConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosEventChannelAdmin_AlreadyConnected'{}} | {'EXCEPTION', #'CosEventChannelAdmin_TypeError'{}} + + +

This operation connects a PushConsumer to the target object. If + a connection already exists or the function push_structured_event + is not supported by the client object an exception is raised.

+
+
+ + suspend_connection(StructuredProxyPushSupplier) -> Reply + Suspend the connection with the target object + + StructuredProxyPushSupplier = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

This operation suspends the connection with the target object. If no connection + exists or the connection already is suspended an exception is raised.

+
+
+ + resume_connection(StructuredProxyPushSupplier) -> Reply + Resume a previously suspended connection + + StructuredProxyPullConsumer = #objref + Reply = ok | {'EXCEPTION', #'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}} | {'EXCEPTION', #'CosNotifyChannelAdmin_NotConnected'{}} + + +

If the connection with the target object have been suspended this function + must be used to resume the connection. If no client have been connected or + the connection is active an exception is raised.

+
+
+ + disconnect_structured_push_supplier(StructuredProxyPushSupplier) -> ok + Close the connection and terminate the target object + + StructuredProxyPushSupplier = #objref + + +

This operation cause the target object to close the connection and terminate.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml new file mode 100644 index 0000000..0f262ac --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml @@ -0,0 +1,195 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyChannelAdmin_­SupplierAdmin + ..._SupplierAdmin + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyChannelAdmin_SupplierAdmin + This module implements the OMG CosNotifyChannelAdmin::SupplierAdmin interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module also exports the functions described in:

+ + +

CosNotification_QoSAdmin

+
+ +

CosNotifyComm_NotifyPublish

+
+ +

CosNotifyFilter_FilterAdmin

+
+
+
+ + + _get_MyID(SupplierAdmin) -> AdminID + Return the objects Id + + SupplierAdmin = #objref + AdminID = long() + + +

When a SupplierAdmin object is created it is given a unique Id + by the creating channel. This readonly attribute maintains this Id.

+
+
+ + _get_MyChannel(SupplierAdmin) -> Channel + Return the objects associated channel + + SupplierAdmin = #objref + Channel = #objref + + +

The creating channel's reference is maintained by this readonly attribute.

+
+
+ + _get_MyOperator(SupplierAdmin) -> OpType + Return the filter scheme + + SupplierAdmin = #objref + OpType = 'AND_OP' | 'OR_OP' + + +

The Operation Type, which determines the semantics the target object will + use for any associated Filters, is maintained by this readonly attribute.

+
+
+ + _get_pull_consumers(SupplierAdmin) -> ProxyIDSeq + Return all associated pull consumers Id:s + + SupplierAdmin = #objref + ProxyIDSeq = [ProxyID] + ProxyID = long() + + +

A sequence of all associated PullProxy Id's is maintained by this + readonly attribute.

+
+
+ + _get_push_consumers(SupplierAdmin) -> ProxyIDSeq + Return all associated push consumers Id:s + + SupplierAdmin = #objref + ProxyIDSeq = [ProxyID] + ProxyID = long() + + +

This operation returns all PushProxy Id's created by the target + object.

+
+
+ + get_proxy_consumer(SupplierAdmin, ProxyID) -> Reply + Return the Proxy which corresponds to the given Id + + SupplierAdmin = #objref + ProxyID = long() + Reply = Proxy | {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}} + Proxy = #objref + + +

The Proxy which corresponds to the given Id is returned by this operation.

+
+
+ + obtain_notification_pull_consumer(SupplierAdmin, SupplierType) -> Reply + Create a new proxy + + SupplierAdmin = #objref + SupplierType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' + Reply = {Proxy, ProxyID} + Proxy = #objref + ProxyID = long() + + +

This operation creates a new proxy and returns its object reference along with its ID. + The SupplierType parameter determines the event type accepted by the proxy.

+
+
+ + obtain_pull_consumer(SupplierAdmin) -> Proxy + Create a new proxy + + SupplierAdmin = #objref + Proxy = #objref + + +

A proxy which accepts #any{} events is created by this operation.

+
+
+ + obtain_notification_push_consumer(SupplierAdmin, SupplierType) -> Reply + Create a new proxy + + SupplierAdmin = #objref + SupplierType = 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' + Reply = {Proxy, ProxyID} + Proxy = #objref + ProxyID = long() + + +

Determined by the SupplierType parameter a compliant proxy is created and + its object reference along with its Id is returned by this operation.

+
+
+ + obtain_push_consumer(SupplierAdmin) -> Proxy + Create a new proxy + + SupplierAdmin = #objref + Proxy = #objref + + +

A proxy which accepts #any{} events is created by this operation.

+
+
+ + destroy(SupplierAdmin) -> ok + Terminate the target object + + SupplierAdmin = #objref + + +

This operation terminates the SupplierAdmin object and notifies the creating channel + that the target object no longer is active.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml b/lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml new file mode 100644 index 0000000..427ca87 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyComm_NotifyPublish.xml @@ -0,0 +1,65 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyComm_NotifyPublish + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyComm_NotifyPublish + This module implements the OMG CosNotifyComm::NotifyPublish interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

All objects, which inherit this interface, export functions described in this module.

+
+ + + offer_change(Object, Added, Removed) -> Reply + Inform the target object which type of events the supplier will deliver + + Object = #objref + Added = Removed = EventTypeSeq + EventTypeSeq = [type] + Reply = ok | {'EXCEPTION', CosNotifyComm_InvalidEventType{type}} + type = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + + +

Objects supporting this interface can be informed by supplier objects about + which type of events that will be delivered in the future. This operation + accepts two parameters describing new and old event types respectively. + If any of the supplied event type names is syntactically incorrect an exception + is raised.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml b/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml new file mode 100644 index 0000000..1ed7f86 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml @@ -0,0 +1,64 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyComm_­NotifySubscribe + ..._NotifySubscribe + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyComm_NotifySubscribe + This module implements the OMG CosNotifyComm::NotifySubscribe interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

All objects, which inherit this interface, export functions described in this module.

+
+ + + subscription_change(Object, Added, Removed) -> Reply + Inform the target object which event types the client will and will not accept in the future + + Object = #objref + Added = Removed = EventTypeSeq + EventTypeSeq = [type] + Reply = ok | {'EXCEPTION', CosNotifyComm_InvalidEventType{type}} + type = #'CosNotification_EventType'{domain_name, type_name} + domain_name = type_name = string() + + +

This operation takes as input two sequences of event type names + specifying events the client will and will not accept in the future + respectively.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml b/lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml new file mode 100644 index 0000000..dd894f2 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyFilter_Filter.xml @@ -0,0 +1,222 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosNotifyFilter_Filter + + + + 2000-02-01 + 1.0 +
+ CosNotifyFilter_Filter + This module implements the OMG CosNotifyFilter::Filter interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+
+ + + _get_constraint_grammar(Filter) -> Grammar + Return which type of Grammar the Filter uses + + Filter = #objref + Grammar = string() + + +

This operation returns which type of Grammar the Filter uses. Currently, only "EXTENDED_TCL" is supported.

+
+
+ + add_constraints(Filter, ConstraintExpSeq) -> Reply + Add new constraints to the filter + + Filter = #objref + ConstraintExpSeq = [Constraint] + ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr} + event_types = #'CosNotification_EventTypeSeq'{} + constraint_expr = string() + Reply = ConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} + constr = ConstraintExp + ConstraintInfoSeq = [ConstraintInfo] + ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id} + constraint_expression = ConstraintExp + constraint_id = long() + + +

Initially, Filters do not contain any constraints, hence, all events will be forwarded. + The add_constraints/2 operation allow us to add constraints to the target object.

+
+
+ + modify_constraints(Filter, ConstraintIDSeq, ConstraintInfoSeq) -> Reply + Modify existing constraints + + Filter = #objref + ConstraintIDSeq = [ConstraintID] + ConstraintID = long() + ConstraintInfoSeq = [ConstraintInfo] + ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id} + constraint_expression = ConstraintExp + constraint_id = long() + Reply = ok | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}} + constr = ConstraintExp + id = long() + ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr} + event_types = #'CosNotification_EventTypeSeq'{} + constraint_expr = string() + + +

This operation is invoked by a client in order to modify the constraints associated + with the target object. The constraints related to the Id's in the parameter sequence + ConstraintIDSeq will, if all values are valid, be deleted. The ConstraintInfoSeq + parameter contains of Id-Expression pairs and a constraint matching one of the unique + Id's will, if all input values are correct, be updated. If the parameters contain incorrect + data en exception will be raised.

+
+
+ + get_constraints(Filter, ConstraintIDSeq) -> Reply + Return all constraints which match the supplied Ids + + Filter = #objref + ConstraintIDSeq = [ConstraintID] + ConstraintID = long() + Reply = ConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}} + ConstraintInfoSeq = [ConstraintInfo] + ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id} + constraint_expression = ConstraintExp + constraint_id = id = long() + + +

This operation return a sequence of ConstraintInfo's, related to the given ConstraintID's, + associated with the target object.

+
+
+ + get_all_constraints(Filter) -> ConstraintInfoSeq + Return all constraints associated with the target object + + Filter = #objref + ConstraintInfoSeq = [ConstraintInfo] + ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id} + constraint_expression = ConstraintExp + constraint_id = long() + + +

All constraints, and their unique Id, associated with the target object will be returned by this operation.

+
+
+ + remove_all_constraints(Filter) -> ok + Remove all constraints associated with the target object + + Filter = #objref + + +

All constraints associated with the target object are removed by this operation and, since + the the target object no longer contain any constraints, true will always be the result of + any match operation.

+
+
+ + destroy(Filter) -> ok + Terminate the target object + + Filter = #objref + + +

This operation terminates the target object.

+
+
+ + match(Filter, Event) -> Reply + Match the Any event if it satisfies at least one constraint + + Filter = #objref + Event = #any + Reply = boolean() | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}} + + +

This operation accepts an #any{} event and returns true if it satisfies + at least one constraint. If the event contains data of the wrong type, e.g., should be + a string() but in fact i a short(), an exception is raised.

+
+
+ + match_structured(Filter, Event) -> Reply + Match the structured event if it satisfies at least one constraint + + Filter = #objref + Event = #'CosNotification_StructuredEvent'{} + Reply = boolean() | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}} + + +

This operation is similar to the match operation but accepts structured + events instead.

+
+
+ + attach_callback(Filter, NotifySubscribe) -> CallbackID + Connect NotifySubscribe object, which should be informed when the target object's constraints are updated + + Filter = #objref + NotifySubscribe = #objref + CallbackID = long() + + +

This operation connects a NotifySubscribe object, which should be informed + when the target object's constraints are updated. A unique Id is returned + which must be stored if we ever want to detach the callback object in the future.

+
+
+ + detach_callback(Filter, CallbackID) -> Reply + Disconnect the NotifySubscribe object with the given Id + + Filter = #objref + CallbackID = long() + Reply = ok | {'EXCEPTION', #'CosNotifyFilter_CallbackNotFound'{}} + + +

If the target object has an associated callback that matches the supplied + Id it will be removed and longer informed of any updates. If no object + with a matching Id is found an exception is raised.

+
+
+ + get_callbacks(Filter) -> CallbackIDSeq + Return all NotifySubscribe Id's associated with the target object + + Filter = #objref + CallbackIDSeq = [CallbackID] + CallbackID = long() + + +

This operation returns a sequence of all connected NotifySubscribe object Id's. + If no callbacks are associated with the target object the list will be empty.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml b/lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml new file mode 100644 index 0000000..ebbba87 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyFilter_FilterAdmin.xml @@ -0,0 +1,111 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyFilter_FilterAdmin + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyFilter_FilterAdmin + This module implements the OMG CosNotifyFilter::FilterAdmin interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

All objects, which inherit this interface, export functions described in this module.

+
+ + + add_filter(Object, Filter) -> FilterID + Add a new filter to the target object + + Object = #objref + Filter = #objref + FilterID = long() + + +

This operation connects a new Filter to the target object. This Filter will, together + with other associated Filters, be used to select events to forward. A unique Id is + returned and should be used if we no longer want to consult the given Filter.

+
+
+ + remove_filter(Object, FilterID) -> ok + Remove a filter associated with the target object + + Object = #objref + FilterID = long() + + +

If a certain Filter no longer should be associated with the target object + this operation must be used. Events will no longer be tested against the Filter + associated with the given Id.

+
+
+ + get_filter(Object, FilterID) -> Reply + Return the filter with the given Id + + Object = #objref + FilterID = long() + Reply = Filter | {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} + Filter = #objref + + +

If the target object is associated with a Filter matching the given Id the + reference will be returned. If no such Filter is known by the target object + an exception is raised.

+
+
+ + get_all_filters(Object) -> FilterIDSeq + Return a list of all filter Id:s associated with the target object + + Object = #objref + FilterIDSeq = [FilterID] + FilterID = long() + + +

Id's for all Filter objects associated with the target object is + returned by this operation.

+
+
+ + remove_all_filters(Object) -> ok + Remove all filters from the target object + + Object = #objref + + +

If we want to remove all Filters associated with the target object we can use this function.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml b/lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml new file mode 100644 index 0000000..c4712e4 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyFilter_FilterFactory.xml @@ -0,0 +1,73 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNotifyFilter_FilterFactory + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosNotifyFilter_FilterFactory + This module implements the OMG CosNotifyFilter::FilterFactory interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+
+ + + create_filter(FilterFactory, Grammar) -> Reply + Create a Filterobject + + FilterFactory = #objref + Grammar = string() + Reply = Filter | {'EXCEPTION', #'CosNotifyFilter_InvalidGrammar'{}} + Filter = #objref + + +

This operation creates a new Filter object, under the condition + that Grammar given is supported. Currently, only "EXTENDED_TCL" is supported.

+
+
+ + create_mapping_filter(FilterFactory, Grammar) -> Reply + Create a MappingFilterobject + + FilterFactory = #objref + Grammar = string() + Reply = MappingFilter | {'EXCEPTION', #'CosNotifyFilter_InvalidGrammar'{}} + Filter = #objref + + +

This operation creates a new MappingFilter object, under the condition + that Grammar given is supported. Currently, only "EXTENDED_TCL" is supported.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml b/lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml new file mode 100644 index 0000000..f5c6a75 --- /dev/null +++ b/lib/cosNotification/doc/src/CosNotifyFilter_MappingFilter.xml @@ -0,0 +1,227 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosNotifyFilter_MappingFilter + + + + 2000-02-01 + 1.0 +
+ CosNotifyFilter_MappingFilter + This module implements the OMG CosNotifyFilter::MappingFilter interface. + +

The main purpose of this module is to match events against associated + constraints and return the value for the first constraint that returns + true for the given event. If all constraints return false the default value + will be returned.

+

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+
+ + + _get_constraint_grammar(MappingFilter) -> Grammar + Return which type of Grammar the MappingFilter uses + + MappingFilter = #objref + Grammar = string() + + +

This operation returns which type of Grammar the MappingFilter uses. + Currently, only "EXTENDED_TCL" is supported.

+
+
+ + _get_value_type(MappingFilter) -> CORBA::TypeCode + Return the CORBA::TypeCodeof the default value associated with the target object + + MappingFilter = #objref + + +

This readonly attribute maintains the CORBA::TypeCode of the default value + associated with the target object.

+
+
+ + _get_default_value(MappingFilter) -> #any + Return the #any{} default value associated with the target object + + MappingFilter = #objref + + +

This readonly attribute maintains the #any{} default value associated with + the target object.

+
+
+ + add_mapping_constraints(MappingFilter, MappingConstraintPairSeq) -> Reply + Add new mapping constraints + + MappingFilter = #objref + MappingConstraintPairSeq = [MappingConstraintPair] + MappingConstraintPair = #'CosNotifyFilter_MappingConstraintPair'{constraint_expression, result_to_set} + constraint_expression = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr} + event_types = #'CosNotification_EventTypeSeq'{} + constraint_expr = string() + result_to_set = #any + Reply = MappingConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} | {'EXCEPTION', #'CosNotifyFilter_InvalidValue'{constr, value}} + constr = ConstraintExp + ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr} + event_types = #'CosNotification_EventTypeSeq'{} + constraint_expr = string() + MappingConstraintInfoSeq = [MappingConstraintInfo] + MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value} + constraint_expression = ConstraintExp + constraint_id = long() + value = #any + + +

This operation add new mapping constraints, which will be used when trying to override + Quality of Service settings defined in the given event. If a constraint return true the + associated value will be returned, otherwise the default value.

+
+
+ + modify_constraints(MappingFilter, ConstraintIDSeq, MappingConstraintInfoSeq) -> Reply + Modify the constraints associated with the target object + + MappingFilter = #objref + ConstraintIDSeq = [ConstraintID] + ConstraintID = long() + MappingConstraintInfoSeq = [MappingConstraintInfo] + MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value} + constraint_expression = ConstraintExp + constraint_id = long() + value = #any + ConstraintInfoSeq = [ConstraintInfo] + ConstraintInfo = #'CosNotifyFilter_ConstraintInfo'{constraint_expression, constraint_id} + constraint_expression = ConstraintExp + constraint_id = long() + Reply = ok | {'EXCEPTION', #'CosNotifyFilter_InvalidConstraint'{constr}} | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}} | {'EXCEPTION', #'CosNotifyFilter_InvalidValue'{constr, value}} + constr = ConstraintExp + id = long() + value = #any + ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr} + event_types = #'CosNotification_EventTypeSeq'{} + constraint_expr = string() + + +

The ConstraintIDSeq supplied should relate to constraints the caller wishes to + remove. If any of the supplied Id's are not found an exception will be raised. This + operation also accepts a sequence of MappingConstraintInfo which will be added. + If the target object cannot modify the constraints as requested an exception is raised + describing which constraint, and why, could not be updated.

+
+
+ + get_mapping_constraints(MappingFilter, ConstraintIDSeq) -> Reply + Return the target object's associated constraints with given ID:s + + MappingFilter = #objref + ConstraintIDSeq = [ConstraintID] + ConstraintID = long() + Reply = MappingConstraintInfoSeq | {'EXCEPTION', #'CosNotifyFilter_ConstraintNotFound'{id}} + MappingConstraintInfoSeq = [MappingConstraintInfo] + MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value} + constraint_expression = ConstraintExp + ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr} + event_types = #'CosNotification_EventTypeSeq'{} + constraint_expr = string() + constraint_id = id = long() + value = #any + + +

When adding a new constraint a unique Id is returned, which is accepted as input for this + operation. The associated constraint is returned, but if no such Id exists an exception is raised.

+
+
+ + get_all_mapping_constraints(MappingFilter) -> MappingConstraintInfoSeq + Return the target object's all associated constraints + + MappingFilter = #objref + MappingConstraintInfoSeq = [MappingConstraintInfo] + MappingConstraintInfo = #'CosNotifyFilter_MappingConstraintInfo'{constraint_expression, constraint_id, value} + constraint_expression = ConstraintExp + ConstraintExp = #'CosNotifyFilter_ConstraintExp'{event_types, constraint_expr} + event_types = #'CosNotification_EventTypeSeq'{} + constraint_expr = string() + constraint_id = long() + value = #any + + +

This operation returns a sequence of all unique Id's associated with the target object. + If no constraint have been added the sequence will be empty.

+
+
+ + remove_all_mapping_constraints(MappingFilter) -> ok + Remove all constraints associated with the target object + + MappingFilter = #objref + + +

This operation removes all constraints associated with the target object.

+
+
+ + destroy(MappingFilter) -> ok + Terminate the target object + + MappingFilter = #objref + + +

This operation terminates the target object. Remember to remove + this Filter from the objects it have been associated with.

+
+
+ + match(MappingFilter, Event) -> Reply + Evaluate the given Any event with the Filter's constraints + + MappingFilter = #objref + Event = #any + Reply = {boolean(), #any} | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}} + + +

This operation evaluates Any events with the Filter's constraints, + and returns the value to use. The value is the default value if all constraints + returns false and the value associated with the first constraint returning true.

+
+
+ + match_structured(MappingFilter, Event) -> Reply + Evaluate the given structured event with the Filter's constraints + + MappingFilter = #objref + Event = #'CosNotification_StructuredEvent'{} + Reply = {boolean(), #any} | {'EXCEPTION', #'CosNotifyFilter_UnsupportedFilterableData'{}} + + +

Similar to match/2 but accepts a structured event as input.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/Makefile b/lib/cosNotification/doc/src/Makefile new file mode 100644 index 0000000..6abcf0e --- /dev/null +++ b/lib/cosNotification/doc/src/Makefile @@ -0,0 +1,254 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(COSNOTIFICATION_VSN) +APPLICATION=cosNotification + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + cosNotificationApp.xml \ + CosNotifyChannelAdmin_EventChannelFactory.xml \ + CosNotifyChannelAdmin_EventChannel.xml \ + CosNotification.xml \ + CosNotification_QoSAdmin.xml \ + CosNotification_AdminPropertiesAdmin.xml \ + CosNotifyChannelAdmin_ConsumerAdmin.xml \ + CosNotifyChannelAdmin_SupplierAdmin.xml \ + CosNotifyComm_NotifyPublish.xml \ + CosNotifyComm_NotifySubscribe.xml \ + CosNotifyFilter_FilterAdmin.xml \ + CosNotifyFilter_FilterFactory.xml \ + CosNotifyFilter_Filter.xml \ + CosNotifyFilter_MappingFilter.xml \ + CosNotifyChannelAdmin_ProxyConsumer.xml \ + CosNotifyChannelAdmin_ProxySupplier.xml \ + CosNotifyChannelAdmin_ProxyPullConsumer.xml \ + CosNotifyChannelAdmin_ProxyPullSupplier.xml \ + CosNotifyChannelAdmin_ProxyPushConsumer.xml \ + CosNotifyChannelAdmin_ProxyPushSupplier.xml \ + CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml \ + CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml \ + CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml \ + CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml \ + CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml \ + CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml \ + CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml \ + CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml \ + + + +XML_PART_FILES = \ + part.xml \ + part_notes.xml +XML_CHAPTER_FILES = \ + ch_contents.xml \ + ch_introduction.xml \ + ch_install.xml \ + ch_system.xml \ + ch_BNF.xml \ + ch_QoS.xml \ + ch_example.xml \ + notes.xml + +BOOK_FILES = book.xml + +TECHNICAL_DESCR_FILES = + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif \ + eventstructure.gif \ + notificationFlow.gif + +PS_FILES = + +# ---------------------------------------------------- + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf + +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(INTERNAL_HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTML_FILES) $(MAN3_FILES) + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) + +endif + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +$(INDEX_TARGET): $(INDEX_SRC) + sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + +release_spec: + diff --git a/lib/cosNotification/doc/src/book.gif b/lib/cosNotification/doc/src/book.gif new file mode 100644 index 0000000000000000000000000000000000000000..94b38687920c5386f0d90df2cfc962d66f52fbce GIT binary patch literal 1081 zcmV-91jhSENk%v~VJrYQ0K@U3Z&d%1>*52OU z=jZ3|@9+2b_W%F@EC2ui04xAE000I5ARvxpX`Uh%Eez$Ma2!{|XMe{g?|T;9x5JA^ zG%bL@N^vRj5RkV9bLkO4ZPIBmas5oR#mf&V1Q#(0YhcjmXe*9~d=7a)?vMy(=-KE* z8yQRzT~`AL3l4P-3kL!Lf=d(yg_TGJLq#4K5D7Jwg%4&P850c&1Y@8d0)H_S5pFPj z7ZR$K4m$^o4iXXx39coCpaZff8wUU$784g63O)Mnh1d zM*Ony;LwB#3?8W4Fn~dfDxggNp6C!kf(B*{AQb3^!o#OZ2{2Ij__0FI3O->S0!o2G zg@f-96evKTsnY>a2Pj~$%K;+++!`!k(;yCksSK!^1M@%uPY44fe1t$i?MDI+c2ZbC za|F=4KrQICaN${m0^A%h5YV8o0a~3adU`fEQr`1qssBIw;^v!UF;k;yW-v@4+eo>JYd}fHVVU z5gLf*p9x%mVi^DlSTI8WPNw|_zy%J@^^O%t7;wu6|1F@62n+%+n+O+(7C~JYKp}tz zPXIAiOdhnDfD0a6fWQkLNGO6;!$2WQfj6jx)&W2YPymny2!Ox=N)36z-FBgSXr4c6dN%+LI-06;0gjrH4CDHEr=iiO;mnh?Fk3i5Wq1C#9AnbqG>3C zxFaCoE>b2iV1odev}UfA7}V< + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosNotification + Niclas Eklund + + 2000-01-31 + 1.0 +
+ + + cosNotification + + + + + + + + + + + + + + +
+ diff --git a/lib/cosNotification/doc/src/ch_BNF.xml b/lib/cosNotification/doc/src/ch_BNF.xml new file mode 100644 index 0000000..545280a --- /dev/null +++ b/lib/cosNotification/doc/src/ch_BNF.xml @@ -0,0 +1,456 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Filters and the Constraint Language BNF + + + 2000-04-13 + + ch_BNF.xml +
+ +
+ Filters and the Constraint Language BNF +

This chapter describes, the grammar supported by + CosNotifyFilter_Filter and + CosNotifyFilter_MappingFilter, + and how to create and use filter objects. +

+ +
+ How to create filter objects +

To be able to filter events we must create a filter and associate + it with one, or more, of the administrative or proxy objects. In the example + below, we choose to associate the filter with a ConsumerAdmin object.

+ +FilterFactory = cosNotificationApp:start_filter_factory(), +Filter = 'CosNotifyFilter_FilterFactory': + create_filter(FilterFactory,"EXTENDED_TCL"), +ConstraintInfoSeq = 'CosNotifyFilter_Filter': + add_constraints(Filter, ConstraintExpSeq), +FilterID = 'CosNotifyChannelAdmin_ConsumerAdmin': + add_filter(AdminConsumer, Filter), + +

"EXTENDED_TCL" is the only grammar supported by Orber Notification + Service.

+

Depending on which operation type the Admin object uses, i.e., + 'AND_OP' or 'OR_OP', events will be tested using the + associated filter. The operation properties are:

+

+ + +

'AND_OP' - must be approved by the proxy's and its parent admin's + filters. If all filters associated with an object (Admin or Proxy) + return false the event will be discarded. In this situation it is pointless + to try and verify with the other object's associated filters since the outcome + still would be the same.

+
+ +

'OR_OP' - if one of the object's (Admin or Proxy) filters return true, the event + will not be checked against any other filter associated with a proxy or its + parent admin. If a object's associated filters all return false, + the event will be forwarded to related proxies/admins, and + tested against any associated filters.

+
+
+

Initially, filters are empty and will always return true. Hence, we must + add constraints by using 'CosNotifyFilter_Filter':add_constraints/2. + As input, the second argument must be a sequence of:

+ +#'CosNotifyFilter_ConstraintExp'{ + event_types = [#'CosNotification_EventType'{ + domain_name = string(), + type_name = string()}], + constraint_expr = string()} + +

The event_types describes which types of events that should be matched using + the associated constraint_expr.

+

If a constraint expression is supposed to apply for all events, then the type_name can + be set to the special event type %ALL in a constraint's event type sequence. The + domain_name should be "" or "*".

+

In the following sections we will take a closer look on how to write + constraint expressions.

+
+ +
+ The CosNotification Constraint Language +

The constraint language supported by the Notification Service is:

+ := /* empty */ + | + + := + + := or + | + + := and + | + + := == + | != + | < + | <= + | > + | >= + | + + := in /* sequence only */ + | + | in $ /* sequence only */ + + := ~ /* string data types only */ + | + + := + + | - + | + + := * + | / + | + + := not + | + + := ( ) + | exist + | + | + | - + | + | TRUE + | FALSE + | + + | exist $ + | $ + | default $ /* discriminated unions only */ + + := /* empty */ + | . + | + | + | /* run-time variable */ + + := /* empty */ + | . + | + | + + := + | + | + | _length /* only valid for arrays or sequences */ + | _d /* discriminated unions only */ + | _type_id /* only valid if possible to obtain */ + | _repos_id /* only valid if possible to obtain */ + + := [ ] + + := ( ) + + := + + := ( ) + + := /* empty */ + | + | - + | + + | + +/* Character set issues */ + := + | \\ < Leader> + + := /* */ + | + + := + | + + := + | . + | . + | . + + := + + := + + | - + + := E + | e + + := + | + + := ' ' + + := /* */ + | + + := + | + | + | + + := \\\\ + | \\' + + := + + := + | + | _ + + is the set of alphabetic characters [A-Za-z] + is the set of digits [0-9] + is the set of ASCII characters that are not , , or + ]]> +

In the absence of parentheses, the following precedence relations hold :

+ + (), exist, default, unary-sign + not + *, / + +, - + ~ + in + ==, !=, , , >, >= + and + or + +
+ +
+ The Constraint Language Data Types +

The Notification Service Constraint Language, defines how to write + constraint expressions, which can be used to filter events. The + representation does, however, differ slightly from ordinary Erlang terms.

+

When creating a ConstraintExp, the field constraint_expr must be + set to contain a string, e.g., . The Notification Service Constraint + Language, is designed to be able to filter structured and unstructured events + using the same constraint expression. The Constraint Language Types and Operations + can be divided into two sub-groups:

+ + +

Basic - arithmetics, strings, constants, numbers etc.

+
+ +

Complex - accessing members of complex data types, such as unions.

+
+
+

Some of the basic types, e.g., integer, are self explanatory. Hence, they are not described further.

+ + + Type/Operation + Examples + Description + + + string + "'MyString'" + Strings are represented as a sequence of zero or more ]]>s enclosed in single quotes, e.g., 'string'. + + + ~ + "'Sring1' ~ 'String2'" + The operator ~is called the substring operator and mean "String1 is contained within String2". + + + boolean + "TRUE == (('lang' ~ 'Erlang' + 'fun' ~ 'functional') >= 2)" + Booleans may only be TRUE or FALSE, i.e., only capital letters. Expressions which evaluate to TRUE or FALSE can be summed up and matched, where TRUE equals 1 and FALSE 0. + + + sequence + "myIntegerSequence[2]" + The BNF use C/C++ notation, i.e., the example will return the thirdelement. + + + _length + "myIntegerSequence._length" + Returns the length of an sequence or array. + + + in + "'Erlang' in $.FunctionalLanguages­StringSeq" + Returns TRUEif a given element is found in the given sequence. The element must be of a simple type and the same as the sequence is defined to contain. + + + $ + "$ == 40" + Denote the current event as well as any run-time variables. If the event is unstructured and its contained value 40, the example will return TRUE. + + + . + "$.MyStructMember == 40" + The structure member operator .may be used to reference its members when the data refers to a named structure, discriminated union, or CORBA::Any data structure. + + + _type_id + "$._type_id == 'MyStruct'" + Returns the unscoped IDL type name of the component. This operation is only valid if said information can be obtained. + + + _repos_id + "$._repos_id == 'IDL:MyModule/MyStruct:1.0'" + Returns the RepositoryId of the component. This operation is only valid if said information can be obtained. + + + _d + "$.eventUnion._d" + May only be used when accessing discriminated unions and refers to the discriminator. + + + exist + "exist $.eventUnion._d and $.eventUnion._d == 10" + To avoid that a filtering of an event fails due to that, for example, we try to compare a union discriminator which does not exist, we can use this operator. + + + default + "default $.eventUnion._d" + If the _doperation is in conjunction with the defaultoperation, TRUE will be returned if the union has a default member that is active. + + + union + "$.(0) == 5"eq. "$.('zero') == 5" + When the component refers to a union, with one of the cases defined as case 0: short zero;, we use 0or 'zero'. The result of the example is TRUEif the union has a discriminator set to 0and the value 5. If more than one case is defined to be'zero', $.('zero')accepts both; $.(0)only returns TRUEif the discriminator is set to 0. Leaving out the identifier, i.e., $.(), refers to the default value. + + + name-value pairs + "$.NameValueSeq('myID') == 5"eq."$.NameValueSeq[1].name == 'myID' and $.NameValueSeq[1].value == 5" + The Notification service makes extensive use of name-value pairssequences within structured events, which allow us to via the identifier nameaccess its value, as shown in the example. + + Table 1: Type and Operator Examples +
+

In the next section we will take a closer look at how it is possible to write constraints using + different types of notation etc.

+
+ +
+ Accessing Data In Events +

To filter events, the supplied constraints must describe the contents of + the events and desired values. We can, for example, state that we are only + interested in receiving events which are of type CommunicationsAlarm. + To be able to achieve this, the constraint must contain information + that points out which fields to compare with. Figure one illustrates a conceptual overview of a + structured event. The exact definition is found in the CosNotification.idl file.

+ + + +Figure 1: The structure of a structured event. + +

The Notification Service supports different constraint expressions + notation:

+ + +

Fully scoped, e.g., "$.header.fixed_header.event_type.type_name == 'CommunicationsAlarm'"

+
+ +

Short hand, e.g., "$type_name == 'CommunicationsAlarm'"

+
+ +

Positional Notation, e.g., "$.0.0.0.1 == 'CommunicationsAlarm'"

+
+
+ +

Which notation to use is up to the user, however, the fully scoped may + be easier to understand, but in some cases, if received from an ORB that do not populate ID:s of + named parts, the positional notation is the only option.

+
+ +

If a constraint, which access fields in a structured event structure, + is supposed to handle unstructured events as well, the CORBA::Any must contain + the same type of members.

+
+

How to filter against the fixed header fields, is described in the + table below.

+ + + Field + Fully Scoped Constraint + Short Hand Constraint + + + type_name + "$.header.fixed_header.event_­type.type_name == 'Type'" + "$type_name == 'Type'" + + + domain_name + "$.header.fixed_header.event_­type.domain_name == 'Domain'" + "$domain_name == 'Domain'" + + + event_name + "$.header.fixed_header.event_­name == 'Event'" + "$event_name == 'Event'" + + Table 2: Fixed Header Constraint Examples +
+

If we are only interested in receiving events regarding 'Domain', 'Event' + and 'Type', the constraint can look like + "$domain_name == 'Domain' and $event_name == 'Event' and $type_name == 'Type'".

+

The variable event header consists of a sequence of name-value pairs. One way to filter on these are to use a constraint that looks + like "($.header.variable_header[1].name == 'priority' and $.header.variable_header[1].value > 0)". An easier way to + accomplish the same result is to use a constraint that treats the name-value + pair as an associative array, i.e., when given a name the corresponding + value is returned. Hence, instead we can use + "$.header.variable_header(priority) > 0".

+

Accessing the event body is done in the same way as for the event header + fields. The user must, however, be aware of, that if a run-time variable + ($variable) is used data in the event header may take precedence. + The order of precedence is:

+ + Reserved, e.g., $curtime + A simple-typed member of $.header.fixed_header. + Properties in $.header.variable_header. + Properties in $.filterable_data. + If no match is found it is translated to $.variable. + +
+ +
+ Mapping Filters +

Mapping Filters may only be associated with Consumer Administrators or Proxy + Suppliers. The purpose of a Mapping Filter is to override Quality of Service + settings.

+

Initially, Mapping Filters are empty and will always return true. Hence, we must + add constraints by using 'CosNotifyFilter_MappingFilter':add_mapping_constraints/2. + If a constraint matches, the associated value will be used instead of the + related Quality of Service system settings.

+

As input, the second argument must be a sequence of:

+ +#'CosNotifyFilter_MappingConstraintPair'{ + constraint_expression = #'CosNotifyFilter_ConstraintExp'{ + event_types = [#'CosNotification_EventType'{ + domain_name = string(), + type_name = string()}], + constraint_expr = string()}, + result_to_set = any()} + +
+
+
+ diff --git a/lib/cosNotification/doc/src/ch_QoS.xml b/lib/cosNotification/doc/src/ch_QoS.xml new file mode 100644 index 0000000..fbc8622 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_QoS.xml @@ -0,0 +1,251 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Quality Of Service and Admin Properties + + + 2000-05-29 + + ch_QoS.xml +
+ +
+ Quality Of Service and Admin Properties +

This chapter explains the allowed properties for + CosNotification_QoSAdmin and + CosNotification_AdminPropertiesAdmin. +

+ +
+ Quality Of Service +

The cosNotification application supports the following QoS settings:

+ + + QoS + Range + Default + + + EventReliability + BestEffort/Persistent + BestEffort + + + ConnectionReliability + BestEffort/Persistent + BestEffort + + + Priority + +/-32767 + 0 + + + OrderPolicy + Any-, Fifo-, Priority- and Deadline-Order + PriorityOrder + + + DiscardPolicy + RejectNewEvents, Any-, Fifo-, Lifo-, Priority- and Deadline-Order + RejectNewEvents + + + MaximumBatchSize + long() > 0 + 1 + + + PacingInterval + TimeBase::TimeT (see cosTime) + 0 + + + StartTimeSupported + boolean + false + + + StopTimeSupported + boolean + false + + + MaxEventsPerConsumer + long() > 0 + 100 + + + Timeout + TimeBase::TimeT (see cosTime) + No timeout + + Table 1: Supported QoS Settings +
+

+

+

+

+

Comments on the table 'Supported QoS Settings':

+ + EventReliability + To allow full Persistent EventReliability, every event must + be stored in a stable storage which would create a relatively + huge overhead. Hence, only lightweight version of the Persistent + QoS is supported. The configuration parameters max_events, + interval_events and timeout_events determine + the behavior of this setting. + ConnectionReliability + If this QoS is set to BestEffort and a client object returns anything + other than ok to its associated Proxy, the Proxy will discard + all events and terminate. Using Persistent and anything other than ok + is returned, events will be dropped but the proxy will retry later when + next delivery is due. A child may not have Persistent while its parent + has BestEffort QoS set, e.g., Proxy vs. Admin. If OBJECT_NOT_EXIST, + NO_PERMISSION or CosEventComm_Disconnected is thrown, + the associated object will terminate even if this parameter is + set to Persistent. + Priority + This QoS will treat all events as if they have the Priority equal to + current value, unless the event itself contains a Priority setting, + this event will be treated accordingly. Note: for this property to + have any effect, the DiscardPolicy and/or OrderPolicy must be set + to PriorityOrder. + OrderPolicy + If set to PriorityOrder, events with the highest Priority will be + delivered first. Deadline order will forward events with shortest + expiry time first. If two events have the same priority, they will be + delivered in FIFO-order. + DiscardPolicy + If set to PriorityOrder and MaxEventsPerConsumer limit is + reached, events + with the lowest Priority will be discarded first. Deadline order will + discard events with shortest expiry time first. + MaximumBatchSize + Only valid if the object is supposed to handle a sequence of structured + events and determines the largest amount of events that may be passed + each time. + PacingInterval + Determines how long an object will wait before forwarding a structured + event sequence of length equal to, or less than MaximumBatchSize. + If set to 0, which is the default behavior, no timeout is used and + the events are forwarded when the MaximumBatchSize is reached. + StartTimeSupported + If set to true events which contains the QoS Property StartTime + (TimeBase::UtcT - absolute time) will not be delivered until the + StartTime value have been exceeded. See also the cosTime application. + StopTimeSupported + If set to true, events which contain the QoS Properties StopTime + (TimeBase::UtcT - absolute time) or Timeout (TimeBase::TimeT - + relative time) will be discarded if the object has not been able to + deliver the event in time. See also the cosTime application. + MaxEventsPerConsumer + The maximum number of events the associated object may store before discarding + events in the way described by the DiscardPolicy. + Timeout + If this QoS property is not included in the event, and the Property + StopTimeSupported equals true, this setting will be applied + if events cannot be delivered within its time limit. + + +

Several of the above QoS Properties can be changed during run-time but we strongly advice + not to since, if a relatively large amount of events are waiting for delivery, some of the + QoS settings would require a total reorder of the events. The QoS property ConnectioReliability + may never be updated during run-time since it may cause deadlock. Run-time, in this case, + means activating the Channel by sending the first event.

+
+
+ +
+ Setting Quality Of Service +

Assume we have a Consumer Admin object which we want to change + the current Quality of Service. Typical usage:

+ +QoSPersistent = + [#'CosNotification_Property' + {name='CosNotification':'ConnectionReliability'(), + value=any:create(orber_tc:short(), + 'CosNotification':'Persistent'())}], +'CosNotification_QoSAdmin':set_qos(Ch, QoSPersistent), + +

If it is not possible to set the requested QoS the UnsupportedQoS + exception is raised, which includes a sequence of PropertyError's + describing which QoS, possible range and why is not allowed. The error + codes are:

+ + UNSUPPORTED_PROPERTY - QoS not supported for this type of target object. + UNAVAILABLE_PROPERTY - due to current QoS settings the given property + is not allowed. + UNSUPPORTED_VALUE - property value out of range; valid range is returned. + UNAVAILABLE_VALUE - due to current QoS settings the given value is + not allowed; valid range is returned. + BAD_PROPERTY - unrecognized property. + BAD_TYPE - type of supplied property is incorrect. + BAD_VALUE - illegal value. + +

The CosNotification_QoSAdmin interface also supports an operation + called validate_qos/2. The purpose of this operations is to check + if a QoS setting is supported by the target object and if so, the operation + returns additional properties which could be optionally added as well.

+
+ +
+ Admin Properties +

The cosNotification application supports the following Admin Properties:

+ + + Property + Range + Default + + + MaxQueueLength + 0 + 0 + + + MaxConsumers + long() >= 0 + 0 + + + MaxSuppliers + long() >= 0 + 0 + + Table 2: Supported Admin Properties +
+

According to the OMG specification the default values for Admin Properties + is supposed to be 0, which means that no limit applies to these + properties.

+ +

Admin Properties can only be set on a Channel Object level, i.e., + they will not have an impact on any Admin or Proxy Objects. Currently, + setting the Admin Property MaxQueueLength have no effect since + we cannot discard events accordingly to the Quality of Service Property + DiscardPolicy.

+
+
+
+
+ diff --git a/lib/cosNotification/doc/src/ch_contents.xml b/lib/cosNotification/doc/src/ch_contents.xml new file mode 100644 index 0000000..e550595 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_contents.xml @@ -0,0 +1,74 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The cosNotification Application + Niclas Eklund + + 2000-01-31 + 1.0 + ch-contents.xml +
+ +
+ Content Overview +

The cosNotification documentation is divided into three sections: +

+ + +

PART ONE - The User's Guide +

+Description of the cosNotification Application including + services and a small tutorial demonstrating + the development of a simple service.

+
+ +

PART TWO - Release Notes +

+A concise history of cosNotification.

+
+ +

PART THREE - The Reference Manual +

+ A quick reference guide, including a + brief description, to all the functions available in cosNotification.

+
+
+
+ +
+ Brief Description of the User's Guide +

The User's Guide contains the following parts:

+ + +

cosNotification overview

+
+ +

cosNotification installation

+
+ +

A tutorial example

+
+
+
+
+ diff --git a/lib/cosNotification/doc/src/ch_example.xml b/lib/cosNotification/doc/src/ch_example.xml new file mode 100644 index 0000000..8cb12bd --- /dev/null +++ b/lib/cosNotification/doc/src/ch_example.xml @@ -0,0 +1,169 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosNotification Examples + Niclas Eklund + + 2000-01-31 + A + ch_example.xml +
+ +
+ A Tutorial on How to Create a Simple Service + +
+ Interface Design +

To use the cosNotification application clients must be implemented. + There are twelve types of clients:

+ + Structured Push Consumer + Sequence Push Consumer + Any Push Consumer + Structured Pull Consumer + Sequence Pull Consumer + Any Pull Consumer + Structured Push Supplier + Sequence Push Supplier + Any Push Supplier + Structured Pull Supplier + Sequence Pull Supplier + Any Pull Supplier + +

The interfaces for these participants are defined in CosNotification.idl + and CosNotifyComm.idl.

+
+ +
+ Generating a Client Interface +

We start by creating an interface which inherits from the correct interface, e.g., CosNotifyComm::SequencePushConsumer. Hence, + we must also implement all operations defined in the SequencePushConsumer interface. The IDL-file could look like:

+ +#include + +module myClientImpl { + + interface ownInterface:CosNotifyComm::SequencePushConsumer { + + void ownFunctions(in any NeededArguments) + raises(Systemexceptions,OwnExceptions); + + }; +}; + +#endif + ]]> +

Run the IDL compiler on this file by calling the ic:gen/1 function. + This will produce the API named myClientImpl_ownInterface.erl. + After generating the API stubs and the server skeletons it is time to + implement the servers and if no special options are sent + to the IDl compiler the file name is myClientImpl_ownInterface_impl.erl.

+

The callback module must contain the necessary functions inherited from + CosNotification.idl and CosNotifyComm.idl.

+
+ +
+ How to Run Everything +

Below is a short transcript on how to run cosNotification.

+ + +%% Start Mnesia and Orber +mnesia:delete_schema([node()]), +mnesia:create_schema([node()]), +orber:install([node()]), +mnesia:start(), +orber:start(), + +%% If cosEvent not installed before it is necessary to do it now. +cosEventApp:install(), + +%% Install cosNotification in the IFR. +cosNotificationApp:install(30), + +%% Register the application specific Client implementations +%% in the IFR. +'oe_myClientImpl':'oe_register'(), + +%% Start the cosNotification application. +cosNotificationApp:start(), + +%% Start a factory using the default configuration +ChFac = cosNotificationApp:start_factory(), +%% ... or use configuration parameters. +ChFac = cosNotificationApp:start_factory([]), + +%% Create a new event channel. Note, if no QoS- anr/or Admin-properties +%% are supplied (i.e. empty list) the default settings are used. +{Ch, ChID} = 'CosNotifyChannelAdmin_EventChannelFactory': + create_channel(ChFac, DefaultQoS, DefaultAdmin), + +%% Retrieve a SupplierAdmin and a Consumer Admin. +{AdminSupplier, ASID}= + 'CosNotifyChannelAdmin_EventChannel':new_for_suppliers(Ch, 'OR_OP'), +{AdminConsumer, ACID}= +\011'CosNotifyChannelAdmin_EventChannel':new_for_consumers(Ch,'OR_OP'), + +%% Use the corresponding Admin object to get access to wanted Proxies + +%% Create a Push Consumer Proxie, i.e., the Client Push Supplier will +%% push events to this Proxy. +{StructuredProxyPushConsumer,ID11}= 'CosNotifyChannelAdmin_SupplierAdmin': + obtain_notification_push_consumer(AdminSupplier, 'STRUCTURED_EVENT')), + +%% Create Push Suppliers Proxies, i.e., the Proxy will push events to the +%% registered Push Consumers. +{ProxyPushSupplier,I4D}='CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_push_supplier(AdminConsumer, 'ANY_EVENT'), +{StructuredProxyPushSupplier,ID5}='CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_push_supplier(AdminConsumer, 'STRUCTURED_EVENT'), +{SequenceProxyPushSupplier,ID6}='CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_push_supplier(AdminConsumer, 'SEQUENCE_EVENT'), + +%% Create application Clients. We can, for example, start the Clients +%% our selves or look them up in the naming service. This is application +%% specific. +SupplierClient = ... +ConsumerClient1 = ... +ConsumerClient2 = ... +ConsumerClient3 = ... + +%% Connect each Client to corresponding Proxy. +'CosNotifyChannelAdmin_StructuredProxyPushConsumer': + connect_structured_push_supplier(StructuredProxyPushConsumer, SupplierClient), +'CosNotifyChannelAdmin_ProxyPushSupplier': + connect_any_push_consumer(ProxyPushSupplier, ConsumerClient1), +'CosNotifyChannelAdmin_StructuredProxyPushSupplier': + connect_structured_push_consumer(StructuredProxyPushSupplier, ConsumerClient2), +'CosNotifyChannelAdmin_SequenceProxyPushSupplier': + connect_sequence_push_consumer(SequenceProxyPushSupplier, ConsumerClient3), + +

The example above, exemplifies a notification system where the SupplierClient + in some way generates event and pushes them to the proxy. The push supplier + proxies will eventually push the events to each ConsumerClient.

+
+
+
+ diff --git a/lib/cosNotification/doc/src/ch_install.xml b/lib/cosNotification/doc/src/ch_install.xml new file mode 100644 index 0000000..3463815 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_install.xml @@ -0,0 +1,146 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Installing cosNotification + Niclas Eklund + + 2000-01-31 + + ch-install.xml +
+ +
+ Installation Process +

This chapter describes how to install cosNotificationApp + in an Erlang Environment. +

+ +
+ Preparation +

Before starting the installation process for cosNotification, + the application Orber must be running.

+
+ +
+ Configuration +

When using the Notification Service the cosNotification application + first must be installed using cosNotificationApp:install() or + cosNotificationApp:install(Seconds), followed by cosNotificationApp:start().

+

Then the Event Channel Factory + must be started:

+ + cosNotificationApp:start_global_factory() - starts and returns a reference to a factory using default configuration parameters. + This operation should be used for a multi-node Orber. + cosNotificationApp:start_global_factory(Options) - starts and returns a reference to a factory using given configuration parameters. + This operation should be used for a multi-node Orber. + cosNotificationApp:start_factory() - starts and returns a reference to a factory using default configuration parameters. + cosNotificationApp:start_factory(Options) - starts and returns a reference to a factory using given configuration parameters. + +

The following options exist:

+ + {pullInterval, Seconds} - determine how often Proxy Pull + Consumers will check for new events with the client application. The + default value is 20 seconds. + {filterOp, OperationType} - determine which type of Administrator + objects should be started, i.e., 'OR_OP' or 'AND_OP'. + The default value is 'OR_OP'. + {timeService, TimeServiceObj | 'undefined'} - to be able to use + Start and/or Stop QoS this option must be used. See the function start_time_service/2 + in the cosTime application. The default value is 'undefined'. + {filterOp, OperationType} - determine which type of Administrator + objects should be started, i.e., 'OR_OP' or 'AND_OP'. + The default value is 'OR_OP'. + {gcTime, Seconds} - this option determines how often, for example, proxies + will garbage collect expired events. The default value is 60. + {gcLimit, Amount} - determines how many events will be stored before, for + example, proxies will garbage collect expired events. The default value is 50. This + option is tightly coupled with the QoS property MaxEventsPerConsumer, i.e., + the gcLimit should be less than MaxEventsPerConsumer and greater than 0. + +

It is possible to define a set of global configuration parameters:

+ + + Key + Range + Default + + + type_check + true | false + true + + + notify + atom() | false + false + + + max_events + integer() > 0 + 50 + + + interval_events + integer() > 0 + 10000 milliseconds + + + timeout_events + integer() > interval_events + 3000000 milliseconds + + Global Configuration Parameters +
+

Comments on the table 'Global Configuration Parameters':

+ + type_check + Determine if supplied IOR:s shall be type checked, i.e. invoking + corba_object:is_a/2, or not. + notify + The given value shall point to an existing module exporting + a function (arity 1) called terminated. This operation + is invoked when a proxy terminates and the argument is a list + containing {proxy, IOR}, {client, IOR} and + {reason, term()}. The return value is ignored. + max_events + If a supplier proxy has not been able to push events to a + consumer and the queue exceeds this limit, then the proxy will + terminate. For this option to have any effect, the + EventReliability and ConnectionReliability QoS + parameters must be set to Persistent. For more information, + see also the QoS chapter. + interval_events + The same requirements as for max_events. When a supplier + proxy detects problems when trying to push events, this parameter + determines how often it should try to call the consumer. + timeout_events + The same requirements as for max_events. If the + proxy has not been able to contact the consumer and this + time-limit is reached, then the proxy will terminate. + +

The Factory is now ready to use. For a more detailed description see + Examples.

+
+
+
+ diff --git a/lib/cosNotification/doc/src/ch_introduction.xml b/lib/cosNotification/doc/src/ch_introduction.xml new file mode 100644 index 0000000..63e4a58 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_introduction.xml @@ -0,0 +1,57 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Introduction to cosNotification + Niclas Eklund + + 2000-01-31 + + ch_introduction.xml +
+ +
+ Overview +

The cosNotification application is a Notification Service compliant with the OMG + Notification Service CosNotification. +

+ +
+ Purpose and Dependencies +

cosNotification is dependent on Orber-3.1.7 or later, + which provides CORBA functionality in an Erlang environment, + cosTime-1.0.1 or later and IDL-files to be compiled using IC-4.0.4 or later.

+
+ +
+ Prerequisites +

To fully understand the concepts presented in the + documentation, it is recommended that the user is familiar + with distributed programming, CORBA and the Orber application. +

+

Recommended reading includes books recommended by the OMG + and Open Telecom Platform Documentation Set. It is also + helpful to have read Concurrent Programming in Erlang.

+
+
+
+ diff --git a/lib/cosNotification/doc/src/ch_system.xml b/lib/cosNotification/doc/src/ch_system.xml new file mode 100644 index 0000000..126bba5 --- /dev/null +++ b/lib/cosNotification/doc/src/ch_system.xml @@ -0,0 +1,83 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The Notification Service Components + Niclas Eklund + + 2000-04-13 + + ch_system.xml +
+ +
+ The Notification Service Components +

This chapter describes the Notification Service Components and how they + interact.

+ +
+ Components +

There are seven components in the OMG Notification Service architecture. + These are described below:

+ + + +Figure 1: The Notification Service Components. + + + Event Channel: acts as a factory for Administrator objects. + Allows clients to set Administrative Properties. + Supplier Administrators: acts as a factory for Proxy Consumers. + Administrators are started as 'AND_OP'- or 'OR_OP'-type, + which determines if events must be validated using both the Administrators + associated Filter and/or its Proxy children Filters. + Consumer Administrators: acts in the same way as Supplier Administrators + but handle Proxy Suppliers. + Consumer Proxy: is connected to a client application. Can be + started as Pull or Push object. If the proxy is Push style + the client application must push events to the Proxy, otherwise the Proxy is + supposed to Pull events. The CosNotification::AdminProperties is + used to set the pacing interval. + Supplier Proxy: Acts in a similar way as the Consumer Proxy, but + if started as a Push proxy it will push events to the client + application. + Filters: used to filter events. May be associated with Proxies + and Administrators. + Mapping Filters: used to override events Quality of Service + settings. Can only be associated with Consumer Administrators and + Proxy Suppliers. + +

When a Proxy is started it is set to accept CORBA::Any, + CosNotification::StructuredEvent or CosNotification::EventBatch + (a sequence of structured events).

+

If a Proxy is supposed to deliver structured events to a client application + and receives an CORBA::Any event, the event is converted to a + structured event with type_name set to "%ANY" and the + event is stored in remainder_of_body.

+

If a Proxy is supposed to deliver CORBA::Any events to a client application + and receives a structured event, the event is stored in an Any type. The + Any Type Code will be equal to the CosNotification::StructuredEvent + Type Code.

+
+
+
+ diff --git a/lib/cosNotification/doc/src/cosNotificationApp.xml b/lib/cosNotification/doc/src/cosNotificationApp.xml new file mode 100644 index 0000000..08bac7f --- /dev/null +++ b/lib/cosNotification/doc/src/cosNotificationApp.xml @@ -0,0 +1,308 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosNotificationApp + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-01-31 + PA1 +
+ cosNotificationApp + The main module of the cosNotification application. + +

To get access to the record definitions for the structures use:

+-include_lib("cosNotification/include/*.hrl").

+

This module contains the functions for starting and stopping the application.

+
+ + + install() -> Return + Install the cosNotification application + + Return = ok | {'EXCEPTION', E} + + +

This operation installs the cosNotification application.

+
+
+ + install(Seconds) -> Return + Install the cosNotification application + + Return = ok | {'EXCEPTION', E} + + +

This operation installs the cosNotification application using Seconds + delay between each block, currently 6, of IFR-registrations. This approach + spreads the IFR database access over a period of time to allow other + applications to run smother.

+
+
+ + install_event() -> Return + Install the necessary cosEvent interfaces + + Return = ok | {'EXCEPTION', E} + + +

This operation, which may only be used if it is impossible to + upgrade to cosEvent-2.0 or later, installs the necessary + cosEvent interfaces. If cosEvent-2.0 is available, use + cosEventApp:install() instead.

+
+
+ + install_event(Seconds) -> Return + Install the necessary cosEvent interfaces + + Return = ok | {'EXCEPTION', E} + + +

This operation, which may only be used if it is impossible to + upgrade to cosEvent-2.0 or later, installs the necessary cosEvent + interfaces using Seconds delay between each block of + IFR-registrations. If cosEvent-2.0 is available, use + cosEventApp:install() instead.

+
+
+ + uninstall() -> Return + Uninstall the cosNotification application + + Return = ok | {'EXCEPTION', E} + + +

This operation uninstalls the cosNotification application.

+
+
+ + uninstall(Seconds) -> Return + Uninstall the cosNotification application + + Return = ok | {'EXCEPTION', E} + + +

This operation uninstalls the cosNotification application using Seconds + delay between each block, currently 6, of IFR-unregistrations. This approach + spreads the IFR database access over a period of time to allow other + applications to run smother.

+
+
+ + uninstall_event() -> Return + Uninstall the inherited cosEvent interfaces + + Return = ok | {'EXCEPTION', E} + + +

This operation uninstalls the inherited cosEvent interfaces. If cosEvent + is in use this function may not be used. This function may only be used if + cosNotificationApp:install_event/1/2 was used. If not, use + cosEventApp:uninstall() instead.

+
+
+ + uninstall_event(Seconds) -> Return + Uninstall the inherited cosEvent interfaces + + Return = ok | {'EXCEPTION', E} + + +

This operation uninstalls the inherited cosEvent interfaces, using Seconds + delay between each block of IFR-unregistrations. If cosEvent + is in use this function may not be used. This function may only be used if + cosNotificationApp:install_event/1/2 was used. If not, use + cosEventApp:uninstall() instead.

+
+
+ + start() -> Return + Start the cosNotification application + + Return = ok | {error, Reason} + + +

This operation starts the cosNotification application.

+
+
+ + stop() -> Return + Stop the cosNotification application + + Return = ok | {error, Reason} + + +

This operation stops the cosNotification application.

+
+
+ + start_global_factory() -> ChannelFactory + Start a global channel factory as default + + ChannelFactory = #objref + + +

This operation creates a + Event Channel Factory + should be used for a multi-node Orber. + The Factory is used to create a new + channel.

+
+
+ + start_global_factory(Options) -> ChannelFactory + Start a global channel factory with options + + Options = [Option] + Option = {pullInterval, Seconds} | {filterOp, Op} | {gcTime, Seconds} | {gcLimit, Anount} | {timeService, #objref} + ChannelFactory = #objref + + +

This operation creates a + Event Channel Factory and + should be used for a multi-node Orber. + The Factory is used to create a new + channel.

+

+ + {pullInterval, Seconds} - determine how often Proxy Pull + Consumers will check for new events with the client application. The + default value is 20 seconds. + {filterOp, OperationType} - determine which type of Administrator + objects should be started, i.e., 'OR_OP' or 'AND_OP'. + The default value is 'OR_OP'. + {timeService, TimeServiceObj | 'undefined'} - to be able to use + Start and/or Stop QoS this option must be used. See the function start_time_service/2 + in the cosTime application. The default value is 'undefined'. + {filterOp, OperationType} - determine which type of Administrator + objects should be started, i.e., 'OR_OP' or 'AND_OP'. + The default value is 'OR_OP'. + {gcTime, Seconds} - this option determines how often, for example, proxies + will garbage collect expired events. The default value is 60. + {gcLimit, Amount} - determines how many events will be stored before, for + example, proxies will garbage collect expired events. The default value is 50. This + option is tightly coupled with the QoS property MaxEventsPerConsumer, i.e., + the gcLimit should be less than MaxEventsPerConsumer and greater than 0. + +
+
+ + start_factory() -> ChannelFactory + Start a channel factory as default + + ChannelFactory = #objref + + +

This operation creates a + Event Channel Factory. + The Factory is used to create a new + channel.

+
+
+ + start_factory(Options) -> ChannelFactory + Start a channel factory with options + + Options = [Option] + Option = {pullInterval, Seconds} | {filterOp, Op} | {gcTime, Seconds} | {gcLimit, Amount} | {timeService, #objref} + ChannelFactory = #objref + + +

This operation creates a + Event Channel Factory. + The Factory is used to create a new + channel.

+
+
+ + stop_factory(ChannelFactory) -> Reply + Terminate the target object + + ChannelFactory = #objref + Reply = ok | {'EXCEPTION', E} + + +

This operation stop the target channel factory.

+
+
+ + start_filter_factory() -> FilterFactory + Start a filter factory + + FilterFactory = #objref + + +

This operation creates a + Filter Factory. + The Factory is used to create a new + Filter's and + MappingFilter's.

+
+
+ + stop_filter_factory(FilterFactory) -> Reply + Terminate the target object + + FilterFactory = #objref + Reply = ok | {'EXCEPTION', E} + + +

This operation stop the target filter factory.

+
+
+ + create_structured_event(Domain, Type, Event, VariableHeader, FilterableBody, BodyRemainder) -> Reply + Create a structured event + + Domain = string() + Type = string() + Event = string() + VariableHeader = [CosNotification::Property] + FilterableBody = [CosNotification::Property] + BodyRemainder = #any data-type + Reply = CosNotification::StructuredEvent | {'EXCEPTION', E} + + +

An easy way to create a structured event is to use this function. + Simple typechecks are performed and if one of the arguments is not + correct a 'BAD_PARAM' exception is thrown.

+
+
+ + type_check() -> Reply + Return the value of the configuration parameter type_check + + Reply = true | false + + +

This operation returns the value of the configuration parameter + type_check.

+
+
+
+ +
+ diff --git a/lib/cosNotification/doc/src/eventstructure.gif b/lib/cosNotification/doc/src/eventstructure.gif new file mode 100644 index 0000000000000000000000000000000000000000..879c96f980f433a2d50d37ae38c19b3fd5905174 GIT binary patch literal 89760 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

XQL6U!x>@n)KtKSJW_{Zh|VBx4^ z&KsGWoG}nsv$VDw_D+HekRIYLS<_1|$SC0S?d#y1zkzKTK(#0>K2RyoUN<=9lY@`YRuChL7Dl zbTb3&y0h8(Z0wDilGnQzJyI_2YG4E~e)stA)Sw2+^xnL#A*Co$5qXb0thkqMLki~t{_)H- z9>e_j%978_#KR!&wg&CZ$>IkOL65?AHIOGor5tWr@_8d++UgPT4}@K^{|5qyp|xy} z0*&J7B(OIGoYgAY-lsDpPUAB^12t~FZm$xFpMoPDyJQI>oO_znh#k%6liroA1|cWO zyLZA>CV7jn;%$(+Xvwg_4E!yj5KE9}NK~~K;4VOK!uGi;{zv8vGwg{jKlQ{ii9p2j zY*zz8Rzpyzj0iKFI*jEk0%aTSdNE`bwDUW`!Zzn@&xWrKgl)9(W^=3#`2|aXlAur; zs3sN*w@s`<9ufAihaCK4BVr>7*f;M#^?28Gl{4JAJqn&s^;(||{!!Pe5lH%zdYxXD zX4jALWm7n8C7tWzt;&R9_tjm4A2;zhmhj{li{yi=O2fFr|I zY>%?F2*xv|w`?Bf$G@^EN83keVNbu+>h|+|m;}xgIT`;7T&uhrdox-}g?~7e*C}&5 N_t0s2W^xHC`#+p#HB0~i literal 0 HcmV?d00001 diff --git a/lib/cosNotification/doc/src/eventstructure.ps b/lib/cosNotification/doc/src/eventstructure.ps new file mode 100644 index 0000000000000000000000000000000000000000..a9ace9a7039809ba68907e904da8b366d4d631c2 GIT binary patch literal 164840 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 + + + + + User's Guide + + + Reference Manual + + + Release Notes + + + Off-Print + + + diff --git a/lib/cosNotification/doc/src/make.dep b/lib/cosNotification/doc/src/make.dep new file mode 100644 index 0000000..031a2b3 --- /dev/null +++ b/lib/cosNotification/doc/src/make.dep @@ -0,0 +1,48 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: CosNotification.tex CosNotification_AdminPropertiesAdmin.tex \ + CosNotification_QoSAdmin.tex CosNotifyChannelAdmin_ConsumerAdmin.tex \ + CosNotifyChannelAdmin_EventChannel.tex CosNotifyChannelAdmin_EventChannelFactory.tex \ + CosNotifyChannelAdmin_ProxyConsumer.tex CosNotifyChannelAdmin_ProxyPullConsumer.tex \ + CosNotifyChannelAdmin_ProxyPullSupplier.tex \ + CosNotifyChannelAdmin_ProxyPushConsumer.tex \ + CosNotifyChannelAdmin_ProxyPushSupplier.tex \ + CosNotifyChannelAdmin_ProxySupplier.tex CosNotifyChannelAdmin_SequenceProxyPullConsumer.tex \ + CosNotifyChannelAdmin_SequenceProxyPullSupplier.tex \ + CosNotifyChannelAdmin_SequenceProxyPushConsumer.tex \ + CosNotifyChannelAdmin_SequenceProxyPushSupplier.tex \ + CosNotifyChannelAdmin_StructuredProxyPullConsumer.tex \ + CosNotifyChannelAdmin_StructuredProxyPullSupplier.tex \ + CosNotifyChannelAdmin_StructuredProxyPushConsumer.tex \ + CosNotifyChannelAdmin_StructuredProxyPushSupplier.tex \ + CosNotifyChannelAdmin_SupplierAdmin.tex CosNotifyComm_NotifyPublish.tex \ + CosNotifyComm_NotifySubscribe.tex CosNotifyFilter_Filter.tex \ + CosNotifyFilter_FilterAdmin.tex CosNotifyFilter_FilterFactory.tex \ + CosNotifyFilter_MappingFilter.tex book.tex \ + ch_BNF.tex ch_QoS.tex ch_contents.tex ch_example.tex \ + ch_install.tex ch_introduction.tex ch_system.tex \ + cosNotificationApp.tex part.tex ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: eventstructure.ps + +book.dvi: notificationFlow.ps + diff --git a/lib/cosNotification/doc/src/notes.gif b/lib/cosNotification/doc/src/notes.gif new file mode 100644 index 0000000000000000000000000000000000000000..e000cca26a383722eca87f4d87a5841292b0b8ea GIT binary patch literal 2005 zcmc(e`(I0c1HeD$>})&L($>wE%9*B;E}M!dPv>-9341YwWX&zf>scU1zfBrl=I{N9;r;i^$ ze)#ZVWMt(1`}gnOy?gui?eOsMn>TM>zkWS5H1z7#tHHs+fq?;|(fIP^%NH+RJb(WD z*|TR)pFVx^ogEz=?d|P)y}qrjt+lnarKLru(`mKZ=H_ONMx$1%@7%d_`}XZyw{G3MdGp4N z8%<43jg5^B4Gq_?U%z(k+SRL9>+9>UT)9$LS65qGTT@eW`SRsUmo8nrc=5u83+KckWzORn^(EXDcf!&zw1P`t<2jr%qK=RFs#Ot5m9!Cr_R@apL&#<7H)K$BrF4 zdi1DLsXTJzNNH(lNl8g@aq;29hl`4e3JVJr3dNyAhYlV*SWr-qpP!$XmzSHHo0F3x zm&-FUGSbu2Wir|R{rmUr+qZY`-n6u|)YR0Jl$1St_9Q1K@7}$8*REYVckbM=V@Fa_ zl0+iezI}UQV&b-K+Y%BIwr<_JdGqE?n>KCSxN*aV4Pvo4E-p?a60KjqJ~lRX-MV!# zF)?e`u3fWc&Fa;wSFKvLa^=buD^>`F!ez^r2?T=0ix)>lMMXwNMnpvL`TX$k@UXD3 zkdTnz;NYO3Ac7zQ0|OT>TD_t~>&yScf|nl;PS)z!tt#o5`J!{InNIkDMn48x{RpYG`B=-}XBZ*Mm zJ0_E9VPQd|(M(NEQ52<8sT2wYK@bv&1j8@{LE!(5`#%Ezya3Qi0HOB$8kHskwQ`Hm z*OY4y(48X7__Y-+c}(wwXZqSxZHKVn+_d2V9bX<;)o5v8$jlB{tz6vnwfvQAiMw6t z0IXVSedvhT17nJCGJ_XCYT%)5*?chw5R9s25QXlX!e_sd7hr)!eyKroJ4zhgi|iRe z9BRcDRXkmj&PH5Z1EswZP1Yik}bX?KQfDMotrhur?Z`l6 z9SHWUks6^bPWsX|jEswdY)vps%VI@IAvY7W9?a_N?~xI!M!5pm(Ry5JJ;$6wSb!Kw z1Ofz-ES$>6ni1O}ScWTvR$Wsm*pF-~}^QqIoOkG6>BJ?$;+XE5N4m%cOVTgl$q1H6Cj2CRZ#Cwk*Z+A1}6-ZGIOnZ zriKR6JwuHEr#89IP&lU0d>}f|iQ2(xTebl}Km=JKc>w~{On}kI=M0e4E*aE>B!t(` zz!7B(z}xLdevm2fNGl*)VFk@hhEN1isQ4%eVdfhlo64C^B-c26^Z?T#Tc$&!YL-EE zsr_sc%})?_z}$saj#x(bLnO=CUH5f1>6}R!!dMZ|W9GTgpb9n@*5fiBqnDrne~DCT zx&%mdn3ma=CO4$ZCjP+)Zks2RB*+Tt`QEtb2g6+n+RKF1oJqVMUCo0mdGDTz#3Q^?T4648gGi%gvvJ#j{AlN2b z`m?E;VM>mcPQBC_Y6=8kn9B=CL=o-QgXt_x2k`|YJusL&`b=Pj%+?u4tr>8h24sDX + + + +

+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosNotification Release Notes + + + + + 2000-01-31 + A + notes.xml +
+ +
+ cosNotification 1.1.12 + +
+ Improvements and New Features + + +

+ The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.

+

+ Own Id: OTP-8201 Aux Id:

+
+
+
+
+ +
+ cosNotification 1.1.11 + +
+ Improvements and New Features + + +

Obsolete guards, e.g. record vs is_record, has been changed + to avoid compiler warnings.

+

Own id: OTP-7987

+
+
+
+
+ +
+ cosNotification 1.1.10 + +
+ Fixed Bugs and Malfunctions + + +

Updated file headers.

+

Own id: OTP-7837 Aux Id:

+
+
+
+
+ +
+ cosNotification 1.1.9 + +
+ Fixed Bugs and Malfunctions + + +

Documentation source included in open source releases.

+

Own id: OTP-7595 Aux Id:

+
+
+
+
+ +
+ cosNotification 1.1.8 + +
+ Fixed Bugs and Malfunctions + + +

The CosNotification proxy objects ignored the gcLimit option, instead + the gcTime value was used.

+

Own id: OTP-7553 Aux Id:

+
+
+
+
+ +
+ cosNotification 1.1.7 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7011

+
+
+
+
+ +
+ cosNotification 1.1.6 + +
+ Improvements and New Features + + +

The documentation source has been converted from SGML to XML.

+

Own id: OTP-6754

+
+
+
+
+ +
+ cosNotification 1.1.5 + +
+ Improvements and New Features + + +

Minor Makefile changes.

+

Own id: OTP-6701

+
+
+
+
+ +
+ cosNotification 1.1.4 + +
+ Improvements and New Features + + +

Removed some unused code.

+

Own id: OTP-6527

+
+
+
+
+ +
+ cosNotification 1.1.3 + +
+ Improvements and New Features + + +

A user can now define the QoS EventReliability to be + Persistent. Note, this is only a lightweight version + and events will be lost if a proxy is terminated.

+

Own id: OTP-5923

+
+
+
+
+ +
+ cosNotification 1.1.2 + +
+ Improvements and New Features + + +

Possible to configure cosNotification not to type check, + by invoking corba_object:is_a/2, supplied IOR:s. When + a type check fails, the feedback has been improved.

+

Own id: OTP-5823 Aux Id: seq10143

+
+
+
+
+ +
+ cosNotification 1.1.1 + +
+ Fixed Bugs and Malfunctions + + +

The app-file contained duplicated modules.

+

Own id: OTP-4976

+
+
+
+
+ +
+ cosNotification 1.1 + +
+ Improvements and New Features + + +

The stub/skeleton-files generated by IC have been improved, + i.e., depending on the IDL-files, reduced the size of the + erl- and beam-files and decreased dependencies off Orber's + Interface Repository. It is necessary to re-compile all IDL-files + and use COS-applications, including Orber, compiled with + IC-4.2.

+

Own id: OTP-4576

+
+
+
+
+ +
+ cosNotification 1.0.6 + +
+ Fixed Bugs and Malfunctions + + +

The exception CosNotifyFilter::InvalidValue, raised by the operation + CosNotifyFilter::MappingFilter::add_mapping_constraints, did not contain + correct data in the body. Hence, it was not possible to pass this + exception to another ORB.

+

Own Id: OTP-4412

+
+ +

It was not possible to set the QoS property PacingInterval to zero and + the default value was not compliant with the OMG specification. The + default value for MaximumBatchSize have also been changed du to the + same reason.

+

Own Id: OTP-4413, OTP-4414

+
+
+
+ +
+ Incompatibilities + + +

The default value, for the QoS properties PacingInterval and MaximumBatchSize, + have been changed to zero (i.e. no timeout) and 1 respectively, which is + compliant with the OMG specification.

+

Own Id: OTP-4413, OTP-4414

+
+
+
+
+ +
+ cosNotification 1.0.5 + +
+ Fixed Bugs and Malfunctions + + +

If one tries to set an unavailable/incorrect property or property value, an + exception is thrown. In some cases the exception was not correct, which + would cause problems if communicating via IIOP.

+

Own Id: OTP-4340

+
+ +

When using Filter's, with the QoS OrderPolicy set to FifoOrder, + and passing a sequence of structured events, they could be + delivered in the wrong order.

+

Own Id: OTP-4272

+
+ +

If Filter's where attached to Supplier proxies it could cause + the Proxy to terminate.

+

Own Id: OTP-4272

+
+
+
+
+ +
+ cosNotification 1.0.4 + +
+ Fixed Bugs and Malfunctions + + +

When passing event sequences, the PushSuppliers and PullSuppliers + could crash if the objects had Filter objects associated and + only a subset of the sequences where approved.

+

Own Id: OTP-4099

+
+ +

SupplierAdmin's did not filter any events, even though Filter objects + had been attached to the SupplierAdmin.

+

Own Id: OTP-4098

+
+ +

If one used the '_get_default_supplier_admin'/1, exported by the + CosNotifyChannelAdmin_EventChannel-module, it resulted in a loop + which overloaded the channel. This is no longer the case.

+

Own Id: OTP-4086

+
+ +

If one used the '_get_default_filter_factory'/1, exported by the + CosNotifyChannelAdmin_EventChannel-module, a new instance was created + each time. Now fixed.

+

Own Id: OTP-4092

+
+
+
+ +
+ Incompatibilities + + +

The include paths for CosNotification.idl have been changed. + Hence, if you include this file in your own IDL-files you must + update your paths to also point to where the cosEvent IDL-files are + stored.

+

Own Id: OTP-4093

+
+
+
+
+ +
+ cosNotification 1.0.3 + +
+ Improvements and New Features + + +

It is now possible to start global channel factories.

+

Own Id: OTP-4078

+
+ +

The Orber, version 3.2.5 or later, configuration parameter + orber_debug_level can now be used to generate reports when abnormal + situations occurs. For more information consult the Orber User's Guide. + Note, it is not recommended to use this option for delivered systems + since some of the reports is not to be considered as errors. + The value of orber_debug_level must be 3, or higher, for reports to + be generated.

+

Own Id: OTP-4077, OTP-3962

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

When using the cosEvent API accessing a cosNotification admins + the objects returned by the functions obtain_push_supplier, + obtain_pull_supplier, obtain_push_consumer and obtain_pull_consumer + was not of the correct type. Due to the interface change + it is not possible to upgrade during runtime.

+

Own Id: OTP-4079

+
+
+
+
+ +
+ cosNotification 1.0.2 + +
+ Improvements and New Features + + +

First release of the cosNotification application.

+

Own Id: -

+
+
+
+
+ + diff --git a/lib/cosNotification/doc/src/notificationFlow.gif b/lib/cosNotification/doc/src/notificationFlow.gif new file mode 100644 index 0000000000000000000000000000000000000000..31d6ee97fbe956fd91449e2aa4fb93d6424a6144 GIT binary patch literal 167734 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 literal 0 HcmV?d00001 diff --git a/lib/cosNotification/doc/src/part.xml b/lib/cosNotification/doc/src/part.xml new file mode 100644 index 0000000..06ae875 --- /dev/null +++ b/lib/cosNotification/doc/src/part.xml @@ -0,0 +1,42 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosNotification User's Guide + Niclas Eklund + + 2000-01-31 + 1.0 +
+ +

The cosNotification application is an Erlang implementation + of the OMG CORBA Notification Service.

+
+ + + + + + + +
+ diff --git a/lib/cosNotification/doc/src/part_notes.xml b/lib/cosNotification/doc/src/part_notes.xml new file mode 100644 index 0000000..af262c3 --- /dev/null +++ b/lib/cosNotification/doc/src/part_notes.xml @@ -0,0 +1,36 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosNotification Release Notes + Niclas Eklund + + 2000-01-31 + 1.0 +
+ +

The cosNotification Application is an Erlang implementation of the OMG + CORBA Notification Service.

+
+ +
+ diff --git a/lib/cosNotification/doc/src/ref_man.gif b/lib/cosNotification/doc/src/ref_man.gif new file mode 100644 index 0000000000000000000000000000000000000000..b13c4efd53ff30209e94a832b9b141aefa01373e GIT binary patch literal 1530 zcmdVZdppw$0KoB|UD(ZKjLpudxl|bD5*~BdW(#wPxjQR!4XwvDQJz|2?rd%yODG+} zTS?d`8$ziw@9efjcbb8~ZJV`F`NeQj-Rb#--RW#!YS zPs_{8OG`^1KYmEb&dp9*T_4@VeSFc{Z zeEIUlix(;Hhy1Lrh+M1f0n>TM(S67S0;;O2u%F4=$ii+~`^0Klrkw{chQc_%8TvSw4P*9Mc zpP!ePmz$fLlanJ52(q)YuU)&AnVEUz%9YEPFK1+AT)K4W;>C;U>FH@{X%{YBNKH*W zfBt+*N=kBaa#B)KVq#)KLPC6e{JC@Ics$E-3+>FMd= z;o5R+g5Q78Vv{ zGTGeR+|10()YOzjBAJ+&7#kZK85t3YL|t879UUD4fq=*3wY9ZzI2;y>)zZ?^)YQaa zFd7;fYHDh#s;Vj~D$2^rC=?2bL?RFfI2;ax!IYGg6crVrP$&cf0fWIH5J*8m0r;Os z`p^I03jpi@P=FC!+v{kk6S6LO_!Iu)95sCwBtcqW%*9y*G+T7kk6cw&i6X!~u9ub^ z(;p_fv9U$vWTl#^q0-1BITpV6n#M{a{we|K$qn8tF1dhi2#U)iChGwf%c>!EMdamI z$h@1HHE$AU0uQ06DJaKq=RDnzU^TZiOigaDbX?9sbbG2Mo zru2uhl#`IQgUVf0v!Xj-d%-$1xRm>;TQmHNwcAfcM=qjwu=nh zQh;0;RMT@!2!f)5xXw7CWD^X8atslf08f~GlvPC&!u3CIvJ6wy=4qhoBAlk74dDIc za5tv{OoL_(_?n6N^K=DFVPbx|J4#5`n`9n$heG9OfAim6K_sx=yuqZzUrzW~%(8B5(t!Xl{Hb0?L6-vF=+wDe8$ zTT`s`Dq0fpfEZM3+{q@m}*YWuf-$-b$k$LLWEZK;Ee|dK!!GAvHA;V z*1da#TyGWrnurc+>Z42^g}P$+dV8CLlZ-G3$5&lvmrHi*;me*Y^_v!=AL*c_d4sqi z`SWVr{)P|6KptK|>YQR5CUyjEppnvPJ-9YQBBMdn(+)quWG#%To7OvoyB^9=`#bkY st1M+qtZTt#!ZD6_9%~hW^bvUb7(Sl{bx5FV=!1r@;+Z6>KNX<-3tg&0LjV8( literal 0 HcmV?d00001 diff --git a/lib/cosNotification/doc/src/ref_man.xml b/lib/cosNotification/doc/src/ref_man.xml new file mode 100644 index 0000000..1cf77c3 --- /dev/null +++ b/lib/cosNotification/doc/src/ref_man.xml @@ -0,0 +1,63 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosNotification Reference Manual + Niclas Eklund + + 2000-01-31 + 1.0 +
+ +

The cosNotification application is an Erlang implementation + of the OMG CORBA Notification Service.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ diff --git a/lib/cosNotification/doc/src/summary.html.src b/lib/cosNotification/doc/src/summary.html.src new file mode 100644 index 0000000..92ade4f --- /dev/null +++ b/lib/cosNotification/doc/src/summary.html.src @@ -0,0 +1 @@ +Orber OMG Notification Service \ No newline at end of file diff --git a/lib/cosNotification/doc/src/user_guide.gif b/lib/cosNotification/doc/src/user_guide.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6275a803db46bc56df2b31240f80e68a4eb28b5 GIT binary patch literal 1581 zcmd6mi9gc|0Kk8njctY*W^QwCJ{HX#%4V)-y(i>aMOY|Iy@!%dZA6YGb49u7IpPyu zxpLn_avvd{2!$L^&hlRW#rysR-_Q5+`C8dn8X8V>k`j;wKQ1gR%+Jry&CSiu&d$utOixe0fB$}JYHD(Fa$;g)e0+Rt zY;1INbYx^?czAedXlQV7@ZGz20|Nv7{r!D?eZ9TCJRYy7r>DESyQ{0Kv$M0KqocjO zy{)aSwY9aSrKP#Kxv8nCv9YnCq2bM&H}&=Pb#-;MwY4=hHPzMCuV25es;a82tgNW0 zc=_^WSy|bO7cWXnOG`>hii?Yjii!#g3kwPg^7Hfa^73+Xb8~WXva_?Zva&KWGoL+s z_Vnq~jEs!*^z{(M&Qxg*t zV`JkpXU-TI85tTH>g((4>FMd}>gwp|kVqtLZEYmX?x|!eX(Kl9CtEE3!%>OGRc>9)Rn&SYM zj~Y~*8(l`PO4G;6R;FqaD@X#~VMifcR)pt=DvF{Q3(>@Ud>(7)(V4{v)PmxVK~kPo zjj~AEyr<1v8vx#~Tk98U5_J`0L}~fU>RjhaAKM=MUf{g5m?T z)+IHOf7l%`QALwKCeyDj6SLD45WBagBU?Fw4{df%%9E4Y2u)Wk*W$nyCUXV^5gf*w zJcTmdm_5ACzSYODr)n2;x_FnPc`B(M`LXIbz9g71J`3n))Gq$bQK+sRivkPkZkj>F zXejb80{#?f()6mQl&jOcTB0m7HQ)B0eJ!3!3LG1z5Dy4!8UDX&qmZHiEZH4hCN$qe z4*)g+{|y}64a+3k1Ar7VS%DkXnyczs>8pr>ch^qPgriJZarAD;X*)P0t_Uea!m)bj zekgBBW+6d2l7{g|`zZIq7r_Y&symb`GN>UKUQ)c!TxUa0r_Gumy9Jeti%E)uL##a# zMGizq*jB%VA7Ip@(A3hq9YH69qL7NjkWRA2q5;hU`xYmEN)bB>aqrz!?T?Ynv*X-7 zk5PfTmt$8kTF6UOKy_o?XHYzxtkg%ZbG*StHxDNDsyD5c2a>x5vWvVCApVgu@XNF$})`XD-pCH3`9zE-Lj6@!*TS9lwVaP}h|-H2`m~ItYQE$0z|a zt4=D`BBR~(5MZ;L{+LQk#4$5Kz`eloKZBK-7eFm?OlZCy;GH~%L;($J;|e#tww(~b et1Zl|+ha7@T8X2%4FJEoWS?mjDfbqXtih~yb literal 0 HcmV?d00001 diff --git a/lib/cosNotification/ebin/.gitignore b/lib/cosNotification/ebin/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/examples/.gitignore b/lib/cosNotification/examples/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/include/.gitignore b/lib/cosNotification/include/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/info b/lib/cosNotification/info new file mode 100644 index 0000000..1b634eb --- /dev/null +++ b/lib/cosNotification/info @@ -0,0 +1,3 @@ +group: orb +short: Orber OMG Notification Service + diff --git a/lib/cosNotification/priv/.gitignore b/lib/cosNotification/priv/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/src/CosEvent.cfg b/lib/cosNotification/src/CosEvent.cfg new file mode 100644 index 0000000..e339913 --- /dev/null +++ b/lib/cosNotification/src/CosEvent.cfg @@ -0,0 +1,20 @@ +{this, "CosEventChannelAdmin::EventChannel"}. +{{handle_info, "CosEventChannelAdmin::EventChannel"}, true}. +{this, "CosEventChannelAdmin::EventChannelFactory"}. +{{handle_info, "CosEventChannelAdmin::EventChannelFactory"}, true}. +{this, "CosEventChannelAdmin::SupplierAdmin"}. +{{handle_info, "CosEventChannelAdmin::SupplierAdmin"}, true}. +{this, "CosEventChannelAdmin::ConsumerAdmin"}. +{{handle_info, "CosEventChannelAdmin::ConsumerAdmin"}, true}. +{this, "CosEventChannelAdmin::ProxyPushSupplier"}. +{{handle_info, "CosEventChannelAdmin::ProxyPushSupplier"}, true}. +{{impl, "CosEventChannelAdmin::ProxyPushSupplier"}, "PusherSupplier_impl"}. +{this, "CosEventChannelAdmin::ProxyPullSupplier"}. +{{handle_info, "CosEventChannelAdmin::ProxyPullSupplier"}, true}. +{{impl, "CosEventChannelAdmin::ProxyPullSupplier"}, "PullerSupplier_impl"}. +{this, "CosEventChannelAdmin::ProxyPushConsumer"}. +{{handle_info, "CosEventChannelAdmin::ProxyPushConsumer"}, true}. +{{impl, "CosEventChannelAdmin::ProxyPushConsumer"}, "PusherConsumer_impl"}. +{this, "CosEventChannelAdmin::ProxyPullConsumer"}. +{{handle_info, "CosEventChannelAdmin::ProxyPullConsumer"}, true}. +{{impl, "CosEventChannelAdmin::ProxyPullConsumer"}, "PullerConsumer_impl"}. diff --git a/lib/cosNotification/src/CosNotification.cfg b/lib/cosNotification/src/CosNotification.cfg new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/src/CosNotification.idl b/lib/cosNotification/src/CosNotification.idl new file mode 100644 index 0000000..e080b44 --- /dev/null +++ b/lib/cosNotification/src/CosNotification.idl @@ -0,0 +1,146 @@ +#ifndef _COS_NOTIFICATION_IDL_ +#define _COS_NOTIFICATION_IDL_ + +#pragma prefix "omg.org" + +#include"CosEventChannelAdmin.idl" +#include"CosEventComm.idl" + +module CosNotification { + typedef string Istring; + typedef Istring PropertyName; + typedef any PropertyValue; + struct Property { + PropertyName name; + PropertyValue value; + }; + typedef sequence PropertySeq; + // The following are the same, but serve different purposes. + typedef PropertySeq OptionalHeaderFields; + typedef PropertySeq FilterableEventBody; + typedef PropertySeq QoSProperties; + typedef PropertySeq AdminProperties; + struct EventType { + string domain_name; + string type_name; + }; + typedef sequence EventTypeSeq; + struct PropertyRange { + PropertyValue low_val; + PropertyValue high_val; + }; + struct NamedPropertyRange { + PropertyName name; + PropertyRange range; + }; + + typedef sequence NamedPropertyRangeSeq; + + enum QoSError_code { + UNSUPPORTED_PROPERTY, + UNAVAILABLE_PROPERTY, + UNSUPPORTED_VALUE, + UNAVAILABLE_VALUE, + BAD_PROPERTY, + BAD_TYPE, + BAD_VALUE + }; + + struct PropertyError { + QoSError_code code; + PropertyName name; + PropertyRange available_range; + }; + + typedef sequence PropertyErrorSeq; + exception UnsupportedQoS { PropertyErrorSeq qos_err; }; + exception UnsupportedAdmin { PropertyErrorSeq admin_err; }; + + // Define the Structured Event structure + struct FixedEventHeader { + EventType event_type; + string event_name; + }; + struct EventHeader { + FixedEventHeader fixed_header; + OptionalHeaderFields variable_header; + }; + + struct StructuredEvent { + EventHeader header; + FilterableEventBody filterable_data; + any remainder_of_body; + }; // StructuredEvent + + typedef sequence EventBatch; + + // The following constant declarations define the standard + // QoS property names and the associated values each property + // can take on. The name/value pairs for each standard property + // are grouped, beginning with a string constant defined for the + // property name, followed by the values the property can take on. + const string EventReliability = "EventReliability"; + const short BestEffort = 0; + const short Persistent = 1; + const string ConnectionReliability = "ConnectionReliability"; + + // Can take on the same values as EventReliability + const string Priority = "Priority"; + const short LowestPriority = -32767; + const short HighestPriority = 32767; + const short DefaultPriority = 0; + const string StartTime = "StartTime"; + + // StartTime takes a value of type TimeBase::UtcT. + const string StopTime = "StopTime"; + // StopTime takes a value of type TimeBase::UtcT. + const string Timeout = "Timeout"; + // Timeout takes on a value of type TimeBase::TimeT + const string OrderPolicy = "OrderPolicy"; + const short AnyOrder = 0; + const short FifoOrder = 1; + const short PriorityOrder = 2; + const short DeadlineOrder = 3; + const string DiscardPolicy = "DiscardPolicy"; + // DiscardPolicy takes on the same values as OrderPolicy, plus + const short LifoOrder = 4; + const short RejectNewEvents = 5; + const string MaximumBatchSize = "MaximumBatchSize"; + // MaximumBatchSize takes on a value of type long + const string PacingInterval = "PacingInterval"; + // PacingInterval takes on a value of type TimeBase::TimeT + const string StartTimeSupported = "StartTimeSupported"; + // StartTimeSupported takes on a boolean value + const string StopTimeSupported = "StopTimeSupported"; + // StopTimeSupported takes on a boolean value + const string MaxEventsPerConsumer = "MaxEventsPerConsumer"; + // MaxEventsPerConsumer takes on a value of type long + + interface QoSAdmin { + QoSProperties get_qos(); + void set_qos ( in QoSProperties qos) + raises ( UnsupportedQoS ); + void validate_qos (in QoSProperties required_qos, + out NamedPropertyRangeSeq available_qos ) + raises ( UnsupportedQoS ); + }; // QosAdmin + + // Admin properties are defined in similar manner as QoS + // properties. The only difference is that these properties + // are related to channel administration policies, as opposed + // message quality of service + const string MaxQueueLength = "MaxQueueLength"; + // MaxQueueLength takes on a value of type long + const string MaxConsumers = "MaxConsumers"; + // MaxConsumers takes on a value of type long + const string MaxSuppliers = "MaxSuppliers"; + // MaxSuppliers takes on a value of type long + interface AdminPropertiesAdmin { + AdminProperties get_admin(); + void set_admin (in AdminProperties admin) + raises ( UnsupportedAdmin); + };// AdminPropertiesAdmin +}; // CosNotification + +#endif /* ifndef _COS_NOTIFICATION_IDL_ */ + diff --git a/lib/cosNotification/src/CosNotification_Common.erl b/lib/cosNotification/src/CosNotification_Common.erl new file mode 100644 index 0000000..0e0f1da --- /dev/null +++ b/lib/cosNotification/src/CosNotification_Common.erl @@ -0,0 +1,1210 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%-------------------------------------------------------------------- +%% File : CosNotification_Common.erl +%% Purpose : +%%-------------------------------------------------------------------- + +-module('CosNotification_Common'). + + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%% External MISC +-export([get_option/3, + create_name/2, + create_name/1, + create_id/0, + create_id/1, + is_debug_compiled/0, + type_check/2, + send_stubborn/5, + create_link/3, + disconnect/3, + do_disconnect/3, + notify/1]). + +%% Internal AdminProperties +-export([init_adm/1, + set_adm/2, + 'MaxQueueLength'/6, + 'MaxConsumers'/6, + 'MaxSuppliers'/6]). +%% Internal QoS +-export([init_qos/1, + set_qos/5, + validate_qos/5, + validate_event_qos/2, + 'EventReliability'/6, + 'ConnectionReliability'/6, + 'Priority'/6, + 'StartTimeSupported'/6, + 'StopTimeSupported'/6, + 'Timeout'/6, + 'OrderPolicy'/6, + 'DiscardPolicy'/6, + 'MaximumBatchSize'/6, + 'PacingInterval'/6, + 'MaxEventsPerConsumer'/6]). + +%%--------------- DEFINITIONS OF CONSTANTS ------------------- +%%--------------- EXTERNAL MISC FUNCTIONS -------------------- +%%------------------------------------------------------------ +%% function : create_link +%% Arguments: Module - which Module to call +%% Env/ArgList - ordinary oe_create arguments. +%% Returns : +%% Exception: +%% Effect : Necessary since we want the supervisor to be a +%% 'simple_one_for_one'. Otherwise, using for example, +%% 'one_for_one', we have to call supervisor:delete_child +%% to remove the childs startspecification from the +%% supervisors internal state. +%%------------------------------------------------------------ +create_link(Module, Env, ArgList) -> + Module:oe_create_link(Env, ArgList). + +%%-----------------------------------------------------------% +%% function : get_option +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +get_option(Key, OptionList, DefaultList) -> + case lists:keysearch(Key, 1, OptionList) of + {value,{Key,Value}} -> + Value; + _ -> + case lists:keysearch(Key, 1, DefaultList) of + {value,{Key,Value}} -> + Value; + _-> + {error, "Invalid option"} + end + end. +%%-----------------------------------------------------------% +%% function : create_name/2 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_name(Name,Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',Name,'_',MSec, '_', Sec, '_', USec]). + +%%-----------------------------------------------------------% +%% function : create_name/1 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_name(Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',MSec, '_', Sec, '_', USec]). + +%%------------------------------------------------------------ +%% function : create_id/0 +%% Arguments: - +%% Returns : id (long) =/= 0 +%% Both default Admin:s have the unique id 0 (OMG spec, 98-11-01, +%% Notification p 148), hence, we may not return 0. +%% Exception: +%% Purpose : Throughout the CosNotification service we use, +%% according to the OMG specification, id:s (long), +%% which must be "unique", to retrieve object references. +%% For example: CosNotifyChannelAdmin::ChannelId/AdminID. +%%------------------------------------------------------------ +create_id(-1) -> + 1; +create_id( 2147483647) -> + -2147483648; +create_id(OldID) -> + OldID+1. + +create_id() -> + {_A,_B,C}=now(), + C. + +%%-----------------------------------------------------------% +%% function : type_check +%% Arguments: Obj - objectrefernce to test. +%% Mod - Module which contains typeID/0. +%% Returns : 'ok' or raises exception. +%% Effect : +%%------------------------------------------------------------ +type_check(Obj, Mod) -> + case cosNotificationApp:type_check() of + false -> + ok; + _ -> + case catch corba_object:is_a(Obj,Mod:typeID()) of + true -> + ok; + false -> + orber:dbg("[~p] CosNotification_Common:type_check(~p);~n" + "The supplied Object is not or does not inherrit from: ~p", + [?LINE, Obj, Mod], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}); + {'EXCEPTION', E} -> + orber:dbg("[~p] CosNotification_Common:type_check(~p, ~p);~n" + "Failed due to: ~p", + [?LINE, Obj, Mod, E], ?DEBUG_LEVEL), + corba:raise(E); + What -> + orber:dbg("[~p] CosNotification_Common:type_check(~p, ~p);~n" + "Failed due to: ~p", + [?LINE, Obj, Mod, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end + end. + + +%%-----------------------------------------------------------% +%% function : notify +%% Arguments: Items - [Item] +%% Item - {proxy, IOR} | {client, IOR} | {reason, term()} +%% Returns : 'ok' or raises exception. +%% Effect : +%%------------------------------------------------------------ +notify(Items) -> + case cosNotificationApp:notify() of + false -> + ok; + Module -> + catch Module:terminated(Items), + ok + end. + + +%%------------------------------------------------------------ +%% function : send_stubborn +%% Arguments: M - module +%% F - function +%% A - arguments +%% MaxR - Maximum no retries +%% Wait - sleep Wait seconds before next try. +%% Returns : see effect +%% Exception: +%% Effect : Retries repeatidly untill anything else besides +%% 'EXIT', 'COMM_FAILURE' or 'OBJECT_NOT_EXIST' +%%------------------------------------------------------------ + +send_stubborn(M, F, A, MaxR, Wait) when is_list(A) -> + send_stubborn(M, F, A, MaxR, Wait, 0); +send_stubborn(M, F, A, MaxR, Wait) -> + send_stubborn(M, F, [A], MaxR, Wait, 0). +send_stubborn(M, F, A, MaxR, _Wait, MaxR) -> + orber:dbg("[~p] CosNotification_Common:send_stubborn( ~p ~p ~p ~p).~n" + "Failed to deliver the event.~n", [?LINE, M,F,A,MaxR], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}); +send_stubborn(M, F, A, MaxR, Wait, Times) -> + ?debug_print("~p:~p(~p) # of retries: ~p~n", [M,F,A, Times]), + case catch apply(M,F,A) of + {'EXCEPTION', E} when is_record(E, 'COMM_FAILURE')-> + NewTimes = Times +1, + timer:sleep(Wait), + send_stubborn(M, F, A, MaxR, Wait, NewTimes); + {'EXIT', _} -> + NewTimes = Times +1, + timer:sleep(Wait), + send_stubborn(M, F, A, MaxR, Wait, NewTimes); + Other -> + Other + end. + + +%%-----------------------------------------------------------% +%% function : disconnect +%% Arguments: Module - one of the interfaces defined in CosEventComm. +%% Function - the appropriate disconnect function. +%% Object - the client object reference. +%% Returns : ok +%% Exception: +%% Effect : If the process would try to diconnect itself it could +%% result in a deadlock. Hence, we spawn a new process to do it. +%%------------------------------------------------------------ +disconnect(Module, Function, Object) -> + spawn(?MODULE, do_disconnect, [Module, Function, Object]), + ok. + +do_disconnect(Module, Function, Object) -> + catch Module:Function(Object), + ?DBG("Disconnect ~p:~p(..).~n", [Module, Function]), + ok. + + + +%%------------------------------------------------------------ +%% function : is_debug_compiled +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +-ifdef(debug). + is_debug_compiled() -> true. +-else. + is_debug_compiled() -> false. +-endif. + + +%%------------------------------------------------------------ +%%--------------- AdminPropertiesAdmin ----------------------- +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% function : init_adm +%% Arguments: Wanted - requested Admins to be set. +%% Returns : #'CosNotification_UnsupportedAdmin'{} | +%% {NewAdmProperties, [MaxQ, MaxC, MaxS]} +%% Effect : may only be used when creating a channel!!!!!!!! +%%------------------------------------------------------------ +init_adm(Wanted) -> + {NewA,_} = set_properties(Wanted, ?not_DEFAULT_ADMINPROPERTIES, channelAdm, + ?not_SUPPORTED_ADMINPROPERTIES, [], [], + false, false, false), + {NewA, [extract_value(NewA, ?not_MaxQueueLength), + extract_value(NewA, ?not_MaxConsumers), + extract_value(NewA, ?not_MaxSuppliers)]}. + +set_adm(Wanted, Current) -> + {NewA,_} = set_properties(Wanted, Current, channelAdm, + ?not_SUPPORTED_ADMINPROPERTIES, + [], [], false, false, false), + {NewA, [extract_value(NewA, ?not_MaxQueueLength), + extract_value(NewA, ?not_MaxConsumers), + extract_value(NewA, ?not_MaxSuppliers)]}. + +'MaxQueueLength'(Req,channelAdm,_, _, _, _) -> admin_ok(Req). +'MaxConsumers'(Req,channelAdm,_, _, _, _)-> admin_ok(Req). +'MaxSuppliers'(Req,channelAdm,_, _, _, _)-> admin_ok(Req). + +admin_ok(Req) -> + case any:get_value(Req#'CosNotification_Property'.value) of + Val when is_integer(Val) andalso Val >= 0 -> + {ok, Req}; + _ -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + + +%%------------------------------------------------------------ +%%--------------- QOS FUNCTIONS ------------------------------ +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% function : init_qos +%% Arguments: Wanted - requested QoS to be set. +%% Returns : see set_properties/9 +%% Effect : may only be used when creating a channel!!!!!!!! +%%------------------------------------------------------------ +init_qos(Wanted) -> + LQS = set_local_qos(?not_DEFAULT_QOS, ?not_CreateInitQoS()), + set_properties(Wanted, ?not_DEFAULT_QOS, channel, ?not_SUPPORTED_QOS, + [], [], false, [], LQS). + +%%------------------------------------------------------------ +%% function : set_qos/5 +%% Arguments: Wanted - requested QoS to be set. +%% Current - current QoS OMG style +%% LQS - local representation of QoS. +%% Type - channel | admin | proxy +%% Parent - Factory if Channel, Channel if Admin etc +%% Childs - Admins if Channel etc +%% Returns : see set_properties/9 +%%------------------------------------------------------------ +set_qos(Wanted, {Current, LQS}, proxy, Parent, _) -> + set_properties(Wanted, Current, proxy, ?not_SUPPORTED_QOS, [], [], Parent, false,LQS); +set_qos(Wanted, {Current, LQS}, admin, Parent, Childs) -> + set_properties(Wanted, Current, admin, ?not_SUPPORTED_QOS, [], [], Parent, Childs,LQS); +set_qos(Wanted, {Current, LQS}, channel, _, Childs) -> + set_properties(Wanted, Current, channel, ?not_SUPPORTED_QOS, [], [], false, Childs,LQS). + +%%------------------------------------------------------------ +%% function : +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : ok - if requested equal to current value. +%% {ok, Req, LQS} - if new and allowed QoS +%% {unsupported,#'CosNotification_PropertyError'{}} otherwise. +%% Effect : +%%------------------------------------------------------------ +'EventReliability'(Req,channel, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of + {Val, Val, _, _} -> + %% Is the value requested. + ok; + {Val, _, Val, _} -> + {ok, Req, LQS}; + {Val, _, _, Val} -> + {ok, Req, LQS}; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end; +'EventReliability'(Req,_,_,_,_,_) -> + %% only valid to set this QoS for channels (or per-event). + {unsupported, + #'CosNotification_PropertyError'{ + code = 'UNAVAILABLE_PROPERTY', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + }. + +%%------------------------------------------------------------ +%% function : 'ConnectionReliability'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +%% The most complex QoS to set is ConnectionReliability, and the reason for this +%% is that we cannot set the Channel to offer best effort while its children +%% offer persistent. A child may only offer Persistent if its parent do, which +%% is why we must check the following: +%% +%% # Persistent Change to Best Effort +%% _____ +%% | | (1) -> Check if children BE +%% |Chann| (2) ok <- +%% ----- +%% | +%% _____ +%% | | (3) -> Check if children BE +%% |Admin| (4) Check if parent Pers. <- +%% ----- +%% | +%% _____ +%% | | (5) -> ok +%% |Proxy| (6) Check if parent Pers. <- +%% ----- +%% NOTE: a parent always exists but we may change the QoS before creating any +%% childrens. The cases (2) and (5) is always ok, i.e., no need to confirm +%% with parent or children. +%%------------------------------------------------------------ +'ConnectionReliability'(Req, channel, _Curr, _Parent, Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of + {Val, Val, _, _} -> + %% Is the value requested. + ok; + {Val, P, Val, P} -> + %% Requested is BestEffort, Current Persistent => (1) + check_with_relatives(Childs, Req, LQS); + {Val, B, B, Val} -> + %% Requested is Persistent, Current BestEffort => (2) + {ok, Req, LQS}; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end; +'ConnectionReliability'(Req, admin, _Curr, Parent, Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of + {Val, Val, _, _} -> + %% Is the value requested. + ok; + {Val, P, Val, P} -> + %% Requested is BestEffort, Current Persistent => (3) + check_with_relatives(Childs, Req, LQS); + {Val, B, B, Val} -> + %% Requested is Persistent, Current BestEffort => (4) + check_with_relatives([Parent], Req, LQS); + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end; +'ConnectionReliability'(Req, proxy, _Curr, Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetConnectionReliability(LQS), ?not_BestEffort, ?not_Persistent} of + {Val, Val, _, _} -> + %% Is the value requested. + ok; + {Val, P, Val, P} -> + %% Requested is BestEffort, Current Persistent => (5) + {ok, Req, LQS}; + {Val, B, B, Val} -> + %% Requested is Persistent, Current BestEffort => (6) + check_with_relatives([Parent], Req, LQS); + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'Priority'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'Priority'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetPriority(LQS), ?not_HighestPriority, ?not_LowestPriority} of + {Val, Val, _, _} -> + ok; + {Val, _, H, L} when Val =< H, Val >= L -> + {ok, Req, LQS}; + {_, _, H, L} -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), L), + high_val=any:create(orber_tc:short(), H) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'StartTimeSupported'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'StartTimeSupported'(Req, _Type, _Curr, _, _, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetStartTimeSupported(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val =/= true, Val =/= false -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:boolean(), false), + high_val=any:create(orber_tc:boolean(), true) + } + } + }; + _-> + {ok, Req, LQS} + end. + +%%------------------------------------------------------------ +%% function : 'StopTimeSupported'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'StopTimeSupported'(Req, _Type, _Curr, _, _, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetStopTimeSupported(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val =/= true, Val =/= false -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:boolean(), false), + high_val=any:create(orber_tc:boolean(), true) + } + } + }; + _-> + {ok, Req, LQS} + end. + +%%------------------------------------------------------------ +%% function : 'Timeout'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'Timeout'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetTimeout(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val >= ?not_MinTimeout, Val =< ?not_MaxTimeout -> + {ok, Req, LQS}; + {Val, _} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinTimeout), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxTimeout) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'OrderPolicy'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'OrderPolicy'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetOrderPolicy(LQS), 'CosNotification':'AnyOrder'(), + 'CosNotification':'PriorityOrder'()} of + {Val, Val,_,_} -> + ok; + {Val, _, L, H} when Val >= L, Val =< H -> + {ok, Req, LQS}; + {Val, _, L, H} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), L), + high_val=any:create(orber_tc:short(), H) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + + +%%------------------------------------------------------------ +%% function : 'DiscardPolicy'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'DiscardPolicy'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetDiscardPolicy(LQS), ?not_AnyOrder, ?not_PriorityOrder} of + {Val, Val,_,_} -> + ok; + {Val, _, L, H} when Val >= L, Val =< H -> + {ok, Req, LQS}; + {Val, _, L, H} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), L), + high_val=any:create(orber_tc:short(), H) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'DiscardPolicy'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'MaximumBatchSize'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetMaximumBatchSize(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val >= ?not_MinBatchSize, Val =< ?not_MaxBatchSize -> + {ok, Req, LQS}; + {Val, _} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinBatchSize), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxBatchSize) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'UNSUPPORTED_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:long(), ?not_MinBatchSize), + high_val=any:create(orber_tc:long(), ?not_MaxBatchSize) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'PacingInterval'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Comment : PacingInterval is defined to be: +%% * TimeBase::UtcT (p 57, 2.5.5, OMG TC Document telecom/98-11-01) +%% * TimeBase::TimeT (p 189, appendix B, OMG TC Document telecom/98-11-01) +%% This implementation use TimeBase::TimeT, especially since +%% TimeBase::UtcT contains information which are of no importance. +%% When writing this, the OMG homepage contained no information +%% regarding this. +%%------------------------------------------------------------ +'PacingInterval'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetPacingInterval(LQS)} of + {Val, Val} -> + ok; + {Val, _} when Val >= ?not_MinPacing, Val =< ?not_MaxPacing -> + {ok, Req, LQS}; + {Val, _} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinPacing), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxPacing) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_TYPE', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : 'MaxEventsPerConsumer'/6 +%% Arguments: Req - Requested QoS, #'CosNotification_Property'{} +%% Type - Requestee, channel | admin | proxy +%% Curr - Current QoS, #'CosNotification_Property'{} +%% Parent - false | ObjRef +%% Childs - false | [ObjRef1, .., ObjRefN] +%% LQS - #qos{} defined in CosNotification_Definitions.hrl +%% Returns : +%% Effect : +%%------------------------------------------------------------ +'MaxEventsPerConsumer'(Req, _Type, _Curr, _Parent, _Childs, LQS) -> + case {any:get_value(Req#'CosNotification_Property'.value), + ?not_GetMaxEventsPerConsumer(LQS)} of + {Val, Val} -> + ok; + {Val, _} when is_integer(Val) andalso + Val >= ?not_MinConsumerEvents andalso + Val =< ?not_MaxConsumerEvents -> + {ok, Req, LQS}; + {Val, _} when is_integer(Val) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinConsumerEvents), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxConsumerEvents) + } + } + }; + _-> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'UNSUPPORTED_VALUE', + name = Req#'CosNotification_Property'.name, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:long(), ?not_MinConsumerEvents), + high_val=any:create(orber_tc:long(), ?not_MaxConsumerEvents) + } + } + } + end. + +%%------------------------------------------------------------ +%% function : validate_qos/5 +%% Arguments: Wanted - requested QoS to be set. +%% Curr - current QoS OMG style and LQS, local +%% representation of QoS, grouped as {OMGQ, LQS} +%% Type - channel | admin | proxy +%% Parent - Factory if Channel, Channel if Admin etc +%% Childs - Admins if Channel etc +%% Returns : NamedPropertySeq | #'CosNotification_UnsupportedQoS'{} +%% case 1 if all supported, case 2 if at least 1 QoS not +%% supported. +%% See also p59, 2.5.6.4, OMG TC Document telecom/98-11-01. Quote: +%% "If the supplied QoS is supported, it returns additional QoS +%% properties which could be optionally added as well." +%%------------------------------------------------------------ +validate_qos(Wanted, Curr, Type, Parent, Childs) -> + %% If not supported this function will raise an exception, which we should + %% not catch, but all we need to is to raise the exception as it is. + {_, LQS}=set_qos(Wanted, Curr, Type, Parent, Childs), + NewNPR = check_limits(LQS, ?not_QOS_LIMITS), + remove_qos(Wanted, LQS, NewNPR). + +remove_qos([], _, NPR) -> + NPR; +remove_qos([H|T], LQS, NPR) -> + NewNPR=remove(NPR, H#'CosNotification_Property'.name), + remove_qos(T, LQS, NewNPR). + +check_limits(LQS, NPR) -> + case {?not_GetEventReliability(LQS), ?not_GetConnectionReliability(LQS), + ?not_Persistent, ?not_BestEffort} of + {P,P,P,_B} -> + New = #'CosNotification_NamedPropertyRange' + {name=?not_EventReliability, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_BestEffort), + high_val=any:create(orber_tc:short(), ?not_BestEffort) + }}, + NewNPR=change(NPR, ?not_EventReliability, New), + remove(NewNPR, ?not_ConnectionReliability); + {_,B,_P,B} -> + remove(NPR, ?not_EventReliability); + {B,P,P,B} -> + New = #'CosNotification_NamedPropertyRange' + {name=?not_ConnectionReliability, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_BestEffort), + high_val=any:create(orber_tc:short(), ?not_BestEffort) + }}, + change(NPR, ?not_ConnectionReliability, New) + end. + +%%------------------------------------------------------------ +%% function : validate_event_qos/2 +%% Arguments: Wanted - requested QoS to be set. +%% Curr - LQS, local representation of QoS +%% Returns : NamedPropertySeq | #'CosNotification_UnsupportedQoS'{} +%% case 1 if all supported, case 2 if at least 1 QoS not +%% supported. +%%------------------------------------------------------------ +validate_event_qos(Wanted, Curr) -> + v_e_q_helper(Wanted, Curr, []), + []. +v_e_q_helper([], _Curr, []) -> + %% Parsed all and foynd no conflicts. + ok; +v_e_q_helper([], _Curr, Unsupp) -> + %% Not possible to use these requested QoS. + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupp}); + +%%--- EventReliability ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability, + value=#any{value=?not_BestEffort}}|T], Curr, Unsupp) -> + %% Always ok. + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability, + value=#any{value=?not_Persistent}}|T], Curr, Unsupp) + when ?not_GetConnectionReliability(Curr) =/= ?not_BestEffort, + ?not_GetEventReliability(Curr) =/= ?not_BestEffort, + ?not_GetStopTimeSupported(Curr) =/= true -> + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_EventReliability}|T], + Curr, Unsupp) -> + %% Impossible to set to Persistent if the connection reliability is best effort. + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_EventReliability, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null)}}|Unsupp]); + +%%--- Priority ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_Priority, value=#any{value=V}}|T], Curr, + Unsupp) -> + if + ?not_GetOrderPolicy(Curr) =/= ?not_AnyOrder, + ?not_GetOrderPolicy(Curr) =/= ?not_Priority, + ?not_GetDiscardPolicy(Curr) =/= ?not_Priority -> + %% No use setting Priority since it's not currently used. + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_Priority, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); + V =< ?not_HighestPriority, V >= ?not_LowestPriority -> + v_e_q_helper(T, Curr, Unsupp); + true -> + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'BAD_VALUE', name = ?not_Priority, + available_range = + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), + ?not_LowestPriority), + high_val=any:create(orber_tc:short(), + ?not_HighestPriority)}}|Unsupp]) + end; + +%%--- StartTime ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_StartTime}|T], Curr, Unsupp) + when ?not_GetStartTimeSupported(Curr) =/= false, + ?not_GetEventReliability(Curr) =/= ?not_Persistent -> + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_StartTime}|T], Curr, Unsupp) -> + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_StartTime, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); + +%%--- StopTime ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_StopTime}|T], Curr, Unsupp) + when ?not_GetStopTimeSupported(Curr) =/= false, + ?not_GetEventReliability(Curr) =/= ?not_Persistent -> + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_StopTime}|T], Curr, Unsupp) -> + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_StopTime, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); + +%%--- Timeout ---%% +v_e_q_helper([#'CosNotification_Property'{name=?not_Timeout}|T], Curr, Unsupp) + when ?not_GetStopTimeSupported(Curr) =/= false, + ?not_GetEventReliability(Curr) =/= ?not_Persistent -> + v_e_q_helper(T, Curr, Unsupp); +v_e_q_helper([#'CosNotification_Property'{name=?not_Timeout}|T], Curr, Unsupp) -> + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', name = ?not_Timeout, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); + +%%--- Unknown Event QoS ---%% +v_e_q_helper([#'CosNotification_Property'{name=Name}|T], Curr, Unsupp) -> + %% Unsupported property. + v_e_q_helper(T, Curr, [#'CosNotification_PropertyError' + {code = 'BAD_PROPERTY', name = Name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + }}|Unsupp]); +v_e_q_helper(What, _, _) -> + %% Not a Property struct. + orber:dbg("[~p] CosNotification_Common:v_e_q_helper(~p);~n" + "Not a CosNotification_Property struct.", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%-------------- QOS HELP FUNCTIONS -------------------------- +%%------------------------------------------------------------ +%% function : set_properties/9 +%% Arguments: Wanted - requested QoS to be set. +%% Current - current QoS OMG style +%% Type - channel | admin | proxy +%% Supported - List of supported QoS +%% Unsupp - acc +%% NewQoS - acc +%% Parent - Factory if Channel, Channel if Admin etc +%% Childs - Admins if Channel etc +%% LQS - local representation of QoS. +%% Returns : {NewOMGStyleQoS, NewLocalQoS} | #'CosNotification_UnsupportedQoS'{} +%%------------------------------------------------------------ +set_properties([], Curr, channelAdm, _, [], NewQoS,_,_,LAS) -> + merge_properties(NewQoS, Curr, LAS); +set_properties([], Curr, _, _, [], NewQoS,_,_,LQS) -> + %% set_local_qos and merge_properties are help functions found at the end of QoS + %% functions. + NewLQS = set_local_qos(NewQoS, LQS), + merge_properties(NewQoS, Curr, NewLQS); +set_properties([], _, channelAdm, _, Unsupp, _,_,_,_) -> + corba:raise(#'CosNotification_UnsupportedAdmin'{admin_err = Unsupp}); +set_properties([], _, _, _, Unsupp, _,_,_,_) -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Unsupp}); + +set_properties([Req|Tail], Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) -> + %% set_values and is_supported are help functions found at the end of QoS + %% functions. + case set_values(is_supported(Supported, Req), Req, Type, Curr, Parent, Childs,LQS) of + {unsupported, U} -> + set_properties(Tail, Curr, Type, Supported, [U|Unsupp], NewQoS, Parent, Childs,LQS); + {ok, S, NewLQS} -> + set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,NewLQS); + {ok, S} -> + set_properties(Tail, Curr, Type, Supported, Unsupp, [S|NewQoS], Parent, Childs,LQS); + ok -> + set_properties(Tail, Curr, Type, Supported, Unsupp, NewQoS, Parent, Childs,LQS) + end. + + +set_values(unsupported,Req,_,_,_,_,_) -> + {unsupported, + #'CosNotification_PropertyError'{ + code = 'BAD_PROPERTY', + name = Req#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + }; +set_values({ok, Func}, Req, Type, Curr, Parent, Childs, LQS) -> + ?MODULE:Func(Req, Type, Curr, Parent, Childs, LQS). + +%% Update OMG style QoS list with new values. +merge_properties([], NewCurrQoS, LQS) -> + {NewCurrQoS, LQS}; +merge_properties([H|T], Curr, LQS) -> + merge_properties(T, lists:keyreplace(H#'CosNotification_Property'.name, %% get key. + #'CosNotification_Property'.name, %% get index. + Curr, H), LQS). + +%% Is the Property S among our supported QoS? +is_supported([], _) -> + unsupported; +is_supported([{Name, Func}|_], #'CosNotification_Property'{name=Name}) -> + {ok, Func}; +is_supported([_|T], S) -> + is_supported(T, S). + +%% Find matching S-Property from a list of OMG style QoS +extract([], _) -> unsupported; +extract([H|_T], S) when H#'CosNotification_Property'.name== + S#'CosNotification_Property'.name -> + {ok, H}; +extract([_|T], S) -> extract(T,S). + +%% Find matching Property name from a list of OMG style QoS +extract_value([], _) -> unsupported; +extract_value([H|_T], Key) when H#'CosNotification_Property'.name== Key -> + {ok, any:get_value(H#'CosNotification_Property'.value)}; +extract_value([_|T], Key) -> extract(T,Key). + +%% Remove matching S-QoS from a list of OMG style QoS +remove(List, Key) -> + lists:keydelete(Key, + #'CosNotification_NamedPropertyRange'.name, %% get index. + List). + +change(List, Key, New) -> + lists:keyreplace(Key, + #'CosNotification_NamedPropertyRange'.name, %% get index. + List, New). +%% Get QoS from supplied objects and check if it's the same as S. +check_with_relatives([], S, LQS) -> + {ok, S, LQS}; +check_with_relatives([undefined|T], S, LQS) -> + check_with_relatives(T, S, LQS); +check_with_relatives([H|T], S, LQS) -> + case catch extract('CosNotification_QoSAdmin':get_qos(H), S) of + {ok, S} -> + check_with_relatives(T, S, LQS); + _-> + %% Varioues reasons for this case (Object not responding, not supported) + {unsupported, + #'CosNotification_PropertyError'{ + code = 'UNAVAILABLE_PROPERTY', + name = S#'CosNotification_Property'.name, + available_range = #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:null(), null), + high_val=any:create(orber_tc:null(), null) + } + } + } + end. + +%% Set new values to locally defined representation of QoS. Using this approach is +%% necessary since we must state the record-field at compile-time. +set_local_qos([], LQS) -> LQS; +set_local_qos([#'CosNotification_Property'{name=N,value=V}|T], LQS) -> + NewLQS = + case N of + "EventReliability" -> + ?not_SetEventReliability(LQS, any:get_value(V)); + "ConnectionReliability" -> + ?not_SetConnectionReliability(LQS, any:get_value(V)); + "Priority" -> + ?not_SetPriority(LQS, any:get_value(V)); + "Timeout" -> + ?not_SetTimeout(LQS, any:get_value(V)); + "OrderPolicy" -> + ?not_SetOrderPolicy(LQS, any:get_value(V)); + "DiscardPolicy" -> + ?not_SetDiscardPolicy(LQS, any:get_value(V)); + "MaximumBatchSize" -> + ?not_SetMaximumBatchSize(LQS, any:get_value(V)); + "PacingInterval" -> + ?not_SetPacingInterval(LQS, any:get_value(V)); + "StartTimeSupported" -> + ?not_SetStartTimeSupported(LQS, any:get_value(V)); + "StopTimeSupported" -> + ?not_SetStopTimeSupported(LQS, any:get_value(V)); + "MaxEventsPerConsumer" -> + ?not_SetMaxEventsPerConsumer(LQS, any:get_value(V)) + end, + set_local_qos(T, NewLQS). + +%%%%%%%%%%%%%%%%% END QOS FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%% + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotification_Definitions.hrl b/lib/cosNotification/src/CosNotification_Definitions.hrl new file mode 100644 index 0000000..755b07c --- /dev/null +++ b/lib/cosNotification/src/CosNotification_Definitions.hrl @@ -0,0 +1,340 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosNotification_Definitions.hrl +%% Purpose : +%%---------------------------------------------------------------------- + +-ifndef(COSNOTIFICATION_DEFINITIONS_HRL). +-define(COSNOTIFICATION_DEFINITIONS_HRL, true). + +%% ---------------- General comment ------------------------------------ +%% ******* README ******** +%% The prefix 'not' is short for notification, and is used to separate locally +%% defined macros from the global ones, i.e., do NOT confuse this with a negation!! +%% +%% In this file you find globally used data structures, constants etc. +%% + +%%--------------- INCLUDES --------------------------------------------- + +%%-------- Constants ------------------------------------------------- +-define(not_SupportedGrammars, ["EXTENDED_TCL"]). + +%% !!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +%% +%% If OMG redefines the values for the constants the definitions +%% below must be redefined!! +%% +%% !!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +-define(not_BestEffort, 0). +-define(not_Persistent, 1). +-define(not_EventReliability, "EventReliability"). +-define(not_ConnectionReliability, "ConnectionReliability"). +-define(not_Priority, "Priority"). +-define(not_LowestPriority, -32767). +-define(not_HighestPriority, 32767). +-define(not_DefaultPriority, 0). +-define(not_StartTime, "StartTime"). +-define(not_StopTime, "StopTime"). +-define(not_Timeout, "Timeout"). +-define(not_OrderPolicy, "OrderPolicy"). +-define(not_AnyOrder, 0). +-define(not_FifoOrder, 1). +-define(not_PriorityOrder, 2). +-define(not_DeadlineOrder, 3). +-define(not_DiscardPolicy, "DiscardPolicy"). +-define(not_LifoOrder, 4). +-define(not_RejectNewEvents, 5). +-define(not_MaximumBatchSize, "MaximumBatchSize"). +-define(not_PacingInterval, "PacingInterval"). +-define(not_StartTimeSupported, "StartTimeSupported"). +-define(not_StopTimeSupported, "StopTimeSupported"). +-define(not_MaxEventsPerConsumer, "MaxEventsPerConsumer"). +-define(not_MaxQueueLength, "MaxQueueLength"). +-define(not_MaxConsumers, "MaxConsumers"). +-define(not_MaxSuppliers, "MaxSuppliers"). + +%%--------------- QOS DEFINITIONS ---------------------------- +%% Limits for QoS. These are our own limits. +-define(not_MaxBatchSize, 10000). +-define(not_MinBatchSize, 1). +-define(not_MinTimeout, 0). +-define(not_MaxTimeout, 100000000000). +-define(not_MinPacing, 0). +-define(not_MaxPacing, 100000000000). +-define(not_MinConsumerEvents, 1). +-define(not_MaxConsumerEvents, 10000). + +-define(not_QOS_LIMITS, +[#'CosNotification_NamedPropertyRange' + {name=?not_EventReliability, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_BestEffort), + high_val=any:create(orber_tc:short(), ?not_Persistent) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_ConnectionReliability, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_BestEffort), + high_val=any:create(orber_tc:short(), ?not_Persistent) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_Priority, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_LowestPriority), + high_val=any:create(orber_tc:short(), ?not_HighestPriority) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_StartTimeSupported, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:boolean(), false), + high_val=any:create(orber_tc:boolean(), true) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_StopTimeSupported, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:boolean(), false), + high_val=any:create(orber_tc:boolean(), true) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_Timeout, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinTimeout), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxTimeout) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_OrderPolicy, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_AnyOrder), + high_val=any:create(orber_tc:short(), ?not_PriorityOrder) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_DiscardPolicy, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:short(), ?not_AnyOrder), + high_val=any:create(orber_tc:short(), ?not_PriorityOrder) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_MaximumBatchSize, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:long(), ?not_MinBatchSize), + high_val=any:create(orber_tc:long(), ?not_MaxBatchSize) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_PacingInterval, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:unsigned_long_long(), ?not_MinPacing), + high_val=any:create(orber_tc:unsigned_long_long(), ?not_MaxPacing) + }}, + #'CosNotification_NamedPropertyRange' + {name=?not_MaxEventsPerConsumer, + range= + #'CosNotification_PropertyRange'{ + low_val=any:create(orber_tc:long(), ?not_MinConsumerEvents), + high_val=any:create(orber_tc:long(), ?not_MaxConsumerEvents) + }} +]. + + + +%% Local record used internally, and the reason for this is we get faster +%% access to QoS settings. +-record(qos, {'EventReliability', + 'ConnectionReliability', + 'Priority', + 'StartTimeSupported', + 'StopTimeSupported', + 'Timeout', + 'OrderPolicy', + 'DiscardPolicy', + 'MaximumBatchSize', + 'PacingInterval', + 'MaxEventsPerConsumer'}). + +%% Global (OMG) representation of QoS. +-define(not_DEFAULT_QOS, +[#'CosNotification_Property'{name=?not_MaximumBatchSize, + value=any:create(orber_tc:long(), 1)}, + #'CosNotification_Property'{name=?not_PacingInterval, + value=any:create(orber_tc:unsigned_long_long(), 0)}, + #'CosNotification_Property'{name=?not_Timeout, + value=any:create(orber_tc:unsigned_long_long(), 0)}, + #'CosNotification_Property'{name=?not_MaxEventsPerConsumer, + value=any:create(orber_tc:long(), 100)}, + #'CosNotification_Property'{name=?not_OrderPolicy, + value=any:create(orber_tc:short(), + ?not_PriorityOrder)}, + #'CosNotification_Property'{name=?not_EventReliability, + value=any:create(orber_tc:short(), + ?not_BestEffort)}, + #'CosNotification_Property'{name=?not_ConnectionReliability, + value=any:create(orber_tc:short(), + ?not_BestEffort)}, + #'CosNotification_Property'{name=?not_DiscardPolicy, + value=any:create(orber_tc:short(), + ?not_RejectNewEvents)}, + #'CosNotification_Property'{name=?not_StartTimeSupported, + value=any:create(orber_tc:boolean(), false)}, + #'CosNotification_Property'{name=?not_StopTimeSupported, + value=any:create(orber_tc:boolean(), false)}, + #'CosNotification_Property'{name=?not_Priority, + value=any:create(orber_tc:short(), ?not_DefaultPriority)}]). + +%%--------------- QOS CREATORS ------------------------------- +-define(not_CreateInitQoS(), #qos{}). + +%%--------------- QOS DESTRUCTORS ---------------------------- +-define(not_DestroyQoS(Q), ok). + +%%--------------- QOS SELECTORS ------------------------------ +-define(not_GetEventReliability(Q), Q#qos.'EventReliability'). +-define(not_GetConnectionReliability(Q), Q#qos.'ConnectionReliability'). +-define(not_GetPriority(Q), Q#qos.'Priority'). +-define(not_GetStartTimeSupported(Q), Q#qos.'StartTimeSupported'). +-define(not_GetStopTimeSupported(Q), Q#qos.'StopTimeSupported'). +-define(not_GetTimeout(Q), Q#qos.'Timeout'). +-define(not_GetOrderPolicy(Q), Q#qos.'OrderPolicy'). +-define(not_GetDiscardPolicy(Q), Q#qos.'DiscardPolicy'). +-define(not_GetMaximumBatchSize(Q), Q#qos.'MaximumBatchSize'). +-define(not_GetPacingInterval(Q), Q#qos.'PacingInterval'). +-define(not_GetMaxEventsPerConsumer(Q), Q#qos.'MaxEventsPerConsumer'). + +%%--------------- QOS MODIFIERS ------------------------------ +-define(not_SetEventReliability(Q,D), Q#qos{'EventReliability'=D}). +-define(not_SetConnectionReliability(Q,D), Q#qos{'ConnectionReliability'=D}). +-define(not_SetPriority(Q,D), Q#qos{'Priority'=D}). +-define(not_SetStartTimeSupported(Q,D), Q#qos{'StartTimeSupported'=D}). +-define(not_SetStopTimeSupported(Q,D), Q#qos{'StopTimeSupported'=D}). +-define(not_SetTimeout(Q,D), Q#qos{'Timeout'=D}). +-define(not_SetOrderPolicy(Q,D), Q#qos{'OrderPolicy'=D}). +-define(not_SetDiscardPolicy(Q,D), Q#qos{'DiscardPolicy'=D}). +-define(not_SetMaximumBatchSize(Q,D), Q#qos{'MaximumBatchSize'=D}). +-define(not_SetPacingInterval(Q,D), Q#qos{'PacingInterval'=D}). +-define(not_SetMaxEventsPerConsumer(Q,D), Q#qos{'MaxEventsPerConsumer'=D}). + +%%--------------- StructuredEvent CREATORS ------------------- +-define(not_CreateSE(StrD,StrT,StrE,PSeqV,PSeqF,AnyR), +#'CosNotification_StructuredEvent'{header = + #'CosNotification_EventHeader'{fixed_header = + #'CosNotification_FixedEventHeader'{event_type = + #'CosNotification_EventType'{domain_name=StrD, + type_name=StrT}, + event_name = StrE}, + variable_header = PSeqV}, + filterable_data = PSeqF, + remainder_of_body = AnyR}). +%% Can be used in guards. +-define(not_isConvertedAny(E), + (((E#'CosNotification_StructuredEvent'.header) + #'CosNotification_EventHeader'.fixed_header) + #'CosNotification_FixedEventHeader'.event_type) + #'CosNotification_EventType'.type_name == "%ANY"). +%% Can NOT be used in guards!!!!! +-define(not_isConvertedStructured(E), + any:get_typecode(E) == 'CosNotification_StructuredEvent':tc()). + +%%--------------- StructuredEvent DESTRUCTORS ---------------- +-define(not_DestroySE(E), ok). + +%%--------------- StructuredEvent SELECTORS ------------------ +-define(not_GetSEHeader(E), E#'StructuredEvent'.header). +-define(not_GetSEFixedHeader(E), E#'StructuredEvent'.header). + +%%--------------- StructuredEvent MODIFIERS ------------------ + +%%-------- QoS support ----------------------------------------------- +-define(not_SUPPORTED_QOS, +[{?not_EventReliability, 'EventReliability'}, + {?not_ConnectionReliability, 'ConnectionReliability'}, + {?not_Priority, 'Priority'}, + {?not_StartTimeSupported, 'StartTimeSupported'}, + {?not_StopTimeSupported, 'StopTimeSupported'}, + {?not_Timeout, 'Timeout'}, + {?not_OrderPolicy, 'OrderPolicy'}, + {?not_DiscardPolicy, 'DiscardPolicy'}, + {?not_MaximumBatchSize, 'MaximumBatchSize'}, + {?not_PacingInterval, 'PacingInterval'}, + {?not_MaxEventsPerConsumer, 'MaxEventsPerConsumer'}]). + +%%-------- ADMINPROPERTIESADMIN -------------------------------------- + +%% According to the OMG TC Document telecom/98-11-01, p 63 (section 2.5.7), the +%% default-value for these 3 admin properties is zero, which means that no limit +%% applies to that property. +-define(not_DEFAULT_ADMINPROPERTIES, +[#'CosNotification_Property'{name=?not_MaxQueueLength, + value=any:create(orber_tc:long(), 0)}, + #'CosNotification_Property'{name=?not_MaxConsumers, + value=any:create(orber_tc:long(), 0)}, + #'CosNotification_Property'{name=?not_MaxSuppliers, + value=any:create(orber_tc:long(), 0)}]). + +-define(not_SUPPORTED_ADMINPROPERTIES, +[{?not_MaxQueueLength, 'MaxQueueLength'}, + {?not_MaxConsumers, 'MaxConsumers'}, + {?not_MaxSuppliers, 'MaxSuppliers'}]). + + +%%-------- MISC -------------------------------------------------------- + +-define(not_DEFAULT_SETTINGS, [{pullInterval, 20}, + {filterOp, 'OR_OP'}, + {gcTime, 60}, + {gcLimit, 50}, + {timeService, undefined}, + {typecheck, true}, + {tty, false}, + {logfile, false}, + {server_options, []}]). +-define(not_CreateDBKey, term_to_binary({now(), node()})). + +-define(DEBUG_LEVEL, 3). + +-ifdef(debug). + +-define(debug_print(F,A), io:format("[~p(~p)] "++F,[?MODULE, ?LINE]++A)). +-define(DBG(F,A), io:format("[~p(~p)] "++F,[?MODULE, ?LINE]++A)). +-define(not_TypeCheck(O,I), ok). +%-define(not_TypeCheck(O,M), 'CosNotification_Common':type_check(O,M)). + +-else. + +-define(debug_print(F,A), ok). +-define(DBG(F,A), ok). +-define(not_TypeCheck(O,I), ok). + +-endif. + + + +-endif. +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin.cfg b/lib/cosNotification/src/CosNotifyChannelAdmin.cfg new file mode 100644 index 0000000..8647b28 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin.cfg @@ -0,0 +1,60 @@ +{this, "CosNotifyChannelAdmin::EventChannel"}. +{from, "CosNotifyChannelAdmin::EventChannel"}. +{{handle_info, "CosNotifyChannelAdmin::EventChannel"}, true}. +{this, "CosNotifyChannelAdmin::EventChannelFactory"}. +{from, "CosNotifyChannelAdmin::EventChannelFactory"}. +{{handle_info, "CosNotifyChannelAdmin::EventChannelFactory"}, true}. +{this, "CosNotifyChannelAdmin::SupplierAdmin"}. +{from, "CosNotifyChannelAdmin::SupplierAdmin"}. +{{handle_info, "CosNotifyChannelAdmin::SupplierAdmin"}, true}. +{this, "CosNotifyChannelAdmin::ConsumerAdmin"}. +{from, "CosNotifyChannelAdmin::ConsumerAdmin"}. +{{handle_info, "CosNotifyChannelAdmin::ConsumerAdmin"}, true}. +{this, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}. +{from, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::StructuredProxyPushSupplier"}, "PusherSupplier_impl"}. +{this, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}. +{from, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::StructuredProxyPullSupplier"}, "PullerSupplier_impl"}. +{this, "CosNotifyChannelAdmin::ProxyPushSupplier"}. +{from, "CosNotifyChannelAdmin::ProxyPushSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::ProxyPushSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::ProxyPushSupplier"}, "PusherSupplier_impl"}. +{this, "CosNotifyChannelAdmin::ProxyPullSupplier"}. +{from, "CosNotifyChannelAdmin::ProxyPullSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::ProxyPullSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::ProxyPullSupplier"}, "PullerSupplier_impl"}. +{this, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}. +{from, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::SequenceProxyPushSupplier"}, "PusherSupplier_impl"}. +{this, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}. +{from, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}. +{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}, true}. +{{impl, "CosNotifyChannelAdmin::SequenceProxyPullSupplier"}, "PullerSupplier_impl"}. +{this, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}. +{from, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::StructuredProxyPushConsumer"}, "PusherConsumer_impl"}. +{this, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}. +{from, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::StructuredProxyPullConsumer"}, "PullerConsumer_impl"}. +{this, "CosNotifyChannelAdmin::ProxyPushConsumer"}. +{from, "CosNotifyChannelAdmin::ProxyPushConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::ProxyPushConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::ProxyPushConsumer"}, "PusherConsumer_impl"}. +{this, "CosNotifyChannelAdmin::ProxyPullConsumer"}. +{from, "CosNotifyChannelAdmin::ProxyPullConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::ProxyPullConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::ProxyPullConsumer"}, "PullerConsumer_impl"}. +{this, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}. +{from, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::SequenceProxyPushConsumer"}, "PusherConsumer_impl"}. +{this, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}. +{from, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}. +{{handle_info, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}, true}. +{{impl, "CosNotifyChannelAdmin::SequenceProxyPullConsumer"}, "PullerConsumer_impl"}. diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin.idl b/lib/cosNotification/src/CosNotifyChannelAdmin.idl new file mode 100644 index 0000000..b345ff5 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin.idl @@ -0,0 +1,275 @@ +#ifndef _COS_NOTIFYCHANNELADMIN_IDL_ +#define _COS_NOTIFYCHANNELADMIN_IDL_ + +#pragma prefix "omg.org" + +#include +#include +#include +#include + +module CosNotifyChannelAdmin { + exception ConnectionAlreadyActive {}; + exception ConnectionAlreadyInactive {}; + exception NotConnected {}; + // Forward declarations + interface ConsumerAdmin; + interface SupplierAdmin; + interface EventChannel; + interface EventChannelFactory; + + enum ProxyType { + PUSH_ANY, + PULL_ANY, + PUSH_STRUCTURED, + PULL_STRUCTURED, + PUSH_SEQUENCE, + PULL_SEQUENCE}; + + enum ObtainInfoMode { + ALL_NOW_UPDATES_OFF, + ALL_NOW_UPDATES_ON, + NONE_NOW_UPDATES_OFF, + NONE_NOW_UPDATES_ON}; + + interface ProxyConsumer : CosNotification::QoSAdmin, CosNotifyFilter::FilterAdmin { + readonly attribute ProxyType MyType; + readonly attribute SupplierAdmin MyAdmin; + + CosNotification::EventTypeSeq obtain_subscription_types(in ObtainInfoMode mode); + + void validate_event_qos (in CosNotification::QoSProperties required_qos, + out CosNotification::NamedPropertyRangeSeq available_qos) + raises (CosNotification::UnsupportedQoS); + }; // ProxyConsumer + + interface ProxySupplier : CosNotification::QoSAdmin, CosNotifyFilter::FilterAdmin { + readonly attribute ProxyType MyType; + readonly attribute ConsumerAdmin MyAdmin; + attribute CosNotifyFilter::MappingFilter priority_filter; + attribute CosNotifyFilter::MappingFilter lifetime_filter; + + CosNotification::EventTypeSeq obtain_offered_types(in ObtainInfoMode mode); + + void validate_event_qos (in CosNotification::QoSProperties required_qos, + out CosNotification::NamedPropertyRangeSeq available_qos) + raises (CosNotification::UnsupportedQoS); + }; // ProxySupplier + + interface ProxyPushConsumer : ProxyConsumer, CosNotifyComm::PushConsumer, + CosEventChannelAdmin::ProxyPushConsumer { + void connect_any_push_supplier (in CosEventComm::PushSupplier push_supplier) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // ProxyPushConsumer + + interface StructuredProxyPushConsumer : ProxyConsumer, CosNotifyComm::StructuredPushConsumer { + void connect_structured_push_supplier (in CosNotifyComm::StructuredPushSupplier push_supplier) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // StructuredProxyPushConsumer + + interface SequenceProxyPushConsumer : ProxyConsumer, CosNotifyComm::SequencePushConsumer { + void connect_sequence_push_supplier (in CosNotifyComm::SequencePushSupplier push_supplier) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // SequenceProxyPushConsumer + + interface ProxyPullSupplier : ProxySupplier, CosNotifyComm::PullSupplier, + CosEventChannelAdmin::ProxyPullSupplier, oe_CosNotificationComm::Event { + void connect_any_pull_consumer (in CosEventComm::PullConsumer pull_consumer) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // ProxyPullSupplier + + interface StructuredProxyPullSupplier : ProxySupplier, CosNotifyComm::StructuredPullSupplier, + oe_CosNotificationComm::Event { + void connect_structured_pull_consumer (in CosNotifyComm::StructuredPullConsumer pull_consumer) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // StructuredProxyPullSupplier + + interface SequenceProxyPullSupplier : ProxySupplier, CosNotifyComm::SequencePullSupplier, + oe_CosNotificationComm::Event { + void connect_sequence_pull_consumer (in CosNotifyComm::SequencePullConsumer pull_consumer) + raises(CosEventChannelAdmin::AlreadyConnected); + }; // SequenceProxyPullSupplier + + interface ProxyPullConsumer : ProxyConsumer, CosNotifyComm::PullConsumer, + CosEventChannelAdmin::ProxyPullConsumer { + void connect_any_pull_supplier (in CosEventComm::PullSupplier pull_supplier) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // ProxyPullConsumer + + interface StructuredProxyPullConsumer : ProxyConsumer, CosNotifyComm::StructuredPullConsumer { + void connect_structured_pull_supplier (in CosNotifyComm::StructuredPullSupplier pull_supplier) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // StructuredProxyPullConsumer + + interface SequenceProxyPullConsumer : ProxyConsumer, CosNotifyComm::SequencePullConsumer { + void connect_sequence_pull_supplier (in CosNotifyComm::SequencePullSupplier pull_supplier) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // SequenceProxyPullConsumer + + interface ProxyPushSupplier : ProxySupplier, CosNotifyComm::PushSupplier, + CosEventChannelAdmin::ProxyPushSupplier, oe_CosNotificationComm::Event { + void connect_any_push_consumer (in CosEventComm::PushConsumer push_consumer) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // ProxyPushSupplier + + interface StructuredProxyPushSupplier : ProxySupplier, CosNotifyComm::StructuredPushSupplier, + oe_CosNotificationComm::Event { + void connect_structured_push_consumer (in CosNotifyComm::StructuredPushConsumer push_consumer) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // StructuredProxyPushSupplier + + interface SequenceProxyPushSupplier : ProxySupplier, CosNotifyComm::SequencePushSupplier, + oe_CosNotificationComm::Event { + void connect_sequence_push_consumer (in CosNotifyComm::SequencePushConsumer push_consumer) + raises(CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises(ConnectionAlreadyInactive, NotConnected); + + void resume_connection() + raises(ConnectionAlreadyActive, NotConnected); + }; // SequenceProxyPushSupplier + + + typedef long ProxyID; + typedef sequence ProxyIDSeq; + + enum ClientType { + ANY_EVENT, + STRUCTURED_EVENT, + SEQUENCE_EVENT}; + + enum InterFilterGroupOperator { + AND_OP, + OR_OP }; + + typedef long AdminID; + typedef sequence AdminIDSeq; + + exception AdminNotFound {}; + exception ProxyNotFound {}; + + struct AdminLimit { + CosNotification::PropertyName name; + CosNotification::PropertyValue value; + }; + + exception AdminLimitExceeded { AdminLimit admin_property_err; }; + + interface ConsumerAdmin : CosNotification::QoSAdmin, CosNotifyComm::NotifySubscribe, + CosNotifyFilter::FilterAdmin, CosEventChannelAdmin::ConsumerAdmin, + oe_CosNotificationComm::Event { + readonly attribute AdminID MyID; + readonly attribute EventChannel MyChannel; + readonly attribute InterFilterGroupOperator MyOperator; + attribute CosNotifyFilter::MappingFilter priority_filter; + attribute CosNotifyFilter::MappingFilter lifetime_filter; + readonly attribute ProxyIDSeq pull_suppliers; + readonly attribute ProxyIDSeq push_suppliers; + + ProxySupplier get_proxy_supplier (in ProxyID proxy_id) + raises (ProxyNotFound); + + ProxySupplier obtain_notification_pull_supplier (in ClientType ctype, out ProxyID proxy_id) + raises (AdminLimitExceeded); + + ProxySupplier obtain_notification_push_supplier (in ClientType ctype, out ProxyID proxy_id) + raises (AdminLimitExceeded); + + void destroy(); + }; // ConsumerAdmin + + interface SupplierAdmin : CosNotification::QoSAdmin, CosNotifyComm::NotifyPublish, + CosNotifyFilter::FilterAdmin, CosEventChannelAdmin::SupplierAdmin , + oe_CosNotificationComm::Event { + readonly attribute AdminID MyID; + readonly attribute EventChannel MyChannel; + readonly attribute InterFilterGroupOperator MyOperator; + readonly attribute ProxyIDSeq pull_consumers; + readonly attribute ProxyIDSeq push_consumers; + + ProxyConsumer get_proxy_consumer (in ProxyID proxy_id) + raises (ProxyNotFound); + + ProxyConsumer obtain_notification_pull_consumer (in ClientType ctype, out ProxyID proxy_id) + raises (AdminLimitExceeded); + + ProxyConsumer obtain_notification_push_consumer (in ClientType ctype, out ProxyID proxy_id) + raises (AdminLimitExceeded); + + void destroy(); + }; // SupplierAdmin + + interface EventChannel : CosNotification::QoSAdmin, CosNotification::AdminPropertiesAdmin, + CosEventChannelAdmin::EventChannel, + oe_CosNotificationComm::Event { + readonly attribute EventChannelFactory MyFactory; + readonly attribute ConsumerAdmin default_consumer_admin; + readonly attribute SupplierAdmin default_supplier_admin; + readonly attribute CosNotifyFilter::FilterFactory default_filter_factory; + + ConsumerAdmin new_for_consumers(in InterFilterGroupOperator op, out AdminID id); + + SupplierAdmin new_for_suppliers(in InterFilterGroupOperator op, out AdminID id); + + ConsumerAdmin get_consumeradmin (in AdminID id) + raises (AdminNotFound); + + SupplierAdmin get_supplieradmin (in AdminID id) + raises (AdminNotFound); + + AdminIDSeq get_all_consumeradmins(); + + AdminIDSeq get_all_supplieradmins(); + }; // EventChannel + + typedef long ChannelID; + typedef sequence ChannelIDSeq; + exception ChannelNotFound {}; + + interface EventChannelFactory { + EventChannel create_channel (in CosNotification::QoSProperties initial_qos, + in CosNotification::AdminProperties initial_admin, + out ChannelID id) + raises(CosNotification::UnsupportedQoS, CosNotification::UnsupportedAdmin); + + ChannelIDSeq get_all_channels(); + + EventChannel get_event_channel (in ChannelID id) + raises (ChannelNotFound); + }; // EventChannelFactory +}; // CosNotifyChannelAdmin + + +#endif /* ifndef _COS_NOTIFYCHANNELADMIN_IDL_ */ + diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl new file mode 100644 index 0000000..5ac8c81 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin_ConsumerAdmin_impl.erl @@ -0,0 +1,670 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%------------------------------------------------------------------- +%% File : CosNotifyChannelAdmin_ConsumerAdmin_impl.erl +%% Purpose : +%%------------------------------------------------------------------- + +-module('CosNotifyChannelAdmin_ConsumerAdmin_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ConsumerAdmin ----------------- +-export([get_proxy_supplier/4, + obtain_notification_pull_supplier/4, + obtain_notification_push_supplier/4, + destroy/3]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifySubscribe ---------- +-export([subscription_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventChannelAdmin::ConsumerAdmin ----- +-export([obtain_push_supplier/3, + obtain_pull_supplier/3]). + +%% Attributes (external) +-export(['_get_MyID'/3, + '_get_MyChannel'/3, + '_get_MyOperator'/3, + '_get_priority_filter'/3, + '_set_priority_filter'/4, + '_get_lifetime_filter'/3, + '_set_lifetime_filter'/4, + '_get_pull_suppliers'/3, + '_get_push_suppliers'/3]). + +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm --------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myId, + myChannel, + myChannelPid, + myOperator, + myFilters = [], + mySuppliers = [], + idCounter = 0, + priorityFilter, + lifetimeFilter, + etsR, + qosGlobal, + qosLocal, + options}). + +%% Data structures constructors +-define(get_InitState(_MyID, _MyCh, _MyChP, _MyOp, _PFil, _LFil, _QoS, _LQS, _O), + #state{myId = _MyID, + myChannel = _MyCh, + myChannelPid = _MyChP, + myOperator = _MyOp, + priorityFilter = _PFil, + lifetimeFilter = _LFil, + qosGlobal = _QoS, + qosLocal = _LQS, + options = _O, + etsR = ets:new(oe_ets, [set, protected])}). + +%% Data structures selectors +-define(get_PushSupplierIDs(S), find_ids(S#state.mySuppliers, pusher)). +-define(get_PullSupplierIDs(S), find_ids(S#state.mySuppliers, puller)). +-define(get_AllSuppliers(S), S#state.mySuppliers). +-define(get_AllSupplierRefs(S), find_refs(S#state.mySuppliers)). +-define(get_Supplier(S, I), find_obj(lists:keysearch(I,1,S#state.mySuppliers), + supplier)). + +-define(get_MyID(S), S#state.myId). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyChannelPid(S), S#state.myChannelPid). +-define(get_MyOperator(S), S#state.myOperator). +-define(get_PrioFilter(S), S#state.priorityFilter). +-define(get_LifeFilter(S), S#state.lifetimeFilter). +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters), + filter)). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +-define(get_Options(S), S#state.options). +-define(get_IdCounter(S), S#state.idCounter). + +%% Data structures modifiers +-define(set_PrioFilter(S,D), S#state{priorityFilter=D}). +-define(set_LifeFilter(S,D), S#state{lifetimeFilter=D}). +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +-define(add_PushSupplier(S,I,R,P),S#state{mySuppliers=[{I,R,P,pusher}|S#state.mySuppliers]}). +-define(add_PullSupplier(S,I,R,P),S#state{mySuppliers=[{I,R,P,puller}|S#state.mySuppliers]}). +-define(del_Supplier(S,I), S#state{mySuppliers= + lists:keydelete(I, 1, + S#state.mySuppliers)}). +-define(del_SupplierRef(S,O), S#state{mySuppliers= + lists:keydelete(O, 2, + S#state.mySuppliers)}). +-define(del_SupplierPid(S,P), S#state{mySuppliers= + lists:keydelete(P, 3, + S#state.mySuppliers)}). +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_filter(lists:keydelete(I, 1, + S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id( + S#state.idCounter)). + +%% MISC +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + case Info of + {'EXIT', Pid, Reason} when ?get_MyChannelPid(State) == Pid -> + ?DBG("PARENT CHANNEL: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', Pid, normal} -> + {noreply, ?del_SupplierPid(State, Pid)}; + _Other -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyId, MyChannel, MyChannelPid, MyOperator, InitQoS, LQS, Options]) -> + process_flag(trap_exit, true), + PriorityFilter = corba:create_nil_objref(), + LifeTimeFilter = corba:create_nil_objref(), + {ok, ?get_InitState(MyId, MyChannel, MyChannelPid, MyOperator, + PriorityFilter, LifeTimeFilter, InitQoS, LQS, Options)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ConsumerAdmin attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyID' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyID'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyID(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyChannel' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyChannel'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyChannel(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyOperator' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyOperator'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyOperator(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_priority_filter' +%% Type : read and write +%% Returns : +%%----------------------------------------------------------- +'_get_priority_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PrioFilter(State), State}. + +'_set_priority_filter'(_OE_THIS, _OE_FROM, State, PrioFilter) -> + {reply, ok, ?set_PrioFilter(State, PrioFilter)}. + +%%----------------------------------------------------------% +%% Attribute: '_get_lifetime_filter' +%% Type : read and write +%% Returns : +%%----------------------------------------------------------- +'_get_lifetime_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_LifeFilter(State), State}. +'_set_lifetime_filter'(_OE_THIS, _OE_FROM, State, LifeFilter) -> + {reply, ok, ?set_LifeFilter(State, LifeFilter)}. + +%%----------------------------------------------------------% +%% Attribute: '_get_pull_suppliers' +%% Type : readonly +%% Returns : ProxyIDSeq +%%----------------------------------------------------------- +'_get_pull_suppliers'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PullSupplierIDs(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_push_suppliers' +%% Type : readonly +%% Returns : ProxyIDSeq +%%----------------------------------------------------------- +'_get_push_suppliers'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PushSupplierIDs(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : get_proxy_supplier +%% Arguments: ProxyID - unique identifier (long) +%% Returns : ObjRef | {'EXCEPTION', #'ProxyNotFound'{}} +%%----------------------------------------------------------- +get_proxy_supplier(_OE_THIS, _OE_FROM, State, Proxy_id) -> + {reply, ?get_Supplier(State, Proxy_id), State}. + +%%----------------------------------------------------------% +%% function : obtain_notification_pull_supplier +%% Arguments: Ctype - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : A Proxy of the requested type. +%%----------------------------------------------------------- +obtain_notification_pull_supplier(OE_THIS, _OE_FROM, State, Ctype) -> + %% Choose which module to use. + {Mod, Type} = + case Ctype of + 'ANY_EVENT' -> + {'CosNotifyChannelAdmin_ProxyPullSupplier', 'PULL_ANY'}; + 'STRUCTURED_EVENT' -> + {'CosNotifyChannelAdmin_StructuredProxyPullSupplier', 'PULL_STRUCTURED'}; + 'SEQUENCE_EVENT' -> + {'CosNotifyChannelAdmin_SequenceProxyPullSupplier', 'PULL_SEQUENCE'}; + _ -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:" + "obtain_notification_pull_supplier(~p);~n" + "Incorrect enumerant", + [?LINE, Ctype], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end, + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, PrRef} -> + ProxyID = ?new_Id(State), + NewState = ?add_PullSupplier(State, ProxyID, PrRef, Pid), + {reply, {PrRef, ProxyID}, ?set_IdCounter(NewState, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:" + "obtain_notification_pull_supplier();~n" + "Unable to create: ~p/~p~n" + "Reason: ~p", [?LINE, Mod, Type, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : obtain_notification_push_supplier +%% Arguments: Ctype - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : A Proxy of the requested type. +%%----------------------------------------------------------- +obtain_notification_push_supplier(OE_THIS, _OE_FROM, State, Ctype) -> + %% Choose which module to use. + {Mod, Type} = + case Ctype of + 'ANY_EVENT' -> + {'CosNotifyChannelAdmin_ProxyPushSupplier', 'PUSH_ANY'}; + 'STRUCTURED_EVENT' -> + {'CosNotifyChannelAdmin_StructuredProxyPushSupplier', 'PUSH_STRUCTURED'}; + 'SEQUENCE_EVENT' -> + {'CosNotifyChannelAdmin_SequenceProxyPushSupplier', 'PUSH_SEQUENCE'}; + _ -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:" + "obtain_notification_push_supplier(~p);~n" + "Incorrect enumerant", [?LINE, Ctype], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end, + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, PrRef} -> + ProxyID = ?new_Id(State), + NewState = ?add_PushSupplier(State, ProxyID, PrRef, Pid), + {reply, {PrRef, ProxyID}, ?set_IdCounter(NewState, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:obtain_notification_push_supplier();~n" + "Unable to create: ~p/~p~n" + "Reason: ~p", + [?LINE, Mod, Type, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + + +%%----------------------------------------------------------% +%% function : destroy +%% Arguments: - +%% Returns : ok +%%------------------------------------------------------------ +destroy(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + admin, ?get_MyChannel(State), + ?get_AllSupplierRefs(State)), + {reply, ok, ?set_BothQoS(State, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + admin, ?get_MyChannel(State), + ?get_AllSupplierRefs(State)), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifySubscribe --------- +%%----------------------------------------------------------* +%% function : subscription_change +%% Arguments: +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{type}} +%%----------------------------------------------------------- +subscription_change(_OE_THIS, _OE_FROM, State, _Added, _Removed) -> + ?DBG("CALLBACK INFORMED: ~p ~p~n",[_Added, _Removed]), + {reply, ok, State}. + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,_) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,_) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventChannelAdmin::ConsumerAdmin ---- +%%----------------------------------------------------------% +%% function : obtain_push_supplier +%% Arguments: - +%% Returns : ProxyPushSupplier +%%----------------------------------------------------------- +obtain_push_supplier(OE_THIS, _OE_FROM, State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case 'CosNotifyChannelAdmin_ProxyPushSupplier':oe_create_link(['PUSH_ANY', OE_THIS, + self(), + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_MyChannel(State), + ?get_Options(State), + ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, PrRef} -> + ProxyID = ?new_Id(State), + NewState = ?add_PushSupplier(State, ProxyID, PrRef, Pid), + {reply, PrRef, ?set_IdCounter(NewState, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:obtain_push_supplier();~n" + "Unable to create: CosNotifyChannelAdmin_ProxyPushSupplier~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : obtain_pull_supplier +%% Arguments: - +%% Returns : ProxyPullSupplier +%%----------------------------------------------------------- +obtain_pull_supplier(OE_THIS, _OE_FROM, State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case 'CosNotifyChannelAdmin_ProxyPullSupplier':oe_create_link(['PULL_ANY', OE_THIS, + self(), + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_MyChannel(State), + ?get_Options(State), + ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, PrRef} -> + ProxyID = ?new_Id(State), + NewState = ?add_PullSupplier(State, ProxyID, PrRef, Pid), + {reply, PrRef, ?set_IdCounter(NewState, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:obtain_pull_supplier();~n" + "Unable to create: CosNotifyChannelAdmin_ProxyPullSupplier~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +%% To match suppliers +find_obj({value, {_,Obj,_,_}},_) -> Obj; +%% To match filters +find_obj({value, {_,Obj}},_) -> Obj; +find_obj(_, supplier) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}; +find_obj(_, filter) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> + find_ids(List, [], false). +find_ids(List, Type) -> + find_ids(List, [], Type). + +find_ids([], Acc, _) -> + Acc; +find_ids([{I,_}|T], Acc, Type) -> + find_ids(T, [I|Acc], Type); +find_ids([{I,_,_,Type}|T], Acc, Type) -> + find_ids(T, [I|Acc], Type); +find_ids([{_I,_,_,_}|T], Acc, Type) -> + find_ids(T, Acc, Type); +find_ids(What, _, _) -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +find_refs(List) -> + find_refs(List, []). + +find_refs([], Acc) -> + Acc; +find_refs([{_,R,_,_}|T], Acc) -> + find_refs(T, [R|Acc]); +find_refs(What, _) -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:find_refs();~n" + "Reference corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single filter. +%% The list do not differ, i.e., no filter removed, raise exception. +delete_filter(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_filter(List, _) -> List. + + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, Events, _Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:filter_events(Events, ?get_AllFilter(State)) of + {[], _} when ?is_ANDOP(State) -> + %% Since AND it doesn't matter what the proxies 'think'. Done. + {noreply, State}; + {[], Failed} -> + %% Is OR but the Proxy may allow the events; pass on. + forward(seq, State, Failed, 'MATCH'); + {Passed, _} when ?is_ANDOP(State) -> + %% Since AND we only forward those who passed this objects filters. + forward(seq, State, Passed, 'MATCH'); + {Passed, []} -> + %% Since OR we forward and tell the proxy to do no filtering. + forward(seq, State, Passed, 'MATCHED'); + {Passed, Failed} -> + %% Since OR we forward both and instruct the proxy to check only + %% the ones that failed. + forward(seq, State, Passed, 'MATCHED'), + forward(seq, State, Failed, 'MATCH') + end. + + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, Event, _Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State)) of + {[], _} when ?is_ANDOP(State) -> + %% Since AND it doesn't matter what the proxies 'think'. Done. + {noreply, State}; + {[], [Failed]} -> + %% Is OR but the Proxy may allow the event; pass on. + forward(any, State, Failed, 'MATCH'); + {[Passed], _} when ?is_ANDOP(State) -> + %% Since AND we only forward those who passed this objects filters. + forward(any, State, Passed, 'MATCH'); + {[Passed], _} -> + %% Since OR we forward and instruct the proxy to do no checks. + forward(any, State, Passed, 'MATCHED') + end. + + + +%% Forward events +forward(Type, State, Event, Status) -> + forward(Type, ?get_AllSuppliers(State), State, Event, Status). +forward(_, [], State, _, _) -> + {noreply, State}; +forward(any, [{_,H,_,_}|T], State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callAny(H, Event, Status) of + ok -> + ?DBG("CONSUMERADM FORWARD ANY: ~p~n",[Event]), + forward(any, T, State, Event, Status); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy no longer exists; dropping it: ~p", + [?LINE, H], ?DEBUG_LEVEL), + NewState = ?del_SupplierRef(State,H), + forward(any, T, NewState, Event, Status); + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy behaves badly: ~p/~p", + [?LINE, R, H], ?DEBUG_LEVEL), + forward(any, T, State, Event, Status); + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy behaves badly: ~p~n" + "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL), + NewState = ?del_SupplierRef(State, H), + forward(any, T, NewState, Event, Status) + end; +forward(seq, [{_,H,_,_}|T], State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callSeq(H, Event, Status) of + ok -> + ?DBG("CONSUMERADM FORWARD SEQUENCE: ~p~n",[Event]), + forward(seq, T, State, Event, Status); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy no longer exists; dropping it: ~p", + [?LINE, H], ?DEBUG_LEVEL), + NewState = ?del_SupplierRef(State,H), + forward(seq, T, NewState, Event, Status); + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy behaves badly: ~p/~p", [?LINE, R, H], ?DEBUG_LEVEL), + forward(seq, T, State, Event, Status); + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_ConsumerAdmin:forward();~n" + "Proxy behaves badly: ~p~n" + "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL), + NewState = ?del_SupplierRef(State, H), + forward(seq, T, NewState, Event, Status) + end. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl new file mode 100644 index 0000000..872a786 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannelFactory_impl.erl @@ -0,0 +1,142 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%------------------------------------------------------------------- +%% File : CosNotifyChannelAdmin_EventChannelFactory_impl.erl +%% Purpose : +%%------------------------------------------------------------------- + +-module('CosNotifyChannelAdmin_EventChannelFactory_impl'). + +%%--------------- INCLUDES ----------------------------------- +%% Application files +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- IMPORTS ------------------------------------ + +%%--------------- EXPORTS ------------------------------------ +%% External +-export([create_channel/5, + get_all_channels/3, + get_event_channel/4]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {adminProp, + idCounter = 0, + options, + etsR, + server_options}). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: See gen_server documentation. +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?debug_print("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, normal} -> + ets:match_delete(State#state.etsR, {'_','_',Pid}), + {noreply, State}; + _Other -> + ?debug_print("TERMINATED: ~p~n",[_Other]), + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init(Options) -> + process_flag(trap_exit, true), + SO = 'CosNotification_Common':get_option(server_options, Options, ?not_DEFAULT_SETTINGS), + {ok, #state{options = Options, + etsR = ets:new(oe_ets, [set, protected]), + server_options = SO}}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : create_channel +%% Arguments: InitQoS +%% InitAdmin +%% Returns : Ch - Channel obj ref +%% Id - Channel Id (out-type) +%%----------------------------------------------------------- +create_channel(OE_THIS, _OE_FROM, State, InitQoS, InitAdmin) -> + {QoS, LQoS} = 'CosNotification_Common':init_qos(InitQoS), + {IAdm, LAdm} = 'CosNotification_Common':init_adm(InitAdmin), + Id = 'CosNotification_Common':create_id(State#state.idCounter), + case 'CosNotifyChannelAdmin_EventChannel':oe_create_link([OE_THIS, QoS, IAdm, + LQoS, LAdm, + State#state.options], + [{sup_child, true}|State#state.server_options]) of + {ok, Pid, Ch} -> + ets:insert(State#state.etsR, {Id,Ch,Pid}), + {reply, {Ch, Id}, State#state{idCounter=Id}}; + _ -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : get_all_channels +%% Arguments: - +%% Returns : ChannelIDSeq - List of alive channels created +%% by this factory. +%%----------------------------------------------------------- +get_all_channels(_OE_THIS, _OE_FROM, State) -> + {reply, lists:flatten(ets:match(State#state.etsR, {'$1','_','_'})), State}. + +%%----------------------------------------------------------% +%% function : get_event_channel +%% Arguments: ChannelId +%% Returns : ChannelRef | 'CosNotifyChannelAdmin_ChannelNotFound' +%%----------------------------------------------------------- +get_event_channel(_OE_THIS, _OE_FROM, State, Id) -> + {reply, find_obj(ets:lookup(State#state.etsR, Id)), State}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj([]) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}; +find_obj([{_, Obj,_}]) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}}. + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl new file mode 100644 index 0000000..f37a97c --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin_EventChannel_impl.erl @@ -0,0 +1,721 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%------------------------------------------------------------------- +%% File : CosNotifyChannelAdmin_EventChannel_impl.erl +%% Purpose : +%% Created : 28 Sep 1999 +%%------------------------------------------------------------------- + +-module('CosNotifyChannelAdmin_EventChannel_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::EventChannel ------------------ +-export([new_for_consumers/4, + new_for_suppliers/4, + get_consumeradmin/4, + get_supplieradmin/4, + get_all_consumeradmins/3, + get_all_supplieradmins/3]). + +%% Attributes (external) +-export(['_get_MyFactory'/3, + '_get_default_consumer_admin'/3, + '_get_default_supplier_admin'/3, + '_get_default_filter_factory'/3]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotification::AdminPropertiesAdmin --- +-export([get_admin/3, + set_admin/4]). + +%%----- Inherit from CosEventChannelAdmin::EventChannel ------ +-export([for_consumers/3, + for_suppliers/3, + destroy/3]). +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm --------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%% Data structures +-record(state, {myFac, + myConsumers = [], + defConsumerAdmin, + defSupplierAdmin, + defConsumerAdminPid, + defSupplierAdminPid, + defFilterFac, + defFilterFacPid, + etsR, + qosLocal, + qosGlobal, + admGlobal, + options, + idCounter = 0, + 'MaxQueueLength', + 'MaxConsumers', + 'MaxSuppliers'}). +%% Data structures constructors +-define(get_InitState(My, Fil, FilPid, QoS, LQoS, GA, MQ, MC, MS, O), + #state{myFac = My, + defFilterFac = Fil, + defFilterFacPid = FilPid, + etsR = ets:new(oe_ets, [set, protected]), + qosLocal = LQoS, + qosGlobal = QoS, + admGlobal = GA, + options = O, + 'MaxQueueLength' = MQ, + 'MaxConsumers' = MC, + 'MaxSuppliers' = MS}). + +%% NOTE!!! +%% When forwarding events, the objects we will contact is ONLY ConsumerAdmins!! +%% Hence, we will store SupplierAdmins and ConsumerAdmins differently. SupplierAdmins +%% we store in our ets-table while the ConsumerAdmins will be stored on the local +%% State. + +%% Data structures selectors +-define(get_supplierAdmins(S), [S#state.defSupplierAdmin| + lists:flatten(ets:match(S#state.etsR, + {'_','$1','_'}))]). +-define(get_consumerAdmins(S), [{0, S#state.defConsumerAdmin,S#state.defConsumerAdminPid} + |S#state.myConsumers]). +-define(get_allAdmins(S), [S#state.defSupplierAdmin, + S#state.defConsumerAdmin| + lists:flatten(ets:match(S#state.etsR, + {'_','$1','_'}))++ + find_field(S#state.myConsumers, 2)]). +-define(get_consumerAdmIDs(S), [0|find_field(S#state.myConsumers, 1)]). +-define(get_supplierAdmIDs(S), [0|lists:flatten(ets:match(S#state.etsR, + {'$1','_','_'}))]). + +-define(get_supplierAdmin(S, I), find_obj(ets:lookup(S#state.etsR, I))). +-define(get_consumerAdmin(S, I), find_obj(lists:keysearch(I,1,S#state.myConsumers))). +-define(get_supplierAmount(S), ets:info(S#state.etsR, size)). +-define(get_consumerAmount(S), length(S#state.myConsumers)). + +-define(get_MyFactory(S), S#state.myFac). +-define(get_defConsumerAdm(S), S#state.defConsumerAdmin). +-define(get_defSupplierAdm(S), S#state.defSupplierAdmin). +-define(get_defConsumerAdmPid(S), S#state.defConsumerAdminPid). +-define(get_defSupplierAdmPid(S), S#state.defSupplierAdminPid). +-define(get_defFilterFac(S), S#state.defFilterFac). +-define(get_defFilterFacPid(S), S#state.defFilterFacPid). +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +-define(get_GlobalAdm(S), S#state.admGlobal). +-define(get_Options(S), S#state.options). +-define(get_MaxQueueLength(S), S#state.'MaxQueueLength'). +-define(get_MaxConsumers(S), S#state.'MaxConsumers'). +-define(get_MaxSuppliers(S), S#state.'MaxSuppliers'). +-define(get_IdCounter(S), S#state.idCounter). + +%% Data structures modifiers +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +-define(set_GlobalAdm(S,D), S#state{admGlobal=D}). +-define(set_AllAdminP(S,GD, MQ, MC, MS), + S#state{admGlobal=GD,'MaxQueueLength'=MQ, + 'MaxConsumers'=MC, 'MaxSuppliers'=MS}). +-define(set_MaxQueueLength(S,D), S#state{'MaxQueueLength'=D}). +-define(set_MaxConsumers(S,D), S#state{'MaxConsumers'=D}). +-define(set_MaxSuppliers(S,D), S#state{'MaxSuppliers'=D}). +-define(set_defConsumerAdm(S,D,P), S#state{defConsumerAdmin=D, defConsumerAdminPid=P}). +-define(set_defSupplierAdm(S,D,P), S#state{defSupplierAdmin=D, defSupplierAdminPid=P}). +-define(set_defFilterFac(S,D,P), S#state{defFilterFac=D, defFilterFacPid=P}). +-define(add_supplierAdmin(S,I,O,P), ets:insert(S#state.etsR, {I,O,P})). +-define(add_consumerAdmin(S,I,O,P), S#state{myConsumers= [{I,O,P}|S#state.myConsumers]}). +-define(del_supplierAdmin(S,I), ets:delete(S#state.etsR, I)). +-define(del_consumerAdmin(S,I), S#state{myConsumers= + lists:keydelete(I, 1, + S#state.myConsumers)}). +-define(del_consumerAdminRef(S,O), S#state{myConsumers= + lists:keydelete(O, 2, + S#state.myConsumers)}). +-define(del_AdminPid(S,P), delete_obj(S, P)). +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). +%% MISC +-define(is_UndefDefConsAdm(S), S#state.defConsumerAdmin == undefined). +-define(is_UndefDefSuppAdm(S), S#state.defSupplierAdmin == undefined). +-define(is_UndefDefFilterFac(S), S#state.defFilterFac == undefined). +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, _Reason} when ?get_defConsumerAdmPid(State) == Pid -> + {noreply, ?set_defConsumerAdm(State, undefined, undefined)}; + {'EXIT', Pid, _Reason} when ?get_defSupplierAdmPid(State) == Pid -> + {noreply, ?set_defSupplierAdm(State, undefined, undefined)}; + {'EXIT', Pid, _Reason} when ?get_defFilterFacPid(State) == Pid -> + {noreply, ?set_defFilterFac(State, undefined, undefined)}; + {'EXIT', Pid, normal} -> + {noreply, ?del_AdminPid(State, Pid)}; + _Other -> + ?DBG("TERMINATED: ~p~n",[_Other]), + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyFac, InitQoS, InitAdmin, LocalQoS, [MaxQ, MaxC, MaxS|_], Options]) -> + process_flag(trap_exit, true), + SO = 'CosNotification_Common':get_option(server_options, Options, + ?not_DEFAULT_SETTINGS), + + ?DBG("CHANNEL INIT STATE:~n~p~n~p~n~p ~p ~p ~p~n~p~n", + [InitQoS, InitAdmin, LocalQoS,MaxQ, MaxC, MaxS, Options]), + + %% Both default Admin:s have the unique id 0 (OMG spec, 98-11-01, + %% Notification p 148), hence, no need to create a unique id. + %% We don't have acces to OE_THIS in this stage so we cannot create the objects + %% now, even though the specification states that. + %% DefConAdm = 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([0],[]), + %% DefSupAdm = 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([0],[]), + + case 'CosNotifyFilter_FilterFactory':oe_create_link([], [{sup_child, true}|SO]) of + {ok, Pid, DefFiFac} -> + {ok, ?get_InitState(MyFac, DefFiFac, Pid, InitQoS, LocalQoS, + InitAdmin, MaxQ, MaxC, MaxS, Options)}; + Reason -> + {stop, Reason} + end. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_EventChannel attributes ------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyFactory' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyFactory'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyFactory(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_default_consumer_admin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_default_consumer_admin'(OE_THIS, _OE_FROM, State) + when ?is_UndefDefConsAdm(State) -> + Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([0, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, DefConAdm} -> + {reply, DefConAdm, ?set_defConsumerAdm(State, DefConAdm, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:_get_default_consumer_admin();~n" + "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +'_get_default_consumer_admin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_defConsumerAdm(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_default_supplier_admin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_default_supplier_admin'(OE_THIS, _OE_FROM, State) + when ?is_UndefDefSuppAdm(State) -> + Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([0, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, DefSupAdm} -> + {reply, DefSupAdm, ?set_defSupplierAdm(State, DefSupAdm, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:_get_default_supplier_admin();~n" + "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +'_get_default_supplier_admin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_defSupplierAdm(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_default_filter_factory' +%% Type : readonly +%% Returns : +%%---------------------------------------------------------- +'_get_default_filter_factory'(_OE_THIS, _OE_FROM, State) + when ?is_UndefDefFilterFac(State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyFilter_FilterFactory':oe_create_link([], [{sup_child, true}|SO]) of + {ok, Pid, DefFiFac} -> + {reply, DefFiFac, ?set_defFilterFac(State, DefFiFac, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:_get_default_filter_factory();~n" + "Unable to create: CosNotifyChannelAdmin_FilterFactory.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +'_get_default_filter_factory'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_defFilterFac(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : new_for_consumers +%% Arguments: Op - InterFilterGroupOperator: 'AND_OP' | 'OR_OP' +%% Determines if the Admin:s proxy-children will +%% use AND or OR when checking Filters. +%% Returns : ConsAdm +%% AdminId (out) +%%----------------------------------------------------------- +new_for_consumers(OE_THIS, _OE_FROM, State, Op) -> + is_admin_limit_reached(?get_MaxConsumers(State), ?get_consumerAmount(State)), + AdminId = ?new_Id(State), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([AdminId, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, AdminCo} -> + %% Due to different storage, adding a new consumer is NOT done in the + %% same way as for suppliers. + NewState = ?add_consumerAdmin(State, AdminId, AdminCo, Pid), + {reply, {AdminCo, AdminId}, ?set_IdCounter(NewState, AdminId)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:nef_for_consumers();~n" + "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : new_for_suppliers +%% Arguments: Op - InterFilterGroupOperator: 'AND_OP' | 'OR_OP' +%% Determines if the Admin:s proxy-children will +%% use AND or OR when checking Filters. +%% Returns : SuppAdm +%% AdminId (out) +%%----------------------------------------------------------- +new_for_suppliers(OE_THIS, _OE_FROM, State, Op) -> + is_admin_limit_reached(?get_MaxSuppliers(State), ?get_supplierAmount(State)), + AdminId = ?new_Id(State), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([AdminId, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, AdminSu} -> + %% Due to different storage, adding a new supplier is NOT done in the + %% same way as for consumers. + ?add_supplierAdmin(State, AdminId, AdminSu, Pid), + {reply, {AdminSu, AdminId}, ?set_IdCounter(State, AdminId)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:new_for_suppliers();~n" + "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : get_consumeradmin +%% Arguments: AdminId +%% Returns : ConsAdmin +%%----------------------------------------------------------- +get_consumeradmin(OE_THIS, _OE_FROM, State, 0) when ?is_UndefDefConsAdm(State) -> + Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([0, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, DefConAdm} -> + {reply, DefConAdm, ?set_defConsumerAdm(State, DefConAdm, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_consumer_admin();~n" + "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +get_consumeradmin(_OE_THIS, _OE_FROM, State, 0) -> + {reply, ?get_defConsumerAdm(State), State}; +get_consumeradmin(_OE_THIS, _OE_FROM, State, AdminId) when is_integer(AdminId) -> + {reply, ?get_consumerAdmin(State, AdminId), State}; +get_consumeradmin(_, _, _, What) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_consumeradmin(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_supplieradmin +%% Arguments: AdminId +%% Returns : +%%----------------------------------------------------------- +get_supplieradmin(OE_THIS, _OE_FROM, State, 0) when ?is_UndefDefSuppAdm(State) -> + Op = 'CosNotification_Common':get_option(filterOp, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([0, OE_THIS, + self(), Op, + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, DefSupAdm} -> + {reply, DefSupAdm, ?set_defSupplierAdm(State, DefSupAdm, Pid)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_supplieradmin();~n" + "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +get_supplieradmin(_OE_THIS, _OE_FROM, State, 0) -> + {reply, ?get_defSupplierAdm(State), State}; +get_supplieradmin(_OE_THIS, _OE_FROM, State, AdminId) when is_integer(AdminId) -> + {reply, ?get_supplierAdmin(State, AdminId), State}; +get_supplieradmin(_, _, _, What) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:get_supplieradmin(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_consumeradmins +%% Arguments: - +%% Returns : AdminIDSeq - a list of all unique ID:s. +%%----------------------------------------------------------- +get_all_consumeradmins(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_consumerAdmIDs(State), State}. + +%%----------------------------------------------------------% +%% function : get_all_supplieradmins +%% Arguments: - +%% Returns : AdminIDSeq - a list of all unique ID:s. +%%----------------------------------------------------------- +get_all_supplieradmins(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_supplierAdmIDs(State), State}. + + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: - +%% Returns : CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {GQoS,LQoS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + channel, false, + ?get_allAdmins(State)), + {reply, ok, ?set_BothQoS(State, GQoS,LQoS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} | +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + channel, false, + ?get_allAdmins(State)), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotification::AdminPropertiesAdmin -- +%%-----------------------------------------------------------% +%% function : get_admin +%% Arguments: - +%% Returns : AdminProperties +%%----------------------------------------------------------- +get_admin(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalAdm(State), State}. + +%%----------------------------------------------------------% +%% function : set_admin +%% Arguments: Admin +%% Returns : +%%----------------------------------------------------------- +set_admin(_OE_THIS, _OE_FROM, State, Admin) -> + {GAdm,[MaxQ, MaxC, MaxS|_]} = + 'CosNotification_Common':set_adm(Admin, ?get_GlobalAdm(State)), + {reply, ok, ?set_AllAdminP(State, GAdm, MaxQ, MaxC, MaxS)}. + +%%----- Inherit from CosEventChannelAdmin::EventChannel ----- +%%----------------------------------------------------------% +%% function : for_consumers +%% Arguments: - +%% Returns : ConsAdm +%%----------------------------------------------------------- +for_consumers(OE_THIS, _OE_FROM, State) -> + is_admin_limit_reached(?get_MaxConsumers(State), ?get_consumerAmount(State)), + AdminId = ?new_Id(State), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ConsumerAdmin':oe_create_link([AdminId, OE_THIS, + self(), 'AND_OP', + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, AdminCo} -> + %% Due to different storage, adding a new consumer is NOT done in the + %% same way as for suppliers. + NewState = ?add_consumerAdmin(State, AdminId, AdminCo, Pid), + {reply, AdminCo, ?set_IdCounter(NewState, AdminId)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:for_consumers();~n" + "Unable to create: CosNotifyChannelAdmin_ConsumerAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : for_suppliers +%% Arguments: - +%% Returns : SuppAdm +%%----------------------------------------------------------- +for_suppliers(OE_THIS, _OE_FROM, State) -> + is_admin_limit_reached(?get_MaxSuppliers(State), ?get_supplierAmount(State)), + AdminId = ?new_Id(State), + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_SupplierAdmin':oe_create_link([AdminId, OE_THIS, + self(), 'AND_OP', + ?get_GlobalQoS(State), + ?get_LocalQoS(State), + ?get_Options(State)], + [{sup_child, true}|SO]) of + {ok, Pid, AdminSu} -> + %% Due to different storage, adding a new supplier is NOT done in the + %% same way as for consumers. + ?add_supplierAdmin(State, AdminId, AdminSu, Pid), + {reply, AdminSu, ?set_IdCounter(State, AdminId)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:for_suppliers();~n" + "Unable to create: CosNotifyChannelAdmin_SupplierAdmin.~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%-----------------------------------------------------------% +%% function : destroy +%% Arguments: - +%% Returns : ok +%%------------------------------------------------------------ +destroy(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, State}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj([]) -> {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}}; +find_obj([{_, Obj,_}]) -> Obj; +find_obj({value, {_, Obj,_}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyChannelAdmin_AdminNotFound'{}}. + + +find_field(List, Field) -> + find_field(List, Field, []). + +find_field([], _, Acc) -> + Acc; +find_field([{I,_,_}|T], 1, Acc) -> + find_field(T, 1, [I|Acc]); +find_field([{_,O,_}|T], 2, Acc) -> + find_field(T, 2, [O|Acc]); +% Left out for now to avoid dialyzer warning. +%find_field([{_,_,P}|T], 3, Acc) -> +% find_field(T, 3, [P|Acc]); +find_field(What, _, _) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:find_field();~n" + "Data corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +delete_obj(State, Pid) -> + case ets:match_object(State#state.etsR, {'_', '_', Pid}) of + [] -> + State#state{myConsumers=lists:keydelete(Pid, 3, State#state.myConsumers)}; + [{Id,_Obj,Pid}] -> + ets:delete(State#state.etsR, Id), + State + end. + +%% Test if we have reached limit for Admin objects. +is_admin_limit_reached(0, _) -> + %% When set to zero it means that there is no limit. + ok; +is_admin_limit_reached(Max, Current) when Current >= Max -> + %% The Current value do not include the default Admin objects, hence + %% we use >= instead of >. + corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO}); +is_admin_limit_reached(_, _) -> + ok. + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, Event, Status) -> + corba:reply(OE_FROM, ok), + forward(seq, State, Event, Status). + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, Event, Status) -> + corba:reply(OE_FROM, ok), + forward(any, State, Event, Status). + +%% Forward events +forward(Type, State, Event, Status) -> + forward(Type, ?get_consumerAdmins(State), State, Event, Status). + +forward(_, [], State, _, _) -> + {noreply, State}; +forward(Type, [{_,undefined,_}|T], State, Event, Status) -> + %% Match if no default objects associated. + forward(Type, T, State, Event, Status); +forward(any, [{_,H,_}|T], State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callAny(H, Event, Status) of + ok -> + ?DBG("CHANNEL FORWARD ANY: ~p~n",[Event]), + forward(any, T, State, Event, Status); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin no longer exists; dropping it: ~p", + [?LINE, H], ?DEBUG_LEVEL), + NewState = ?del_consumerAdminRef(State,H), + forward(any, T, NewState, Event, Status); + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin behaves badly: ~p/~p", + [?LINE, R, H], ?DEBUG_LEVEL), + forward(any, T, State, Event, Status); + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin behaves badly: ~p~n" + "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL), + NewState = ?del_consumerAdminRef(State, H), + forward(any, T, NewState, Event, Status) + end; +forward(seq, [{_,H,_}|T], State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callSeq(H, Event, Status) of + ok -> + ?DBG("CHANNEL FORWARD SEQUENCE: ~p~n",[Event]), + forward(seq, T, State, Event, Status); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin no longer exists; dropping it: ~p", + [?LINE, H], ?DEBUG_LEVEL), + NewState = ?del_consumerAdminRef(State,H), + forward(seq, T, NewState, Event, Status); + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin behaves badly: ~p/~p", + [?LINE, R, H], ?DEBUG_LEVEL), + forward(seq, T, State, Event, Status); + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_EventChannel:forward();~n" + "Admin behaves badly: ~p~n" + "Dropping it: ~p", [?LINE, R, H], ?DEBUG_LEVEL), + NewState = ?del_consumerAdminRef(State,H), + forward(seq, T, NewState, Event, Status) + end. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl b/lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl new file mode 100644 index 0000000..1c3f3d8 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyChannelAdmin_SupplierAdmin_impl.erl @@ -0,0 +1,579 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%------------------------------------------------------------------- +%% File : CosNotifyChannelAdmin_SupplierAdmin_impl.erl +%% Purpose : +%%------------------------------------------------------------------- + +-module('CosNotifyChannelAdmin_SupplierAdmin_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::SupplierAdmin ----------------- +-export([get_proxy_consumer/4, + obtain_notification_pull_consumer/4, + obtain_notification_push_consumer/4, + destroy/3]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifyPublish ------------ +-export([offer_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventChannelAdmin::SupplierAdmin ----- +-export([obtain_push_consumer/3, + obtain_pull_consumer/3]). + +%% Attributes (external) +-export(['_get_MyID'/3, + '_get_MyChannel'/3, + '_get_MyOperator'/3, + '_get_pull_consumers'/3, + '_get_push_consumers'/3]). + +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm --------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myId, + myChannel, + myChannelPid, + myOperator, + myFilters = [], + idCounter = 0, + etsR, + qosGlobal, + qosLocal, + options}). + +%% Data structures constructors +-define(get_InitState(_MyID, _MyCh, _MyChP, _MyOp, _QoS, _LQS, _O), + #state{myId = _MyID, + myChannel = _MyCh, + myChannelPid = _MyChP, + myOperator = _MyOp, + qosGlobal = _QoS, + qosLocal = _LQS, + options = _O, + etsR = ets:new(oe_ets, [set, protected])}). + +%% Data structures selectors +-define(get_PushConsumers(S), lists:flatten(ets:match(S#state.etsR, + {'_','$1','_',pusher}))). +-define(get_PullConsumers(S), lists:flatten(ets:match(S#state.etsR, + {'_','$1','_',puller}))). +-define(get_AllConsumers(S), lists:flatten(ets:match(S#state.etsR, + {'_','$1','_','_'}))). +-define(get_PushConsumerIDs(S), lists:flatten(ets:match(S#state.etsR, + {'$1','_','_',pusher}))). +-define(get_PullConsumerIDs(S), lists:flatten(ets:match(S#state.etsR, + {'$1','_','_',puller}))). + +-define(get_Consumer(S, I), find_obj(ets:lookup(S#state.etsR, I), consumer)). + +-define(get_MyID(S), S#state.myId). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyChannelPid(S), S#state.myChannelPid). +-define(get_MyOperator(S), S#state.myOperator). +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters), + filter)). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +-define(get_Options(S), S#state.options). +-define(get_IdCounter(S), S#state.idCounter). + +%% Data structures modifiers +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +-define(add_PushConsumer(S,I,R,P),ets:insert(State#state.etsR, {I,R,P,pusher})). +-define(add_PullConsumer(S,I,R,P),ets:insert(State#state.etsR, {I,R,P,puller})). +-define(del_Consumer(S,I), ets:delete(S#state.etsR, I)). +-define(del_ConsumerPid(S,P), ets:match_delete(S#state.etsR, {'_','_',P,'_'})). +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_filter(lists:keydelete(I, 1, + S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). + +%% MISC +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + case Info of + {'EXIT', Pid, Reason} when ?get_MyChannelPid(State) == Pid -> + ?DBG("PARENT CHANNEL: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', Pid, normal} -> + ?del_ConsumerPid(State, Pid), + {noreply, State}; + _Other -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyId, MyChannel, MyChannelPid, MyOperator, InitQoS, LQS, Options]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(MyId, MyChannel, MyChannelPid, MyOperator, InitQoS, LQS, Options)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ConsumerAdmin attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyID' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyID'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyID(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyChannel' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyChannel'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyChannel(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyOperator' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyOperator'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyOperator(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_pull_consumers' +%% Type : readonly +%% Returns : ProxyIDSeq +%%----------------------------------------------------------- +'_get_pull_consumers'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PullConsumerIDs(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_push_consumers' +%% Type : readonly +%% Returns : ProxyIDSeq +%%----------------------------------------------------------- +'_get_push_consumers'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PushConsumerIDs(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : get_proxy_consumer +%% Arguments: ProxyId - unique identifier (long) +%% Returns : ObjRef | {'EXCEPTION', #'ProxyNotFound'{}} +%%----------------------------------------------------------- +get_proxy_consumer(_OE_THIS, _OE_FROM, State, ProxyId) -> + {reply, ?get_Consumer(State, ProxyId), State}. + +%%----------------------------------------------------------% +%% function : obtain_notification_pull_consumer +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +obtain_notification_pull_consumer(OE_THIS, _OE_FROM, State, Ctype) -> + %% Choose which module to use. + {Mod, Type} = + case Ctype of + 'ANY_EVENT' -> + {'CosNotifyChannelAdmin_ProxyPullConsumer', 'PULL_ANY'}; + 'STRUCTURED_EVENT' -> + {'CosNotifyChannelAdmin_StructuredProxyPullConsumer', 'PULL_STRUCTURED'}; + 'SEQUENCE_EVENT' -> + {'CosNotifyChannelAdmin_SequenceProxyPullConsumer', 'PULL_SEQUENCE'}; + _ -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:" + "obtain_notification_pull_consumer(~p);~n" + "Incorrect enumerant", + [?LINE, Ctype], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end, + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, Proxy} -> + ProxyID = ?new_Id(State), + ?add_PullConsumer(State, ProxyID, Proxy, Pid), + {reply, {Proxy, ProxyID}, ?set_IdCounter(State, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:" + "obtain_notification_pull_consumer();~n" + "Unable to create: ~p/~p~n" + "Reason: ~p", [?LINE, Mod, Type, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : obtain_notification_push_supplier +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +obtain_notification_push_consumer(OE_THIS, _OE_FROM, State, Ctype) -> + %% Choose which module to use. + {Mod, Type} = + case Ctype of + 'ANY_EVENT' -> + {'CosNotifyChannelAdmin_ProxyPushConsumer', 'PUSH_ANY'}; + 'STRUCTURED_EVENT' -> + {'CosNotifyChannelAdmin_StructuredProxyPushConsumer', 'PUSH_STRUCTURED'}; + 'SEQUENCE_EVENT' -> + {'CosNotifyChannelAdmin_SequenceProxyPushConsumer', 'PUSH_SEQUENCE'}; + _ -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:" + "obtain_notification_push_consumer(~p);~n" + "Incorrect enumerant", [?LINE, Ctype], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end, + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch Mod:oe_create_link([Type, OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, Proxy} -> + ProxyID = ?new_Id(State), + ?add_PushConsumer(State, ProxyID, Proxy, Pid), + {reply, {Proxy, ProxyID}, ?set_IdCounter(State, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:" + "obtain_notification_push_consumer();~n" + "Unable to create: ~p/~p~n" + "Reason: ~p", [?LINE, Mod, Type, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : destroy +%% Arguments: - +%% Returns : ok +%%------------------------------------------------------------ +destroy(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + admin, ?get_MyChannel(State), + ?get_AllConsumers(State)), + {reply, ok, ?set_BothQoS(State, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + admin, ?get_MyChannel(State), + ?get_AllConsumers(State)), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifyPublish ----------- +%%----------------------------------------------------------* +%% function : offer_change +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +offer_change(_OE_THIS, _OE_FROM, State, _Added, _Removed) -> + {reply, ok, State}. + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:remove_filter(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:get_filter(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventChannelAdmin::SupplierAdmin ---- +%%----------------------------------------------------------% +%% function : obtain_push_consumer +%% Arguments: - +%% Returns : ProxyPushConsumer +%%----------------------------------------------------------- +obtain_push_consumer(OE_THIS, _OE_FROM, State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ProxyPushConsumer': + oe_create_link(['PUSH_ANY', OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, Proxy} -> + ProxyID = ?new_Id(State), + ?add_PushConsumer(State, ProxyID, Proxy, Pid), + {reply, Proxy, ?set_IdCounter(State, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:obtain_push_consumer();~n" + "Unable to create: CosNotifyChannelAdmin_ProxyPushConsumer~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : obtain_pull_consumer +%% Arguments: - +%% Returns : ProxyPullConsumer +%%----------------------------------------------------------- +obtain_pull_consumer(OE_THIS, _OE_FROM, State) -> + SO = 'CosNotification_Common':get_option(server_options, ?get_Options(State), + ?not_DEFAULT_SETTINGS), + case catch 'CosNotifyChannelAdmin_ProxyPullConsumer': + oe_create_link(['PULL_ANY', OE_THIS, self(), ?get_GlobalQoS(State), + ?get_LocalQoS(State), ?get_MyChannel(State), + ?get_Options(State), ?get_MyOperator(State)], + [{sup_child, true}|SO]) of + {ok, Pid, Proxy} -> + ProxyID = ?new_Id(State), + ?add_PullConsumer(State, ProxyID, Proxy, Pid), + {reply, Proxy, ?set_IdCounter(State, ProxyID)}; + What -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:obtain_push_consumer();~n" + "Unable to create: CosNotifyChannelAdmin_ProxyPullConsumer~n" + "Reason: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj([], consumer) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}; +find_obj([], filter) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}; +%% To match consumers +find_obj([{_,Obj,_,_}],_) -> Obj; +%% To match filters +find_obj({value, {_,Obj}},_) -> Obj; +find_obj(_,consumer) -> {'EXCEPTION', #'CosNotifyChannelAdmin_ProxyNotFound'{}}; +find_obj(_,filter) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(What, _) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single filter. +%% The list do not differ, i.e., no filter removed, raise exception. +delete_filter(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_filter(List, _) -> List. + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, Events, _Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:filter_events(Events, ?get_AllFilter(State)) of + {[], _} -> + {noreply, State}; + {Passed, _} -> + forward(seq, State, Passed, 'MATCHED') + end. + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, Event, _Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State)) of + {[], _} -> + {noreply, State}; + {[Passed], _} -> + forward(any, State, Passed, 'MATCHED') + end. + +%% Forward events +forward(any, State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callAny(?get_MyChannel(State), + Event, Status) of + ok -> + ?DBG("SUPPLIERADM FORWARD ANY: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + {stop, normal, State} + end; +forward(seq, State, Event, Status) -> + case catch oe_CosNotificationComm_Event:callSeq(?get_MyChannel(State), + Event, Status) of + ok -> + ?DBG("SUPPLIERADM FORWARD SEQUENCE: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] CosNotifyChannelAdmin_SupplierAdmin:forward();~n" + "Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + {stop, normal, State} + end. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyComm.cfg b/lib/cosNotification/src/CosNotifyComm.cfg new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosNotification/src/CosNotifyComm.idl b/lib/cosNotification/src/CosNotifyComm.idl new file mode 100644 index 0000000..f0386f0 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyComm.idl @@ -0,0 +1,83 @@ +#ifndef _COS_NOTIFYCOMM_IDL_ +#define _COS_NOTIFYCOMM_IDL_ + +#pragma prefix "omg.org" + + +#include + +module CosNotifyComm { + exception InvalidEventType { CosNotification::EventType type; }; + + interface NotifyPublish { + void offer_change (in CosNotification::EventTypeSeq added, + in CosNotification::EventTypeSeq removed) + raises (InvalidEventType); + }; // NotifyPublish + + interface NotifySubscribe { + void subscription_change(in CosNotification::EventTypeSeq added, + in CosNotification::EventTypeSeq removed) + raises (InvalidEventType); + }; // NotifySubscribe + + interface PushConsumer : NotifyPublish, CosEventComm::PushConsumer { }; // PushConsumer + + interface PullConsumer : NotifyPublish, CosEventComm::PullConsumer { }; // PullConsumer + + interface PullSupplier : NotifySubscribe, CosEventComm::PullSupplier { }; // PullSupplier + + interface PushSupplier : NotifySubscribe, CosEventComm::PushSupplier { }; + + interface StructuredPushConsumer : NotifyPublish { + void push_structured_event(in CosNotification::StructuredEvent notification) + raises(CosEventComm::Disconnected); + + void disconnect_structured_push_consumer(); + }; // StructuredPushConsumer + + interface StructuredPullConsumer : NotifyPublish { + void disconnect_structured_pull_consumer(); + }; // StructuredPullConsumer + + interface StructuredPullSupplier : NotifySubscribe { + CosNotification::StructuredEvent pull_structured_event() + raises(CosEventComm::Disconnected); + + CosNotification::StructuredEvent try_pull_structured_event(out boolean has_event) + raises(CosEventComm::Disconnected); + + void disconnect_structured_pull_supplier(); + }; // StructuredPullSupplier + + interface StructuredPushSupplier : NotifySubscribe { + void disconnect_structured_push_supplier(); + }; // StructuredPushSupplier + + interface SequencePushConsumer : NotifyPublish { + void push_structured_events(in CosNotification::EventBatch notifications) + raises(CosEventComm::Disconnected); + + void disconnect_sequence_push_consumer(); + }; // SequencePushConsumer + + interface SequencePullConsumer : NotifyPublish { + void disconnect_sequence_pull_consumer(); + }; // SequencePullConsumer + + interface SequencePullSupplier : NotifySubscribe { + CosNotification::EventBatch pull_structured_events(in long max_number) + raises(CosEventComm::Disconnected); + CosNotification::EventBatch try_pull_structured_events(in long max_number, out boolean has_event) + raises(CosEventComm::Disconnected); + + void disconnect_sequence_pull_supplier(); + }; // SequencePullSupplier + + interface SequencePushSupplier : NotifySubscribe { + void disconnect_sequence_push_supplier(); + }; // SequencePushSupplier +}; // CosNotifyComm + +#endif /* ifndef _COS_NOTIFYCOMM_IDL_ */ + diff --git a/lib/cosNotification/src/CosNotifyFilter.cfg b/lib/cosNotification/src/CosNotifyFilter.cfg new file mode 100644 index 0000000..167550e --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter.cfg @@ -0,0 +1,6 @@ +{this, "CosNotifyFilter::Filter"}. +{{handle_info, "CosNotifyFilter::Filter"}, true}. +{this, "CosNotifyFilter::MappingFilter"}. +{{handle_info, "CosNotifyFilter::MappingFilter"}, true}. +{this, "CosNotifyFilter::FilterFactory"}. +{{handle_info, "CosNotifyFilter::FilterFactory"}, true}. diff --git a/lib/cosNotification/src/CosNotifyFilter.idl b/lib/cosNotification/src/CosNotifyFilter.idl new file mode 100644 index 0000000..c6498dd --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter.idl @@ -0,0 +1,140 @@ +#ifndef _COS_NOTIFYFILTER_IDL_ +#define _COS_NOTIFYFILTER_IDL_ + +#pragma prefix "omg.org" + +#include +#include + +module CosNotifyFilter { + typedef long ConstraintID; + struct ConstraintExp { + CosNotification::EventTypeSeq event_types; + string constraint_expr; + }; + + typedef sequence ConstraintIDSeq; + typedef sequence ConstraintExpSeq; + struct ConstraintInfo { + ConstraintExp constraint_expression; + ConstraintID constraint_id; + }; + typedef sequence ConstraintInfoSeq; + struct MappingConstraintPair { + ConstraintExp constraint_expression; + any result_to_set; + }; + typedef sequence MappingConstraintPairSeq; + struct MappingConstraintInfo { + ConstraintExp constraint_expression; + ConstraintID constraint_id; + any value; + }; + typedef sequence MappingConstraintInfoSeq; + typedef long CallbackID; + typedef sequence CallbackIDSeq; + exception UnsupportedFilterableData {}; + exception InvalidGrammar {}; + exception InvalidConstraint {ConstraintExp constr;}; + exception DuplicateConstraintID {ConstraintID id;}; + exception ConstraintNotFound {ConstraintID id;}; + exception CallbackNotFound {}; + exception InvalidValue {ConstraintExp constr; any value;}; + interface Filter { + readonly attribute string constraint_grammar; + ConstraintInfoSeq add_constraints (in ConstraintExpSeq constraint_list) + raises (InvalidConstraint); + + void modify_constraints (in ConstraintIDSeq del_list, + in ConstraintInfoSeq modify_list) + raises (InvalidConstraint, ConstraintNotFound); + + ConstraintInfoSeq get_constraints(in ConstraintIDSeq id_list) + raises (ConstraintNotFound); + + ConstraintInfoSeq get_all_constraints(); + + void remove_all_constraints(); + void destroy(); + boolean match (in any filterable_data) + raises (UnsupportedFilterableData); + + boolean match_structured (in CosNotification::StructuredEvent filterable_data) + raises (UnsupportedFilterableData); + + boolean match_typed (in CosNotification::PropertySeq filterable_data) + raises (UnsupportedFilterableData); + + CallbackID attach_callback (in CosNotifyComm::NotifySubscribe callback); + + void detach_callback (in CallbackID callback) + raises ( CallbackNotFound ); + + CallbackIDSeq get_callbacks(); + }; // Filter + + interface MappingFilter { + readonly attribute string constraint_grammar; + + readonly attribute CORBA::TypeCode value_type; + + readonly attribute any default_value; + + MappingConstraintInfoSeq add_mapping_constraints (in MappingConstraintPairSeq pair_list) + raises (InvalidConstraint, InvalidValue); + + void modify_mapping_constraints (in ConstraintIDSeq del_list, + in MappingConstraintInfoSeq modify_list) + raises (InvalidConstraint, InvalidValue, ConstraintNotFound); + + MappingConstraintInfoSeq get_mapping_constraints (in ConstraintIDSeq id_list) + raises (ConstraintNotFound); + + MappingConstraintInfoSeq get_all_mapping_constraints(); + + void remove_all_mapping_constraints(); + + void destroy(); + + boolean match (in any filterable_data, out any result_to_set) + raises (UnsupportedFilterableData); + + boolean match_structured (in CosNotification::StructuredEvent filterable_data, out any result_to_set) + raises (UnsupportedFilterableData); + + boolean match_typed (in CosNotification::PropertySeq filterable_data, out any result_to_set) + raises (UnsupportedFilterableData); + }; // MappingFilter + + + interface FilterFactory { + + Filter create_filter (in string constraint_grammar) + raises (InvalidGrammar); + + MappingFilter create_mapping_filter (in string constraint_grammar, in any default_value) + raises(InvalidGrammar); + }; // FilterFactory + + typedef long FilterID; + typedef sequence FilterIDSeq; + exception FilterNotFound {}; + + interface FilterAdmin { + FilterID add_filter (in Filter new_filter); + + void remove_filter (in FilterID filter) + raises (FilterNotFound); + + Filter get_filter (in FilterID filter) + raises (FilterNotFound); + + FilterIDSeq get_all_filters(); + + void remove_all_filters(); + }; // FilterAdmin +}; // CosNotifyFilter + + +#endif /* ifndef _COS_NOTIFYFILTER_IDL_ */ + diff --git a/lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl b/lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl new file mode 100644 index 0000000..9a7b431 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter_FilterFactory_impl.erl @@ -0,0 +1,125 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosNotifyFilter_FilterFactory_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('CosNotifyFilter_FilterFactory_impl'). + + +%%--------------- INCLUDES ----------------------------------- +%% Application files +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- IMPORTS ------------------------------------ + +%%--------------- EXPORTS ------------------------------------ +%% External +-export([create_filter/3, + create_mapping_filter/4]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {adminProp, + etsR, + options}). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: See gen_server documentation. +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(_Info, State) -> + ?debug_print("INFO: ~p DATA: ~p~n", [State, _Info]), + {noreply, State}. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init(Options) -> + process_flag(trap_exit, true), + {ok, #state{options = Options}}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : create_filter +%% Arguments: InitGrammar - string() +%% Returns : CosNotifyFilter::Filter | +%% {'EXCEPTION', InvalidGrammar} +%%----------------------------------------------------------- +create_filter(OE_THIS, State, InitGrammar) -> + case lists:member(InitGrammar, ?not_SupportedGrammars) of + true -> + SO = 'CosNotification_Common':get_option(server_options, State#state.options, + ?not_DEFAULT_SETTINGS), + Fi='CosNotifyFilter_Filter':oe_create_link([OE_THIS, self(), + InitGrammar], + SO), + {reply, Fi, State}; + _ -> + corba:raise(#'CosNotifyFilter_InvalidGrammar'{}) + end. + +%%----------------------------------------------------------% +%% function : create_mapping_filter +%% Arguments: InitGrammar - string() +%% Returns : CosNotifyFilter::Filter | +%% {'EXCEPTION', InvalidGrammar} +%%----------------------------------------------------------- +create_mapping_filter(OE_THIS, State, InitGrammar, DefVal) -> + case lists:member(InitGrammar, ?not_SupportedGrammars) of + true -> + SO = 'CosNotification_Common':get_option(server_options, State#state.options, + ?not_DEFAULT_SETTINGS), + Fi='CosNotifyFilter_MappingFilter':oe_create_link([OE_THIS, self(), + InitGrammar, DefVal], + SO), + {reply, Fi, State}; + _ -> + corba:raise(#'CosNotifyFilter_InvalidGrammar'{}) + end. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl b/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl new file mode 100644 index 0000000..042e180 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter_Filter_impl.erl @@ -0,0 +1,670 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosNotifyFilter_Filter_impl.erl +%% Purpose : +%% Note : For an event to be forwarded it's sufficient that at least +%% one of the constraints return 'true'. +%% ALL functions in this module are internal. May NOT be used +%% externally in ANY WAY; only CosNotification system modules. +%%---------------------------------------------------------------------- + +-module('CosNotifyFilter_Filter_impl'). + +%%--------------- INCLUDES ----------------------------------- +%% Application files +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- IMPORTS ------------------------------------ + +%%--------------- EXPORTS ------------------------------------ +%% External Attributes +-export(['_get_constraint_grammar'/2]). +%% External Functions +-export([add_constraints/3, + modify_constraints/4, + get_constraints/3, + get_all_constraints/2, + remove_all_constraints/2, + destroy/2, + match/3, + match_structured/3, + match_typed/3, + attach_callback/3, + detach_callback/3, + get_callbacks/2]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%%######### MISC ########## +-define(create_ConstraintInfo(_Types, _Con, _ID), + #'CosNotifyFilter_ConstraintInfo'{ + constraint_expression = + #'CosNotifyFilter_ConstraintExp'{ + event_types = _Types, + constraint_expr = _Con}, + constraint_id = _ID + }). + +%%#### Data structures #### +-record(state, {constraint_grammar, + constraints = [], + filters = [], + callbacks = [], + idCounter = 0, + filterFactory, + factoryPid, + etsR}). + +%% Data structures constructors +-define(get_InitState(Fac, Pid, Gr), + #state{constraint_grammar=Gr, + filterFactory=Fac, + factoryPid=Pid, + etsR = ets:new(oe_ets, [bag, protected])}). + +%%------------------- Data structures selectors ------------------- +%% Grammar +-define(get_Grammar(S), S#state.constraint_grammar). +%% Callbacks +% Left out for now to avoid dialyzer warning. +%-define(get_Callback(S,I), find_obj(lists:keysearch(I, 1, S#state.callbacks), +% callback)). +-define(get_AllCallback(S), lists:map(fun({_V, C}) -> C end, + S#state.callbacks)). +-define(get_AllCallbackID(S), lists:map(fun({V, _C}) -> V end, + S#state.callbacks)). +%% ID:s +-define(get_IdCounter(S), S#state.idCounter). + +%% Constraints +-define(get_Constraint(S,I), find_obj(lists:keysearch(I, 1, S#state.constraints), + constraint)). +-define(get_AllConstraints(S), lists:map(fun({I, C, _W, _WC, _K, T}) -> + ?create_ConstraintInfo(T, C, I) + end, + S#state.constraints)). +-define(get_ConstraintAllData(S), S#state.constraints). +-define(get_ConstraintData(S,I), lists:keysearch(I, 1, S#state.constraints)). +-define(match_Type(S,I,ET), ets:lookup(S#state.etsR, {I, ET})). +%% Parse Tree +-define(get_ParseTree(S,K), find_obj(ets:lookup(S#state.etsR, K), tree)). + +%%------------------- Data structures modifiers ------------------- +%% Callbacks +-define(del_Callback(S,I), S#state{callbacks = + delete_obj(lists:keydelete(I,1, + S#state.callbacks), + S#state.callbacks, callback)}). +-define(del_AllCallbacks(S), S#state{callbacks=[]}). +-define(add_Callback(S,V,C), S#state{idCounter=V, + callbacks = [{V,C}|S#state.callbacks]}). +%% ID:s +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). + +%% Constraints +-define(del_Constraint(S, I), match_delete(S, S#state.constraints, I)). +-define(del_AllConstraints(S), clear_DB(S)). +-define(add_Constraint(S,I,C,W,_WC,K,T), S#state{constraints = + [{I, C, W, _WC, K, T}|S#state.constraints]}). +-define(set_Constraints(S,C), S#state{constraints = C}). + +-define(del_AllTypes(S), ets:match_delete(S#state.etsR, {'_','_',types})). +-define(del_Type(S,I), ets:match_delete(S#state.etsR, {{I, '_'}, '_', types})). +-define(add_Type(S,I,ET,K), ets:insert(S#state.etsR, {{I, ET}, K, types})). + +%% Parse Tree +-define(add_ParseTree(S,K,T), ets:insert(S#state.etsR, {K, T, tree})). +-define(del_ParseTree(S,K), ets:delete(S#state.etsR, K)). +-define(del_AllParseTress(S), ets:match_delete(S#state.etsR, {'_','_',tree})). + +%%------------------- MISC ---------------------------------------- +-define(is_EmptyFilter(S), S#state.constraints==[]). + +-define(InfoSeq2EventTypeSeq(L), lists:flatten( + lists:map(fun(#'CosNotifyFilter_ConstraintInfo' + {constraint_expression= + #'CosNotifyFilter_ConstraintExp' + {event_types = ET}}) -> + ET + end, + L))). + +%%-----------------------------------------------------------% +%% Function : handle_info, code_change +%% Arguments: See gen_server documentation. +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?debug_print("INFO: ~p DATA: ~p~n", [State, Info]), + case Info of + {'EXIT', _Pid, _Reason} -> + {noreply, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% Function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([FiFac, FacPid, ConstraintGr]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(FiFac, FacPid, ConstraintGr)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external attributes ---------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Function : '_get_constraint_grammar'/2 +%% Type : readonly +%% Returns : Grammar - string() +%%----------------------------------------------------------- +'_get_constraint_grammar'(_OE_THIS, State) -> + {reply, ?get_Grammar(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Function : add_constraints/3 +%% Arguments: CL - CosNotifyFilter::ConstraintExpSeq +%% Returns : CosNotifyFilter::ConstraintInfoSeq | +%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} +%%----------------------------------------------------------- +add_constraints(_OE_THIS, State, CL) -> + {NewState, Filters, Info, EventTSeq} = try_create_filters(State, CL), + NewState2=store_filters(NewState, Filters), + inform_callbacks(?get_AllCallback(NewState2), EventTSeq, []), + {reply, Info, NewState2}. + +%%----------------------------------------------------------% +%% Function : modify_constraints/4 +%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq +%% AddConstraintInfoSeq - CosNotifyFilter::ConstraintInfoSeq +%% Returns : ok | +%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} | +%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound} +%%----------------------------------------------------------- +%% The OMG specification (TC Document telecom/98-11-01, chapter +%% 3.2.1.3) states (concerning IDs): +%% +%% "If all input values supplied within a particular invocation +%% of this operation are valid, then the specific constraints +%% identified by the values contained in the first input parameter +%% will be deleted from the list of those encapsulated by the target +%% filter object." +%% +%% Hence, first we must check if all ID's exists before deleting. +modify_constraints(_OE_THIS, State, IDs, AddConstraintInfoSeq) -> + %% The following functions are 'safe', i.e., they do not alter any data. + RemoveConstraintInfoSeq = lookup_constraints(IDs, State), + lookup_constraints(AddConstraintInfoSeq, State), + {NewState, Filters, _Info, AddedEventTSeq} = + try_create_filters(State, AddConstraintInfoSeq), + RemovedEventTSeq = ?InfoSeq2EventTypeSeq(RemoveConstraintInfoSeq), + + %% We cannot change anything before our checks (see above). Hence, + %% do NOT move the following lines above this point. + NewState2 = delete_constraints(IDs, NewState), + +%% The OMG specification (TC Document telecom/98-11-01, chapter +%% 3.2.1.3) states (concerning AddConstraintInfoSeq): +%% +%% "If all input values supplied within a particular invocation of this +%% operation are valid, then the constraint expression associated with the +%% already encapsulated constraint identified by the numeric value contained +%% within each element of the input sequence will be modified to the new +%% constraint expression that is contained within the same sequence element." +%% +%% This, our interpretation, implies that ALL previous data related +%% to each unique ID should be removed and replaced by the new data. + + NewState3 = delete_constraints(AddConstraintInfoSeq, NewState2), + NewState4 = store_filters(NewState3, Filters), + inform_callbacks(?get_AllCallback(NewState4), + AddedEventTSeq, RemovedEventTSeq), + {reply, ok, NewState4}. + +%%----------------------------------------------------------% +%% Function : get_constraints/3 +%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq +%% Returns : CosNotifyFilter::ConstraintInfoSeq | +%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound} +%%----------------------------------------------------------- +get_constraints(_OE_THIS, State, IDs) -> + {reply, lookup_constraints(IDs, State), State}. + +%%----------------------------------------------------------% +%% Function : get_all_constraints/2 +%% Arguments: - +%% Returns : CosNotifyFilter::ConstraintInfoSeq +%%----------------------------------------------------------- +get_all_constraints(_OE_THIS, State) -> + {reply, ?get_AllConstraints(State), State}. + +%%----------------------------------------------------------% +%% Function : remove_all_constraints/2 +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_constraints(_OE_THIS, State) -> + {reply, ok, ?del_AllConstraints(State)}. + +%%----------------------------------------------------------% +%% Function : destroy/2 +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +destroy(_OE_THIS, State) -> + {stop, normal, ok, State}. + +%%----------------------------------------------------------% +%% Function : match/3 +%% Arguments: Event - #any{} +%% Returns : boolean() | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- + +match(_OE_THIS, State, Event) when is_record(Event,'any'), ?is_EmptyFilter(State) -> + {reply, true, State}; +match(_OE_THIS, State, Event) when is_record(Event,'any') -> + match_any_event(State, Event, ?get_ConstraintAllData(State)); +match(_,_,What) -> + orber:dbg("[~p] CosNotifyFilter_Filter:match(~p);~n" + "Not an CORBA::Any", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% Function : match_structured/3 +%% Arguments: Event - CosNotification::StructuredEvent +%% Returns : boolean() | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match_structured(_OE_THIS, State, Event) when + is_record(Event,'CosNotification_StructuredEvent') andalso ?is_EmptyFilter(State) -> + {reply, true, State}; +match_structured(_OE_THIS, State, Event) when + is_record(Event,'CosNotification_StructuredEvent') -> + match_str_event(State, Event, ?get_ConstraintAllData(State)); +match_structured(_,_,What) -> + orber:dbg("[~p] CosNotifyFilter_Filter:match_structured(~p);~n" + "Not a StructuredEvent", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------* +%% Function : match_typed/3 +%% Arguments: Data - CosNotification::PropertySeq +%% Returns : boolean() | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match_typed(_OE_THIS, _State, _Data) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% Function : attach_callback/3 +%% Arguments: CB - CosNotifyComm::NotifySubscribe +%% Returns : ID - CosNotifyFilter::CallbackID +%%----------------------------------------------------------- +attach_callback(_OE_THIS, State, CB) -> + 'CosNotification_Common':type_check(CB, 'CosNotifyComm_NotifySubscribe'), + CBID = ?new_Id(State), + {reply, CBID, ?add_Callback(State, CBID, CB)}. + +%%----------------------------------------------------------% +%% Function : detach_callback/3 +%% Arguments: ID - CosNotifyFilter::CallbackID +%% Returns : ok | {'EXCEPTION', CosNotifyFilter::CallbackNotFound} +%%----------------------------------------------------------- +detach_callback(_OE_THIS, State, ID) when is_integer(ID) -> + {reply, ok, ?del_Callback(State, ID)}; +detach_callback(_,_,What) -> + orber:dbg("[~p] CosNotifyFilter_Filter:detach_callback(~p);~n" + "Not an integer", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% Function : get_callbacks/2 +%% Arguments: - +%% Returns : CosNotifyFilter::CallbackIDSeq +%%----------------------------------------------------------- +get_callbacks(_OE_THIS, State) -> + {reply, ?get_AllCallbackID(State), State}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +%% To match callbacks +find_obj({value, {_, Obj}},_) -> Obj; +%% To match constraints +find_obj({value, {Id, Con, _, _, _, Types}}, _) -> + ?create_ConstraintInfo(Types, Con, Id); +find_obj([{_, Tree, tree}|_], tree) -> Tree; +% Left out for now to avoid dialyzer warning. +%find_obj(_,callback) -> {'EXCEPTION', #'CosNotifyFilter_CallbackNotFound'{}}; +find_obj(_,tree) -> undefined; +find_obj(_,constraint) -> error. + +%% Delete a single object. +delete_obj(List,List,callback) -> corba:raise(#'CosNotifyFilter_CallbackNotFound'{}); +delete_obj(List,_,_) -> List. + +%% Delete given object from list and all related objects in DB (parse tree and types). +match_delete(State, Constraints, ID) -> + match_delete(State, Constraints, ID, []). +match_delete(_, [], _, _) -> + error; +match_delete(State, [{ID, _Con, _Which, _WC, Key, _Types}|T], ID, Acc) -> + ?del_Type(State, ID), + ?del_ParseTree(State, Key), + {ok, ?set_Constraints(State, Acc++T)}; +match_delete(State, [H|T], ID, Acc) -> + match_delete(State, T, ID, [H|Acc]). + +%% Remove all data related with constraints; for now, since no other data +%% stored in DB, we do in a rather brutal way. +clear_DB(State) -> + catch ets:delete(State#state.etsR), + State#state{etsR = ets:new(oe_ets, [bag, protected]), constraints=[]}. + +%% Given a list of Constrain IDs we want to find the related constraints. +%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!! +lookup_constraints(IDs, State) -> + lookup_constraints(IDs, State, []). +lookup_constraints([], _State, Accum) -> + Accum; +lookup_constraints([H|T], State, Accum) + when is_record(H, 'CosNotifyFilter_ConstraintInfo') -> + case ?get_Constraint(State, H#'CosNotifyFilter_ConstraintInfo'.constraint_id) of + error -> + corba:raise(#'CosNotifyFilter_ConstraintNotFound' + {id = H#'CosNotifyFilter_ConstraintInfo'.constraint_id}); + _Con -> + %% We don't need to collect the result since the input already is of + %% the correct type, i.e., ConstraintInfoSeq + lookup_constraints(T, State, Accum) + end; +lookup_constraints([H|T], State, Accum) when is_integer(H) -> + case ?get_Constraint(State,H) of + error -> + corba:raise(#'CosNotifyFilter_ConstraintNotFound'{id=H}); + Con -> + lookup_constraints(T, State, [Con|Accum]) + end; +lookup_constraints(_, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%% Given a list of Constrain IDs we want to delet the related constraints. +%% We need also to return the ConstraintInfoSeq described related to the +%% given ID's. +delete_constraints([], State) -> + State; +delete_constraints([H|T], State) + when is_record(H, 'CosNotifyFilter_ConstraintInfo') -> + case catch ?del_Constraint(State, + H#'CosNotifyFilter_ConstraintInfo'.constraint_id) of + {ok, NewState} -> + delete_constraints(T, NewState); + Reason -> + orber:dbg("[~p] 'CosNotifyFilter_Filter':modify_constraints().~n" + "Unable to remove: ~p~n" + "Reason: ~p~n", + [?LINE, H, Reason], ?DEBUG_LEVEL), + delete_constraints(T, State) + end; +delete_constraints([H|T], State) -> + case catch ?del_Constraint(State,H) of + {ok, NewState} -> + delete_constraints(T, NewState); + Reason -> + orber:dbg("[~p] 'CosNotifyFilter_Filter':modify_constraints().~n" + "Unable to remove: ~p~n" + "Reason: ~p~n", + [?LINE, H, Reason], ?DEBUG_LEVEL), + delete_constraints(T, State) + end. + +%% Inform all registered callbacks that the constraints have changed. +%% Added and Removed must be a CosNotification::EventTypeSeq +inform_callbacks([],_,_) -> + ok; +inform_callbacks([H|T], Added, Removed) -> + case catch 'CosNotifyComm_NotifySubscribe':subscription_change(H, Added, Removed) of + ok -> + ?debug_print("INFORMED CALLBACK: ~p ADDED: ~p REMOVED: ~p", + [H, Added, Removed]), + inform_callbacks(T, Added, Removed); + Other -> + orber:dbg("[~p] 'CosNotifyComm_NotifySubscribe':subscription_change().~n" + "Unable to inform callback: ~p~n" + "Reason: ~p~n", + [?LINE, H, Other], ?DEBUG_LEVEL), + inform_callbacks(T, Added, Removed) + end. + +%%----------------------------------------------------------- +%% Function : try_create_filters/2 +%% Arguments: CL - #'CosNotifyFilter_ConstraintExp'{ +%% event_types = [#'CosNotification_EventType'{ +%% domain_name = Str, type_name = Str}] +%% constraint_expr = Str} +%% Returns : {State, AccumList} +%%----------------------------------------------------------- +%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!! +try_create_filters(State, CL) -> + try_create_filters(State, CL, [], [], []). +try_create_filters(State, [], Accum, InfoSeq, EventTSeq) -> + {State, Accum, InfoSeq, EventTSeq}; +try_create_filters(State, [#'CosNotifyFilter_ConstraintExp'{event_types = Types, + constraint_expr = Con}|T], + Accum, InfoSeq, EventTSeq) -> + case catch cosNotification_Filter:create_filter(Con) of + {ok, Tree} -> + case catch cosNotification_Filter:check_types(Types) of + true -> + ID = ?new_Id(State), + Key = ?not_CreateDBKey, + NewETSeq = Types ++ EventTSeq, + try_create_filters(?set_IdCounter(State, ID), T, + [{ID, true, [], Key, Types, Con, Tree}|Accum], + [?create_ConstraintInfo(Types, Con, ID)|InfoSeq], + NewETSeq); + {ok, Which, WC} -> + ID = ?new_Id(State), + Key = ?not_CreateDBKey, + NewETSeq = Types ++ EventTSeq, + try_create_filters(?set_IdCounter(State, ID), T, + [{ID, Which, WC, Key, Types, Con, Tree}|Accum], + [?create_ConstraintInfo(Types, Con, ID)|InfoSeq], + NewETSeq); + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; + _ -> + corba:raise(#'CosNotifyFilter_InvalidConstraint' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}}) + end; +try_create_filters(State, [#'CosNotifyFilter_ConstraintInfo' + {constraint_expression = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}, + constraint_id=ID}|T], Accum, InfoSeq, EventTSeq) -> + case catch cosNotification_Filter:create_filter(Con) of + {ok, Tree} -> + case catch cosNotification_Filter:check_types(Types) of + true -> + Key = ?not_CreateDBKey, + NewETSeq = Types ++ EventTSeq, + try_create_filters(State, T, + [{ID, true, [], Key, Types, Con, Tree}|Accum], + [?create_ConstraintInfo(Types, Con, ID)|InfoSeq], + NewETSeq); + {ok, Which, WC} -> + Key = ?not_CreateDBKey, + NewETSeq = Types ++ EventTSeq, + try_create_filters(State, T, + [{ID, Which, WC, Key, Types, Con, Tree}|Accum], + [?create_ConstraintInfo(Types, Con, ID)|InfoSeq], + NewETSeq); + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; + _ -> + corba:raise(#'CosNotifyFilter_InvalidConstraint' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}}) + end; +try_create_filters(_,_,_,_,_) -> + %% The list contained something else but ConstraintExp. + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------- +%% Function : store_filters/4 +%% Arguments: Filters - a list of filters. +%% Returns : +%%----------------------------------------------------------- + +store_filters(State, []) -> + State; +store_filters(State, [{ID, Which, WC, Key, Types, Con, Tree}|T]) -> + ?add_ParseTree(State, Key, Tree), + write_types(State, Types, ID, Key), + store_filters(?add_Constraint(State, ID, Con, Which, WC, Key, Types), T). + + +write_types(_State, [],_, _) -> + ok; +write_types(State, [EventType|T], ID, Key) -> + ?add_Type(State, ID, EventType, Key), + ?debug_print("FILTER: ~p ~p ~p~n", [ID, Key, EventType]), + write_types(State, T, ID, Key). + +%%----------------------------------------------------------- +%% Function : match_any_event +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +match_any_event(State, _Event, []) -> + ?debug_print("FILTER REJECTED: ~p~n", [_Event]), + {reply, false, State}; +match_any_event(State, Event, [{_, _, _, _, Key, _}|T]) -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), Event) of + true -> + ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]), + {reply, true, State}; + _ -> + match_any_event(State, Event, T) + end. + + +%%----------------------------------------------------------- +%% Function : match_str_event +%% Arguments: +%% Returns : +%%----------------------------------------------------------- + +match_str_event(State, _Event, []) -> + ?debug_print("FILTER REJECTED: ~p~n", [_Event]), + {reply, false, State}; +match_str_event(State, Event, [{ID, _Con, Which, WC, Key, _Types}|T]) -> + ET = ((Event#'CosNotification_StructuredEvent'.header) + #'CosNotification_EventHeader'.fixed_header) + #'CosNotification_FixedEventHeader'.event_type, + CheckList = + case Which of + both -> + [ET]; + domain -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}]; + type -> + [ET, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}]; + _ -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}] + end, + case check_DB(State, ID, CheckList) of + false -> + %% No match, may have used wildcards, e.g., "dom*". + case catch cosNotification_Filter:match_types( + ET#'CosNotification_EventType'.domain_name, + ET#'CosNotification_EventType'.type_name, + WC) of + true -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), + Event) of + true -> + ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]), + {reply, true, State}; + _ -> + match_str_event(State, Event, T) + end; + _-> + match_str_event(State, Event, T) + end; + Key -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), + Event) of + true -> + ?debug_print("FILTER APPROVED: ~p~n", [Event]), + {reply, true, State}; + _ -> + match_str_event(State, Event, T) + end + end. + +check_DB(_, _, []) -> + false; +check_DB(State, ID, [H|T]) -> + case ?match_Type(State, ID, H) of + [] -> + check_DB(State, ID, T); + [{_, K, types}|_] -> + K + end. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ + diff --git a/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl b/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl new file mode 100644 index 0000000..f910300 --- /dev/null +++ b/lib/cosNotification/src/CosNotifyFilter_MappingFilter_impl.erl @@ -0,0 +1,578 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosNotifyFilter_MappingFilter_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('CosNotifyFilter_MappingFilter_impl'). + +%%--------------- INCLUDES ----------------------------------- +%% Application files +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- IMPORTS ------------------------------------ + +%%--------------- EXPORTS ------------------------------------ +%% External Attributes +-export(['_get_constraint_grammar'/2, + '_get_value_type'/2, + '_get_default_value'/2]). +%% External Functions +-export([add_mapping_constraints/3, + modify_mapping_constraints/4, + get_mapping_constraints/3, + get_all_mapping_constraints/2, + remove_all_mapping_constraints/2, + destroy/2, + match/3, + match_structured/3, + match_typed/3]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%%######### MISC ########## +-define(create_MappingInfo(_Types, _Con, _ID, _A), + #'CosNotifyFilter_MappingConstraintInfo'{ + constraint_expression = + #'CosNotifyFilter_ConstraintExp'{ + event_types = _Types, + constraint_expr = _Con}, + constraint_id = _ID, + value = _A + }). +%%#### Data structures #### +-record(state, {constraint_grammar, + value, + typeC, + constraints = [], + filters = [], + idCounter = 0, + filterFactory, + factoryPid, + etsR}). + +%% Data structures constructors +-define(get_InitState(Gr, DVal, FF, FP), + #state{constraint_grammar=Gr, + value = DVal, + typeC = any:get_typecode(DVal), + filterFactory = FF, + factoryPid = FP, + etsR = ets:new(oe_ets, [bag, protected])}). + +%%------------------- Data structures selectors ------------------- +%% Attributes +-define(get_Grammar(S), S#state.constraint_grammar). +-define(get_DefVal(S), S#state.value). +-define(get_DefTC(S), S#state.typeC). +-define(get_DefAny(S), S#state.value). + +%% ID:s +-define(get_IdCounter(S), S#state.idCounter). + +%% Constraints +-define(get_Constraint(S,I), find_obj(lists:keysearch(I, 1, S#state.constraints), + constraint)). +-define(get_AllConstraints(S), lists:map(fun({I, C, _W, _WC, _K, T, A}) -> + ?create_MappingInfo(T, C, I, A) + end, + S#state.constraints)). +-define(get_ConstraintAllData(S), S#state.constraints). +-define(get_ConstraintData(S,I), lists:keysearch(I, 1, S#state.constraints)). +-define(match_Type(S,I,ET), ets:lookup(S#state.etsR, {I, ET})). +%% Parse Tree +-define(get_ParseTree(S,K), find_obj(ets:lookup(S#state.etsR, K), tree)). + +%%------------------- Data structures modifiers ------------------- +%% ID:s +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). + +%% Constraints +-define(del_Constraint(S, I), match_delete(S, S#state.constraints, I)). +-define(del_AllConstraints(S), clear_DB(S)). +-define(add_Constraint(S,I,C,W,_WC,K,T,A), S#state{constraints = + [{I, C, W, _WC, K, T, A}|S#state.constraints]}). +-define(set_Constraints(S,C), S#state{constraints = C}). + +-define(del_AllTypes(S), ets:match_delete(S#state.etsR, {'_','_',types})). +-define(del_Type(S,I), ets:match_delete(S#state.etsR, {{I, '_'}, '_', types})). +-define(add_Type(S,I,ET,K), ets:insert(S#state.etsR, {{I, ET}, K, types})). + +%% Parse Tree +-define(add_ParseTree(S,K,T), ets:insert(S#state.etsR, {K, T, tree})). +-define(del_ParseTree(S,K), ets:delete(S#state.etsR, K)). +-define(del_AllParseTress(S), ets:match_delete(S#state.etsR, {'_','_',tree})). + +%%------------------- MISC ---------------------------------------- +-define(is_EmptyFilter(S), S#state.constraints==[]). +-define(is_EqualType(S,T), S#state.typeC==any:get_typecode(T)). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: See gen_server documentation. +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?debug_print("INFO: ~p DATA: ~p~n", [State, Info]), + case Info of + {'EXIT', _Pid, _Reason} -> + {noreply, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([FiFac, FacPid, InitGr, DefVal]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(InitGr, DefVal, FiFac, FacPid)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external attributes ---------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Function : '_get_constraint_grammar'/2 +%% Type : readonly +%% Returns : string() +%%----------------------------------------------------------- +'_get_constraint_grammar'(_OE_THIS, State) -> + {reply, ?get_Grammar(State), State}. +%%----------------------------------------------------------% +%% Function : '_get_value_type'/2 +%% Type : readonly +%% Returns : CORBA::TypeCode +%%----------------------------------------------------------- +'_get_value_type'(_OE_THIS, State) -> + {reply, ?get_DefTC(State), State}. +%%----------------------------------------------------------% +%% Function : '_get_default_value'/2 +%% Type : readonly +%% Returns : #any{} +%%----------------------------------------------------------- +'_get_default_value'(_OE_THIS, State) -> + {reply, ?get_DefVal(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Function : add_mapping_constraints/3 +%% Arguments: Pairs - CosNotifyFilter::MappingConstraintPairSeq +%% Returns : CosNotifyFilter::MappingConstraintInfoSeq | +%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} | +%% {'EXCEPTION', CosNotifyFilter::InvalidValue} +%%----------------------------------------------------------- +add_mapping_constraints(_OE_THIS, State, Pairs) -> + {NewState, Filters, Info} = try_create_filters(State, Pairs), + NewState2=store_filters(NewState, Filters), + {reply, Info, NewState2}. + +%%----------------------------------------------------------% +%% Function : modify_mapping_constraints/4 +%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq +%% Info - CosNotifyFilter::MappingConstraintInfoSeq +%% Returns : ok | +%% {'EXCEPTION', CosNotifyFilter::InvalidConstraint} | +%% {'EXCEPTION', CosNotifyFilter::InvalidValue} | +%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound} +%%----------------------------------------------------------- +modify_mapping_constraints(_OE_THIS, State, IDs, InfoSeq) -> + lookup_constraints(IDs, State), + lookup_constraints(InfoSeq, State), + {NewState, Filters, _Info} = try_create_filters(State, InfoSeq), + + %% We cannot change anything before our checks (see above). Hence, + %% do NOT move the following lines above this point. + + NewState2 = delete_constraints(IDs, NewState), + NewState3 = delete_constraints(InfoSeq, NewState2), + NewState4 = store_filters(NewState3, Filters), + {reply, ok, NewState4}. + +%%----------------------------------------------------------% +%% Function : get_mapping_constraints/3 +%% Arguments: IDs - CosNotifyFilter::ConstraintIDSeq +%% Returns : CosNotifyFilter::MappingConstraintInfoSeq | +%% {'EXCEPTION', CosNotifyFilter::ConstraintNotFound} +%%----------------------------------------------------------- +get_mapping_constraints(_OE_THIS, State, IDs) -> + {reply, lookup_constraints(IDs, State), State}. + +%%----------------------------------------------------------% +%% Function : get_all_mapping_constraints/2 +%% Arguments: - +%% Returns : CosNotifyFilter::MappingConstraintInfoSeq +%%----------------------------------------------------------- +get_all_mapping_constraints(_OE_THIS, State) -> + {reply, ?get_AllConstraints(State), State}. + +%%----------------------------------------------------------% +%% Function : remove_all_mapping_constraints/2 +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_mapping_constraints(_OE_THIS, State) -> + {reply, ok, ?del_AllConstraints(State)}. + +%%----------------------------------------------------------% +%% Function : destroy/2 +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +destroy(_OE_THIS, State) -> + {stop, normal, ok, State}. + +%%----------------------------------------------------------% +%% Function : match/3 +%% Arguments: Event - #any{} +%% Returns : boolean(), #any{} (out-type) | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match(_OE_THIS, State, Event) when is_record(Event,'any') andalso ?is_EmptyFilter(State) -> + {reply, {false, ?get_DefAny(State)}, State}; +match(_OE_THIS, State, Event) when is_record(Event,'any') -> + match_any_event(State, Event, ?get_ConstraintAllData(State)); +match(_,_,_) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%----------------------------------------------------------% +%% Function : match_structured/3 +%% Arguments: Event - CosNotification::StructuredEvent +%% Returns : boolean(), #any{} (out-type) | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match_structured(_OE_THIS, State, Event) when + is_record(Event,'CosNotification_StructuredEvent') andalso ?is_EmptyFilter(State) -> + {reply, {false, ?get_DefAny(State)}, State}; +match_structured(_OE_THIS, State, Event) when + is_record(Event,'CosNotification_StructuredEvent') -> + match_str_event(State, Event, ?get_ConstraintAllData(State)); +match_structured(_,_,_) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------* +%% Function : match_typed/3 +%% Arguments: Data - CosNotification::PropertySeq +%% Returns : boolean() , #any{} (out-type) | +%% {'EXCEPTION', CosNotifyFilter::UnsupportedFilterableData} +%%----------------------------------------------------------- +match_typed(_OE_THIS, _State, _Data) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}). + +%%--------------- LOCAL FUNCTIONS ---------------------------- +%% To match constraints +find_obj({value, {Id, Con, _, _, _, Types, Any}}, _) -> + ?create_MappingInfo(Types, Con, Id, Any); +find_obj([{_, Tree, tree}|_], tree) -> Tree; +find_obj(_,tree) -> undefined; +find_obj(_,constraint) -> error. + +%% Delete given object from list and all related objects in DB (parse tree and types). +match_delete(State, Constraints, ID) -> + match_delete(State, Constraints, ID, []). +match_delete(_, [], _, _) -> + error; +match_delete(State, [{ID, _Con, _Which, _WC, Key, _Types, _Any}|T], ID, Acc) -> + ?del_Type(State, ID), + ?del_ParseTree(State, Key), + {ok, ?set_Constraints(State, Acc++T)}; +match_delete(State, [H|T], ID, Acc) -> + match_delete(State, T, ID, [H|Acc]). + +%% Remove all data related with constraints; for now, since no other data +%% stored in DB, we do in a rather brutal way. +clear_DB(State) -> + catch ets:delete(State#state.etsR), + State#state{etsR = ets:new(oe_ets, [bag, protected]), constraints=[]}. + +%% Given a list of Constrain IDs we want to find the related constraints. +%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!! +lookup_constraints(IDs, State) -> + lookup_constraints(IDs, State, []). +lookup_constraints([], _State, Accum) -> + Accum; +lookup_constraints([H|T], State, Accum) + when is_record(H, 'CosNotifyFilter_MappingConstraintInfo') -> + case ?get_Constraint(State, H#'CosNotifyFilter_MappingConstraintInfo'.constraint_id) of + error -> + corba:raise(#'CosNotifyFilter_ConstraintNotFound' + {id = H#'CosNotifyFilter_MappingConstraintInfo'.constraint_id}); + _Con -> + %% We don't need to collect the result since the input already is of + %% the correct type, i.e., ConstraintInfoSeq + lookup_constraints(T, State, Accum) + end; +lookup_constraints([H|T], State, Accum) when is_integer(H) -> + case ?get_Constraint(State,H) of + error -> + corba:raise(#'CosNotifyFilter_ConstraintNotFound'{id=H}); + Con -> + lookup_constraints(T, State, [Con|Accum]) + end; +lookup_constraints(_, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%% Given a list of Constrain IDs we want to delet the related constraints. +%% We need also to return the ConstraintInfoSeq described related to the +%% given ID's. +delete_constraints([], State) -> + State; +delete_constraints([H|T], State) + when is_record(H, 'CosNotifyFilter_MappingConstraintInfo') -> + case catch ?del_Constraint(State, + H#'CosNotifyFilter_MappingConstraintInfo'.constraint_id) of + {ok, NewState} -> + delete_constraints(T, NewState); + Reason -> + orber:dbg("[~p] 'CosNotifyFilter_MappingFilter':modify_mapping_constraints().~n" + "Unable to remove: ~p~n" + "Reason: ~p~n", + [?LINE, H, Reason], ?DEBUG_LEVEL), + delete_constraints(T, State) + end; +delete_constraints([H|T], State) -> + case catch ?del_Constraint(State,H) of + {ok, NewState} -> + delete_constraints(T, NewState); + Reason -> + orber:dbg("[~p] 'CosNotifyFilter_MappingFilter':modify_mapping_constraints().~n" + "Unable to remove: ~p~n" + "Reason: ~p~n", + [?LINE, H, Reason], ?DEBUG_LEVEL), + delete_constraints(T, State) + end. + +%%----------------------------------------------------------- +%% Function : try_create_filters/2 +%% Arguments: CL - #'CosNotifyFilter_MappingConstraintPair{ +%% constraint_expression = +%% #'CosNotifyFilter_ConstraintExp'{ +%% event_types = +%% [#'CosNotification_EventType'{ +%% domain_name = Str, type_name = Str}] +%% constraint_expr = Str}, +%% result_to_set = Any} +%% Returns : {State, AccumList} +%%----------------------------------------------------------- +%% !!!!!! This function may not alter any data in DB in any way !!!!!!!!!! +try_create_filters(State, CL) -> + try_create_filters(State, CL, [], []). +try_create_filters(State, [], Accum, InfoSeq) -> + {State, Accum, InfoSeq}; +try_create_filters(State, [#'CosNotifyFilter_MappingConstraintPair' + {constraint_expression = + #'CosNotifyFilter_ConstraintExp'{event_types = Types, + constraint_expr = Con}, + result_to_set=Any}|T], Accum, InfoSeq) -> + case catch {?is_EqualType(State,Any), cosNotification_Filter:create_filter(Con)} of + {false, _} -> + corba:raise(#'CosNotifyFilter_InvalidValue' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}, + value=Any}); + {_, {ok, Tree}} -> + case catch cosNotification_Filter:check_types(Types) of + true -> + ID = ?new_Id(State), + Key = ?not_CreateDBKey, + try_create_filters(?set_IdCounter(State, ID), T, + [{ID, true, [], Key, Types, Con, Tree, Any}|Accum], + [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]); + {ok, Which, WC} -> + ID = ?new_Id(State), + Key = ?not_CreateDBKey, + try_create_filters(?set_IdCounter(State, ID), T, + [{ID, Which, WC, Key, Types, Con, Tree, Any}|Accum], + [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]); + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; + _ -> + corba:raise(#'CosNotifyFilter_InvalidConstraint' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}}) + end; +try_create_filters(State, [#'CosNotifyFilter_MappingConstraintInfo' + {constraint_expression = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}, + constraint_id=ID, + value=Any}|T], Accum, InfoSeq) -> + case catch cosNotification_Filter:create_filter(Con) of + {ok, Tree} -> + case catch cosNotification_Filter:check_types(Types) of + true -> + Key = ?not_CreateDBKey, + try_create_filters(State, T, + [{ID, true, [], Key, Types, Con, Tree, Any}|Accum], + [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]); + {ok, Which, WC} -> + Key = ?not_CreateDBKey, + try_create_filters(State, T, + [{ID, Which, WC, Key, Types, Con, Tree, Any}|Accum], + [?create_MappingInfo(Types, Con, ID, Any)|InfoSeq]); + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; + _ -> + corba:raise(#'CosNotifyFilter_InvalidConstraint' + {constr = #'CosNotifyFilter_ConstraintExp' + {event_types = Types, constraint_expr = Con}}) + end; +try_create_filters(_,_,_,_) -> + %% The list contained something else but ConstraintExp. + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------- +%% Function : store_filters/4 +%% Arguments: Filters - a list of filters. +%% Returns : +%%----------------------------------------------------------- + +store_filters(State, []) -> + State; +store_filters(State, [{ID, Which, WC, Key, Types, Con, Tree, Any}|T]) -> + ?add_ParseTree(State, Key, Tree), + write_types(State, Types, ID, Key), + store_filters(?add_Constraint(State, ID, Con, Which, WC, Key, Types, Any), T). + + +write_types(_State, [],_, _) -> + ok; +write_types(State, [EventType|T], ID, Key) -> + ?add_Type(State, ID, EventType, Key), + ?debug_print("FILTER: ~p ~p ~p~n", [ID, Key, EventType]), + write_types(State, T, ID, Key). + +%%----------------------------------------------------------- +%% Function : match_any_event +%% Arguments: Event - #any{} +%% Returns : +%%----------------------------------------------------------- +match_any_event(State, _Event, []) -> + ?debug_print("FILTER REJECTED: ~p~n", [_Event]), + {reply, {false, ?get_DefAny(State)}, State}; +match_any_event(State, Event, [{_, _, _, _, Key, Any}|T]) -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), Event) of + true -> + ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]), + {reply, {true, Any}, State}; + _ -> + match_any_event(State, Event, T) + end. + + +%%----------------------------------------------------------- +%% Function : match_str_event +%% Arguments: +%% Returns : +%%----------------------------------------------------------- + +match_str_event(State, _Event, []) -> + ?debug_print("FILTER REJECTED: ~p~n", [_Event]), + {reply, {false, ?get_DefAny(State)}, State}; +match_str_event(State, Event, [{ID, _Con, Which, WC, Key, _Types, Any}|T]) -> + ET = ((Event#'CosNotification_StructuredEvent'.header) + #'CosNotification_EventHeader'.fixed_header) + #'CosNotification_FixedEventHeader'.event_type, + CheckList = + case Which of + both -> + [ET]; + domain -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}]; + type -> + [ET, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}]; + _ -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}] + end, + case check_DB(State, ID, CheckList) of + false -> + %% No match, may have used wildcards, e.g., "dom*". + case catch cosNotification_Filter:match_types( + ET#'CosNotification_EventType'.domain_name, + ET#'CosNotification_EventType'.type_name, + WC) of + true -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), + Event) of + true -> + ?debug_print("FILTER APPROVED (WC): ~p~n", [Event]), + {reply, {true, Any}, State}; + _ -> + match_str_event(State, Event, T) + end; + _-> + match_str_event(State, Event, T) + end; + Key -> + case catch cosNotification_Filter:eval(?get_ParseTree(State,Key), + Event) of + true -> + ?debug_print("FILTER APPROVED: ~p~n", [Event]), + {reply, {true, Any}, State}; + _ -> + match_str_event(State, Event, T) + end + end. + +check_DB(_, _, []) -> + false; +check_DB(State, ID, [H|T]) -> + case ?match_Type(State, ID, H) of + [] -> + check_DB(State, ID, T); + [{_, K, types}|_] -> + K + end. +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ + diff --git a/lib/cosNotification/src/CosTypedEvent.idl b/lib/cosNotification/src/CosTypedEvent.idl new file mode 100644 index 0000000..d77c377 --- /dev/null +++ b/lib/cosNotification/src/CosTypedEvent.idl @@ -0,0 +1,57 @@ +#ifndef _COS_TYPED_EVENT_IDL_ +#define _COS_TYPED_EVENT_IDL_ + +#pragma prefix "omg.org" + +#include + +module CosTypedEventComm { + + interface TypedPushConsumer : CosEventComm::PushConsumer { + Object get_typed_consumer(); + }; + + interface TypedPullSupplier : CosEventComm::PullSupplier { + Object get_typed_supplier(); + }; +}; + +module CosTypedEventChannelAdmin { + + exception InterfaceNotSupported {}; + exception NoSuchImplementation {}; + typedef string Key; + + + interface TypedProxyPushConsumer : + CosEventChannelAdmin::ProxyPushConsumer, + CosTypedEventComm::TypedPushConsumer { }; + + interface TypedProxyPullSupplier : + CosEventChannelAdmin::ProxyPullSupplier, + CosTypedEventComm::TypedPullSupplier { }; + + interface TypedSupplierAdmin : + CosEventChannelAdmin::SupplierAdmin { + TypedProxyPushConsumer obtain_typed_push_consumer(in Key supported_interface) + raises(InterfaceNotSupported); + CosEventChannelAdmin::ProxyPullConsumer obtain_typed_pull_consumer (in Key uses_interface) + raises(NoSuchImplementation); + }; + + interface TypedConsumerAdmin : + CosEventChannelAdmin::ConsumerAdmin { + TypedProxyPullSupplier obtain_typed_pull_supplier(in Key supported_interface) + raises (InterfaceNotSupported); + CosEventChannelAdmin::ProxyPushSupplier obtain_typed_push_supplier(in Key uses_interface) + raises(NoSuchImplementation); + }; + + interface TypedEventChannel { + TypedConsumerAdmin for_consumers(); + TypedSupplierAdmin for_suppliers(); + void destroy (); + }; +}; + +#endif /* ifndef _COS_TYPED_EVENT_IDL_ */ diff --git a/lib/cosNotification/src/CosTypedNotification.idl b/lib/cosNotification/src/CosTypedNotification.idl new file mode 100644 index 0000000..882cde1 --- /dev/null +++ b/lib/cosNotification/src/CosTypedNotification.idl @@ -0,0 +1,109 @@ +#ifndef _COS_TYPED_NOTIFICATION_IDL_ +#define _COS_TYPED_NOTIFICATION_IDL_ + +#pragma prefix "omg.org" + +#include +#include +#include + +module CosTypedNotifyComm { + interface TypedPushConsumer : CosTypedEventComm::TypedPushConsumer, CosNotifyComm::NotifyPublish { }; // TypedPushConsumer + + interface TypedPullSupplier : CosTypedEventComm::TypedPullSupplier, CosNotifyComm::NotifySubscribe { }; // TypedPullSupplier +}; // CosTypedNotifyComm + + +module CosTypedNotifyChannelAdmin { + // Forward declaration + interface TypedEventChannelFactory; + typedef string Key; + interface TypedProxyPushConsumer : CosNotifyChannelAdmin::ProxyConsumer, CosTypedNotifyComm::TypedPushConsumer { + void connect_typed_push_supplier (in CosEventComm::PushSupplier push_supplier) + raises (CosEventChannelAdmin::AlreadyConnected); + }; // TypedProxyPushConsumer + + interface TypedProxyPullSupplier : CosNotifyChannelAdmin::ProxySupplier, CosTypedNotifyComm::TypedPullSupplier { + void connect_typed_pull_consumer (in CosEventComm::PullConsumer pull_consumer) + raises (CosEventChannelAdmin::AlreadyConnected); + }; // TypedProxyPullSupplier + + interface TypedProxyPullConsumer : CosNotifyChannelAdmin::ProxyConsumer, CosNotifyComm::PullConsumer { + void connect_typed_pull_supplier (in CosTypedEventComm::TypedPullSupplier pull_supplier) + raises (CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises (CosNotifyChannelAdmin::ConnectionAlreadyInactive, CosNotifyChannelAdmin::NotConnected); + + void resume_connection() + raises (CosNotifyChannelAdmin::ConnectionAlreadyActive, CosNotifyChannelAdmin::NotConnected); + }; // TypedProxyPullConsumer + + interface TypedProxyPushSupplier : CosNotifyChannelAdmin::ProxySupplier, CosNotifyComm::PushSupplier { + void connect_typed_push_consumer (in CosTypedEventComm::TypedPushConsumer push_consumer) + raises (CosEventChannelAdmin::AlreadyConnected, CosEventChannelAdmin::TypeError); + + void suspend_connection() + raises (CosNotifyChannelAdmin::ConnectionAlreadyInactive, CosNotifyChannelAdmin::NotConnected); + + void resume_connection() + raises (CosNotifyChannelAdmin::ConnectionAlreadyActive, CosNotifyChannelAdmin::NotConnected); + }; // TypedProxyPushSupplier + + interface TypedConsumerAdmin : CosNotifyChannelAdmin::ConsumerAdmin, CosTypedEventChannelAdmin::TypedConsumerAdmin { + TypedProxyPullSupplier obtain_typed_notification_pull_supplier(in Key supported_interface, + out CosNotifyChannelAdmin::ProxyID proxy_id) + raises( CosTypedEventChannelAdmin::InterfaceNotSupported, CosNotifyChannelAdmin::AdminLimitExceeded ); + + TypedProxyPushSupplier obtain_typed_notification_push_supplier(in Key uses_interface, + out CosNotifyChannelAdmin::ProxyID proxy_id) + raises(CosTypedEventChannelAdmin::NoSuchImplementation, CosNotifyChannelAdmin::AdminLimitExceeded); + }; // TypedConsumerAdmin + + interface TypedSupplierAdmin : CosNotifyChannelAdmin::SupplierAdmin, CosTypedEventChannelAdmin::TypedSupplierAdmin { + TypedProxyPushConsumer obtain_typed_notification_push_consumer(in Key supported_interface, + out CosNotifyChannelAdmin::ProxyID proxy_id) + raises( CosTypedEventChannelAdmin::InterfaceNotSupported, CosNotifyChannelAdmin::AdminLimitExceeded); + TypedProxyPullConsumer obtain_typed_notification_pull_consumer(in Key uses_interface, + out CosNotifyChannelAdmin::ProxyID proxy_id ) + raises(CosTypedEventChannelAdmin::NoSuchImplementation, CosNotifyChannelAdmin::AdminLimitExceeded); + }; // TypedSupplierAdmin + + interface TypedEventChannel : CosNotification::QoSAdmin, CosNotification::AdminPropertiesAdmin, + CosTypedEventChannelAdmin::TypedEventChannel { + readonly attribute TypedEventChannelFactory MyFactory; + readonly attribute TypedConsumerAdmin default_consumer_admin; + readonly attribute TypedSupplierAdmin default_supplier_admin; + readonly attribute CosNotifyFilter::FilterFactory default_filter_factory; + + TypedConsumerAdmin new_for_typed_notification_consumers(in CosNotifyChannelAdmin::InterFilterGroupOperator op, + out CosNotifyChannelAdmin::AdminID id); + + TypedSupplierAdmin new_for_typed_notification_suppliers(in CosNotifyChannelAdmin::InterFilterGroupOperator op, + out CosNotifyChannelAdmin::AdminID id); + + TypedConsumerAdmin get_consumeradmin (in CosNotifyChannelAdmin::AdminID id ) + raises (CosNotifyChannelAdmin::AdminNotFound); + + TypedSupplierAdmin get_supplieradmin (in CosNotifyChannelAdmin::AdminID id) + raises (CosNotifyChannelAdmin::AdminNotFound); + + CosNotifyChannelAdmin::AdminIDSeq get_all_consumeradmins(); + + CosNotifyChannelAdmin::AdminIDSeq get_all_supplieradmins(); + }; // TypedEventChannel + + interface TypedEventChannelFactory { + TypedEventChannel create_typed_channel (in CosNotification::QoSProperties initial_QoS, + in CosNotification::AdminProperties initial_admin, + out CosNotifyChannelAdmin::ChannelID id) + raises( CosNotification::UnsupportedQoS, CosNotification::UnsupportedAdmin); + + CosNotifyChannelAdmin::ChannelIDSeq get_all_typed_channels(); + + TypedEventChannel get_typed_event_channel (in CosNotifyChannelAdmin::ChannelID id) + raises (CosNotifyChannelAdmin::ChannelNotFound); + }; // TypedEventChannelFactory +}; // CosTypedNotifyChannelAdmin + +#endif /* ifndef _COS_TYPED_NOTIFICATION_IDL_ */ diff --git a/lib/cosNotification/src/Makefile b/lib/cosNotification/src/Makefile new file mode 100644 index 0000000..637c633 --- /dev/null +++ b/lib/cosNotification/src/Makefile @@ -0,0 +1,369 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug -W +endif + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(COSNOTIFICATION_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/cosNotification-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + CosNotification_Common \ + CosNotifyChannelAdmin_ConsumerAdmin_impl \ + CosNotifyChannelAdmin_EventChannelFactory_impl \ + CosNotifyChannelAdmin_EventChannel_impl \ + CosNotifyChannelAdmin_SupplierAdmin_impl \ + CosNotifyFilter_Filter_impl \ + CosNotifyFilter_MappingFilter_impl \ + CosNotifyFilter_FilterFactory_impl \ + PullerConsumer_impl \ + PullerSupplier_impl \ + PusherConsumer_impl \ + PusherSupplier_impl \ + cosNotificationApp \ + cosNotification_Scanner \ + cosNotification_Filter \ + cosNotification_eventDB + +ERL_FILES = $(MODULES:%=%.erl) +HRL_FILES = \ + CosNotification_Definitions.hrl + +YECC_FILES = cosNotification_Grammar.yrl + +GEN_YECC_ERL_FILES = cosNotification_Grammar.erl + +GEN_YECC_HRL_FILES = + +GEN_NOTIFICATION_ERL_FILES = \ + oe_CosNotification.erl \ + CosNotification.erl \ + CosNotification_AdminPropertiesAdmin.erl \ + CosNotification_EventHeader.erl \ + CosNotification_EventType.erl \ + CosNotification_FixedEventHeader.erl \ + CosNotification_NamedPropertyRange.erl \ + CosNotification_Property.erl \ + CosNotification_PropertyError.erl \ + CosNotification_PropertyRange.erl \ + CosNotification_QoSAdmin.erl \ + CosNotification_StructuredEvent.erl \ + CosNotification_UnsupportedAdmin.erl \ + CosNotification_UnsupportedQoS.erl \ + CosNotification_EventBatch.erl \ + CosNotification_EventTypeSeq.erl \ + CosNotification_NamedPropertyRangeSeq.erl \ + CosNotification_PropertyErrorSeq.erl \ + CosNotification_PropertySeq.erl + +GEN_CHANNELADMIN_ERL_FILES = \ + oe_CosNotifyChannelAdmin.erl \ + CosNotifyChannelAdmin_AdminLimit.erl \ + CosNotifyChannelAdmin_AdminLimitExceeded.erl \ + CosNotifyChannelAdmin_AdminNotFound.erl \ + CosNotifyChannelAdmin_ChannelNotFound.erl \ + CosNotifyChannelAdmin_ConnectionAlreadyActive.erl \ + CosNotifyChannelAdmin_ConnectionAlreadyInactive.erl \ + CosNotifyChannelAdmin_ConsumerAdmin.erl \ + CosNotifyChannelAdmin_EventChannel.erl \ + CosNotifyChannelAdmin_EventChannelFactory.erl \ + CosNotifyChannelAdmin_NotConnected.erl \ + CosNotifyChannelAdmin_ProxyConsumer.erl \ + CosNotifyChannelAdmin_ProxyNotFound.erl \ + CosNotifyChannelAdmin_ProxyPullConsumer.erl \ + CosNotifyChannelAdmin_ProxyPullSupplier.erl \ + CosNotifyChannelAdmin_ProxyPushConsumer.erl \ + CosNotifyChannelAdmin_ProxyPushSupplier.erl \ + CosNotifyChannelAdmin_ProxySupplier.erl \ + CosNotifyChannelAdmin_SequenceProxyPullConsumer.erl \ + CosNotifyChannelAdmin_SequenceProxyPullSupplier.erl \ + CosNotifyChannelAdmin_SequenceProxyPushConsumer.erl \ + CosNotifyChannelAdmin_SequenceProxyPushSupplier.erl \ + CosNotifyChannelAdmin_StructuredProxyPullConsumer.erl \ + CosNotifyChannelAdmin_StructuredProxyPullSupplier.erl \ + CosNotifyChannelAdmin_StructuredProxyPushConsumer.erl \ + CosNotifyChannelAdmin_StructuredProxyPushSupplier.erl \ + CosNotifyChannelAdmin_SupplierAdmin.erl \ + CosNotifyChannelAdmin_AdminIDSeq.erl \ + CosNotifyChannelAdmin_ChannelIDSeq.erl \ + CosNotifyChannelAdmin_ProxyIDSeq.erl + +GEN_NOTIFYFILTER_ERL_FILES = \ + oe_CosNotifyFilter.erl \ + CosNotifyFilter_CallbackNotFound.erl \ + CosNotifyFilter_ConstraintExp.erl \ + CosNotifyFilter_ConstraintInfo.erl \ + CosNotifyFilter_ConstraintNotFound.erl \ + CosNotifyFilter_DuplicateConstraintID.erl \ + CosNotifyFilter_Filter.erl \ + CosNotifyFilter_FilterAdmin.erl \ + CosNotifyFilter_FilterFactory.erl \ + CosNotifyFilter_FilterNotFound.erl \ + CosNotifyFilter_InvalidConstraint.erl \ + CosNotifyFilter_InvalidGrammar.erl \ + CosNotifyFilter_InvalidValue.erl \ + CosNotifyFilter_MappingConstraintInfo.erl \ + CosNotifyFilter_MappingConstraintPair.erl \ + CosNotifyFilter_MappingFilter.erl \ + CosNotifyFilter_UnsupportedFilterableData.erl \ + CosNotifyFilter_CallbackIDSeq.erl \ + CosNotifyFilter_ConstraintExpSeq.erl \ + CosNotifyFilter_ConstraintIDSeq.erl \ + CosNotifyFilter_ConstraintInfoSeq.erl \ + CosNotifyFilter_FilterIDSeq.erl \ + CosNotifyFilter_MappingConstraintInfoSeq.erl \ + CosNotifyFilter_MappingConstraintPairSeq.erl + +GEN_NOTIFYCOMM_ERL_FILES = \ + oe_CosNotifyComm.erl \ + CosNotifyComm_InvalidEventType.erl \ + CosNotifyComm_NotifyPublish.erl \ + CosNotifyComm_NotifySubscribe.erl \ + CosNotifyComm_PullConsumer.erl \ + CosNotifyComm_PullSupplier.erl \ + CosNotifyComm_PushConsumer.erl \ + CosNotifyComm_PushSupplier.erl \ + CosNotifyComm_SequencePullConsumer.erl \ + CosNotifyComm_SequencePullSupplier.erl \ + CosNotifyComm_SequencePushConsumer.erl \ + CosNotifyComm_SequencePushSupplier.erl \ + CosNotifyComm_StructuredPullConsumer.erl \ + CosNotifyComm_StructuredPullSupplier.erl \ + CosNotifyComm_StructuredPushConsumer.erl \ + CosNotifyComm_StructuredPushSupplier.erl \ + +GEN_OE_EVENTCOMM_ERL_FILES = \ + oe_cosNotificationAppComm.erl \ + oe_CosNotificationComm_Event.erl + +EXTERNAL_INC_PATH = ../include + +GEN_NOTIFICATION_HRL_FILES = \ + oe_CosNotification.hrl \ + CosNotification.hrl \ + CosNotification_AdminPropertiesAdmin.hrl \ + CosNotification_QoSAdmin.hrl \ + +EXTERNAL_GEN_NOTIFICATION_HRL_FILES = \ + $(GEN_NOTIFICATION_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_CHANNELADMIN_HRL_FILES = \ + oe_CosNotifyChannelAdmin.hrl \ + CosNotifyChannelAdmin.hrl \ + CosNotifyChannelAdmin_ConsumerAdmin.hrl \ + CosNotifyChannelAdmin_EventChannel.hrl \ + CosNotifyChannelAdmin_EventChannelFactory.hrl \ + CosNotifyChannelAdmin_ProxyConsumer.hrl \ + CosNotifyChannelAdmin_ProxyPullConsumer.hrl \ + CosNotifyChannelAdmin_ProxyPullSupplier.hrl \ + CosNotifyChannelAdmin_ProxyPushConsumer.hrl \ + CosNotifyChannelAdmin_ProxyPushSupplier.hrl \ + CosNotifyChannelAdmin_ProxySupplier.hrl \ + CosNotifyChannelAdmin_SequenceProxyPullConsumer.hrl \ + CosNotifyChannelAdmin_SequenceProxyPullSupplier.hrl \ + CosNotifyChannelAdmin_SequenceProxyPushConsumer.hrl \ + CosNotifyChannelAdmin_SequenceProxyPushSupplier.hrl \ + CosNotifyChannelAdmin_StructuredProxyPullConsumer.hrl \ + CosNotifyChannelAdmin_StructuredProxyPullSupplier.hrl \ + CosNotifyChannelAdmin_StructuredProxyPushConsumer.hrl \ + CosNotifyChannelAdmin_StructuredProxyPushSupplier.hrl \ + CosNotifyChannelAdmin_SupplierAdmin.hrl \ + +EXTERNAL_GEN_CHANNELADMIN_HRL_FILES = \ + $(GEN_CHANNELADMIN_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_NOTIFYFILTER_HRL_FILES = \ + oe_CosNotifyFilter.hrl \ + CosNotifyFilter.hrl \ + CosNotifyFilter_Filter.hrl \ + CosNotifyFilter_FilterAdmin.hrl \ + CosNotifyFilter_FilterFactory.hrl \ + CosNotifyFilter_MappingFilter.hrl + +EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES = \ + $(GEN_NOTIFYFILTER_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_NOTIFYCOMM_HRL_FILES = \ + oe_CosNotifyComm.hrl \ + CosNotifyComm.hrl \ + CosNotifyComm_NotifyPublish.hrl \ + CosNotifyComm_NotifySubscribe.hrl \ + CosNotifyComm_PullConsumer.hrl \ + CosNotifyComm_PullSupplier.hrl \ + CosNotifyComm_PushConsumer.hrl \ + CosNotifyComm_PushSupplier.hrl \ + CosNotifyComm_SequencePullConsumer.hrl \ + CosNotifyComm_SequencePullSupplier.hrl \ + CosNotifyComm_SequencePushConsumer.hrl \ + CosNotifyComm_SequencePushSupplier.hrl \ + CosNotifyComm_StructuredPullConsumer.hrl \ + CosNotifyComm_StructuredPullSupplier.hrl \ + CosNotifyComm_StructuredPushConsumer.hrl \ + CosNotifyComm_StructuredPushSupplier.hrl \ + +EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES = \ + $(GEN_NOTIFYCOMM_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_OE_EVENTCOMM_HRL_FILES = \ + oe_cosNotificationAppComm.hrl \ + oe_CosNotificationComm.hrl \ + oe_CosNotificationComm_Event.hrl + +GEN_ERL_FILES = \ + $(GEN_NOTIFICATION_ERL_FILES) \ + $(GEN_OE_EVENTCOMM_ERL_FILES) \ + $(GEN_NOTIFYCOMM_ERL_FILES) \ + $(GEN_NOTIFYFILTER_ERL_FILES) \ + $(GEN_CHANNELADMIN_ERL_FILES) \ + $(GEN_YECC_ERL_FILES) + +GEN_HRL_FILES = \ + $(EXTERNAL_GEN_NOTIFICATION_HRL_FILES) \ + $(GEN_OE_EVENTCOMM_HRL_FILES) \ + $(EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES) \ + $(EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES) \ + $(EXTERNAL_GEN_CHANNELADMIN_HRL_FILES) \ + $(GEN_YECC_HRL_FILES) + + +GEN_FILES = \ + $(GEN_HRL_FILES) \ + $(GEN_ERL_FILES) + +TARGET_FILES = \ + $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +IDL_FILES = \ + CosNotification.idl \ + CosNotifyChannelAdmin.idl \ + CosNotifyFilter.idl \ + CosNotifyComm.idl \ + cosNotificationAppComm.idl + +APPUP_FILE = cosNotification.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + +APP_FILE = cosNotification.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosNotification/ebin \ + -pa $(ERL_TOP)/lib/ic/ebin\ + -pa $(ERL_TOP)/lib/orber/ebin \ + -pa $(ERL_TOP)/lib/cosEvent/ebin \ + -pa $(ERL_TOP)/lib/cosTime/ebin \ + -I$(ERL_TOP)/lib/cosEvent/src + +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -pa $(ERL_TOP)/lib/orber/include \ + -pa $(ERL_TOP)/lib/cosNotification/include \ + -pa $(ERL_TOP)/lib/cosEvent/include \ + -pa $(ERL_TOP)/lib/cosTime/include \ + -I$(ERL_TOP)/lib/orber/include \ + -I$(ERL_TOP)/lib/cosNotification/include \ + -I$(ERL_TOP)/lib/cosEvent/include \ + -I$(ERL_TOP)/lib/cosTime/include \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,"cosNotification_$(COSNOTIFICATION_VSN)"}' + +YECC_COMPILE_FLAGS = + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + +debug: + @${MAKE} TYPE=debug + +cleanb: + rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +clean: + rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +$(GEN_NOTIFICATION_ERL_FILES) $(EXTERNAL_GEN_NOTIFICATION_HRL_FILES): CosNotification.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotification.cfg"}' CosNotification.idl + mv $(GEN_NOTIFICATION_HRL_FILES) $(EXTERNAL_INC_PATH) +$(GEN_CHANNELADMIN_ERL_FILES) $(EXTERNAL_GEN_CHANNELADMIN_HRL_FILES): CosNotifyChannelAdmin.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyChannelAdmin.cfg"}' CosNotifyChannelAdmin.idl + mv $(GEN_CHANNELADMIN_HRL_FILES) $(EXTERNAL_INC_PATH) +$(GEN_NOTIFYFILTER_ERL_FILES) $(EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES): CosNotifyFilter.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyFilter.cfg"}' CosNotifyFilter.idl + mv $(GEN_NOTIFYFILTER_HRL_FILES) $(EXTERNAL_INC_PATH) +$(GEN_OE_EVENTCOMM_ERL_FILES) $(GEN_OE_EVENTCOMM_HRL_FILES): cosNotificationAppComm.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosNotificationComm.cfg"}' cosNotificationAppComm.idl +$(GEN_NOTIFYCOMM_ERL_FILES) $(EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES): CosNotifyComm.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyComm.cfg"}' CosNotifyComm.idl + mv $(GEN_NOTIFYCOMM_HRL_FILES) $(EXTERNAL_INC_PATH) +$(GEN_YECC_ERL_FILES) $(GEN_YECC_HRL_FILES): cosNotification_Grammar.yrl + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(YECC_FILES) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(IDL_FILES) $(YECC_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include + +release_docs_spec: diff --git a/lib/cosNotification/src/PullerConsumer_impl.erl b/lib/cosNotification/src/PullerConsumer_impl.erl new file mode 100644 index 0000000..fe6f9f8 --- /dev/null +++ b/lib/cosNotification/src/PullerConsumer_impl.erl @@ -0,0 +1,773 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : PullerConsumer_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('PullerConsumer_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% cosEvent files. +-include_lib("cosEvent/include/CosEventChannelAdmin.hrl"). +-include_lib("cosEvent/include/CosEventComm.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ProxyPullConsumer ------------- +-export([connect_any_pull_supplier/4]). + +%%----- CosNotifyChannelAdmin::SequenceProxyPullConsumer ----- +-export([connect_sequence_pull_supplier/4]). + +%%----- CosNotifyChannelAdmin::StructuredProxyPullConsumer --- +-export([connect_structured_pull_supplier/4]). + +%%----- CosNotifyChannelAdmin::*ProxyPullConsumer ------------ +-export([suspend_connection/3, + resume_connection/3]). + +%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer ---- +-export([obtain_subscription_types/4, + validate_event_qos/4]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifyPublish ------------ +-export([offer_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventComm::PullConsumer ------------- +-export([disconnect_pull_consumer/3]). + +%%----- Inherit from CosNotifyComm::SequencePullConsumer ---- +-export([disconnect_sequence_pull_consumer/3]). + +%%----- Inherit from CosNotifyComm::StructuredPullConsumer -- +-export([disconnect_structured_pull_consumer/3]). + +%%----- Inherit from CosEventChannelAdmin::ProxyPullConsumer +-export([connect_pull_supplier/4]). + + +%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier +-export(['_get_MyType'/3, + '_get_MyAdmin'/3]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myType, + myAdmin, + myAdminPid, + myChannel, + myFilters = [], + myOperator, + idCounter = 0, + client, + qosGlobal, + qosLocal, + suspended = false, + pullTimer, + pullInterval, + publishType = false, + etsR, + eventCounter = 0, + eventDB, + this}). + +%% Data structures constructors +-define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _PI, _MyOP, _GT, _GL, _TR), + #state{myType = _MyT, + myAdmin = _MyA, + myAdminPid = _MyAP, + myChannel = _Ch, + myOperator = _MyOP, + qosGlobal = _QS, + qosLocal = _LQS, + pullInterval = _PI, + etsR = ets:new(oe_ets, [set, protected]), + eventDB = cosNotification_eventDB:create_db(_LQS, _GT, _GL, _TR)}). + +%%-------------- Data structures selectors ----------------- +%% Attributes +-define(get_MyType(S), S#state.myType). +-define(get_MyAdmin(S), S#state.myAdmin). +-define(get_MyAdminPid(S), S#state.myAdminPid). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyOperator(S), S#state.myOperator). +%% Client Object +-define(get_Client(S), S#state.client). +%% QoS +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +%% Filters +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +%% Admin +-define(get_PullInterval(S), S#state.pullInterval). +-define(get_PullTimer(S), S#state.pullTimer). +-define(get_PacingInterval(S), round(?not_GetPacingInterval((S#state.qosLocal))/10000000)). +-define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))). +%% Publish +-define(get_AllPublish(S), lists:flatten(ets:match(S#state.etsR, + {'$1',publish}))). +-define(get_PublishType(S), S#state.publishType). +%% ID +-define(get_IdCounter(S), S#state.idCounter). +%% Event +-define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB)). +-define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M)). +-define(get_EventCounter(S), S#state.eventCounter). + +%%-------------- Data structures modifiers ----------------- +%% Client Object +-define(set_Client(S,D), S#state{client=D}). +-define(del_Client(S), S#state{client=undefined}). +-define(set_Suspended(S), S#state{client=true}). +-define(set_NotSuspended(S), S#state{client=false}). +-define(set_Unconnected(S), S#state{client=undefined}). +%% QoS +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +%% Filters +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_obj(lists:keydelete(I, 1, S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +%% Admin +-define(set_PullInterval(S,V), S#state{pullInterval=V}). +-define(set_PullTimer(S,T), S#state{pullTimer=T}). +%% Publish +-define(add_Publish(S,E), ets:insert(S#state.etsR, {E, publish})). +-define(del_Publish(S,E), ets:delete(S#state.etsR, E)). +-define(set_PublishType(S,T), S#state{publishType=T}). +%% ID +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). +%% Event +-define(add_Event(S,E), cosNotification_eventDB:add_event(S#state.eventDB, E)). +-define(update_EventDB(S,Q), S#state{eventDB= + cosNotification_eventDB:update(S#state.eventDB, Q)}). + +-define(set_EventCounter(S,V), S#state{eventCounter=V}). +-define(add_to_EventCounter(S,V),S#state{eventCounter=S#state.eventCounter+V}). +-define(reset_EventCounter(S), S#state{eventCounter=0}). +-define(increase_EventCounter(S),S#state{eventCounter=(S#state.eventCounter+1)}). +-define(decrease_EventCounter(S),S#state{eventCounter=S#state.eventCounter-1}). +-define(add_ToEventCounter(S,A), S#state{eventCounter=(S#state.eventCounter+A)}). +-define(sub_FromEventCounter(S,_A), S#state{eventCounter=(S#state.eventCounter-_A)}). +-define(set_EventCounterTo(S,V), S#state{eventCounter=V}). + +%%-------------- MISC ---------------------------------------- +-define(is_ANY(S), S#state.myType == 'PULL_ANY'). +-define(is_STRUCTURED(S), S#state.myType == 'PULL_STRUCTURED'). +-define(is_SEQUENCE(S), S#state.myType == 'PULL_SEQUENCE'). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). +-define(is_UnConnected(S), S#state.client == undefined). +-define(is_Connected(S), S#state.client =/= undefined). +-define(is_Suspended(S), S#state.suspended == true). +-define(is_NotSuspended(S), S#state.suspended == false). +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, Reason} when ?get_MyAdminPid(State) == Pid-> + ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', _Pid, _Reason} -> + ?DBG("PROXYPUSHSUPPLIER: ~p TERMINATED.~n",[_Reason]), + {noreply, State}; + pull -> + try_pull_events(State); + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, Options, Operator]) -> + process_flag(trap_exit, true), + Secs = timer:seconds('CosNotification_Common':get_option(pullInterval, + Options, + ?not_DEFAULT_SETTINGS)), + GCTime = 'CosNotification_Common':get_option(gcTime, Options, + ?not_DEFAULT_SETTINGS), + GCLimit = 'CosNotification_Common':get_option(gcLimit, Options, + ?not_DEFAULT_SETTINGS), + TimeRef = 'CosNotification_Common':get_option(timeService, Options, + ?not_DEFAULT_SETTINGS), + timer:start(), + {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, InitQoS, + LQS, MyChannel, Secs, Operator, GCTime, + GCLimit, TimeRef)}. + +terminate(_Reason, State) when ?is_UnConnected(State) -> + %% We are currently not connected to a client. Hence, no need for sending + %% a disconnect request. + stop_timer(State), + ok; +terminate(_Reason, State) when ?is_ANY(State) -> + stop_timer(State), + 'CosNotification_Common':disconnect('CosEventComm_PullSupplier', + disconnect_pull_supplier, + ?get_Client(State)); +terminate(_Reason, State) when ?is_SEQUENCE(State) -> + stop_timer(State), + 'CosNotification_Common':disconnect('CosNotifyComm_SequencePullSupplier', + disconnect_sequence_pull_supplier, + ?get_Client(State)); +terminate(_Reason, State) when ?is_STRUCTURED(State) -> + stop_timer(State), + 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPullSupplier', + disconnect_structured_pull_supplier, + ?get_Client(State)). + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ProxyConsumer attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyType' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyType'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyType(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyAdmin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyAdmin(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----- CosEventChannelAdmin::ProxyPullConsumer ------------- +%%----------------------------------------------------------% +%% function : connect_pull_supplier +%% Arguments: Client - CosEventComm::PullSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_pull_supplier(OE_THIS, OE_FROM, State, Client) -> + connect_any_pull_supplier(OE_THIS, OE_FROM, State, Client). + +%%----- CosNotifyChannelAdmin::ProxyPullConsumer ------------ +%%----------------------------------------------------------% +%% function : connect_any_pull_supplier +%% Arguments: Client - CosEventComm::PullSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_any_pull_supplier(OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) -> + 'CosNotification_Common':type_check(Client, 'CosEventComm_PullSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + NewState = start_timer(State), + {reply, ok, NewState#state{client = Client, this = OE_THIS}} + end; +connect_any_pull_supplier(_, _, _,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::SequenceProxyPullConsumer ---- +%%----------------------------------------------------------% +%% function : connect_sequence_pull_supplier +%% Arguments: Client - CosNotifyComm::SequencePullSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%%----------------------------------------------------------- +connect_sequence_pull_supplier(OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) -> + 'CosNotification_Common':type_check(Client, 'CosNotifyComm_SequencePullSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + NewState = start_timer(State), + {reply, ok, NewState#state{client = Client, this = OE_THIS}} + end; +connect_sequence_pull_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::StructuredProxyPullConsumer -- +%%----------------------------------------------------------% +%% function : connect_structured_pull_supplier +%% Arguments: Client - CosNotifyComm::StructuredPullSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%%----------------------------------------------------------- +connect_structured_pull_supplier(OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) -> + 'CosNotification_Common':type_check(Client, 'CosNotifyComm_StructuredPullSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + NewState = start_timer(State), + {reply, ok, NewState#state{client = Client, this = OE_THIS}} + end; +connect_structured_pull_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::*ProxyPullConsumer ----------- +%%----------------------------------------------------------% +%% function : suspend_connection +%% Arguments: +%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyInactive'{}} | +%% {'EXCEPTION', #'NotConneced'{}} +%%----------------------------------------------------------- +suspend_connection(_OE_THIS, _OE_FROM, State) when ?is_Connected(State) -> + if + ?is_Suspended(State) -> + corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}); + true -> + stop_timer(State), + {reply, ok, ?set_Suspended(State)} + end; +suspend_connection(_, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}). + +%%----------------------------------------------------------% +%% function : resume_connection +%% Arguments: +%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyActive'{}} | +%% {'EXCEPTION', #'NotConneced'{}} +%%----------------------------------------------------------- +resume_connection(_OE_THIS, _OE_FROM, State) when ?is_Connected(State) -> + if + ?is_NotSuspended(State) -> + corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyActive'{}); + true -> + NewState = start_timer(State), + {reply, ok, ?set_NotSuspended(NewState)} + end; +resume_connection(_, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}). + +%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer --- +%%----------------------------------------------------------% +%% function : obtain_subscription_types +%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin) +%% Returns : CosNotification::EventTypeSeq +%%----------------------------------------------------------- +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') -> + {reply, ?get_AllPublish(State), ?set_PublishType(State, false)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') -> + {reply, ?get_AllPublish(State), ?set_PublishType(State, true)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') -> + {reply, [], ?set_PublishType(State, false)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') -> + {reply, [], ?set_PublishType(State, true)}; +obtain_subscription_types(_,_,_,What) -> + orber:dbg("[~p] PullerConsumer:obtain_subscription_types(~p);~n" + "Incorrect enumerant", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : validate_event_qos +%% Arguments: RequiredQoS - CosNotification::QoSProperties +%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}} +%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out) +%%----------------------------------------------------------- +validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) -> + AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS, + ?get_LocalQoS(State)), + {reply, {ok, AvilableQoS}, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + NewState = ?update_EventDB(State, LQS), + {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifyPublish ----------- +%%----------------------------------------------------------% +%% function : offer_change +%% Arguments: Added - #'CosNotification_EventType'{} +%% Removed - #'CosNotification_EventType'{} +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}} +%%----------------------------------------------------------- +offer_change(_OE_THIS, _OE_FROM, State, Added, Removed) -> + cosNotification_Filter:validate_types(Added), + cosNotification_Filter:validate_types(Removed), + %% On this "side" we don't really care about which + %% type of events the client will supply. + %% Perhaps, later on, if we want to check this against Filters + %% associated with this object we may change this approach, i.e., if + %% the filter will not allow passing certain event types. But the + %% user should see to that that situation never occurs. It would add + %% extra overhead. Also see PusherSupplier- and PullerSuppler- + %% 'subscription_change'. + update_publish(add, State, Added), + update_publish(remove, State, Removed), + case ?get_PublishType(State) of + true -> + %% Perhaps we should handle exception here?! + %% Probably not. Better to stay "on-line". + catch 'CosNotifyComm_NotifySubscribe': + subscription_change(?get_Client(State), Added, Removed), + ok; + _-> + ok + end, + {reply, ok, State}. + +update_publish(_, _, [])-> + ok; +update_publish(add, State, [H|T]) -> + ?add_Publish(State, H), + update_publish(add, State, T); +update_publish(remove, State, [H|T]) -> + ?del_Publish(State, H), + update_publish(remove, State, T). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] PullerConsumer:remove_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] PullerConsumer:get_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventComm::PullConsumer ------------- +%%----------------------------------------------------------% +%% function : disconnect_pull_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_pull_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----- Inherit from CosNotifyComm::SequencePullConsumer ---- +%%----------------------------------------------------------% +%% function : disconnect_sequence_pull_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_sequence_pull_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----- Inherit from CosNotifyComm::StructuredPullConsumer ---- +%%----------------------------------------------------------% +%% function : disconnect_structured_pull_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_structured_pull_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj({value, {_, Obj}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(What, _) -> + orber:dbg("[~p] PullerConsumer:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single object. +%% The list don not differ, i.e., no filter removed, raise exception. +delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_obj(List,_) -> List. + +%% Start timer which send a message each time we should pull for new events. +start_timer(State) -> + case catch timer:send_interval(?get_PullInterval(State), pull) of + {ok,PullTRef} -> + ?DBG("PULL CONSUMER STARTED PULL TIMER ~p~n", + [?get_PullInterval(State)]), + ?set_PullTimer(State, PullTRef); + What -> + orber:dbg("[~p] PullerConsumer:start_timer();~n" + "Unable to invoke timer:send_interval/2: ~p", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. +stop_timer(State) -> + ?DBG("PULL CONSUMER STOPPED TIMER~n",[]), + timer:cancel(?get_PullTimer(State)). + +%% Try pull event(s); which method is determined by which type this proxy is. +try_pull_events(State) when ?is_ANY(State) -> + case catch 'CosEventComm_PullSupplier':try_pull(?get_Client(State)) of + {_,false} -> + {noreply, State}; + {Event, true} -> + case ?not_isConvertedStructured(Event) of + true -> + forward(seq, State, + cosNotification_eventDB:filter_events([any:get_value(Event)], + ?get_AllFilter(State))); + _ -> + forward(any, State, + cosNotification_eventDB:filter_events([Event], + ?get_AllFilter(State))) + end; + _-> + {noreply, State} + end; +try_pull_events(State) when ?is_SEQUENCE(State) -> + case catch 'CosNotifyComm_SequencePullSupplier': + try_pull_structured_events(?get_Client(State), ?get_BatchLimit(State)) of + {_,false} -> + {noreply, State}; + {EventSeq, true} -> + %% We cannot convert parts of the sequence to any, event though they + %% are converted from any to structured. Would be 'impossible' to send. + forward(seq, State, + cosNotification_eventDB:filter_events(EventSeq, + ?get_AllFilter(State))); + _-> + {noreply, State} + end; +try_pull_events(State) when ?is_STRUCTURED(State) -> + case catch 'CosNotifyComm_StructuredPullSupplier': + try_pull_structured_event(?get_Client(State)) of + {_,false} -> + {noreply, State}; + {Event, true} when ?not_isConvertedAny(Event) -> + forward(any, State, + cosNotification_eventDB:filter_events([Event#'CosNotification_StructuredEvent'.remainder_of_body], + ?get_AllFilter(State))); + {Event, true} -> + forward(seq, State, + cosNotification_eventDB:filter_events([Event], + ?get_AllFilter(State))); + _-> + {noreply, State} + end. + + + +%% Forward events +forward(_, State, {[], _}) when ?is_ANDOP(State) -> + %% Did not pass filtering. Since AND no need to pass on. + {noreply, State}; +forward(Type, State, {[], Failed}) -> + %% Did not pass filtering, but since OR it may pass Admin filters, hence, pass + %% on to Admin + forward(Type, State, Failed, ?get_MyAdmin(State), 'MATCH'); +forward(Type, State, {Passed, _}) when ?is_ANDOP(State) -> + %% Did pass filtering, but since AND we must pass it to Admin to check against + %% its Filters. Just ignore the ones that failed. + forward(Type, State, Passed, ?get_MyAdmin(State), 'MATCH'); +forward(Type, State, {Passed, []}) -> + %% Did pass filtering, and since OR we can pass it to the Channel directly. + forward(Type, State, Passed, ?get_MyChannel(State), 'MATCHED'); +forward(Type, State, {Passed, Failed}) -> + %% Some passed filtering, and since OR we can pass the ones that passed directly + %% to the channel and the other ones via the admin. + forward(Type, State, Passed, ?get_MyChannel(State), 'MATCHED'), + forward(Type, State, Failed, ?get_MyAdmin(State), 'MATCH'). + +forward(any, State, [Event], SendTo, Status) -> + case catch oe_CosNotificationComm_Event:callAny(SendTo, Event, Status) of + ok -> + ?DBG("PROXY FORWARD ANY: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, R}]), + {stop, normal, State} + end; +forward(seq, State, Event, SendTo, Status) -> + case catch oe_CosNotificationComm_Event:callSeq(SendTo, Event, Status) of + ok -> + ?DBG("PROXY FORWARD SEQUENCE: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] PullerConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, R}]), + {stop, normal, State} + end. + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/PullerSupplier_impl.erl b/lib/cosNotification/src/PullerSupplier_impl.erl new file mode 100644 index 0000000..9f12f9c --- /dev/null +++ b/lib/cosNotification/src/PullerSupplier_impl.erl @@ -0,0 +1,914 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : PullerSupplier_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('PullerSupplier_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% cosEvent files. +-include_lib("cosEvent/include/CosEventChannelAdmin.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ProxyPullSupplier ------------- +-export([connect_any_pull_consumer/4]). + +%%----- CosNotifyChannelAdmin::SequenceProxyPullSupplier ----- +-export([connect_sequence_pull_consumer/4]). + +%%----- CosNotifyChannelAdmin::StructuredProxyPullSupplier --- +-export([connect_structured_pull_consumer/4]). + +%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier ---- +-export([obtain_offered_types/4, + validate_event_qos/4]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifySubscribe ---------- +-export([subscription_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventComm::PullSupplier ------------- +-export([pull/3, + try_pull/3, + disconnect_pull_supplier/3]). + +%%----- Inherit from CosNotifyComm::SequencePullSupplier -- +-export([pull_structured_events/4, + try_pull_structured_events/4, + disconnect_sequence_pull_supplier/3]). + +%%----- Inherit from CosNotifyComm::StructuredPullSupplier -- +-export([pull_structured_event/3, + try_pull_structured_event/3, + disconnect_structured_pull_supplier/3]). + +%%----- Inherit from CosEventChannelAdmin::ProxyPullSupplier +-export([connect_pull_consumer/4]). + +%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier +-export(['_get_MyType'/3, + '_get_MyAdmin'/3, + '_get_priority_filter'/3, + '_set_priority_filter'/4, + '_get_lifetime_filter'/3, + '_set_lifetime_filter'/4]). + +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm -------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myType, + myAdmin, + myAdminPid, + myChannel, + myFilters = [], + myOperator, + idCounter = 0, + prioFil, + lifetFil, + client, + qosGlobal, + qosLocal, + pacingTimer, + respondTo, + subscribeType = false, + subscribeData = true, + etsR, + eventDB}). + +%% Data structures constructors +-define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _MyOp, _GT, _GL, _TR), + #state{myType = _MyT, + myAdmin = _MyA, + myAdminPid= _MyAP, + myChannel = _Ch, + myOperator= _MyOp, + qosGlobal = _QS, + qosLocal = _LQS, + etsR = ets:new(oe_ets, [set, protected]), + eventDB = cosNotification_eventDB:create_db(_LQS, _GT, _GL, _TR)}). + + +%% Data structures selectors +%% Attributes +-define(get_MyType(S), S#state.myType). +-define(get_MyAdmin(S), S#state.myAdmin). +-define(get_MyAdminPid(S), S#state.myAdmin). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyOperator(S), S#state.myOperator). +-define(get_PrioFil(S), S#state.prioFil). +-define(get_LifeTFil(S), S#state.lifetFil). +%% Client Object +-define(get_Client(S), S#state.client). +%% QoS +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +%% Filters +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +%% Event +-define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB)). +-define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M)). +-define(get_RespondTo(S), S#state.respondTo). +%% Amin +-define(get_PacingTimer(S), S#state.pacingTimer). +-define(get_PacingInterval(S), round(?not_GetPacingInterval((S#state.qosLocal))/10000000)). +-define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))). +%% Subscribe +-define(get_AllSubscribe(S), lists:flatten(ets:match(S#state.etsR, + {'$1',subscribe}))). +-define(get_SubscribeType(S), S#state.subscribeType). +-define(get_SubscribeData(S), S#state.subscribeData). +%% ID +-define(get_IdCounter(S), S#state.idCounter). +-define(get_SubscribeDB(S), S#state.etsR). + +%% Data structures modifiers +%% Attributes +-define(set_PrioFil(S,D), S#state{prioFil=D}). +-define(set_LifeTFil(S,D), S#state{lifetFil=D}). +%% Client Object +-define(set_Client(S,D), S#state{client=D}). +-define(del_Client(S), S#state{client=undefined}). +%% QoS +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +-define(update_EventDB(S,Q), S#state{eventDB= + cosNotification_eventDB:update(S#state.eventDB, Q)}). +%% Filters +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_obj(lists:keydelete(I, 1, S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +-define(set_Unconnected(S), S#state{client=undefined}). +-define(reset_RespondTo(S), S#state{respondTo=undefined}). +-define(set_RespondTo(S,F), S#state{respondTo=F}). +%% Event +-define(add_Event(S,E), catch cosNotification_eventDB: + add_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil)). +-define(addAndGet_Event(S,E), catch cosNotification_eventDB: + add_and_get_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil)). +%% Admin +-define(set_PacingTimer(S,T), S#state{pacingTimer=T}). +%% Subscribe +-define(add_Subscribe(S,E), ets:insert(S#state.etsR, {E, subscribe})). +-define(del_Subscribe(S,E), ets:delete(S#state.etsR, E)). +-define(set_SubscribeType(S,T), S#state{subscribeType=T}). +-define(set_SubscribeData(S,D), S#state{subscribeData=D}). +%% ID +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). + +%% MISC +-define(is_ANY(S), S#state.myType == 'PULL_ANY'). +-define(is_STRUCTURED(S), S#state.myType == 'PULL_STRUCTURED'). +-define(is_SEQUENCE(S), S#state.myType == 'PULL_SEQUENCE'). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). +-define(is_UnConnected(S), S#state.client == undefined). +-define(is_Connected(S), S#state.client =/= undefined). +-define(is_Waiting(S), S#state.respondTo =/= undefined). +-define(is_SubscribedFor(S,K), ets:lookup(S#state.etsR, K) =/= []). +-define(is_BatchLimitReached(S,M), cosNotification_eventDB: + status(S#state.eventDB, {batchLimit, + ?not_GetMaximumBatchSize((S#state.qosLocal)), M})). + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, Reason} when ?get_MyAdminPid(State)==Pid-> + ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', _Pid, _Reason} -> + ?DBG("PROXYPUSHSUPPLIER: ~p TERMINATED.~n",[_Reason]), + {noreply, State}; + {pacing, TS} when ?is_Waiting(State) -> + case ?get_PacingTimer(State) of + {_, TS} -> + ?DBG("PULL SUPPLIER PACING LIMIT REACHED~n",[]), + {RespondTo, Max} = ?get_RespondTo(State), + {EventSeq, _} = ?get_Events(State, Max), + corba:reply(RespondTo, EventSeq), + {noreply, ?reset_RespondTo(State)}; + _ -> + %% Must have been an old timer event, i.e., we reached the + %% Batch Limit before Pace limit and we were not able + %% to stop the timer before it triggered an event. + ?DBG("PULL SUPPLIER OLD PACING LIMIT REACHED~n",[]), + {noreply, State} + end; + {pacing, _} -> + ?DBG("PULL SUPPLIER PACING LIMIT REACHED BUT NO CLIENT; IMPOSSIBLE!!!~n",[]), + {noreply, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, Options, Operator]) -> + process_flag(trap_exit, true), + GCTime = 'CosNotification_Common':get_option(gcTime, Options, + ?not_DEFAULT_SETTINGS), + GCLimit = 'CosNotification_Common':get_option(gcLimit, Options, + ?not_DEFAULT_SETTINGS), + TimeRef = 'CosNotification_Common':get_option(timeService, Options, + ?not_DEFAULT_SETTINGS), + {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, + Operator, GCTime, GCLimit, TimeRef)}. + +terminate(_Reason, State) when ?is_UnConnected(State) -> + ok; +terminate(_Reason, State) -> + Client = ?get_Client(State), + case catch corba_object:is_nil(Client) of + false when ?is_ANY(State) -> + 'CosNotification_Common':disconnect('CosEventComm_PullConsumer', + disconnect_pull_consumer, + Client); + false when ?is_SEQUENCE(State) -> + 'CosNotification_Common':disconnect('CosNotifyComm_SequencePullConsumer', + disconnect_sequence_pull_consumer, + Client); + false when ?is_STRUCTURED(State) -> + 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPullConsumer', + disconnect_structured_pull_consumer, + Client); + _ -> + ok + end. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ProxySupplier attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyType' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyType'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyType(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyAdmin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyAdmin(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_*et_priority_filter' +%% Type : read/write +%% Returns : +%%----------------------------------------------------------- +'_get_priority_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PrioFil(State), State}. +'_set_priority_filter'(_OE_THIS, _OE_FROM, State, PrioF) -> + {reply, ok, ?set_PrioFil(State, PrioF)}. + + +%%----------------------------------------------------------% +%% Attribute: '_*et_lifetime_filter' +%% Type : read/write +%% Returns : +%%----------------------------------------------------------- +'_get_lifetime_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_LifeTFil(State), State}. +'_set_lifetime_filter'(_OE_THIS, _OE_FROM, State, LifeTF) -> + {reply, ok, ?set_LifeTFil(State, LifeTF)}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----- CosEventChannelAdmin::ProxyPullSupplier ------------- +%%----------------------------------------------------------% +%% function : connect_pull_consumer +%% Arguments: Client - CosEventComm::PullConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_pull_consumer(OE_THIS, OE_FROM, State, Client) -> + connect_any_pull_consumer(OE_THIS, OE_FROM, State, Client). + +%%----- CosNotifyChannelAdmin::ProxyPullSupplier ------------ +%%----------------------------------------------------------% +%% function : connect_any_pull_consumer +%% Arguments: Client - CosEventComm::PullConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_any_pull_consumer(_OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) -> + ?not_TypeCheck(Client, 'CosEventComm_PullConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_any_pull_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::SequenceProxyPullSupplier ---- +%%----------------------------------------------------------% +%% function : connect_sequence_pull_consumer +%% Arguments: Client - CosNotifyComm::SequencePullConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%%----------------------------------------------------------- +connect_sequence_pull_consumer(_OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) -> + ?not_TypeCheck(Client, 'CosNotifyComm_SequencePullConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_sequence_pull_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::StructuredProxyPullSupplier -- +%%----------------------------------------------------------% +%% function : connect_structured_pull_consumer +%% Arguments: Client - CosNotifyComm::StructuredPullConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} | +%% {'EXCEPTION', #'BAD_OPERATION'{}} +%%----------------------------------------------------------- +connect_structured_pull_consumer(_OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) -> + ?not_TypeCheck(Client, 'CosNotifyComm_StructuredPullConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_structured_pull_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier --- +%%----------------------------------------------------------% +%% function : obtain_offered_types +%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin) +%% Returns : CosNotification::EventTypeSeq +%%----------------------------------------------------------- +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') -> + {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, false)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') -> + {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, true)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') -> + {reply, [], ?set_SubscribeType(State, false)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') -> + {reply, [], ?set_SubscribeType(State, true)}; +obtain_offered_types(_,_,_,What) -> + orber:dbg("[~p] PullerSupplier:obtain_offered_types(~p);~n" + "Incorrect enumerant", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : validate_event_qos +%% Arguments: RequiredQoS - CosNotification::QoSProperties +%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}} +%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out) +%%----------------------------------------------------------- +validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) -> + AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS, + ?get_LocalQoS(State)), + {reply, {ok, AvilableQoS}, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + NewState = ?update_EventDB(State, LQS), + {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifySubscribe --------- +%%----------------------------------------------------------% +%% function : subscription_change +%% Arguments: Added - Removed - CosNotification::EventTypeSeq +%% Returns : ok +%%----------------------------------------------------------- +subscription_change(_OE_THIS, _OE_FROM, State, Added, Removed) -> + cosNotification_Filter:validate_types(Added), + cosNotification_Filter:validate_types(Removed), + %% On this "side", we care about which type of events the client + %% will require, since the client (or an agent) clearly stated + %% that it's only interested in these types of events. + %% Also see PusherConsumer- and PullerConsumer-'offer_change'. + update_subscribe(remove, State, Removed), + CurrentSub = ?get_AllSubscribe(State), + NewState = + case cosNotification_Filter:check_types(Added++CurrentSub) of + true -> + %% Types supplied does in some way cause all events to be valid. + %% Smart? Would have been better to not supply any at all. + ?set_SubscribeData(State, true); + {ok, Which, WC} -> + ?set_SubscribeData(State, {Which, WC}) + end, + update_subscribe(add, NewState, Added), + case ?get_SubscribeType(NewState) of + true -> + %% Perhaps we should handle exception here?! + %% Probably not. Better to stay "on-line". + catch 'CosNotifyComm_NotifyPublish': + offer_change(?get_Client(NewState), Added, Removed), + ok; + _-> + ok + end, + {reply, ok, NewState}. + +update_subscribe(_, _, [])-> + ok; +update_subscribe(add, State, [H|T]) -> + ?add_Subscribe(State, H), + update_subscribe(add, State, T); +update_subscribe(remove, State, [H|T]) -> + ?del_Subscribe(State, H), + update_subscribe(remove, State, T). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] PullerSupplier:remove_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] PullerSupplier:get_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventComm::PullSupplier ------------- +%%----------------------------------------------------------% +%% function : disconnect_pull_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_pull_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : pull +%% Arguments: - +%% Returns : any - CORBA::ANY +%%----------------------------------------------------------- +pull(_OE_THIS, OE_FROM, State) when ?is_ANY(State) -> + case ?get_Event(State) of + {[], _} -> + {noreply, ?set_RespondTo(State, OE_FROM)}; + {Event,_} -> + {reply, Event, State} + end; +pull(_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : try_pull +%% Arguments: - +%% Returns : any - CORBA::ANY +%% HasEvent - boolean (out-type) +%%----------------------------------------------------------- +try_pull(_OE_THIS, _OE_FROM, State) when ?is_ANY(State) -> + case ?get_Event(State) of + {[], _} -> + {reply, {any:create(orber_tc:null(), null), false}, State}; + {Event, Bool} -> + {reply, {Event, Bool}, State} + end; +try_pull(_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyComm::SequencePullSupplier ---- +%%----------------------------------------------------------% +%% function : disconnect_sequence_pull_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_sequence_pull_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : pull_structured_events +%% Arguments: Max - long() +%% Returns : [StructuredEvent, ..] +%%----------------------------------------------------------- +pull_structured_events(_OE_THIS, OE_FROM, State, Max) when ?is_SEQUENCE(State) -> + case ?is_BatchLimitReached(State, Max) of + true -> + %% This test is not fool-proof; if Events have been stored + %% using StartTime they will still be there but we cannot + %% deliver them anyway. To solve this "problem" would cost! + %% Hence, since it works fine otherwise it will do. + case ?get_Events(State, Max) of + {[], false} -> + NewState = start_timer(State), + {noreply, ?set_RespondTo(NewState, {OE_FROM, Max})}; + {Event,_} -> + {reply, Event, State} + end; + _-> + NewState = start_timer(State), + {noreply, ?set_RespondTo(NewState, {OE_FROM, Max})} + end; +pull_structured_events(_,_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : try_pull_structured_events +%% Arguments: Max - long() +%% Returns : [StructuredEvent, ..] +%% HasEvent - Boolean() +%%----------------------------------------------------------- +try_pull_structured_events(_OE_THIS, _OE_FROM, State, Max) when ?is_SEQUENCE(State) -> + {reply, ?get_Events(State, Max), State}; +try_pull_structured_events(_,_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyComm::StructuredPullSupplier -- +%%----------------------------------------------------------% +%% function : disconnect_structured_pull_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_structured_pull_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : pull_structured_event +%% Arguments: - +%% Returns : +%%----------------------------------------------------------- +pull_structured_event(_OE_THIS, OE_FROM, State) when ?is_STRUCTURED(State) -> + case ?get_Event(State) of + {[], _} -> + {noreply, ?set_RespondTo(State, OE_FROM)}; + {Event,_} -> + {reply, Event, State} + end; +pull_structured_event(_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : try_pull_structured_event +%% Arguments: - +%% Returns : +%%----------------------------------------------------------- +try_pull_structured_event(_OE_THIS, _OE_FROM, State) when ?is_STRUCTURED(State) -> + case ?get_Event(State) of + {[], _} -> + {reply, + {?not_CreateSE("","","",[],[],any:create(orber_tc:null(), null)), false}, + State}; + {Event, Bool} -> + {reply, {Event, Bool}, State} + end; +try_pull_structured_event(_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj({value, {_, Obj}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(_, _) -> corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single object. +%% The list do not differ, i.e., no filter removed, raise exception. +delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_obj(List,_) -> List. + + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, EventsIn, Status) -> + %% We should do something here, i.e., see what QoS this Object offers and + %% act accordingly. + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventsIn, + ?get_AllFilter(State), + ?get_SubscribeDB(State), + Status) of + {[], _} -> + ?DBG("PROXY NOSUBSCRIPTION SEQUENCE/STRUCTURED: ~p~n",[EventsIn]), + {noreply, State}; + %% Just one event and we got a client waiting => there is no need to store + %% the event, just transform it and pass it on. + {[Event], _} when ?is_ANY(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED SEQUENCE[1]==>ANY: ~p~n",[Event]), + AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event), + case ?addAndGet_Event(State, AnyEvent) of + {[], _} -> + ?DBG("PROXY RECEIVED UNDELIVERABLE SEQUENCE[1]: ~p~n", + [Event]), + %% Cannot deliver the event at the moment; perhaps Starttime + %% set or Deadline passed. + {noreply, State}; + {PossiblyOtherEvent, _} -> + ?DBG("PROXY RECEIVED SEQUENCE[1] ~p; DELIVER: ~p~n", + [Event, PossiblyOtherEvent]), + corba:reply(?get_RespondTo(State), PossiblyOtherEvent), + {noreply, ?reset_RespondTo(State)} + end; + {[Event],_} when ?is_STRUCTURED(State), ?is_Waiting(State) -> + case ?addAndGet_Event(State, Event) of + {[], _} -> + ?DBG("PROXY RECEIVED UNDELIVERABLE SEQUENCE[1]: ~p~n", + [Event]), + %% Cannot deliver the event at the moment; perhaps Starttime + %% set or Deadline passed. + {noreply, State}; + {PossiblyOtherEvent, _} -> + ?DBG("PROXY RECEIVED SEQUENCE[1] ~p; DELIVER: ~p~n", + [Event, PossiblyOtherEvent]), + corba:reply(?get_RespondTo(State), PossiblyOtherEvent), + {noreply, ?reset_RespondTo(State)} + end; + %% A sequence of events => store them and extract the first (according to QoS) + %% event and forward it. + {Events,_} when ?is_ANY(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED SEQUENCE==>ANY: ~p~n",[Events]), + store_events(State, Events), + case ?get_Event(State) of + {[], _} -> + {noreply, State}; + {AnyEvent, _} -> + corba:reply(?get_RespondTo(State), AnyEvent), + {noreply, ?reset_RespondTo(State)} + end; + {Events, _} when ?is_STRUCTURED(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]), + store_events(State, Events), + case ?get_Event(State) of + {[], _} -> + {noreply, State}; + {_StrEvent, _} -> + corba:reply(?get_RespondTo(State), Events), + {noreply, ?reset_RespondTo(State)} + end; + {Events, _} when ?is_SEQUENCE(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]), + %% Store them first and extract Max events in QoS order. + store_events(State, Events), + {RespondTo, Max} = ?get_RespondTo(State), + case ?is_BatchLimitReached(State, Max) of + true -> + {EventSeq, _} = ?get_Events(State, Max), + corba:reply(RespondTo, EventSeq), + stop_timer(State), + {noreply, ?reset_RespondTo(State)}; + _-> + {noreply, State} + end; + %% No client waiting. Store the event(s). + {Events, _} -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]), + store_events(State, Events), + {noreply, State} + end. + +store_events(_State, []) -> + ok; +store_events(State, [Event|Rest]) when ?is_ANY(State) -> + AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event), + ?add_Event(State,AnyEvent), + store_events(State, Rest); +store_events(State, [Event|Rest]) -> + ?add_Event(State,Event), + store_events(State, Rest). + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, EventIn, Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventIn, + ?get_AllFilter(State), + ?get_SubscribeDB(State), + Status) of + {[],_} -> + ?DBG("PROXY NOSUBSCRIPTION ANY: ~p~n",[EventIn]), + {noreply, State}; + {Event,_} when ?is_ANY(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED ANY: ~p~n",[Event]), + case ?addAndGet_Event(State, Event) of + {[],_} -> + %% Unable to deliver the event (Starttime, Deadline etc). + {noreply, State}; + {MaybeOtherEvent , _} -> + corba:reply(?get_RespondTo(State), MaybeOtherEvent), + {noreply, ?reset_RespondTo(State)} + end; + {Event,_} when ?is_ANY(State) -> + ?DBG("PROXY RECEIVED ANY: ~p~n",[Event]), + ?add_Event(State,Event), + {noreply, State}; + {Event,_} when ?is_STRUCTURED(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED ANY==>STRUCTURED: ~p~n",[Event]), + case ?addAndGet_Event(State, ?not_CreateSE("","%ANY","",[],[],Event)) of + {[],_} -> + %% Unable to deliver the event (Starttime, Deadline etc). + {noreply, State}; + {MaybeOtherEvent , _} -> + corba:reply(?get_RespondTo(State), MaybeOtherEvent), + {noreply, ?reset_RespondTo(State)} + end; + {Event,_} when ?is_SEQUENCE(State), ?is_Waiting(State) -> + ?DBG("PROXY RECEIVED ANY==>SEQUENCE[1]: ~p~n",[Event]), + ?add_Event(State,?not_CreateSE("","%ANY","",[],[],Event)), + {RespondTo, Max} = ?get_RespondTo(State), + case ?is_BatchLimitReached(State, Max) of + true -> + {EventSeq, _} = ?get_Events(State, Max), + corba:reply(RespondTo, EventSeq), + stop_timer(State), + {noreply, ?reset_RespondTo(State)}; + _ -> + {noreply, State} + end; + {Event,_} -> + ?DBG("PROXY RECEIVED ANY==>STRUCTURED/SEQUENCE: ~p~n",[Event]), + ?add_Event(State,?not_CreateSE("","%ANY","",[],[],Event)), + {noreply, State} + end. + + + +%% Start timers which send a message each time we should push events. Only used +%% when this objects is defined to supply sequences. +start_timer(State) -> + TS = now(), + case catch timer:send_after(timer:seconds(?get_PacingInterval(State)), + {pacing, TS}) of + {ok,PacTRef} -> + ?DBG("PULL SUPPLIER STARTED TIMER, BATCH LIMIT: ~p~n", + [?get_BatchLimit(State)]), + ?set_PacingTimer(State, {PacTRef, TS}); + What -> + orber:dbg("[~p] PullerSupplier:start_timer();~n" + "Unable to invoke timer:send_interval/2: ~p", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +stop_timer(State) -> + case ?get_PacingTimer(State) of + undefined -> + ok; + {Timer, _} -> + ?DBG("PULL SUPPLIER STOPPED TIMER~n",[]), + timer:cancel(Timer) + end. + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/PusherConsumer_impl.erl b/lib/cosNotification/src/PusherConsumer_impl.erl new file mode 100644 index 0000000..195e81e --- /dev/null +++ b/lib/cosNotification/src/PusherConsumer_impl.erl @@ -0,0 +1,729 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : PusherConsumer_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('PusherConsumer_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% cosEvent files. +-include_lib("cosEvent/include/CosEventChannelAdmin.hrl"). +-include_lib("cosEvent/include/CosEventComm.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ProxyPushConsumer ------------- +-export([connect_any_push_supplier/4]). + +%%----- CosNotifyChannelAdmin::SequenceProxyPushConsumer ----- +-export([connect_sequence_push_supplier/4]). + +%%----- CosNotifyChannelAdmin::StructuredProxyPushConsumer --- +-export([connect_structured_push_supplier/4]). + +%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer ---- +-export([obtain_subscription_types/4, + validate_event_qos/4]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifyPublish ------------ +-export([offer_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventComm::PushConsumer ------------- +-export([push/4, + disconnect_push_consumer/3]). + +%%----- Inherit from CosNotifyComm::SequencePushConsumer ---- +-export([push_structured_events/4, + disconnect_sequence_push_consumer/3]). + +%%----- Inherit from CosNotifyComm::StructuredPushConsumer -- +-export([push_structured_event/4, + disconnect_structured_push_consumer/3]). + +%%----- Inherit from CosEventChannelAdmin::ProxyPushConsumer +-export([connect_push_supplier/4]). + +%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier +-export(['_get_MyType'/3, + '_get_MyAdmin'/3]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myType, + myAdmin, + myAdminPid, + myChannel, + myFilters = [], + myOperator, + idCounter = 0, + client, + qosGlobal, + qosLocal, + publishType = false, + etsR, + eventDB}). + +%% Data structures constructors +-define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _EDB, _MyOP), + #state{myType = _MyT, + myAdmin = _MyA, + myAdminPid= _MyAP, + myChannel = _Ch, + myOperator= _MyOP, + qosGlobal = _QS, + qosLocal = _LQS, + etsR = ets:new(oe_ets, [set, protected]), + eventDB = _EDB}). + +%%-------------- Data structures selectors ----------------- +%% Attributes +-define(get_MyType(S), S#state.myType). +-define(get_MyAdmin(S), S#state.myAdmin). +-define(get_MyAdminPid(S), S#state.myAdminPid). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyOperator(S), S#state.myOperator). +%% Client Object +-define(get_Client(S), S#state.client). +%% QoS +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +%% Filters +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +%% Publish +-define(get_AllPublish(S), lists:flatten(ets:match(S#state.etsR, + {'$1',publish}))). +-define(get_PublishType(S), S#state.publishType). +%% ID +-define(get_IdCounter(S), S#state.idCounter). +%% Event +-define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB)). +-define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M)). + +-define(get_EventCounter(S), S#state.eventCounter). +%% Admin +-define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))). + +%%-------------- Data structures modifiers ----------------- +%% Client Object +-define(set_Client(S,D), S#state{client=D}). +-define(del_Client(S), S#state{client=undefined}). +-define(set_Unconnected(S), S#state{client=undefined}). +%% QoS +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +%% Filters +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_obj(lists:keydelete(I, 1, S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +%% Publish +-define(add_Publish(S,E), ets:insert(S#state.etsR, {E, publish})). +-define(del_Publish(S,E), ets:delete(S#state.etsR, E)). +-define(set_PublishType(S,T), S#state{publishType=T}). +%% ID +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). +%% Event +-define(add_Event(S,E), cosNotification_eventDB:add_event(S#state.eventDB, E)). +-define(update_EventDB(S,Q), S#state{eventDB= + cosNotification_eventDB:update(S#state.eventDB, Q)}). + +-define(set_EventCounter(S,V), S#state{eventCounter=V}). +-define(add_to_EventCounter(S,V),S#state{eventCounter=S#state.eventCounter+V}). +-define(reset_EventCounter(S), S#state{eventCounter=0}). +-define(increase_EventCounter(S),S#state{eventCounter=(S#state.eventCounter+1)}). +-define(decrease_EventCounter(S),S#state{eventCounter=S#state.eventCounter-1}). +-define(add_ToEventCounter(S,A), S#state{eventCounter=(S#state.eventCounter+A)}). +-define(sub_FromEventCounter(S,_A), S#state{eventCounter=(S#state.eventCounter-_A)}). +-define(set_EventCounterTo(S,V), S#state{eventCounter=V}). + +%% MISC +-define(is_ANY(S), S#state.myType == 'PUSH_ANY'). +-define(is_STRUCTURED(S), S#state.myType == 'PUSH_STRUCTURED'). +-define(is_SEQUENCE(S), S#state.myType == 'PUSH_SEQUENCE'). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). +-define(is_UnConnected(S), S#state.client == undefined). +-define(is_Connected(S), S#state.client =/= undefined). +-define(is_PersistentConnection(S), + ?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_PersistentEvent(S), + ?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent). +-define(is_BatchLimitReached(S), S#state.eventCounter >= + ?not_GetMaximumBatchSize((S#state.qosLocal))). + + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, Reason} when ?get_MyAdminPid(State)==Pid-> + ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', _Pid, _Reason} -> + ?DBG("PROXYPUSHCONSUMER: ~p TERMINATED.~n",[_Reason]), + {noreply, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init(['PUSH_SEQUENCE', MyAdmin, MyAdminPid, InitQoS, LQS, + MyChannel, Options, Operator]) -> + process_flag(trap_exit, true), + %% Only if MyType is 'PUSH_SEQUENCE' we need an ets to store events in. + %% Otherwise we'll forward them at once. Why? We don't know when the next event + %% is due. + GCTime = 'CosNotification_Common':get_option(gcTime, Options, + ?not_DEFAULT_SETTINGS), + GCLimit = 'CosNotification_Common':get_option(gcLimit, Options, + ?not_DEFAULT_SETTINGS), + TimeRef = 'CosNotification_Common':get_option(timeService, Options, + ?not_DEFAULT_SETTINGS), + {ok, ?get_InitState('PUSH_SEQUENCE', MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, + cosNotification_eventDB:create_db(LQS, GCTime, GCLimit, TimeRef), + Operator)}; +init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, _Options, Operator]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, + undefined, Operator)}. + +terminate(_Reason, State) when ?is_UnConnected(State) -> + ok; +terminate(_Reason, State) -> + Client = ?get_Client(State), + case catch corba_object:is_nil(Client) of + false when ?is_ANY(State) -> + 'CosNotification_Common':disconnect('CosEventComm_PushSupplier', + disconnect_push_supplier, + Client); + false when ?is_SEQUENCE(State) -> + 'CosNotification_Common':disconnect('CosNotifyComm_SequencePushSupplier', + disconnect_sequence_push_supplier, + Client); + false when ?is_STRUCTURED(State) -> + 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPushSupplier', + disconnect_structured_push_supplier, + Client); + _ -> + ok + end. + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ProxyConsumer attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyType' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyType'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyType(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyAdmin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyAdmin(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----- CosEventChannelAdmin::ProxyPushConsumer ------------- +%%----------------------------------------------------------% +%% function : connect_push_supplier +%% Arguments: Client - CosEventComm::PushSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_push_supplier(OE_THIS, OE_FROM, State, Client) -> + connect_any_push_supplier(OE_THIS, OE_FROM, State, Client). + +%%----- CosNotifyChannelAdmin::ProxyPushConsumer ------------ +%%----------------------------------------------------------% +%% function : connect_any_push_supplier +%% Arguments: Client - CosEventComm::PushSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%% Both exceptions from CosEventChannelAdmin!!! +%%----------------------------------------------------------- +connect_any_push_supplier(_OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) -> + ?not_TypeCheck(Client, 'CosEventComm_PushSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_any_push_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::SequenceProxyPushConsumer ---- +%%----------------------------------------------------------% +%% function : connect_sequence_push_supplier +%% Arguments: Client - CosNotifyComm::SequencePushSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%%----------------------------------------------------------- +connect_sequence_push_supplier(_OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) -> + ?not_TypeCheck(Client, 'CosNotifyComm_SequencePushSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_sequence_push_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::StructuredProxyPushConsumer -- +%%----------------------------------------------------------% +%% function : connect_structured_push_supplier +%% Arguments: Client - CosNotifyComm::StructuredPushSupplier +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%%----------------------------------------------------------- +connect_structured_push_supplier(_OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) -> + ?not_TypeCheck(Client, 'CosNotifyComm_StructuredPushSupplier'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, ?set_Client(State, Client)} + end; +connect_structured_push_supplier(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyChannelAdmin::ProxyConsumer --- +%%----------------------------------------------------------% +%% function : obtain_subscription_types +%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin) +%% Returns : CosNotification::EventTypeSeq +%%----------------------------------------------------------- +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') -> + {reply, ?get_AllPublish(State), ?set_PublishType(State, false)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') -> + {reply, ?get_AllPublish(State), ?set_PublishType(State, true)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') -> + {reply, [], ?set_PublishType(State, false)}; +obtain_subscription_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') -> + {reply, [], ?set_PublishType(State, true)}; +obtain_subscription_types(_,_,_,What) -> + orber:dbg("[~p] PusherConsumer:obtain_subscription_types(~p);~n" + "Incorrect enumerant", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : validate_event_qos +%% Arguments: RequiredQoS - CosNotification::QoSProperties +%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}} +%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out) +%%----------------------------------------------------------- +validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) -> + AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS, + ?get_LocalQoS(State)), + {reply, {ok, AvilableQoS}, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + NewState = ?update_EventDB(State, LQS), + {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifyPublish ----------- +%%----------------------------------------------------------% +%% function : offer_change +%% Arguments: Added - #'CosNotification_EventType'{} +%% Removed - #'CosNotification_EventType'{} +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}} +%%----------------------------------------------------------- +offer_change(_OE_THIS, _OE_FROM, State, Added, Removed) -> + cosNotification_Filter:validate_types(Added), + cosNotification_Filter:validate_types(Removed), + %% On this "side" we don't really care about which + %% type of events the client will supply. + %% Perhaps, later on, if we want to check this against Filters + %% associated with this object we may change this approach, i.e., if + %% the filter will not allow passing certain event types. But the + %% user should see to that that situation never occurs. It would add + %% extra overhead. Also see PusherSupplier- and PullerSuppler- + %% 'subscription_change'. + update_publish(add, State, Added), + update_publish(remove, State, Removed), + case ?get_PublishType(State) of + true -> + %% Perhaps we should handle exception here?! + %% Probably not. Better to stay "on-line". + catch 'CosNotifyComm_NotifySubscribe': + subscription_change(?get_Client(State), Added, Removed), + ok; + _-> + ok + end, + {reply, ok, State}. + +update_publish(_, _, [])-> + ok; +update_publish(add, State, [H|T]) -> + ?add_Publish(State, H), + update_publish(add, State, T); +update_publish(remove, State, [H|T]) -> + ?del_Publish(State, H), + update_publish(remove, State, T). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] PusherConsumer:remove_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] PusherConsumer:get_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + +%%----- Inherit from CosEventComm::PushConsumer ------------- +%%----------------------------------------------------------% +%% function : disconnect_push_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_push_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : push +%% Arguments: AnyEvent +%% Returns : ok | +%%----------------------------------------------------------- +push(OE_THIS, OE_FROM, State, Event) when ?is_ANY(State) -> + corba:reply(OE_FROM, ok), + case {?not_isConvertedStructured(Event), + cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State))} of + {_, {[],_}} when ?is_ANDOP(State) -> + {noreply, State}; + {true, {[],[_]}} -> + %% Is OR and converted, change back and forward to Admin + forward(seq, ?get_MyAdmin(State), State, [any:get_value(Event)], + 'MATCH', OE_THIS); + {_, {[],[_]}} -> + %% Is OR and not converted, forward to Admin + forward(any, ?get_MyAdmin(State), State, Event, 'MATCH', OE_THIS); + {true, {[_],_}} when ?is_ANDOP(State) -> + %% Is AND and converted, change back and forward to Admin + forward(seq, ?get_MyAdmin(State), State, [any:get_value(Event)], + 'MATCH', OE_THIS); + {true, {[_],_}} -> + %% Is OR and converted, change back and forward to Channel + forward(seq, ?get_MyChannel(State), State, [any:get_value(Event)], + 'MATCHED', OE_THIS); + {_, {[_],_}} when ?is_ANDOP(State) -> + %% Is AND and not converted, forward to Admin + forward(any, ?get_MyAdmin(State), State, Event, 'MATCH', OE_THIS); + _ -> + %% Is OR and not converted, forward to Channel + forward(any, ?get_MyChannel(State), State, Event, 'MATCHED', OE_THIS) + end; +push(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyComm::SequencePushConsumer ---- +%%----------------------------------------------------------% +%% function : disconnect_sequence_push_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_sequence_push_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : push_structured_events +%% Arguments: CosNotification::EventBatch +%% Returns : ok | +%%----------------------------------------------------------- +push_structured_events(OE_THIS, OE_FROM, State, Events) when ?is_SEQUENCE(State) -> + corba:reply(OE_FROM, ok), + %% We cannot convert parts of the sequence to any, event though they + %% are converted from any to structured. Would be 'impossible' to send. + case cosNotification_eventDB:filter_events(Events, ?get_AllFilter(State)) of + {[],_} when ?is_ANDOP(State) -> + {noreply, State}; + {[],Failed} -> + forward(seq, ?get_MyAdmin(State), State, Failed, 'MATCH', OE_THIS); + {Passed, _} when ?is_ANDOP(State) -> + forward(seq, ?get_MyAdmin(State), State, Passed, 'MATCH', OE_THIS); + {Passed, []} -> + forward(seq, ?get_MyChannel(State), State, Passed, 'MATCHED', OE_THIS); + {Passed, Failed} -> + %% Is OR, send Passed to channel and Failed to Admin. + forward(seq, ?get_MyChannel(State), State, Passed, 'MATCHED', OE_THIS), + forward(seq, ?get_MyAdmin(State), State, Failed, 'MATCH', OE_THIS) + end; +push_structured_events(_,_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- Inherit from CosNotifyComm::StructuredPushConsumer -- +%%----------------------------------------------------------% +%% function : disconnect_structured_push_consumer +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_structured_push_consumer(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----------------------------------------------------------% +%% function : push_structured_event +%% Arguments: CosNotification::StructuredEvent +%% Returns : ok | +%%----------------------------------------------------------- +push_structured_event(OE_THIS, OE_FROM, State, Event) when ?is_STRUCTURED(State) -> + corba:reply(OE_FROM, ok), + case {?not_isConvertedAny(Event), + cosNotification_eventDB:filter_events([Event], ?get_AllFilter(State))} of + {_, {[],_}} when ?is_ANDOP(State) -> + {noreply, State}; + {true, {[],[_]}} -> + %% Is OR and converted, change back and forward to Admin + forward(any, ?get_MyAdmin(State), State, + Event#'CosNotification_StructuredEvent'.remainder_of_body, + 'MATCH', OE_THIS); + {_, {[],[_]}} -> + %% Is OR and not converted, forward to Admin + forward(seq, ?get_MyAdmin(State), State, [Event], 'MATCH', OE_THIS); + {true, {[_],_}} when ?is_ANDOP(State) -> + %% Is AND and converted, change back and forward to Admin + forward(any, ?get_MyAdmin(State), State, + Event#'CosNotification_StructuredEvent'.remainder_of_body, + 'MATCH', OE_THIS); + {true, {[_],_}} -> + %% Is OR and converted, change back and forward to Channel + forward(any, ?get_MyChannel(State), State, + Event#'CosNotification_StructuredEvent'.remainder_of_body, + 'MATCHED', OE_THIS); + {_, {[_],_}} when ?is_ANDOP(State) -> + %% Is AND and not converted, forward to Admin + forward(seq, ?get_MyAdmin(State), State, [Event], 'MATCH', OE_THIS); + _ -> + %% Is OR and not converted, forward to Channel + forward(seq, ?get_MyChannel(State), State, [Event], 'MATCHED', OE_THIS) + end; +push_structured_event(_,_,_,_) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj({value, {_, Obj}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(What, _) -> + orber:dbg("[~p] PusherConsumer:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single object. +%% The list don not differ, i.e., no filter removed, raise exception. +delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_obj(List,_) -> List. + +%% Forward events +forward(any, SendTo, State, Event, Status, OE_THIS) -> + case catch oe_CosNotificationComm_Event:callAny(SendTo, Event, Status) of + ok -> + ?DBG("PROXY FORWARD ANY: ~p~n",[Event]), + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, OE_THIS}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, OE_THIS}, + {client, ?get_Client(State)}, + {reason, R}]), + {stop, normal, State} + end; +forward(seq, SendTo, State, Event, Status, OE_THIS) -> + case catch oe_CosNotificationComm_Event:callSeq(SendTo, Event, Status) of + ok -> + {noreply, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + ?DBG("ADMIN NO LONGER EXIST; DROPPING: ~p~n", [Event]), + 'CosNotification_Common':notify([{proxy, OE_THIS}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + R when ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Dropping: ~p", [?LINE, R, Event], ?DEBUG_LEVEL), + {noreply, State}; + R -> + orber:dbg("[~p] PusherConsumer:forward();~n" + "Admin/Channel respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, R, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, OE_THIS}, + {client, ?get_Client(State)}, + {reason, R}]), + {stop, normal, State} + end. + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/PusherSupplier_impl.erl b/lib/cosNotification/src/PusherSupplier_impl.erl new file mode 100644 index 0000000..51949b8 --- /dev/null +++ b/lib/cosNotification/src/PusherSupplier_impl.erl @@ -0,0 +1,1052 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : PusherSupplier_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('PusherSupplier_impl'). + + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% cosEvent files. +-include_lib("cosEvent/include/CosEventChannelAdmin.hrl"). +-include_lib("cosEvent/include/CosEventComm.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%%----- CosNotifyChannelAdmin::ProxyPushSupplier ------------- +-export([connect_any_push_consumer/4]). + +%%----- CosNotifyChannelAdmin::StructuredProxyPushSupplier --- +-export([connect_structured_push_consumer/4]). + +%%----- CosNotifyChannelAdmin::SequenceProxyPushSupplier ----- +-export([connect_sequence_push_consumer/4]). + +%%----- CosNotifyChannelAdmin::*ProxyPushSupplier ------------ +-export([suspend_connection/3, + resume_connection/3]). + +%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier ---- +-export([obtain_offered_types/4, + validate_event_qos/4]). + +%%----- Inherit from CosNotification::QoSAdmin --------------- +-export([get_qos/3, + set_qos/4, + validate_qos/4]). + +%%----- Inherit from CosNotifyComm::NotifySubscribe ---------- +-export([subscription_change/5]). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ------------ +-export([add_filter/4, + remove_filter/4, + get_filter/4, + get_all_filters/3, + remove_all_filters/3]). + +%%----- Inherit from CosEventComm::PushSupplier ------------- +-export([disconnect_push_supplier/3]). + +%%----- Inherit from CosNotifyComm::StructuredPushSupplier -- +-export([disconnect_structured_push_supplier/3]). + +%%----- Inherit from CosNotifyComm::SequencePushSupplier ---- +-export([disconnect_sequence_push_supplier/3]). + +%%----- Inherit from CosEventChannelAdmin::ProxyPushSupplier +-export([connect_push_consumer/4]). + +%% Attributes (external) CosNotifyChannelAdmin::ProxySupplier +-export(['_get_MyType'/3, + '_get_MyAdmin'/3, + '_get_priority_filter'/3, + '_set_priority_filter'/4, + '_get_lifetime_filter'/3, + '_set_lifetime_filter'/4]). + +%%--------------- Internal ----------------------------------- +%%----- Inherit from cosNotificationComm --------------------- +-export([callAny/5, + callSeq/5]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + +%%--------------- LOCAL DEFINITIONS -------------------------- +%% Data structures +-record(state, {myType, + myAdmin, + myAdminPid, + myChannel, + myFilters = [], + myOperator, + idCounter = 0, + prioFil, + lifetFil, + client, + qosGlobal, + qosLocal, + suspended = false, + pacingTimer, + subscribeType = false, + subscribeData = true, + etsR, + eventDB, + this, + maxCache, + cacheTimeout, + cacheInterval}). + +%% Data structures constructors +-define(get_InitState(_MyT, _MyA, _MyAP, _QS, _LQS, _Ch, _MyOp, _GT, _GL, _TR), + #state{myType = _MyT, + myAdmin = _MyA, + myAdminPid= _MyAP, + qosGlobal = _QS, + qosLocal = _LQS, + myChannel = _Ch, + myOperator=_MyOp, + etsR = ets:new(oe_ets, [set, protected]), + eventDB = cosNotification_eventDB:create_db(_LQS, _GT, _GL, _TR), + maxCache = cosNotificationApp:max_events()}). + +%% Data structures selectors +%%-------------- Data structures selectors ----------------- +%% Attributes +-define(get_MyType(S), S#state.myType). +-define(get_MyAdmin(S), S#state.myAdmin). +-define(get_MyAdminPid(S), S#state.myAdminPid). +-define(get_MyChannel(S), S#state.myChannel). +-define(get_MyOperator(S), S#state.myOperator). +-define(get_PrioFil(S), S#state.prioFil). +-define(get_LifeTFil(S), S#state.lifetFil). +%% Client Object +-define(get_Client(S), S#state.client). +%% QoS +-define(get_GlobalQoS(S), S#state.qosGlobal). +-define(get_LocalQoS(S), S#state.qosLocal). +-define(get_BothQoS(S), {S#state.qosGlobal, S#state.qosLocal}). +%% Filters +-define(get_Filter(S, I), find_obj(lists:keysearch(I, 1, S#state.myFilters))). +-define(get_AllFilter(S), S#state.myFilters). +-define(get_AllFilterID(S), find_ids(S#state.myFilters)). +%% Amin +-define(get_PacingTimer(S), S#state.pacingTimer). +-define(get_PacingInterval(S), round(?not_GetPacingInterval((S#state.qosLocal))/10000000)). +-define(get_BatchLimit(S), ?not_GetMaximumBatchSize((S#state.qosLocal))). +%% Subscribe +-define(get_AllSubscribe(S), lists:flatten(ets:match(S#state.etsR, + {'$1',subscribe}))). +-define(get_SubscribeType(S), S#state.subscribeType). +-define(get_SubscribeData(S), S#state.subscribeData). +%% ID +-define(get_IdCounter(S), S#state.idCounter). +-define(get_SubscribeDB(S), S#state.etsR). +%% Event +-define(is_PersistentConnection(S), + (?not_GetConnectionReliability((S#state.qosLocal)) == ?not_Persistent)). +-define(is_PersistentEvent(S), + (?not_GetEventReliability((S#state.qosLocal)) == ?not_Persistent)). + +-define(get_Event(S), cosNotification_eventDB:get_event(S#state.eventDB, + false)). +% (not ?is_PersistentEvent(S)))). +-define(get_Events(S,M), cosNotification_eventDB:get_events(S#state.eventDB, M, false)). +% (not ?is_PersistentEvent(S)))). + +%%-------------- Data structures modifiers ----------------- +%% Attributes +-define(set_PrioFil(S,D), S#state{prioFil=D}). +-define(set_LifeTFil(S,D), S#state{lifetFil=D}). +%% Client Object +-define(set_Client(S,D), S#state{client=D}). +-define(del_Client(S), S#state{client=undefined}). +-define(set_Unconnected(S), S#state{client=undefined}). +-define(set_Suspended(S), S#state{suspended=true}). +-define(set_NotSuspended(S), S#state{suspended=false}). +%% QoS +-define(set_LocalQoS(S,D), S#state{qosLocal=D}). +-define(set_GlobalQoS(S,D), S#state{qosGlobal=D}). +-define(set_BothQoS(S,GD,LD), S#state{qosGlobal=GD, qosLocal=LD}). +%% Filters +-define(add_Filter(S,I,O), S#state{myFilters=[{I,O}|S#state.myFilters]}). +-define(del_Filter(S,I), S#state{myFilters= + delete_obj(lists:keydelete(I, 1, S#state.myFilters), + S#state.myFilters)}). +-define(del_AllFilter(S), S#state{myFilters=[]}). +%% Admin +-define(set_PacingTimer(S,T), S#state{pacingTimer=T}). +%% Publish +%% Subscribe +-define(add_Subscribe(S,E), ets:insert(S#state.etsR, {E, subscribe})). +-define(del_Subscribe(S,E), ets:delete(S#state.etsR, E)). +-define(set_SubscribeType(S,T), S#state{subscribeType=T}). +-define(set_SubscribeData(S,D), S#state{subscribeData=D}). +%% ID +-define(set_IdCounter(S,V), S#state{idCounter=V}). +-define(new_Id(S), 'CosNotification_Common':create_id(S#state.idCounter)). +%% Events +-define(add_Event(S,E), catch cosNotification_eventDB: + add_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil)). +-define(addAndGet_Event(S,E), catch cosNotification_eventDB: + add_and_get_event(S#state.eventDB, E, S#state.lifetFil, S#state.prioFil, + false)). +% ?is_PersistentEvent(S))). +-define(update_EventDB(S,Q), S#state{eventDB= + cosNotification_eventDB:update(S#state.eventDB, Q)}). + + +%%-------------- MISC ---------------------------------------- +-define(is_ANY(S), S#state.myType == 'PUSH_ANY'). +-define(is_STRUCTURED(S), S#state.myType == 'PUSH_STRUCTURED'). +-define(is_SEQUENCE(S), S#state.myType == 'PUSH_SEQUENCE'). +-define(is_ANDOP(S), S#state.myOperator == 'AND_OP'). +-define(is_UnConnected(S), S#state.client == undefined). +-define(is_Connected(S), S#state.client =/= undefined). +-define(is_Suspended(S), S#state.suspended == true). +-define(is_NotSuspended(S), S#state.suspended == false). +-define(is_BatchLimitReached(S), cosNotification_eventDB:status(S#state.eventDB, + {batchLimit, + ?not_GetMaximumBatchSize((S#state.qosLocal))})). +-define(has_Filters(S), S#state.myFilters =/= []). + +%%----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%----------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, #state{cacheTimeout = Timeout, + cacheInterval = Interval} = State) -> + ?DBG("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, Reason} when ?get_MyAdminPid(State)==Pid -> + ?DBG("PARENT ADMIN: ~p TERMINATED.~n",[Reason]), + {stop, Reason, State}; + {'EXIT', _Pid, _Reason} -> + ?DBG("PROXYPUSHSUPPLIER: ~p TERMINATED.~n",[_Reason]), + {noreply, State}; + pacing -> + lookup_and_push(State, true); + cacheInterval -> + lookup_and_push(State, true); + cacheTimeout when Timeout == undefined, Interval == undefined -> + %% Late message, do not terminate + {noreply, State}; + cacheTimeout -> + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, State#state.client}, + {reason, + {timer, "Reached upper limit"}}]), + {stop, normal, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([MyType, MyAdmin, MyAdminPid, InitQoS, LQS, MyChannel, Options, Operator]) -> + process_flag(trap_exit, true), + GCTime = 'CosNotification_Common':get_option(gcTime, Options, + ?not_DEFAULT_SETTINGS), + GCLimit = 'CosNotification_Common':get_option(gcLimit, Options, + ?not_DEFAULT_SETTINGS), + TimeRef = 'CosNotification_Common':get_option(timeService, Options, + ?not_DEFAULT_SETTINGS), + timer:start(), + {ok, ?get_InitState(MyType, MyAdmin, MyAdminPid, + InitQoS, LQS, MyChannel, Operator, GCTime, GCLimit, TimeRef)}. + +terminate(_Reason, State) when ?is_UnConnected(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + stop_timer(State#state.pacingTimer), + %% We are not connected to a Client. Hence, no need to invoke disconnect. + ok; +terminate(_Reason, State) when ?is_ANY(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + stop_timer(State#state.pacingTimer), + 'CosNotification_Common':disconnect('CosEventComm_PushConsumer', + disconnect_push_consumer, + ?get_Client(State)); +terminate(_Reason, State) when ?is_SEQUENCE(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + stop_timer(State#state.pacingTimer), + 'CosNotification_Common':disconnect('CosNotifyComm_SequencePushConsumer', + disconnect_sequence_push_consumer, + ?get_Client(State)); +terminate(_Reason, State) when ?is_STRUCTURED(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + stop_timer(State#state.pacingTimer), + 'CosNotification_Common':disconnect('CosNotifyComm_StructuredPushConsumer', + disconnect_structured_push_consumer, + ?get_Client(State)). + +%%----------------------------------------------------------- +%%----- CosNotifyChannelAdmin_ProxySupplier attributes ------ +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_MyType' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyType'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyType(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_MyAdmin' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_MyAdmin'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_MyAdmin(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_*et_priority_filter' +%% Type : read/write +%% Returns : +%%----------------------------------------------------------- +'_get_priority_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_PrioFil(State), State}. +'_set_priority_filter'(_OE_THIS, _OE_FROM, State, PrioF) -> + {reply, ok, ?set_PrioFil(State, PrioF)}. + +%%----------------------------------------------------------% +%% Attribute: '_*et_lifetime_filter' +%% Type : read/write +%% Returns : +%%----------------------------------------------------------- +'_get_lifetime_filter'(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_LifeTFil(State), State}. +'_set_lifetime_filter'(_OE_THIS, _OE_FROM, State, LifeTF) -> + {reply, ok, ?set_LifeTFil(State, LifeTF)}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----- CosEventChannelAdmin::ProxyPushSupplier ------------- +%%----------------------------------------------------------% +%% function : connect_push_consumer +%% Arguments: Client - CosEventComm::PushConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%% Both exceptions from CosEventChannelAdmin!!!! +%%----------------------------------------------------------- +connect_push_consumer(OE_THIS, OE_FROM, State, Client) -> + connect_any_push_consumer(OE_THIS, OE_FROM, State, Client). + +%%----- CosNotifyChannelAdmin::ProxyPushSupplier ------------ +%%----------------------------------------------------------% +%% function : connect_any_push_consumer +%% Arguments: Client - CosEventComm::PushConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%% Both exceptions from CosEventChannelAdmin!!!! +%%----------------------------------------------------------- +connect_any_push_consumer(OE_THIS, _OE_FROM, State, Client) when ?is_ANY(State) -> + 'CosNotification_Common':type_check(Client, 'CosEventComm_PushConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, State#state{client = Client, this = OE_THIS}} + end; +connect_any_push_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::SequenceProxyPushSupplier ---- +%%----------------------------------------------------------% +%% function : connect_sequence_push_consumer +%% Arguments: Client - CosNotifyComm::SequencePushConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%%----------------------------------------------------------- +connect_sequence_push_consumer(OE_THIS, _OE_FROM, State, Client) when ?is_SEQUENCE(State) -> + 'CosNotification_Common':type_check(Client, + 'CosNotifyComm_SequencePushConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + NewState = start_timer(State), + {reply, ok, NewState#state{client = Client, this = OE_THIS}} + end; +connect_sequence_push_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::StructuredProxyPushSupplier --- +%%----------------------------------------------------------% +%% function : connect_structured_push_consumer +%% Arguments: Client - CosNotifyComm::StructuredPushConsumer +%% Returns : ok | {'EXCEPTION', #'AlreadyConnected'{}} | +%% {'EXCEPTION', #'TypeError'{}} +%%----------------------------------------------------------- +connect_structured_push_consumer(OE_THIS, _OE_FROM, State, Client) when ?is_STRUCTURED(State) -> + 'CosNotification_Common':type_check(Client, + 'CosNotifyComm_StructuredPushConsumer'), + if + ?is_Connected(State) -> + corba:raise(#'CosEventChannelAdmin_AlreadyConnected'{}); + true -> + {reply, ok, State#state{client = Client, this = OE_THIS}} + end; +connect_structured_push_consumer(_, _, _, _) -> + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----- CosNotifyChannelAdmin::*ProxyPushSupplier ----------- +%%----------------------------------------------------------% +%% function : suspend_connection +%% Arguments: +%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyInactive'{}} | +%% {'EXCEPTION', #'NotConneced'{}} +%%----------------------------------------------------------- +suspend_connection(_OE_THIS, _OE_FROM, State) when ?is_Connected(State) -> + if + ?is_Suspended(State) -> + corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyInactive'{}); + true -> + stop_timer(State#state.pacingTimer), + {reply, ok, State#state{pacingTimer = undefined, + suspended=true}} + end; +suspend_connection(_,_,_)-> + corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}). + +%%----------------------------------------------------------% +%% function : resume_connection +%% Arguments: +%% Returns : ok | {'EXCEPTION', #'ConnectionAlreadyActive'{}} | +%% {'EXCEPTION', #'NotConneced'{}} +%%----------------------------------------------------------- +resume_connection(_OE_THIS, OE_FROM, State) when ?is_Connected(State) -> + if + ?is_NotSuspended(State) -> + corba:raise(#'CosNotifyChannelAdmin_ConnectionAlreadyActive'{}); + true -> + corba:reply(OE_FROM, ok), + if + ?is_SEQUENCE(State) -> + start_timer(State); + true -> + ok + end, + lookup_and_push(?set_NotSuspended(State)) + end; +resume_connection(_,_,_) -> + corba:raise(#'CosNotifyChannelAdmin_NotConnected'{}). + +%%----- Inherit from CosNotifyChannelAdmin::ProxySupplier --- +%%----------------------------------------------------------% +%% function : obtain_offered_types +%% Arguments: Mode - enum 'ObtainInfoMode' (CosNotifyChannelAdmin) +%% Returns : CosNotification::EventTypeSeq +%%----------------------------------------------------------- +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_OFF') -> + {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, false)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'ALL_NOW_UPDATES_ON') -> + {reply, ?get_AllSubscribe(State), ?set_SubscribeType(State, true)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_OFF') -> + {reply, [], ?set_SubscribeType(State, false)}; +obtain_offered_types(_OE_THIS, _OE_FROM, State, 'NONE_NOW_UPDATES_ON') -> + {reply, [], ?set_SubscribeType(State, true)}; +obtain_offered_types(_,_,_,What) -> + orber:dbg("[~p] PusherSupplier:obtain_offered_types(~p);~n" + "Bad enumerant", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_OPERATION'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : validate_event_qos +%% Arguments: RequiredQoS - CosNotification::QoSProperties +%% Returns : ok | {'EXCEPTION', #'UnsupportedQoS'{}} +%% AvilableQoS - CosNotification::NamedPropertyRangeSeq (out) +%%----------------------------------------------------------- +validate_event_qos(_OE_THIS, _OE_FROM, State, RequiredQoS) -> + AvilableQoS = 'CosNotification_Common':validate_event_qos(RequiredQoS, + ?get_LocalQoS(State)), + {reply, {ok, AvilableQoS}, State}. + +%%----- Inherit from CosNotification::QoSAdmin -------------- +%%----------------------------------------------------------% +%% function : get_qos +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +get_qos(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_GlobalQoS(State), State}. + +%%----------------------------------------------------------% +%% function : set_qos +%% Arguments: QoS - CosNotification::QoSProperties, i.e., +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : ok | {'EXCEPTION', CosNotification::UnsupportedQoS} +%%----------------------------------------------------------- +set_qos(_OE_THIS, _OE_FROM, State, QoS) -> + {NewQoS, LQS} = 'CosNotification_Common':set_qos(QoS, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + NewState = ?update_EventDB(State, LQS), + {reply, ok, ?set_BothQoS(NewState, NewQoS, LQS)}. + +%%----------------------------------------------------------% +%% function : validate_qos +%% Arguments: Required_qos - CosNotification::QoSProperties +%% [#'Property'{name, value}, ...] where name eq. string() +%% and value eq. any(). +%% Returns : {'EXCEPTION', CosNotification::UnsupportedQoS} +%% {ok, CosNotification::NamedPropertyRangeSeq} +%%----------------------------------------------------------- +validate_qos(_OE_THIS, _OE_FROM, State, Required_qos) -> + QoS = 'CosNotification_Common':validate_qos(Required_qos, ?get_BothQoS(State), + proxy, ?get_MyAdmin(State), + false), + {reply, {ok, QoS}, State}. + +%%----- Inherit from CosNotifyComm::NotifySubscribe --------- +%%----------------------------------------------------------% +%% function : subscription_change +%% Arguments: Added - #'CosNotification_EventType'{} +%% Removed - #'CosNotification_EventType'{} +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}} +%%----------------------------------------------------------- +subscription_change(_OE_THIS, _OE_FROM, State, Added, Removed) -> + cosNotification_Filter:validate_types(Added), + cosNotification_Filter:validate_types(Removed), + %% On this "side", we care about which type of events the client + %% will require, since the client (or an agent) clearly stated + %% that it's only interested in these types of events. + %% Also see PusherConsumer- and PullerConsumer-'offer_change'. + update_subscribe(remove, State, Removed), + CurrentSub = ?get_AllSubscribe(State), + NewState = + case cosNotification_Filter:check_types(Added++CurrentSub) of + true -> + %% Types supplied does in some way cause all events to be valid. + %% Smart? Would have been better to not supply any at all. + ?set_SubscribeData(State, true); + {ok, Which, WC} -> + ?set_SubscribeData(State, {Which, WC}) + end, + update_subscribe(add, NewState, Added), + case ?get_SubscribeType(NewState) of + true -> + %% Perhaps we should handle exception here?! + %% Probably not. Better to stay "on-line". + catch 'CosNotifyComm_NotifyPublish': + offer_change(?get_Client(NewState), Added, Removed), + ok; + _-> + ok + end, + {reply, ok, NewState}. + +update_subscribe(_, _, [])-> + ok; +update_subscribe(add, State, [H|T]) -> + ?add_Subscribe(State, H), + update_subscribe(add, State, T); +update_subscribe(remove, State, [H|T]) -> + ?del_Subscribe(State, H), + update_subscribe(remove, State, T). + +%%----- Inherit from CosNotifyFilter::FilterAdmin ----------- +%%----------------------------------------------------------% +%% function : add_filter +%% Arguments: Filter - CosNotifyFilter::Filter +%% Returns : FilterID - long +%%----------------------------------------------------------- +add_filter(_OE_THIS, _OE_FROM, State, Filter) -> + 'CosNotification_Common':type_check(Filter, 'CosNotifyFilter_Filter'), + FilterID = ?new_Id(State), + NewState = ?set_IdCounter(State, FilterID), + {reply, FilterID, ?add_Filter(NewState, FilterID, Filter)}. + +%%----------------------------------------------------------% +%% function : remove_filter +%% Arguments: FilterID - long +%% Returns : ok +%%----------------------------------------------------------- +remove_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ok, ?del_Filter(State, FilterID)}; +remove_filter(_,_,_,What) -> + orber:dbg("[~p] PusherSupplier:remove_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_filter +%% Arguments: FilterID - long +%% Returns : Filter - CosNotifyFilter::Filter | +%% {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}} +%%----------------------------------------------------------- +get_filter(_OE_THIS, _OE_FROM, State, FilterID) when is_integer(FilterID) -> + {reply, ?get_Filter(State, FilterID), State}; +get_filter(_,_,_,What) -> + orber:dbg("[~p] PusherSupplier:get_filter(~p); Not an integer", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : get_all_filters +%% Arguments: - +%% Returns : Filter - CosNotifyFilter::FilterIDSeq +%%----------------------------------------------------------- +get_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ?get_AllFilterID(State), State}. + +%%----------------------------------------------------------% +%% function : remove_all_filters +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +remove_all_filters(_OE_THIS, _OE_FROM, State) -> + {reply, ok, ?del_AllFilter(State)}. + + +%%----- Inherit from CosEventComm::PushSupplier ------------- +%%----------------------------------------------------------% +%% function : disconnect_push_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_push_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----- Inherit from CosNotifyComm::StructuredPushSupplier -- +%%----------------------------------------------------------% +%% function : disconnect_structured_push_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_structured_push_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%----- Inherit from CosNotifyComm::SequencePushSupplier ---- +%%----------------------------------------------------------% +%% function : disconnect_sequence_push_supplier +%% Arguments: - +%% Returns : ok +%%----------------------------------------------------------- +disconnect_sequence_push_supplier(_OE_THIS, _OE_FROM, State) -> + {stop, normal, ok, ?set_Unconnected(State)}. + +%%--------------- LOCAL FUNCTIONS ---------------------------- +find_obj({value, {_, Obj}}) -> Obj; +find_obj(_) -> {'EXCEPTION', #'CosNotifyFilter_FilterNotFound'{}}. + +find_ids(List) -> find_ids(List, []). +find_ids([], Acc) -> Acc; +find_ids([{I,_}|T], Acc) -> find_ids(T, [I|Acc]); +find_ids(What, _) -> + orber:dbg("[~p] PusherSupplier:find_ids();~n" + "Id corrupt: ~p", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%% Delete a single object. +%% The list do not differ, i.e., no filter removed, raise exception. +delete_obj(List,List) -> corba:raise(#'CosNotifyFilter_FilterNotFound'{}); +delete_obj(List,_) -> List. + +%%----------------------------------------------------------- +%% function : callSeq +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callSeq(_OE_THIS, OE_FROM, State, EventsIn, Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventsIn, + ?get_AllFilter(State), + ?get_SubscribeDB(State), + Status) of + {[],_} -> + ?DBG("PROXY NOSUBSCRIPTION SEQUENCE/STRUCTURED: ~p~n",[EventsIn]), + {noreply, State}; + {Events,_} when ?is_Suspended(State) -> + store_events(State, Events), + {noreply, State}; + {Events,_} when ?is_UnConnected(State) -> + orber:dbg("[~p] PusherSupplier:callAny();~n" + "Not connected, dropping event(s): ~p", + [?LINE, Events], ?DEBUG_LEVEL), + {noreply, State}; + {[Event],_} when ?is_STRUCTURED(State) -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Event]), + empty_db(State, ?addAndGet_Event(State, Event)); + {[Event],_} when ?is_ANY(State) -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Event]), + AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event), + empty_db(State, ?addAndGet_Event(State, AnyEvent)); + {Events,_} -> + ?DBG("PROXY RECEIVED SEQUENCE: ~p~n",[Events]), + store_events(State, Events), + lookup_and_push(State) + end. + +%%----------------------------------------------------------- +%% function : callAny +%% Arguments: +%% Returns : +%%----------------------------------------------------------- +callAny(_OE_THIS, OE_FROM, State, EventIn, Status) -> + corba:reply(OE_FROM, ok), + case cosNotification_eventDB:validate_event(?get_SubscribeData(State), EventIn, + ?get_AllFilter(State), + ?get_SubscribeDB(State), + Status) of + {[],_} -> + ?DBG("PROXY NOSUBSCRIPTION ANY: ~p~n",[EventIn]), + %% To be on the safe side, test if there are any events that not + %% have been forwarded (should only be possible if StartTime is used). + lookup_and_push(State); + {Event,_} when ?is_Suspended(State), ?is_ANY(State) -> + ?add_Event(State, Event), + {noreply, State}; + {Event,_} when ?is_Suspended(State) -> + ?add_Event(State, ?not_CreateSE("","%ANY","",[],[],Event)), + {noreply, State}; + {Event,_} when ?is_UnConnected(State) -> + orber:dbg("[~p] PusherSupplier:callAny();~n" + "Not connected, dropping event: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + {noreply, State}; + {Event,_} when ?is_ANY(State) -> + ?DBG("PROXY RECEIVED ANY: ~p~n",[Event]), + %% We must store the event since there may be other events that should + %% be delivered first, e.g., higher priority. + empty_db(State, ?addAndGet_Event(State, Event)); + {Event,_} when ?is_SEQUENCE(State) -> + ?DBG("PROXY RECEIVED ANY==>SEQUENCE: ~p~n",[Event]), + StrEvent = ?not_CreateSE("","%ANY","",[],[],Event), + ?add_Event(State, StrEvent), + lookup_and_push(State); + {Event,_} -> + ?DBG("PROXY RECEIVED ANY==>STRUCTURED: ~p~n",[Event]), + StrEvent = ?not_CreateSE("","%ANY","",[],[],Event), + empty_db(State, ?addAndGet_Event(State, StrEvent)) + end. + +%% Lookup and push "the correct" amount of events. +lookup_and_push(State) -> + %% The boolean indicates, if false, that we will only push events if we have + %% passed the BatchLimit. If true we will ignore this limit and push events + %% anyway (typcially invoked when pacing limit passed). + lookup_and_push(State, false). +lookup_and_push(State, false) when ?is_SEQUENCE(State) -> + case ?is_BatchLimitReached(State) of + true -> + case ?get_Events(State, ?get_BatchLimit(State)) of + {[], _, _} -> + ?DBG("BATCHLIMIT (~p) REACHED BUT NO EVENTS FOUND~n", + [?get_BatchLimit(State)]), + {noreply, State}; + {Events, _, Keys} -> + ?DBG("BATCHLIMIT (~p) REACHED, EVENTS FOUND: ~p~n", + [?get_BatchLimit(State), Events]), + case catch 'CosNotifyComm_SequencePushConsumer': + push_structured_events(?get_Client(State), Events) of + ok -> + cosNotification_eventDB:delete_events(Keys), + lookup_and_push(reset_cache(State), false); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + ?DBG("PUSH SUPPLIER CLIENT NO LONGER EXIST~n", []), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + What when ?is_PersistentEvent(State), + ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p", + [?LINE, What], ?DEBUG_LEVEL), + check_cache(State); + What when ?is_PersistentConnection(State) -> + %% Here we should do something when we want to handle + %% Persistent EventReliability. + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p~n" + "Dropping events: ~p", + [?LINE, What, Events], ?DEBUG_LEVEL), + cosNotification_eventDB:delete_events(Keys), + {noreply, State}; + WhatII -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p~n" + "Terminating and dropping events: ~p", + [?LINE, WhatII, Events], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, WhatII}]), + {stop, normal, State} + end + end; + _ -> + ?DBG("BATCHLIMIT (~p) NOT REACHED~n",[?get_BatchLimit(State)]), + {noreply, State} + end; +lookup_and_push(State, true) when ?is_SEQUENCE(State) -> + case ?get_Events(State, ?get_BatchLimit(State)) of + {[], _, _} -> + ?DBG("PACELIMIT REACHED BUT NO EVENTS FOUND~n", []), + {noreply, State}; + {Events, _, Keys} -> + ?DBG("PACELIMIT REACHED, EVENTS FOUND: ~p~n", [Events]), + case catch 'CosNotifyComm_SequencePushConsumer': + push_structured_events(?get_Client(State), Events) of + ok -> + cosNotification_eventDB:delete_events(Keys), + lookup_and_push(reset_cache(State), false); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client no longer exists; terminating and dropping events: ~p", + [?LINE, Events], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + What when ?is_PersistentEvent(State), + ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p", + [?LINE, What], ?DEBUG_LEVEL), + check_cache(State); + What when ?is_PersistentConnection(State) -> + %% Here we should do something when we want to handle + %% Persistent EventReliability. + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p~n" + "Dropping events: ~p", + [?LINE, What, Events], ?DEBUG_LEVEL), + cosNotification_eventDB:delete_events(Keys), + {noreply, State}; + WhatII -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p~n" + "Terminating and dropping events: ~p", + [?LINE, WhatII, Events], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, WhatII}]), + {stop, normal, State} + end + end; +lookup_and_push(State, _) -> + empty_db(State, ?get_Event(State)). + + +%% Push all events stored while not connected or received in sequence. +empty_db(State, {[], _, _}) -> + {noreply, State}; +empty_db(State, {Event, _, Keys}) when ?is_STRUCTURED(State) -> + case catch 'CosNotifyComm_StructuredPushConsumer': + push_structured_event(?get_Client(State), Event) of + ok -> + cosNotification_eventDB:delete_events(Keys), + NewState = reset_cache(State), + empty_db(NewState, ?get_Event(NewState)); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + What when ?is_PersistentEvent(State), + ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p", + [?LINE, What], ?DEBUG_LEVEL), + check_cache(State); + What when ?is_PersistentConnection(State) -> + %% Here we should do something when we want to handle + %% Persistent EventReliability. + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client respond incorrect: ~p~n" + "Dropping event: ~p", + [?LINE, What, Event], ?DEBUG_LEVEL), + cosNotification_eventDB:delete_events(Keys), + {noreply, State}; + WhatII -> + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, WhatII, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, WhatII}]), + {stop, normal, State} + end; +empty_db(State, {Event, _, Keys}) when ?is_ANY(State) -> + case catch 'CosEventComm_PushConsumer':push(?get_Client(State), Event) of + ok -> + cosNotification_eventDB:delete_events(Keys), + NewState = reset_cache(State), + empty_db(NewState, ?get_Event(NewState)); + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') orelse + is_record(E, 'NO_PERMISSION') orelse + is_record(E, 'CosEventComm_Disconnected') -> + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client no longer exists; terminating and dropping: ~p", + [?LINE, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, {'EXCEPTION', E}}]), + {stop, normal, State}; + What when ?is_PersistentEvent(State), + ?is_PersistentConnection(State) -> + orber:dbg("[~p] PusherSupplier:lookup_and_push();~n" + "Client respond incorrect: ~p", + [?LINE, What], ?DEBUG_LEVEL), + check_cache(State); + What when ?is_PersistentConnection(State) -> + %% Here we should do something when we want to handle + %% Persistent EventReliability. + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client respond incorrect: ~p~n" + "Dropping Event: ~p", + [?LINE, What, Event], ?DEBUG_LEVEL), + cosNotification_eventDB:delete_events(Keys), + {noreply, State}; + WhatII -> + orber:dbg("[~p] PusherSupplier:empty_db();~n" + "Client respond incorrect: ~p~n" + "Terminating and dropping: ~p", + [?LINE, WhatII, Event], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, ?get_Client(State)}, + {reason, WhatII}]), + {stop, normal, State} + end. + +reset_cache(#state{cacheTimeout = undefined, + cacheInterval = undefined} = State) -> + State; +reset_cache(State) -> + stop_timer(State#state.cacheTimeout), + stop_timer(State#state.cacheInterval), + State#state{cacheTimeout = undefined, + cacheInterval = undefined}. + +check_cache(#state{maxCache = Max, cacheTimeout = Timeout, + cacheInterval = Interval} = State) -> + case cosNotification_eventDB:status(State#state.eventDB, eventCounter) of + Count when Count > Max -> + %% Reached the upper limit, terminate. + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, State#state.client}, + {reason, {max_events, Max}}]), + {stop, normal, State}; + _ when Timeout == undefined, Interval == undefined -> + case {timer:send_interval(cosNotificationApp:interval_events(), + cacheInterval), + timer:send_after(cosNotificationApp:timeout_events(), + cacheTimeout)} of + {{ok, IntervalRef}, {ok, TimeoutRef}} -> + {noreply, State#state{cacheTimeout = TimeoutRef, + cacheInterval = IntervalRef}}; + Error -> + orber:dbg("[~p] PusherSupplier:check_cache();~n" + "Unable to start timers: ~p", + [?LINE, Error], ?DEBUG_LEVEL), + 'CosNotification_Common':notify([{proxy, State#state.this}, + {client, State#state.client}, + {reason, {timer, Error}}]), + {stop, normal, State} + end; + _ -> + %% Timers already started. + {noreply, State} + end. + +store_events(_State, []) -> + ok; +store_events(State, [Event|Rest]) when ?is_ANY(State) -> + AnyEvent = any:create('CosNotification_StructuredEvent':tc(),Event), + ?add_Event(State, AnyEvent), + store_events(State, Rest); +store_events(State, [Event|Rest]) -> + ?add_Event(State, Event), + store_events(State, Rest). + +%% Start timers which send a message each time we should push events. Only used +%% when this objects is defined to supply sequences. +start_timer(State) -> + case ?get_PacingInterval(State) of + 0 -> + ?DBG("PUSH SUPPLIER STARTED NO TIMER (0), BATCH LIMIT: ~p~n", + [?get_BatchLimit(State)]), + + State; + PacInt -> + case catch timer:send_interval(timer:seconds(PacInt), pacing) of + {ok,PacTRef} -> + ?DBG("PUSH SUPPLIER STARTED TIMER, BATCH LIMIT: ~p~n", + [?get_BatchLimit(State)]), + ?set_PacingTimer(State, PacTRef); + What -> + orber:dbg("[~p] PusherSupplier:start_timer();~n" + "Unable to invoke timer:send_interval/2: ~p", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end + end. + +stop_timer(undefined) -> + ?DBG("PUSH SUPPLIER HAVE NO TIMER TO STOP~n",[]), + ok; +stop_timer(Timer) -> + ?DBG("PUSH SUPPLIER STOPPED TIMER~n",[]), + timer:cancel(Timer), + ok. + + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/cosNotification.app.src b/lib/cosNotification/src/cosNotification.app.src new file mode 100644 index 0000000..04beac3 --- /dev/null +++ b/lib/cosNotification/src/cosNotification.app.src @@ -0,0 +1,120 @@ +{application, cosNotification, + [{description, "The Erlang CosNotification application"}, + {vsn, "%VSN%"}, + {modules, + [ + 'CosNotification_Common', + 'CosNotifyChannelAdmin_ConsumerAdmin_impl', + 'CosNotifyChannelAdmin_EventChannelFactory_impl', + 'CosNotifyChannelAdmin_EventChannel_impl', + 'CosNotifyChannelAdmin_SupplierAdmin_impl', + 'PullerConsumer_impl', + 'PullerSupplier_impl', + 'PusherConsumer_impl', + 'PusherSupplier_impl', + 'cosNotificationApp', + 'CosNotifyFilter_Filter_impl', + 'CosNotifyFilter_MappingFilter_impl', + 'CosNotifyFilter_FilterFactory_impl', + 'cosNotification_Scanner', + 'cosNotification_Grammar', + 'cosNotification_Filter', + 'cosNotification_eventDB', + 'oe_CosNotification', + 'oe_cosNotificationAppComm', + 'oe_CosNotificationComm_Event', + 'CosNotification', + 'CosNotification_AdminPropertiesAdmin', + 'CosNotification_EventHeader', + 'CosNotification_EventType', + 'CosNotification_FixedEventHeader', + 'CosNotification_NamedPropertyRange', + 'CosNotification_Property', + 'CosNotification_PropertyError', + 'CosNotification_PropertyRange', + 'CosNotification_QoSAdmin', + 'CosNotification_StructuredEvent', + 'CosNotification_UnsupportedAdmin', + 'CosNotification_UnsupportedQoS', + 'CosNotification_EventBatch', + 'CosNotification_EventTypeSeq', + 'CosNotification_NamedPropertyRangeSeq', + 'CosNotification_PropertyErrorSeq', + 'CosNotification_PropertySeq', + 'oe_CosNotifyChannelAdmin', + 'CosNotifyChannelAdmin_AdminLimit', + 'CosNotifyChannelAdmin_AdminLimitExceeded', + 'CosNotifyChannelAdmin_AdminNotFound', + 'CosNotifyChannelAdmin_ChannelNotFound', + 'CosNotifyChannelAdmin_ConnectionAlreadyActive', + 'CosNotifyChannelAdmin_ConnectionAlreadyInactive', + 'CosNotifyChannelAdmin_ConsumerAdmin', + 'CosNotifyChannelAdmin_EventChannel', + 'CosNotifyChannelAdmin_EventChannelFactory', + 'CosNotifyChannelAdmin_NotConnected', + 'CosNotifyChannelAdmin_ProxyConsumer', + 'CosNotifyChannelAdmin_ProxyNotFound', + 'CosNotifyChannelAdmin_ProxyPullConsumer', + 'CosNotifyChannelAdmin_ProxyPullSupplier', + 'CosNotifyChannelAdmin_ProxyPushConsumer', + 'CosNotifyChannelAdmin_ProxyPushSupplier', + 'CosNotifyChannelAdmin_ProxySupplier', + 'CosNotifyChannelAdmin_SequenceProxyPullConsumer', + 'CosNotifyChannelAdmin_SequenceProxyPullSupplier', + 'CosNotifyChannelAdmin_SequenceProxyPushConsumer', + 'CosNotifyChannelAdmin_SequenceProxyPushSupplier', + 'CosNotifyChannelAdmin_StructuredProxyPullConsumer', + 'CosNotifyChannelAdmin_StructuredProxyPullSupplier', + 'CosNotifyChannelAdmin_StructuredProxyPushConsumer', + 'CosNotifyChannelAdmin_StructuredProxyPushSupplier', + 'CosNotifyChannelAdmin_SupplierAdmin', + 'CosNotifyChannelAdmin_AdminIDSeq', + 'CosNotifyChannelAdmin_ChannelIDSeq', + 'CosNotifyChannelAdmin_ProxyIDSeq', + 'oe_CosNotifyComm', + 'CosNotifyComm_InvalidEventType', + 'CosNotifyComm_NotifyPublish', + 'CosNotifyComm_NotifySubscribe', + 'CosNotifyComm_PullConsumer', + 'CosNotifyComm_PullSupplier', + 'CosNotifyComm_PushConsumer', + 'CosNotifyComm_PushSupplier', + 'CosNotifyComm_SequencePullConsumer', + 'CosNotifyComm_SequencePullSupplier', + 'CosNotifyComm_SequencePushConsumer', + 'CosNotifyComm_SequencePushSupplier', + 'CosNotifyComm_StructuredPullConsumer', + 'CosNotifyComm_StructuredPullSupplier', + 'CosNotifyComm_StructuredPushConsumer', + 'CosNotifyComm_StructuredPushSupplier', + 'oe_CosNotifyFilter', + 'CosNotifyFilter_CallbackNotFound', + 'CosNotifyFilter_ConstraintExp', + 'CosNotifyFilter_ConstraintInfo', + 'CosNotifyFilter_ConstraintNotFound', + 'CosNotifyFilter_DuplicateConstraintID', + 'CosNotifyFilter_Filter', + 'CosNotifyFilter_FilterAdmin', + 'CosNotifyFilter_FilterFactory', + 'CosNotifyFilter_FilterNotFound', + 'CosNotifyFilter_InvalidConstraint', + 'CosNotifyFilter_InvalidGrammar', + 'CosNotifyFilter_InvalidValue', + 'CosNotifyFilter_MappingConstraintInfo', + 'CosNotifyFilter_MappingConstraintPair', + 'CosNotifyFilter_MappingFilter', + 'CosNotifyFilter_UnsupportedFilterableData', + 'CosNotifyFilter_CallbackIDSeq', + 'CosNotifyFilter_ConstraintExpSeq', + 'CosNotifyFilter_ConstraintIDSeq', + 'CosNotifyFilter_ConstraintInfoSeq', + 'CosNotifyFilter_FilterIDSeq', + 'CosNotifyFilter_MappingConstraintInfoSeq', + 'CosNotifyFilter_MappingConstraintPairSeq' + ] + }, + {registered, [cosNotificationSup, oe_cosNotificationFactory]}, + {applications, [orber, stdlib, kernel]}, + {env, []}, + {mod, {cosNotificationApp, []}} +]}. diff --git a/lib/cosNotification/src/cosNotification.appup.src b/lib/cosNotification/src/cosNotification.appup.src new file mode 100644 index 0000000..6c3b283 --- /dev/null +++ b/lib/cosNotification/src/cosNotification.appup.src @@ -0,0 +1,7 @@ +{"%VSN%", + [ + ], + [ + ] +}. + diff --git a/lib/cosNotification/src/cosNotificationApp.erl b/lib/cosNotification/src/cosNotificationApp.erl new file mode 100644 index 0000000..ba44163 --- /dev/null +++ b/lib/cosNotification/src/cosNotificationApp.erl @@ -0,0 +1,447 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosNotificationApp.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module(cosNotificationApp). + +%%--------------- INCLUDES ----------------------------------- +%% Local +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). +%%--------------- EXPORTS------------------------------------- +%% cosNotification API external +-export([start/0, stop/0, + start_factory/1, start_factory/0, stop_factory/1, + start_global_factory/0, start_global_factory/1, + start_filter_factory/1, start_filter_factory/0, stop_filter_factory/1, + install/0, install/1, uninstall/0, uninstall/1, + install_event/0, install_event/1, uninstall_event/0, uninstall_event/1, + install_typed/0, install_typed/1, uninstall_typed/0, uninstall_typed/1, + create_structured_event/6, type_check/0, notify/0, max_events/0, + timeout_events/0, interval_events/0]). + +%% Application callbacks +-export([start/2, init/1, stop/1]). + +%%--------------- DEFINES ------------------------------------ +-define(IDL_MODULES, ['oe_CosNotification', + 'oe_cosNotificationAppComm', + 'oe_CosNotifyComm', + 'oe_CosNotifyFilter', + 'oe_CosNotifyChannelAdmin']). +-define(EVENT_IDL_MODULES, ['oe_CosEventComm', + 'oe_CosEventChannelAdmin']). +-define(TYPED_IDL_MODULES, ['oe_CosTypedEvent', + 'oe_CosTypedNotification']). + +-define(FACTORY_NAME, oe_cosNotificationFactory). +-define(SUPERVISOR_NAME, cosNotificationSup). + + +%%------------------------------------------------------------ +%% function : install/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ + +install() -> + install(0). + +install(Time) when is_integer(Time) -> + install_loop(?IDL_MODULES, timer:seconds(Time)); +install(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : install_event/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ + +install_event() -> + install_event(0). + +install_event(Time) when is_integer(Time) -> + install_loop(?EVENT_IDL_MODULES, timer:seconds(Time)); +install_event(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : install_typed/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ + +install_typed() -> + install_typed(0). + +install_typed(Time) when is_integer(Time) -> + install_loop(?TYPED_IDL_MODULES, timer:seconds(Time)); +install_typed(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +install_loop([], _) -> + ok; +install_loop([H|T], Time) -> + H:'oe_register'(), + timer:sleep(Time), + install_loop(T, Time). + +%%------------------------------------------------------------ +%% function : uninstall/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosNotificationin from the IFR DB +%%------------------------------------------------------------ + +uninstall() -> + uninstall(0). + +uninstall(Time) when is_integer(Time) -> + uninstall_loop(lists:reverse(?IDL_MODULES), timer:seconds(Time)); +uninstall(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : uninstall_event/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosNotificationin from the IFR DB +%%------------------------------------------------------------ + +uninstall_event() -> + uninstall_event(0). + +uninstall_event(Time) when is_integer(Time) -> + uninstall_loop(lists:reverse(?EVENT_IDL_MODULES), timer:seconds(Time)); +uninstall_event(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : uninstall_typed/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosNotificationin from the IFR DB +%%------------------------------------------------------------ + +uninstall_typed() -> + uninstall_typed(0). + +uninstall_typed(Time) when is_integer(Time) -> + uninstall_loop(lists:reverse(?TYPED_IDL_MODULES), timer:seconds(Time)); +uninstall_typed(_Time) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +uninstall_loop([], _) -> + ok; +uninstall_loop([H|T], Time) -> + H:'oe_unregister'(), + timer:sleep(Time), + uninstall_loop(T, Time). + + +%%------------------------------------------------------------ +%% function : start/stop +%% Arguments: +%% Returns : +%% Effect : Starts or stops the cosTRansaction application. +%%------------------------------------------------------------ + +start() -> + application:start(cosNotification). +stop() -> + application:stop(cosNotification). + +%%------------------------------------------------------------ +%% function : start_factory +%% Arguments: none or an argumentlist whith default values. +%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason} +%% Effect : Starts a CosNotifyChannelAdmin_EventChannelFactory +%%------------------------------------------------------------ +start_factory() -> + start_factory(?not_DEFAULT_SETTINGS). + +start_factory(Args) when is_list(Args) -> + SO = 'CosNotification_Common':get_option(server_options, Args, ?not_DEFAULT_SETTINGS), + SPEC = ['CosNotifyChannelAdmin_EventChannelFactory',Args, + [{sup_child, true}, + {regname, {local, oe_cosNotificationFactory}}|SO]], + case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + Other-> + orber:dbg("[~p] cosNotificationApp:start_factory( ~p ).~n" + "Reason: ~p~n", [?LINE, Args, Other], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +start_factory(Args) -> + orber:dbg("[~p] cosNotificationApp:start_factory( ~p ).~n" + "Bad parameters~n", [?LINE, Args], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%------------------------------------------------------------ +%% function : start_global_factory +%% Arguments: none or an argumentlist whith default values. +%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason} +%% Effect : Starts a CosNotifyChannelAdmin_EventChannelFactory +%%------------------------------------------------------------ +start_global_factory() -> + start_global_factory(?not_DEFAULT_SETTINGS). + +start_global_factory(Args) when is_list(Args) -> + SO = 'CosNotification_Common':get_option(server_options, Args, ?not_DEFAULT_SETTINGS), + Name = create_name(), + SPEC = ['CosNotifyChannelAdmin_EventChannelFactory',Args, + [{sup_child, true}, + {regname, {global, Name}}|SO]], + case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + Other-> + orber:dbg("[~p] cosNotificationApp:start_global_factory( ~p ).~n" + "Reason: ~p~n", [?LINE, Args, Other], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +start_global_factory(Args) -> + orber:dbg("[~p] cosNotificationApp:start_global_factory( ~p ).~n" + "Bad parameters~n", [?LINE, Args], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%------------------------------------------------------------ +%% function : stop_factory +%% Arguments: Factory Object Reference +%% Returns : ok | {'EXCEPTION', _} +%% Effect : +%%------------------------------------------------------------ + +stop_factory(Fac)-> + corba:dispose(Fac). + +%%------------------------------------------------------------ +%% function : start_filter_factory +%% Arguments: none or an argumentlist which by default is defined +%% in CosNotification_Definitions.hrl, i.e., '?not_FILTERFAC_DEF' +%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason} +%% Effect : Starts a CosNotifyChannelAdmin_EventChannelFactory +%%------------------------------------------------------------ +start_filter_factory() -> + start_filter_factory([{typecheck, true}, + {tty, false}, + {logfile, false}, + {server_options, []}]). +start_filter_factory(Args) when is_list(Args) -> + SO = 'CosNotification_Common':get_option(server_options, Args, + ?not_DEFAULT_SETTINGS), + SPEC = ['CosNotifyFilter_FilterFactory',Args, [{sup_child, true}|SO]], + case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + Other-> + orber:dbg("[~p] cosNotificationApp:start_filter_factory( ~p ).~n" + "Reason: ~p~n", [?LINE, Args, Other], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +start_filter_factory(Args) -> + orber:dbg("[~p] cosNotificationApp:start_filter_factory( ~p ).~n" + "Bad parameters~n", [?LINE, Args], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%------------------------------------------------------------ +%% function : stop_filter_factory +%% Arguments: FilterFactory Object Reference +%% Returns : ok | {'EXCEPTION', _} +%% Effect : +%%------------------------------------------------------------ + +stop_filter_factory(Fac)-> + corba:dispose(Fac). + + +%%------------------------------------------------------------ +%% function : create_structured_event +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +create_structured_event(StrD,StrT,StrE,PSeqV,PSeqF,AnyR) + when is_list(StrD) andalso is_list(StrT) andalso is_list(StrE) + andalso is_list(PSeqV) andalso is_list(PSeqF) andalso + is_record(AnyR, any) -> +#'CosNotification_StructuredEvent'{header = + #'CosNotification_EventHeader'{fixed_header = + #'CosNotification_FixedEventHeader'{event_type = + #'CosNotification_EventType'{domain_name=StrD, + type_name=StrT}, + event_name = StrE}, + variable_header = PSeqV}, + filterable_data = PSeqF, + remainder_of_body = AnyR}; +create_structured_event(_StrD,_StrT,_StrE,_PSeqV,_PSeqF,_AnyR) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%------------------------------------------------------------ +%% function : type_check +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +type_check() -> + case application:get_env(cosNotification, type_check) of + {ok, Boolean} when is_atom(Boolean) -> + Boolean; + _ -> + true + end. + +%%------------------------------------------------------------ +%% function : notify +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +notify() -> + case application:get_env(cosNotification, notify) of + {ok, Module} when is_atom(Module) -> + Module; + _ -> + false + end. + +%%------------------------------------------------------------ +%% function : max_events +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +max_events() -> + case application:get_env(cosNotification, max_events) of + {ok, Max} when is_integer(Max) -> + Max; + _ -> + 50 + end. + +%%------------------------------------------------------------ +%% function : timeout_events +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +timeout_events() -> + case application:get_env(cosNotification, timeout_events) of + {ok, Max} when is_integer(Max) -> + Max; + _ -> + 3000000 %% 5 minutes + end. + + +%%------------------------------------------------------------ +%% function : interval_events +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +interval_events() -> + case application:get_env(cosNotification, interval_events) of + {ok, Max} when is_integer(Max) -> + Max; + _ -> + 10000 %% 10 seconds + end. + + +%%------------------------------------------------------------ +%% function : start +%% Arguments: Type - see module application +%% Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +start(_, _) -> + supervisor:start_link({local, ?SUPERVISOR_NAME}, cosNotificationApp, app_init). + + +%%------------------------------------------------------------ +%% function : stop +%% Arguments: Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +stop(_) -> + ok. + +%%------------------------------------------------------------ +%% function : init +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%% Starting using create_factory/X +init(own_init) -> + {ok,{{simple_one_for_one,50,10}, + [{"oe_NotChild", + {'CosNotification_Common',create_link, []}, + transient,100000,worker, + ['CosNotifyChannelAdmin_EventChannel', + 'CosNotifyChannelAdmin_EventChannel_impl']}]}}; +%% When starting as an application. +init(app_init) -> + {ok,{{simple_one_for_one,50,10}, + [{"oe_NotChild", + {'CosNotification_Common',create_link, []}, + transient,100000,worker, + ['CosNotifyChannelAdmin_EventChannel', + 'CosNotifyChannelAdmin_EventChannel_impl']}]}}. + + + +%%------------------------------------------------------------ +%% function : create_name +%% Arguments: +%% Returns : +%% Effect : Create a unique name to use when, for eaxmple, starting +%% a new server. +%%------------------------------------------------------------ +create_name() -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',MSec, '_', Sec, '_', USec]). + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/cosNotificationAppComm.idl b/lib/cosNotification/src/cosNotificationAppComm.idl new file mode 100644 index 0000000..09e0af2 --- /dev/null +++ b/lib/cosNotification/src/cosNotificationAppComm.idl @@ -0,0 +1,17 @@ +#ifndef _OE_COSNOTIFICATIONCOMM_IDL_ +#define _OE_COSNOTIFICATIONCOMM_IDL_ + +#include + +module oe_CosNotificationComm { + + interface Event { + + enum status {MATCH, MATCHED}; + void callSeq(in CosNotification::EventBatch events, in status stat); + void callAny(in any event, in status stat); + }; + +}; +#endif /* ifndef _OE_COSNOTIFICATIONCOMM_IDL_ */ + diff --git a/lib/cosNotification/src/cosNotificationComm.cfg b/lib/cosNotification/src/cosNotificationComm.cfg new file mode 100644 index 0000000..89d2075 --- /dev/null +++ b/lib/cosNotification/src/cosNotificationComm.cfg @@ -0,0 +1,3 @@ +{this, "oe_CosNotificationComm::Event"}. +{from, "oe_CosNotificationComm::Event"}. +{{handle_info, "oe_CosNotificationComm::Event"}, true}. diff --git a/lib/cosNotification/src/cosNotification_Filter.erl b/lib/cosNotification/src/cosNotification_Filter.erl new file mode 100644 index 0000000..dd3b5be --- /dev/null +++ b/lib/cosNotification/src/cosNotification_Filter.erl @@ -0,0 +1,964 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosNotification_Filter.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module(cosNotification_Filter). + + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%% Internal Filter Functions +-export([eval/1, + eval/2, + create_filter/1, + check_types/1, + match_types/3, + validate_types/1]). + +%%--------------- DEFINES ------------------------------------ +-define(EVENT_PATH, [{dotid,"header"}, {dotid,"fixed_header"}, + {dotid,"event_name"}]). +-define(DOMAIN_PATH, [{dotid,"header"}, {dotid,"fixed_header"}, + {dotid,"event_type"}, {dotid,"domain_name"}]). +-define(TYPE_PATH, [{dotid,"header"}, {dotid,"fixed_header"}, + {dotid,"event_type"}, {dotid,"type_name"}]). +-define(VARIABLE_PATH(I), [{dotid,"header"}, {dotid,"variable_header"}, {dotid,I}]). +-define(FILTERABLE_PATH(I), [{dotid,"filterable_data"}, {dotid,I}]). + + +%%------------------------------------------------------------ +%%--------------- FILTER FUNCTIONS --------------------------- +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% function : create_filter/1 +%% Arguments: String - Filter grammar +%% Returns : +%% Effect : +%%------------------------------------------------------------ +create_filter(Str) -> + {ok, Tokens} = cosNotification_Scanner:scan(Str), + case cosNotification_Grammar:parse(Tokens) of + {ok, Filter} -> + {ok, Filter}; + _-> + corba:raise(#'CosNotifyFilter_InvalidConstraint'{constr = Str}) + end. + +%%------------------------------------------------------------ +%% function : eval +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +eval('$empty') -> true; +eval(Tree) -> eval(Tree, []). + + +%% Leaf expressions (literals and idents). +eval('$empty', _) -> true; +eval(Lit, _Env) when is_number(Lit) -> Lit; +eval(Lit, _Env) when is_list(Lit) -> Lit; %list == string +eval(Lit, _Env) when is_atom(Lit) -> Lit; %atom == bool +eval({component, V}, []) -> + %% Cannot evaluate variables at this stage. + throw({error, {unbound_variable, V}}); +eval({component, V}, Env) -> + case catch lookup(V, Env, undefined) of + {ok, Val} -> + Val; + _X -> + {error, {unbound_variable, V}} + end; + +%% CORBA2.3-15/26 states: +%% "The name parameters in tk_objref, tk_struct, tk_union, tk_enum, tk_alias, +%% tk_value, tk_value_box, tk_abstract_interface, tk_native and tk_except TypeCodes +%% and the member name parameters in tk_struct, tk_union, tk_enum, tk_value and +%% tk_except TypeCodes are not specified by (or significant in) GIOP. Agents should +%% not make assumptions about type equivalence based on these name values; only the +%% structural information (including RepositoryId values, if provided) is +%% significant. If provided, the strings should be the simple, unscoped names +%% supplied in the OMG IDL definition text. If omitted, they are encoded as empty +%% strings." +%% Makes it rather hard to follow the grammar 100 %. +eval({default_component, V}, Env) -> + case catch lookup(V, Env, default_component) of + {ok, false} -> + false; + {ok, true} -> + true; + _X -> + {error, {unbound_variable, V}} + end; +eval({exist_component, V}, Env) -> + case catch lookup(V, Env, exist_component) of + {ok, false} -> + false; + {ok, _} -> + true; + {error, _} -> + false; + _X -> + {error, {unbound_variable, V}} + end; +%% Arithmetic expressions. +eval({'*', X, Y}, Env) -> + eval_arith({fun(_X, _Y) -> _X*_Y end, X, Y}, Env); +eval({'/', X, Y}, Env) -> + eval_arith({fun(_X, _Y) -> _X/_Y end, X, Y}, Env); +eval({'+', X, Y}, Env) -> + eval_arith({fun(_X, _Y) -> _X+_Y end, X, Y}, Env); +eval({'-', X, Y}, Env) -> + eval_arith({fun(_X, _Y) -> _X-_Y end, X, Y}, Env); +eval({'u-', X}, Env) -> + eval_arith({fun(_X) -> -_X end, X}, Env); +%% Relational expressions. +eval({'==', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X == _Y end, X, Y}, Env); +eval({'!=', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X /= _Y end, X, Y}, Env); +eval({'<', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X < _Y end, X, Y}, Env); +eval({'<=', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X =< _Y end, X, Y}, Env); +eval({'>', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X > _Y end, X, Y}, Env); +eval({'>=', X, Y}, Env) -> + eval_rel({fun(_X, _Y) -> _X >= _Y end, X, Y}, Env); +eval({'~', Needle, Haystack}, Env) -> %substring match + N = eval(Needle, Env), + H = eval(Haystack, Env), + if + is_list(N) andalso is_list(H) -> + string:str(H, N) /= 0; + true -> + throw({error, {bad_type, Needle, Haystack}}) + end; +eval({'in', Needle, Haystack}, Env) -> %set membership + N = eval(Needle, Env), + H = eval(Haystack, Env), + if + is_list(H) -> + lists:member(N, H); + true -> + throw({error, {bad_type, Needle, Haystack}}) + end; +%% Boolean expressions. +eval({'and', false, _Y}, _Env) -> + false; +eval({'and', _X, false}, _Env) -> + false; +eval({'and', X, Y}, Env) -> + eval_and_bool({fun(_X, _Y) -> _X and _Y end, X, Y}, Env); + +eval({'or', true, _Y}, _Env) -> + true; +eval({'or', _X, true}, _Env) -> + true; +eval({'or', X, Y}, Env) -> + eval_or_bool({fun(_X, _Y) -> _X or _Y end, X, Y}, Env); +eval({'not', X}, Env) -> + eval_bool({fun(_X) -> not _X end, X}, Env); +%% Catch-all +eval(_T, _Env) -> + throw({error, internal}). + +eval_bool({Fun, X}, Env) -> + Xe = eval(X, Env), + if + is_atom(Xe) -> + Fun(Xe); + true -> + throw({error, {bad_type, X}}) + end. +eval_and_bool({Fun, X, Y}, Env) -> + case eval(X, Env) of + false -> + %% No need for evaluating the other expression. + false; + Xe -> + Ye = eval(Y, Env), + if + is_atom(Xe) andalso is_atom(Ye) -> + Fun(Xe, Ye); + true -> + throw({error, {bad_type, X, Y}}) + end + end. +eval_or_bool({Fun, X, Y}, Env) -> + case eval(X, Env) of + true -> + %% No need for evaluating the other expression. + true; + Xe -> + Ye = eval(Y, Env), + if + is_atom(Xe) andalso is_atom(Ye) -> + Fun(Xe, Ye); + true -> + throw({error, {bad_type, X, Y}}) + end + end. + + +%% According to issue 2203, OMG stated that arithmetic operations involving booleans +%% is allowed. TRUE equals 1 and FALSE 0. They refer to: + +%% "We at NEC like this feature, and feel it is both required and +%% standard with the way CORBA treats boolean values. We feel it's +%% required because it allows the constraint grammar to handle +%% expressions that combine the results of boolean comparisons, +%% which we feel is typically expected of a constraint grammar +%% (e.g., ($.fruit == apples) + ($.color == red) + ($.kind == macintosh) > 2) +%% Furthermore, while we have no fundamental opposition to explicitly +%% stating that TRUE=1 and FALSE=0, we don't necessarily feel it's +%% necessary because section 12.3.1 of CORBA alread states that +%% "Boolean values are encoded as single octets, where TRUE is the +%% value 1, and FALSE is 0." Essentially, we feel CORBA already +%% defines TRUE to be 1 and FALSE to be 0, however we are not +%% opposed to adding such a statement into Notification if folks +%% feel it's necessary." +%% If still valid, see: ftp://ftp.omg.org/pub/docs/telecom/99-07-06.txt + +%% The section they refer to (CORBA-2.0) merely states that TRUE and FALSE are +%% encoded as 1 and 0 in GIOP. Does not imply that booleans may be used as numeric. +%% But, they have stated that this should be the case so..... + +remap_bool(Num) when is_number(Num) -> Num; +remap_bool(true) -> 1; +remap_bool(false) -> 0; +remap_bool(X) -> throw({error, {bad_type, X}}). + +eval_arith({Fun, X}, Env) -> + Xe = remap_bool(eval(X, Env)), + Fun(Xe); +eval_arith({Fun, X, Y}, Env) -> + Xe = remap_bool(eval(X, Env)), + Ye = remap_bool(eval(Y, Env)), + Fun(Xe, Ye). + +eval_rel({Fun, X, Y}, Env) -> + Xe = eval(X, Env), + Ye = eval(Y, Env), + if + is_number(Xe) andalso is_number(Ye) -> + Fun(Xe, Ye); + is_list(Xe) andalso is_list(Ye) -> + Fun(Xe, Ye); + is_atom(Xe) andalso is_atom(Ye) -> + Fun(Xe, Ye); + true -> + throw({error, {bad_type, X, Y}}) + end. + +%%------------------------------------------------------------ +%% function : get_variable +%% Arguments: A sequence of CosNotification::Property{}, i.e., +%% name-value pairs. +%% ID - name in the Property +%% Any - remainder of body +%% Returns : Value in the Property | false +%% Comment : When searching for a variable we must start with +%% 'variable_header' followed by 'filterable_body'. +%% If not found we will then look in the 'remainder_of_body' +%%------------------------------------------------------------ + +get_variable([], ID, Any) when is_record(Any, any) -> + case {any:get_value(Any), any:get_typecode(Any)} of + {#'CosNotification_Property'{name=ID, value=A}, _} -> + any:get_value(A); + {_, TC} when is_atom(TC) -> + %% Since TC atom it must be a simple type, which don't have members. + throw({error, {bad_id, ID}}); + {Value, {tk_alias,_,ID,_}} when is_record(Value, any) -> + %% {tk_alias, IFRId, ID, TypeCode} + any:get_value(Value); + {Value, {tk_alias,_,ID,_}} -> + %% {tk_alias, IFRId, ID, TypeCode} + Value; + {Value, _TC} -> + get_variable([],ID, Value) + end; +get_variable([], ID, #'CosNotification_Property'{name=ID, value=Any}) -> + any:get_value(Any); +get_variable([], ID, [#'CosNotification_Property'{name=ID, value=Any}|_]) -> + any:get_value(Any); +get_variable([], ID, [H|T]) when is_record(H, 'CosNotification_Property') -> + get_variable([], ID, T); +get_variable([], ID, false) -> + throw({error, {bad_id, ID}}); +get_variable([], ID, Value) -> + M = element(1, Value), + case catch M:tc() of + {tk_struct,_,_,SList} -> + %% {tk_struct, Id, Name, ElementList}. + Field = get_field(ID, SList), + element(Field, Value); + {tk_union,_,_,_, DefNo, UList} -> + %% {tk_union, Id, Name, DiscrTC, Default, ElementList} + case id2switch(UList, ID) of + [default] when DefNo >= 0 -> + element(3, Value); + [default] -> + throw({error, {bad_id, "Bad Union ID supplied"}}); + Found -> + case catch lists:member(element(2, Value), Found) of + true -> + element(3, Value); + _ -> + throw({error, {bad_id, "Bad Union ID supplied"}}) + end + end; + _-> + throw({error, {bad_id, ID}}) + end; +get_variable([#'CosNotification_Property'{name=ID, value=A}|_], ID, _) -> + any:get_value(A); +get_variable([_|T], ID, Any) -> + get_variable(T, ID, Any). + +%%------------------------------------------------------------ +%% function : lookup +%% Arguments: T - A parse tree representing the grammar. +%% S - The event we want to extract data from +%% Op - which type of lookup should be done on this +%% component, e.g., 'default' or 'exist'. +%% Returns : {ok, boolean()} | +%% {error, _} +%% Comment : WARNING!!!! +%% This function uses some Orber core information to +%% extract data, e.g., TypeCode representation. Why? +%% We don't want to see the performance take a plunge +%% due to that users write constraints which they +%% can/may not know is slow. The alternative would be +%% to use the IFR. However, these shortcuts aren't +%% that frequent and we can easily update the code. +%% To update, investigate: +%% * lookup/3 cases related to '_type_id' +%% * lookup/3 cases related to unions +%% * get_variable/3 +%% * id2switch/2 +%% * switch2alias/2 +%%------------------------------------------------------------ +%% Done parsing, return the result. +lookup([],S,_) -> {ok, S}; +lookup('$empty', #'CosNotification_StructuredEvent'{remainder_of_body = Any},_) -> + {ok, any:get_value(Any)}; +lookup('$empty',S,_) when is_record(S, any) -> + {ok, any:get_value(S)}; + +%%------- varid -------- +%% CosNotification-revision-98-11-01/46 states: +%% "The following rules govern translation of a run-time variable, $variable , +%% into a specific event field. If the run-time variable is reserved +%% (e.g., $curtime) this translation takes precedence. Next, the first matching +%% translation is chosen respectively from: +%% * a simple-typed member of $.header.fixed_header, +%% * properties in $.header.variable_header, +%% and properties in $.header.filterable_data. +%% If no match is found, the translation defaults to $.variable. +%% Given these rules, an unstructured event with a $.priority member and a +%% structured event using $.header.variable_header(priority) can be specified +%% in a generic constraint using the run-time variable $priority . +%% Alternatively, a constraint can be written specifically for a structured or +%% unstructured event by avoiding the use of run-time variables." + +%% The above contains one error; $.header.filterable_data is not a part of the +%% header, but contained in the event body. + +%% For any events we must first verify that a path exist, e.g., +%% "header"->"fixed_header"->"event_type"->"domain_name", otherwise we will +%% use {dotid, "xxx"}. +lookup([{varid, "type_name"}|T], + #'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {fixed_header = #'CosNotification_FixedEventHeader' + {event_type = #'CosNotification_EventType'{type_name=TN}}}}, Op) -> + lookup(T, TN, Op); +lookup([{varid, "type_name"}|T], Any, Op) when is_record(Any, any) -> + case locate_var([?TYPE_PATH, ?VARIABLE_PATH("type_name"), + ?FILTERABLE_PATH("type_name")], Any, Op) of + {ok, Val} -> + lookup(T, Val, Op); + _ -> + lookup(T, get_variable([], "type_name", Any), Op) + end; +lookup([{varid, "domain_name"}|T], + #'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {fixed_header = #'CosNotification_FixedEventHeader' + {event_type = #'CosNotification_EventType'{domain_name=DN}}}}, Op) -> + lookup(T, DN, Op); +lookup([{varid, "domain_name"}|T], Any, Op) when is_record(Any, any) -> + case locate_var([?DOMAIN_PATH, ?VARIABLE_PATH("domain_name"), + ?FILTERABLE_PATH("domain_name")], Any, Op) of + {ok, Val} -> + lookup(T, Val, Op); + _ -> + lookup(T, get_variable([], "domain_name", Any), Op) + end; +lookup([{varid, "event_name"}|T], + #'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {fixed_header = #'CosNotification_FixedEventHeader' + {event_name = EN}}}, Op) -> + lookup(T, EN, Op); +lookup([{varid, "event_name"}|T], Any, Op) when is_record(Any, any) -> + case locate_var([?EVENT_PATH, ?VARIABLE_PATH("event_name"), + ?FILTERABLE_PATH("event_name")], Any, Op) of + {ok, Val} -> + lookup(T, Val, Op); + _ -> + lookup(T, get_variable([], "event_name", Any), Op) + end; + +lookup([{varid, ID}|T], + #'CosNotification_StructuredEvent'{header = + #'CosNotification_EventHeader'{variable_header = VS}, + filterable_data = FS, + remainder_of_body = Any}, Op) -> + lookup(T, get_variable(VS++FS, ID, Any), Op); +lookup([{varid, ID}|T], Any, Op) -> + case locate_var([?VARIABLE_PATH(ID), ?FILTERABLE_PATH(ID)], Any, Op) of + {ok, Val} -> + lookup(T, Val, Op); + _ -> + lookup(T, get_variable([], ID, Any), Op) + end; + +%%------- dotid -------- +%% First level +lookup([{dotid, "header"}|T], + #'CosNotification_StructuredEvent'{header = S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "filterable_data"}|T], + #'CosNotification_StructuredEvent'{filterable_data = S}, Op) -> + lookup(T, S, Op); + +lookup([{dotid, remainder_of_body}|T], + #'CosNotification_StructuredEvent'{remainder_of_body = S}, Op) -> + lookup(T, S, Op); +%% Second level. Previous token must have been header +lookup([{dotid, "fixed_header"}|T], + #'CosNotification_EventHeader'{fixed_header = S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "variable_header"}|T], + #'CosNotification_EventHeader'{variable_header = S}, Op) -> + lookup(T, S, Op); +%% Third level. Previous token must have been fixed_header. +lookup([{dotid, "event_type"}|T], + #'CosNotification_FixedEventHeader'{event_type = S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "event_name"}|T], + #'CosNotification_FixedEventHeader'{event_name = S}, Op) -> + lookup(T, S, Op); +%% Fourth level. Previous token must have been event_type +lookup([{dotid, "domain_name"}|T], #'CosNotification_EventType'{domain_name = S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "type_name"}|T], #'CosNotification_EventType'{type_name = S}, Op) -> + lookup(T, S, Op); + +%% Leaf expressions +lookup([{dotid, "name"}|T], #'CosNotification_Property'{name=S}, Op) -> + lookup(T, S, Op); +lookup([{dotid, "value"}|T], #'CosNotification_Property'{value=S}, Op) -> + lookup(T, S, Op); + +lookup([{dotid, ID}|T], + #'CosNotification_StructuredEvent'{remainder_of_body = Any}, Op) -> + lookup(T, get_variable([], ID, Any), Op); +lookup([{dotid, ID}|T], Any, Op) -> + lookup(T, get_variable([], ID, Any), Op); + +lookup([{associd, ID}|T], S, Op) when is_list(S) -> + %% Refers to an associative array, i.e., a list of + %% #'CosNotification_Property'{name=ID, value=A} + lookup(T, get_variable(S, ID, false), Op); + +lookup([{dotint, Position}|T], S, Op) when is_record(S, any) -> + lookup(T, element(Position+2, any:get_value(S)), Op); +lookup([{dotint, Position}|T], S, Op) -> + lookup(T, element(Position+2, S), Op); + +lookup([{uint, ID}|T], S, Op) when is_record(S, any) -> + lookup([{uint, ID}|T], any:get_value(S), Op); +lookup([{uint, ID} |T], S, Op) when is_tuple(S) -> + case catch element(2, S) of + ID -> + %% The supplied union do contain the requested discriminator. + lookup(T, element(3, S), Op); + _Other when Op == exist_component -> + throw({error, {bad_id, "Bad Union ID"}}); + Other -> + %% Check if default is allowed. + M = element(1, S), + case catch M:tc() of + {tk_union,_,_,_,DefNo, UList} -> + %% {tk_union, Id, Name, DiscrTC, Default, ElementList} + case switch2alias(UList, ID) of + {ok, [], _} -> + throw({error, {bad_id, "Bad Union ID"}}); + {ok, default, _} when DefNo >= 0 -> + lookup(T, element(3, S), Op); + {ok, List, _} -> + case lists:member(Other, List) of + true -> + lookup(T, element(3, S), Op); + _-> + throw({error, {bad_id, "Bad Union ID"}}) + end + end + end + end; +lookup([{ustr, ID}|T], S, Op) when is_record(S, any) -> + lookup([{ustr, ID}|T], any:get_value(S), Op); +lookup([{ustr, ID}|T], S, Op) when is_tuple(S) -> + M = element(1, S), + case catch M:tc() of + {tk_union,_,_,_,DefNo, UList} -> + case id2switch(UList, ID) of + [default] when DefNo >= 0 -> + lookup(T, element(3, S), Op); + [default] -> + throw({error, {bad_id, "Bad Union ID supplied"}}); + Found -> + case catch lists:member(element(2, S), Found) of + true -> + lookup(T, element(3, S), Op); + _ -> + throw({error, {bad_id, "Bad Union ID supplied"}}) + end + end + end; +lookup([default|T], S, Op) when is_record(S, any) -> + lookup([default|T], any:get_value(S), Op); +lookup([default|T], S, Op) when is_tuple(S) -> + M = element(1, S), + case catch M:tc() of + {tk_union,_,_,_,DefNo, _UList} when DefNo < 0 -> + %% {tk_union, Id, Name, DiscrTC, Default, ElementList} + throw({error, {bad_id, "No default discriminator"}}); + {tk_union,_,_,_,_DefNo, UList} -> + %% {tk_union, Id, Name, DiscrTC, Default, ElementList} + %% Check if the label really is default. + case lists:keymember(element(2, S), 1, UList) of + false -> + lookup(T, element(3, S), Op); + _-> + throw({error, {bad_id, "Bad Union"}}) + end; + _-> + throw({error, {bad_id, "Bad Union"}}) + end; + +lookup([{arrindex, Index}|T], S, Op) when is_tuple(S) -> + %% The OMG uses c/c++ index. We must add one. + lookup(T, element(Index+1,S), Op); + +%%%%%%%%%%%%%%%%%%%%%%% LEAF EXPRESSIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% got '$._length', which maps to the 'remainder_of_body' +lookup(['_length'], + #'CosNotification_StructuredEvent'{remainder_of_body = Any}, _Op) -> + {ok, length(any:get_value(Any))}; +lookup(['_length'], S, _Op) when is_record(S, any) -> + {ok, length(any:get_value(S))}; +lookup(['_length'], S, _Op) when is_list(S) -> + {ok, length(S)}; +lookup(['_length'], S, _Op) when is_tuple(S) -> + {ok, length(tuple_to_list(S))}; + +%% got '$._d', which maps to the 'remainder_of_body' +%% The discriminator may, accordiong to the CORBA specification, be (2.3/p3-37): +%% * integer_type +%% * char_type +%% * boolean_type +%% * enum_type +%% * scoped_name +lookup(['_d'], + #'CosNotification_StructuredEvent'{remainder_of_body = Any}, + default_component) -> + lookup(['_d'], any:get_value(Any), default_component); +lookup(['_d'], S, default_component) when is_record(S, any) -> + lookup(['_d'], any:get_value(S), default_component); +lookup(['_d'], S, default_component) -> + M = element(1, S), + case catch M:tc() of + {tk_union,_,_,_,DefNo,_} when DefNo < 0 -> + %% '-1' indicates that no default value may exist. + {ok, false}; + {tk_union,_,_,_,_,UList} -> + %% May be using the default setting; check if the Value is in the list. + {ok, not lists:keymember(element(2, S), 1, UList)}; + _ -> + {ok, false} + end; +lookup(['_d'], + #'CosNotification_StructuredEvent'{remainder_of_body = Any}, _Op) -> + {ok, element(2, any:get_value(Any))}; +lookup(['_d'], S, _Op) when is_record(S, any) -> + {ok, element(2, any:get_value(S))}; +lookup(['_d'], S, _Op) -> + {ok, element(2, S)}; + + +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_StructuredEvent') -> + {ok, "StructuredEvent"}; +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_EventHeader') -> + {ok, "EventHeader"}; +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_FixedEventHeader') -> + {ok, "FixedEventHeader"}; +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_EventType') -> + {ok, "EventType"}; +lookup(['_type_id'], S, _Op) when is_record(S,'CosNotification_Property') -> + {ok, "Property"}; +lookup(['_type_id'], S, _Op) when is_tuple(S) -> + M=element(1, S), + Name = case catch M:tc() of + {tk_union,_,ID,_,_,_} -> + ID; + {tk_enum, _, ID, _} -> + ID; + {tk_exception, _, ID, _} -> + ID; + {tk_alias, _, ID, _} -> + ID; + {tk_struct,_,ID,_} -> + ID + end, + {ok, Name}; + +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_StructuredEvent') -> + {ok, 'CosNotification_StructuredEvent':id()}; +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_EventHeader') -> + {ok, 'CosNotification_EventHeader':id()}; +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_FixedEventHeader') -> + {ok, 'CosNotification_FixedEventHeader':id()}; +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_EventType') -> + {ok, 'CosNotification_EventType':id()}; +lookup(['_repos_id'], S, _Op) when is_record(S,'CosNotification_Property') -> + {ok, 'CosNotification_Property':id()}; +lookup(['_repos_id'], S, _Op) when is_tuple(S) -> + M = element(1, S), + {ok, M:id()}; + +lookup(_, _, _) -> + error. + + +%%------------------------------------------------------------ +%% function : locate_var +%% Arguments: Paths - A list of path-lists which tells us where +%% to search for runtime variables and in which +%% order. +%% S - Data +%% Op - se lookup/3 +%% Returns : {error, _} | +%% {ok, Val} +%%------------------------------------------------------------ +locate_var([], _S, _) -> + {error, "not found"}; +locate_var([H|T], S, Op) -> + case catch lookup(H, S, Op) of + {ok, Val} -> + {ok,Val}; + _ -> + locate_var(T, S, Op) + end. + +%%------------------------------------------------------------ +%% function : id2switch +%% Arguments: UList - The list of elements contained in the +%% Union TypeCode. +%% ID - string() eq name of element. +%% Returns : Acc - A list of switches related to given ID. +%%------------------------------------------------------------ +id2switch(UList, ID) -> + id2switch(UList, ID, [], false). +id2switch([], _, Acc, _) -> + Acc; +id2switch([{Sw, ID, _}|T], ID, Acc, _) -> + id2switch(T, ID, [Sw|Acc], true); +id2switch([_|_T], _ID, Acc, true) -> + Acc; +id2switch([_|T], ID, Acc, Found) -> + id2switch(T, ID, Acc, Found). + +%%------------------------------------------------------------ +%% function : switch2alias +%% Arguments: UList - The list of elements contained in the +%% Union TypeCode. +%% Switch - the union discriminator. +%% Returns : Acc - A list of switches that are defined with the same +%% ID - The switches common ID. +%% Comment : A union IDL code can look like: +%% union Union switch(long) { +%% case 1: +%% case 2: long ID; }; +%% In this case supplying Switch == 1 (or) the result +%% should be {ok, [1,2], "ID"} +%%------------------------------------------------------------ +switch2alias([], _Switch) -> + %% Is it really possible to define an empty union?? + {ok, [], undefined}; +switch2alias([{Sw, ID, TC}|UList], Switch) -> + switch2alias([{Sw, ID, TC}|UList], Switch, [], ID, false). + + +switch2alias([{default, ID, _}], _, _, _, false) -> + {ok, default, ID}; +switch2alias([], _, _Acc, _, false) -> + {ok, [], undefined}; +switch2alias([], _, Acc, PreviousID, _) -> + {ok, Acc, PreviousID}; + +%% Seen the ID before but just found the correct switch, e.g., +%% [... {0,"K",{tk_string,0}}, {2,"K",{tk_string,0}}...] and switch eq '2' +switch2alias([{Switch, PreviousID, _}|T], Switch, Acc, PreviousID, _Found) -> + switch2alias(T, Switch, [Switch|Acc], PreviousID, true); + +%% First time for this ID and found the correct switch +switch2alias([{Switch, ID, _}|T], Switch, _Acc, _PreviousID, false) -> + switch2alias(T, Switch, [Switch], ID, true); + +%% Seen this ID and found the correct switch before. +switch2alias([{Sw, PreviousID, _}|T], Switch, Acc, PreviousID, true) -> + switch2alias(T, Switch, [Sw|Acc], PreviousID, true); + +%% Seen this ID but not found the correct switch. +switch2alias([{Sw, PreviousID, _}|T], Switch, Acc, PreviousID, false) -> + switch2alias(T, Switch, [Sw|Acc], PreviousID, false); + +%% No more of the correct ID/Switch. Done. +switch2alias([{_, _ID, _}|_], _, Acc, PreviousID, true) -> + {ok, Acc, PreviousID}; +%% Not found correct switch and ID is updated. +switch2alias([{Sw, ID, _}|T], Switch, _Acc, _PreviousID, Found) -> + switch2alias(T, Switch, [Sw], ID, Found). + + +%%------------------------------------------------------------ +%% function : get_field +%% Arguments: ID - element name +%% List - The list of elements contained in the +%% TypeCode. +%% Returns : false | +%% offset +%%------------------------------------------------------------ +get_field(ID, List) -> + get_field(ID, List, 2). +get_field(_ID, [], _) -> + false; +get_field(ID, [ID|_], I) -> + %% Memberlists in enum. + I; +get_field(ID, [{ID,_}|_], I) -> + %% Memberlists in structs. + I; +get_field(ID, [_|T], I) -> + get_field(ID, T, I+1). + +%%------------------------------------------------------------ +%% function : check_types +%% Arguments: A sequence of CosNotification::EventType{}, i.e., +%% name-value pairs. +%% Returns : {ok, WhichType, WC} +%% WhichType - type/domain/both +%% WC - [Types using wildcard] +%%------------------------------------------------------------ +%% With check_types we try to determin if one or more EventTypes force us to check +%% all events against this constraint. For example: +%% EventType A1 has domain_name="car",type_name = "*" +%% EventType A2 has domain_name="*",type_name = "DodgeViper" +%% Since A1 says that we must test against any type_name and A2 +%% against any domain_name, we must test all events using these permutations. +%% It's better to do these test now instead of when we are up and running. But +%% if a client change the constraints VERY often it's up to them and they have +%% to accept the delay. +%%------------------------------------------------------------ + +%% If types is an empty list it means that this constraint must be used +%% for all events. +check_types([]) -> true; +check_types(Types) -> check_types(Types, both, []). +check_types([], Which, WildCard) -> {ok, Which, WildCard}; +%% The following cases means that all events matches. +check_types([#'CosNotification_EventType'{domain_name="",type_name = ""}|_T],_,_) -> + true; +check_types([#'CosNotification_EventType'{domain_name="",type_name = "*"}|_T],_,_) -> + true; +check_types([#'CosNotification_EventType'{domain_name="*",type_name = ""}|_T],_,_) -> + true; +check_types([#'CosNotification_EventType'{domain_name="*",type_name = "*"}|_T],_,_) -> + true; +%% The following cases means that all events must be tested using this constraint. +check_types([#'CosNotification_EventType'{domain_name="",type_name = Ty}|T], domain,WC) when is_list(Ty) -> + check_wildcard(T, all, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name="*",type_name = Ty}|T], domain, WC) when is_list(Ty) -> + check_wildcard(T, all, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = ""}|T], type,WC) when is_list(Do) -> + check_wildcard(T, all, WC, Do, ""); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = "*"}|T], type,WC) when is_list(Do) -> + check_wildcard(T, all, WC, Do, ""); +%% The following cases is used to prevent other cases from converting, +%% for example, all->type. +check_types([#'CosNotification_EventType'{domain_name="",type_name = Ty}|T], all,WC) when is_list(Ty) -> + check_wildcard(T, all, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name="*",type_name = Ty}|T], all,WC) when is_list(Ty) -> + check_wildcard(T, all, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = ""}|T], all,WC) when is_list(Do) -> + check_wildcard(T, all, WC, Do, ""); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = "*"}|T], all,WC) when is_list(Do) -> + check_wildcard(T, all, WC, Do, ""); +%% The following cases means that all events with matching Type must be +%% tested using this constraint. +check_types([#'CosNotification_EventType'{domain_name="",type_name = Ty}|T], _W,WC) when is_list(Ty) -> + check_wildcard(T, type, WC, "", Ty); +check_types([#'CosNotification_EventType'{domain_name="*",type_name = Ty}|T], _W,WC) when is_list(Ty) -> + check_wildcard(T, type, WC, "", Ty); +%% The following cases means that all events with matching Domain must be +%% tested using this constraint. +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = ""}|T], _W,WC) when is_list(Do) -> + check_wildcard(T, domain, WC, Do, ""); +check_types([#'CosNotification_EventType'{domain_name=Do,type_name = "*"}|T], _W,WC) when is_list(Do) -> + check_wildcard(T, domain, WC, Do, ""); +%% Sorry, no shortcuts. +check_types([#'CosNotification_EventType'{domain_name=Do,type_name=Ty}|T], W,WC) when is_list(Do) andalso is_list(Ty) -> + check_wildcard(T, W, WC, Do, Ty); +check_types([H|_], _,_) when is_record(H, 'CosNotification_EventType') -> + %% Not valid. + corba:raise(#'CosNotifyComm_InvalidEventType'{type=H}); +check_types(_,_,_) -> + %% Wasn't even a correct input. + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +check_wildcard(Types, Which, WC, Domain, Type) -> + NewWC = + case {string:chr(Domain, $*), string:chr(Type, $*)} of + {0, 0} -> + WC; + {0, _}-> + [{type, Domain, convert_wildcard(Type, [])}|WC]; + {_, 0}-> + [{domain, convert_wildcard(Domain, []), Type}|WC]; + _-> + [{both, convert_wildcard(Domain, []), convert_wildcard(Type, [])}|WC] + end, + check_types(Types, Which, NewWC). + +%% Change '*' to '.*', see regexp:parse/2 documentation. +convert_wildcard([], Acc) -> + case regexp:parse(lists:reverse(Acc)) of + {ok, Expr} -> + Expr; + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +convert_wildcard([$*|T], Acc) -> + convert_wildcard(T, [$*, $.|Acc]); +convert_wildcard([H|T], Acc) -> + convert_wildcard(T, [H|Acc]). + +%%------------------------------------------------------------ +%% function : match_types +%% Arguments: A sequence of {Which, Domain, Type}, i.e., the same as +%% returned from cosNotification_Filter:check_types/3 +%% Returns : bolean() +%%------------------------------------------------------------ +match_types(_, _, []) -> + false; +match_types(Domain, Type, [{domain, WCDomain, Type}|T]) -> + L=length(Domain), + case catch regexp:matches(Domain, WCDomain) of + {match, []} -> + match_types(Domain, Type, T); + {match, [{1, L}]} -> + true; + _-> + match_types(Domain, Type, T) + end; +match_types(Domain, Type, [{type, Domain, WCType}|T]) -> + L=length(Type), + case catch regexp:matches(Type, WCType) of + {match, []} -> + match_types(Domain, Type, T); + {match, [{1, L}]} -> + true; + _-> + match_types(Domain, Type, T) + end; +match_types(Domain, Type, [{both, WCDomain, WCType}|T]) -> + L1=length(Domain), + case catch regexp:matches(Domain, WCDomain) of + {match, []} -> + match_types(Domain, Type, T); + {match, [{1, L1}]} -> + L2=length(Type), + case catch regexp:matches(Type, WCType) of + {match, []} -> + match_types(Domain, Type, T); + {match, [{1, L2}]} -> + true; + _-> + match_types(Domain, Type, T) + end; + _-> + match_types(Domain, Type, T) + end; +match_types(Domain, Type, [_|T]) -> + match_types(Domain, Type, T). + +%%------------------------------------------------------------ +%% function : validate_types +%% Arguments: A sequence of CosNotification::EventType{}, i.e., +%% name-value pairs. +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyComm_InvalidEventType'{}} +%%------------------------------------------------------------ + +validate_types([]) -> + ok; +validate_types([#'CosNotification_EventType'{domain_name=Do,type_name=Ty}|T]) + when is_list(Do) andalso is_list(Ty) -> + validate_types(T); +validate_types([H|_]) + when is_record(H, 'CosNotification_EventType') -> + %% Not valid. + corba:raise(#'CosNotifyComm_InvalidEventType'{type=H}); +validate_types(_) -> + %% Wasn't even a correct input. + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/src/cosNotification_Grammar.yrl b/lib/cosNotification/src/cosNotification_Grammar.yrl new file mode 100644 index 0000000..98233bf --- /dev/null +++ b/lib/cosNotification/src/cosNotification_Grammar.yrl @@ -0,0 +1,166 @@ +%%-------------------------------------------------------------------- +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%-------------------------------------------------------------------- +%% File : cosNotification_Grammar.yrl +%% Purpose : Implement the constraint grammar for CosNotification filters. +%%-------------------------------------------------------------------- + +Nonterminals + '' '' '' '' '' '' + '' '' '' '' '' + '' '' '' '' '' ''. + +Terminals +% 'dbslsh' 'bslshd' + 'bslsh' 'ident' 'string' + '_length' '_d''_type_id' '_repos_id' + 'not' 'or' 'and' 'num' + 'in' '~' '.' 'dollar' + 'ADDOP' 'RELOP' 'MULOP' 'default' 'exist' + 'TRUE' 'FALSE' + '(' ')' '[' ']' 'int'. + +Left 100 'or'. +Left 200 'and'. +%Nonassoc 300 'RELOP'. % '==', '!=', '<', '>', '<=', '=>' +Left 300 'RELOP'. +%Nonassoc 400 'in'. +Left 400 'in'. +%Nonassoc 500 '~'. +Left 500 '~'. +Left 600 'ADDOP'. % '+', '-' +Left 700 'MULOP'. % '*', '/' +Unary 800 'not'. +Unary 900 'exist'. +Unary 900 'default'. +%Unary 900 'u-'. % unary minus + +Rootsymbol ''. +Endsymbol '$end'. + +'' -> '$empty' : '$empty'. +'' -> '' : '$1'. + +'' -> '' : '$1'. + +'' -> '' : '$1'. + +'' -> '' 'or' '' : {'or', '$1', '$3'}. +'' -> '' : '$1'. + +'' -> '' 'and' '' : {'and', '$1', '$3'}. +'' -> '' : '$1'. + +'' -> '' 'RELOP' '' : {element(2, '$2'), '$1', '$3'}. +'' -> '' : '$1'. + +'' -> '' : '$1'. +'' -> '' 'in' '' : {'in', '$1', '$3'}. +'' -> '' 'in' 'dollar' '' : {'in', '$1', examin_comp({'component', '$4'})}. + +'' -> '' : '$1'. +'' -> '' '~' '' : {'~', '$1', '$3'}. + +'' -> '' : '$1'. +'' -> '' 'ADDOP' '' : {element(2, '$2'), '$1', '$3'}. + +'' -> '' : '$1'. +'' -> '' 'MULOP' '' : {element(2, '$2'), '$1', '$3'}. + +'' -> '' : '$1'. +'' -> 'not' '' : {'not', '$2'}. + +'' -> '(' '' ')' : '$2'. +'' -> 'num' : element(2, '$1'). +'' -> 'int' : element(2, '$1'). +'' -> 'string' : element(2, '$1'). +'' -> 'TRUE' : 'true'. +'' -> 'FALSE' : 'false'. +'' -> 'ADDOP' 'num' : create_unary(element(2, '$1'), element(2, '$2')). +'' -> 'ADDOP' 'int' : create_unary(element(2, '$1'), element(2, '$2')). +'' -> '' : list_to_atom('$1'). +'' -> 'dollar' '' : examin_comp({component, '$2'}). +'' -> 'default' 'dollar' '' : examin_comp({'default_component', '$3'}). +'' -> 'exist' 'dollar' '' : examin_comp({'exist_component', '$3'}). + +%% The following rules are used to create Components. The format used is: +%% [...] +'' -> '.' '' : '$2'. +'' -> '[' 'int' ']' '' : [{'arrindex', element(2, '$2')} | '$4']. %% CompArray +'' -> '(' '' ')' '' : [{'associd', '$2'} | '$4']. %%CompAssoc +'' -> '' '' : [{'varid', '$1'} | '$2']. %% run-time variable +'' -> '$empty' : []. + +'' -> '.' '' : '$2'. +'' -> '[' 'int' ']' '' : [{'arrindex', element(2, '$2')} | '$4']. %% CompArray +'' -> '(' '' ')' '' : [{'associd', '$2'} | '$4']. %%CompAssoc +'' -> '$empty' : []. + +'' -> '' '' : [{'dotid', '$1'} | '$2']. +'' -> 'int' '' : [{'dotint', element(2, '$1')} | '$2']. %% ComPos +'' -> '(' '' ')' '' : ['$2' | '$4']. %% UnionPos +'' -> '_length' : ['_length']. %% arrays or sequences ONLY +'' -> '_d' : ['_d']. %% discriminated unions ONLY +'' -> '_type_id' : ['_type_id']. %% ok if info can be obtained +'' -> '_repos_id' : ['_repos_id']. %% ok if info can be obtained + +'' -> 'ident' : element(2, '$1'). +'' -> 'bslsh' 'ident' : element(2, '$2'). + +'' -> 'int' : {'uint', element(2, '$1')}. +'' -> 'ADDOP' 'int' : {'uint', create_unary(element(2, '$1'), element(2, '$2'))}. +'' -> 'string' : {'ustr', element(2, '$1')}. +'' -> '$empty': 'default'. + +Erlang code. +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%---------------------------------------------------------------------- +%% File : cosNotification_Grammar.erl +%% Purpose : THIS FILE HAS BEEN GENERATED. DO NOT EDIT!!!! +%%---------------------------------------------------------------------- + +-include("CosNotification_Definitions.hrl"). + +create_unary('+', Val) when is_number(Val) -> Val; +create_unary('-', Val) when is_number(Val) -> -Val; +create_unary(_, _) -> return_error(0, "syntax error"). + +examin_comp({T, []}) -> + {T, '$empty'}; +examin_comp(V) -> + V. + diff --git a/lib/cosNotification/src/cosNotification_Scanner.erl b/lib/cosNotification/src/cosNotification_Scanner.erl new file mode 100644 index 0000000..e9c5431 --- /dev/null +++ b/lib/cosNotification/src/cosNotification_Scanner.erl @@ -0,0 +1,268 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosNotification_Scanner.erl +%% Purpose : Scan and pre-process a grammar. +%%---------------------------------------------------------------------- + +-module('cosNotification_Scanner'). + +-export([scan/1]). + +scan(Str) -> + RSL = scan(Str, 1, [], any), + {ok, lists:reverse(RSL)}. + + +%% Guard macros used at top scan functions only +-define(is_number(X), X >= $0, X =< $9). +-define(is_upper(X), X >= $A, X =< $Z). +-define(is_lower(X), X >= $a, X =< $z). + +%%---------------------------------------------------------------------- +%% scan +%% +%% A-Z +scan([X|Str], Line, Out, Type) when ?is_upper(X) -> + scan_name(Str, [X], Line, Out, Type); +%% a-z +scan([X|Str], Line, Out, Type) when ?is_lower(X) -> + scan_name(Str, [X], Line, Out, Type); +%% 0-9 +scan([X|Str], Line, Out, Type) when ?is_number(X) -> + scan_number(Str, [X], Line, Out, Type); + +%% RELOP:s == != <= >= > < +scan([$=,$= | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '=='} | Out], any); +scan([$!,$= | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '!='} | Out], any); +scan([$<,$= | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '<='} | Out], any); +scan([$>,$= | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '>='} | Out], any); +scan([$> | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '>'} | Out], any); +scan([$< | Str], Line, Out, _Type) -> + scan(Str, Line, [{'RELOP', '<'} | Out], any); + +%% ADDOP:s + - +scan([$+ | Str], Line, Out, Type) -> + scan(Str, Line, [{'ADDOP', '+'} | Out], Type); +scan([$- | Str], Line, Out, Type) -> + scan(Str, Line, [{'ADDOP', '-'} | Out], Type); + +%% MULOP:s * / +scan([$* | Str], Line, Out, _Type) -> + scan(Str, Line, [{'MULOP', '*'} | Out], any); +scan([$/ | Str], Line, Out, _Type) -> + scan(Str, Line, [{'MULOP', '/'} | Out], any); + +%% TAB +scan([9| T], Line, Out, Type) -> scan(T, Line, Out, Type); +%% SP +scan([32| T], Line, Out, Type) -> scan(T, Line, Out, Type); +%% CR +scan([$\r|Str], Line, Out, Type) -> + scan(Str, Line, Out, Type); +%% LF +scan([$\n|Str], Line, Out, Type) -> + scan(Str, Line+1, Out, Type); +%% \\ +scan([92, 92 | Str], Line, Out, Type) -> + scan(Str, Line, [{'dbslsh', Line} | Out], Type); +%% \' +scan([92, 39 | Str], Line, Out, Type) -> + scan(Str, Line, [{'bslshd', Line} | Out], Type); +%% '\' +scan([92 | Str], Line, Out, Type) -> + scan(Str, Line, [{'bslsh', Line} | Out], Type); +%% '_' +scan([$_ | Str], Line, Out, dollar) -> + scan_name(Str, [$_], Line, Out, dollar); +%% '$' +scan([$$, 92 | Str], Line, Out, _Type) -> + scan(Str, Line, [{'bslsh', Line}, {'dollar', Line} | Out], dollar); +scan([$$ | Str], Line, Out, _Type) -> + scan(Str, Line, [{'dollar', Line} | Out], dollar); +scan([$"|Str], Line, Out, Type) -> + scan_const(char, Str, [], Line, Out, Type); +scan([$'|Str], Line, Out, Type) -> + scan_const(string, Str, [], Line, Out, Type); + +%% Writing '+.' is not allowed ('+' or '-' are only allowed +%% as unary for (within a component) which must be en integer). +scan([$. | Str], Line, [{'ADDOP', Op}|Out], _) -> + scan_frac(Str, [$.], Line, [{'ADDOP', Op}|Out], any); +%% Must be a +scan([$. | Str], Line, Out, dollar) -> + scan(Str, Line, [{'.',Line} | Out], dollar); +%% Number +scan([$. | Str], Line, Out, Type) -> + scan_frac(Str, [$.], Line, Out, Type); +scan([C|Str], Line, Out, Type) -> + scan(Str, Line, [{list_to_atom([C]), Line} | Out], Type); + +scan([], _Line, Out, _Type) -> + Out. + +%%---------------------------------------------------------------------- +%% scan_name +%% + +scan_number([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> + scan_number(Str, [X|Accum], Line, Out, Type); +scan_number([X|Str], Accum, Line, Out, dollar) when X==$. -> + scan(Str, Line, [{'.', Line}, + {'int', list_to_integer(lists:reverse(Accum))} | Out], dollar); +scan_number([X|Str], Accum, Line, Out, Type) when X==$. -> + scan_frac(Str, [X|Accum], Line, Out, Type); +scan_number([X|Str], Accum, Line, Out, Type) when X==$e -> + scan_exp(Str, [X|Accum], Line, Out, Type); +scan_number([X|Str], Accum, Line, Out, Type) when X==$E -> + scan_exp(Str, [X|Accum], Line, Out, Type); +scan_number(Str, Accum, Line, Out, Type) -> + scan(Str, Line, [{'int', list_to_integer(lists:reverse(Accum))} | Out], Type). + + +%% Floating point number scan. +%% +%% Non trivial scan. A float consists of an integral part, a +%% decimal point, a fraction part, an e or E and a signed integer +%% exponent. Either the integer part or the fraction part but not +%% both may be missing, and either the decimal point or the +%% exponent part but not both may be missing. The exponent part +%% must consist of an e or E and a possibly signed exponent. +%% +%% Analysis shows that "1." ".7" "1e2" ".5e-3" "1.7e2" "1.7e-2" +%% is allowed and "1" ".e9" is not. The sign is only allowed just +%% after an e or E. The scanner reads a number as an integer +%% until it encounters a "." so the integer part only error case +%% will not be caught in the scanner (but rather in expression +%% evaluation) + +scan_frac([$e | _Str], [$.], _Line, _Out, _Type) -> + {error, "illegal_float"}; +scan_frac([$E | _Str], [$.], _Line, _Out, _Type) -> + {error, "illegal_float"}; +scan_frac(Str, Accum, Line, Out, Type) -> + scan_frac2(Str, Accum, Line, Out, Type). + +scan_frac2([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> + scan_frac2(Str, [X|Accum], Line, Out, Type); +scan_frac2([X|Str], Accum, Line, Out, Type) when X==$e -> + scan_exp(Str, [X|Accum], Line, Out, Type); +scan_frac2([X|Str], Accum, Line, Out, Type) when X==$E -> + scan_exp(Str, [X|Accum], Line, Out, Type); +%% Since '.2' is allowed, we add '0' in front to be sure (erlang do not allow +%% list_to_float(".2") and list_to_float("0.2") eq. list_to_float("00.2")). +scan_frac2(Str, Accum, Line, Out, Type) -> + scan(Str, Line, [{'num', list_to_float([$0|lists:reverse(Accum)])} | Out], Type). + +scan_exp([X|Str], Accum, Line, Out, Type) when X==$- -> + scan_exp2(Str, [X|Accum], Line, Out, Type); +scan_exp(Str, Accum, Line, Out, Type) -> + scan_exp2(Str, Accum, Line, Out, Type). + +scan_exp2([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> + scan_exp2(Str, [X|Accum], Line, Out, Type); +%% Since '.2' is allowed, we add '0' in front to be sure (erlang do not allow +%% list_to_float(".2")). +scan_exp2(Str, Accum, Line, Out, Type) -> + scan(Str, Line, [{'num', list_to_float([$0|lists:reverse(Accum)])} | Out], Type). + + +scan_name([X|Str], Accum, Line, Out, Type) when ?is_upper(X) -> + scan_name(Str, [X|Accum], Line, Out, Type); +scan_name([X|Str], Accum, Line, Out, Type) when ?is_lower(X) -> + scan_name(Str, [X|Accum], Line, Out, Type); +scan_name([X|Str], Accum, Line, Out, Type) when ?is_number(X) -> + scan_name(Str, [X|Accum], Line, Out, Type); +scan_name([$_|Str], Accum, Line, Out, dollar) -> + scan_name(Str, [$_|Accum], Line, Out, dollar); +scan_name(S, Accum, Line, [{bslsh,LL} | Out], Type) -> + %% An escaped identifier. + L = lists:reverse(Accum), + scan(S, Line, [{'ident', L}, {bslsh,LL} | Out], Type); +scan_name(S, Accum, Line, Out, Type) -> + L = lists:reverse(Accum), + {X, NewType} = case check_name(L) of + false -> + {{'ident', L}, Type}; + _ -> + {{list_to_atom(L), Line}, any} + end, + scan(S, Line, [X | Out], NewType). + +%% Shall scan a constant +scan_const(char, [$" | Rest], Accum, Line, Out, Type) -> + scan(Rest, Line, + [{'ident', list_to_atom(lists:reverse(Accum))} | Out], Type); +scan_const(char, [], _Accum, _Line, Out, _Type) -> %% Bad string +% {error, "bad_string"}; + Out; +scan_const(string, [$' | Rest], Accum, Line, Out, Type) -> + scan(Rest, Line, + [{'string', lists:reverse(Accum)} | Out], Type); +scan_const(Mode, [$\\, C | Rest], Accum, Line, Out, Type) -> + case escaped_char(C) of + error -> + %% Bad escape character + %% {error, "bad_escape_character"}; + scan_const(Mode, Rest, [C | Accum], Line, Out, Type); + EC -> + scan_const(Mode, Rest, [EC | Accum], Line, Out, Type) + end; +scan_const(Mode, [C | Rest], Accum, Line, Out, Type) -> + scan_const(Mode, Rest, [C | Accum], Line, Out, Type). + +%% Escaped character. Escaped chars are repr as two characters in the +%% input list of letters and this is translated into one char. +escaped_char($n) -> $\n; +escaped_char($t) -> $\t; +escaped_char($v) -> $\v; +escaped_char($b) -> $\b; +escaped_char($r) -> $ ; +escaped_char($f) -> $\f; +escaped_char($a) -> $\a; +escaped_char($\\) -> $\\; +escaped_char($?) -> $?; +escaped_char($') -> $'; +escaped_char($") -> $"; +%% Error +escaped_char(_Other) -> error. + + +check_name("exist") -> true; +check_name("default") -> true; +check_name("_length") -> true; +check_name("_d") -> true; +check_name("_type_id") -> true; +check_name("_repos_id") -> true; +check_name("not") -> true; +check_name("or") -> true; +check_name("and") -> true; +check_name("FALSE") -> true; +check_name("TRUE") -> true; +check_name("in") -> true; +check_name(_) -> false. + + diff --git a/lib/cosNotification/src/cosNotification_eventDB.erl b/lib/cosNotification/src/cosNotification_eventDB.erl new file mode 100644 index 0000000..89332d5 --- /dev/null +++ b/lib/cosNotification/src/cosNotification_eventDB.erl @@ -0,0 +1,1350 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosNotification_eventDB.erl +%% Purpose : +%% Purpose : This module is supposed to centralize Event storage. +%% Comments: +%% * Setting Order Policy to AnyOrder eq. Priority order +%% +%% * Setting Discard Policy to AnyOrder eq. RejectNewEvents. +%% +%% * DB ordering: Since the deliver- and discard-order may differ we need +%% two ets-tables, both of type 'ordered_set'. They contain: +%% - table 1 (T1): deliver order key and the associated event. +%% - table 2 (T2): discard order key. +%% +%% When adding a new event we add, if necessary, related keys in T2. +%% For example, if we should discard events in FIFO order, the delivery +%% order may be set to Priority order. If the Max Event limit is reached +%% we first look in T2 to find out which event to discard by using and +%% reorder the key elements. T2 gives {TimeStamp, Priority}, which is used +%% to lookup in T1 as {Priority, TimeStamp}. +%% A TimeStamp is always included in the DB keys, even if FIFO or LIFO +%% is used, since lots of events probably will have the same prioity and +%% with a little bit of bad luck some events will never be delivered. +%% +%% Note: deliver order AnyOrder and PriorityOrder is equal since the later +%% is defined as default. +%% discard order AnyOrder and RejectNewEvents is equal since the later +%% is defined as default. +%% The keys used is ('-' indicates T2 is not needed and, thus, not instantiated): +%% +%% T1 policy T1 Key T2 Policy T2 Key +%% ------------------------------------------------------------------ +%% DeadlineOrder {DL, Key, Prio} PriorityOrder {Prio, Key, DL} +%% DeadlineOrder {DL, Key} FifoOrder {Key, DL} +%% DeadlineOrder {DL, Key} LifoOrder {Key, DL} +%% DeadlineOrder {DL, Key} RejectNewEvents - +%% DeadlineOrder {DL, Key} DeadlineOrder - +%% FifoOrder {Key, DL} DeadlineOrder {DL, Key} +%% FifoOrder {Key, Prio} PriorityOrder {Prio, Key} +%% FifoOrder Key RejectNewEvents - +%% FifoOrder Key Fifo - +%% FifoOrder Key Lifo - +%% PriorityOrder {Prio, Key, DL} DeadlineOrder {DL, Key, Prio} +%% PriorityOrder {Prio, Key} Fifo {Key, Prio} +%% PriorityOrder {Prio, Key} Lifo {Key, Prio} +%% PriorityOrder {Prio, Key} RejectNewEvents - +%% ------------------------------------------------------------------ +%% DL == Deadline, Key == TimeStamp, Prio == Priority +%% +%% NOTE: If defined, the Discard DB Keys are the same as in Event DB, except +%% that the first and last Key change place. {K1,K2}<->{K2,K1} and +%% {K1,K2,K3}<->{K3,K2,K1}. +%%---------------------------------------------------------------------- + +-module(cosNotification_eventDB). + + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +-include_lib("cosTime/include/TimeBase.hrl"). + +%% Application files +-include("CosNotification.hrl"). +-include("CosNotifyChannelAdmin.hrl"). +-include("CosNotifyComm.hrl"). +-include("CosNotifyFilter.hrl"). + +-include("CosNotification_Definitions.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%% Internal Filter Functions +-export([validate_event/5, + create_db/4, + destroy_db/1, + get_event/1, + get_event/2, + get_events/2, + get_events/3, + delete_events/1, + update/2, + update/4, + add_event/2, + add_event/4, + add_and_get_event/2, + add_and_get_event/3, + add_and_get_event/4, + add_and_get_event/5, + gc_events/2, + gc_events_local/4, + gc_start/2, + filter_events/2, + filter_events/3, + status/2]). + +%%--------------- DATA STRUCTURES ---------------------------- +-record(dbRef, {orderRef, discardRef, orderPolicy, discardPolicy, + defPriority, maxEvents, defStopT, startTsupport, + stopTsupport, gcTime, gcLimit, timeRef}). + + + +%%--------------- DEFINES ------------------------------------ + +-define(CreateRef(OR, DR, O, D, DP, ME, DS, StaT, StoT, GT, GL, TR), + #dbRef{orderRef=OR, discardRef=DR, orderPolicy=O, discardPolicy=D, + defPriority=DP, maxEvents=ME, defStopT=DS, startTsupport=StaT, + stopTsupport=StoT, gcTime=GT, gcLimit=round(ME*GL/100), + timeRef=TR}). + + +-define(get_OrderP(DR), DR#dbRef.orderPolicy). +-define(get_DiscardP(DR), DR#dbRef.discardPolicy). +-define(get_OrderRef(DR), DR#dbRef.orderRef). +-define(get_DiscardRef(DR), DR#dbRef.orderRef). +-define(get_DefPriority(DR), DR#dbRef.defPriority). +-define(get_MaxEvents(DR), DR#dbRef.maxEvents). +-define(get_DefStopT(DR), DR#dbRef.defStopT). +-define(get_StartTsupport(DR), DR#dbRef.startTsupport). +-define(get_StopTsupport(DR), DR#dbRef.stopTsupport). +-define(get_GCTime(DR), DR#dbRef.gcTime). +-define(get_GCLimit(DR), DR#dbRef.gcLimit). +-define(get_TimeRef(DR), DR#dbRef.timeRef). + +-define(set_OrderP(DR, O), DR#dbRef{orderPolicy = O}). +-define(set_DiscardP(DR, D), DR#dbRef{discardPolicy = D}). +-define(set_OrderRef(DR, E), DR#dbRef{orderRef = E}). +-define(set_DiscardRef(DR, E), DR#dbRef{orderRef = E}). +-define(set_DefPriority(DR, DP), DR#dbRef{defPriority = DP}). +-define(set_MaxEvents(DR, ME), DR#dbRef{maxEvents = ME}). +-define(set_DefStopT(DR, DS), DR#dbRef{defStopT = DS}). +-define(set_StartTsupport(DR, B), DR#dbRef{startTsupport = B}). +-define(set_StopTsupport(DR, B), DR#dbRef{stopTsupport = B}). + +-define(is_StartTNotSupported(DR), DR#dbRef.startTsupport == false). +-define(is_StopTNotSupported(DR), DR#dbRef.stopTsupport == false). +-define(is_TimeoutNotUsed(DR), DR#dbRef.defStopT == 0). + + +%%------------------------------------------------------------ +%% function : status +%% Arguments: DBRef +%% Key - which information we want. +%% Returns : Data related to the Key. +%%------------------------------------------------------------ +status(DBRef, eventCounter) -> + ets:info(?get_OrderRef(DBRef), size); +status(DBRef, {batchLimit, Limit}) -> + case ets:info(?get_OrderRef(DBRef), size) of + Current when is_integer(Current) andalso Current >= Limit -> + ?debug_print("BATCH LIMIT (~p) REACHED, CONTAINS: ~p~n", [Limit, Current]), + true; + _Other -> + ?debug_print("BATCH LIMIT (~p) NOT REACHED, CONTAINS: ~p~n", + [Limit, _Other]), + false + end; +status(DBRef, {batchLimit, Limit, TemporaryMax}) -> + case ets:info(?get_OrderRef(DBRef), size) of + Current when is_integer(Current) andalso Current >= TemporaryMax -> + ?debug_print("MAX LIMIT (~p) REACHED, CONTAINS: ~p~n", + [TemporaryMax, Current]), + true; + Current when is_integer(Current) andalso Current >= Limit -> + ?debug_print("BATCH LIMIT (~p) REACHED, CONTAINS: ~p~n", [Limit, Current]), + true; + _Other -> + ?debug_print("BATCH LIMIT (~p) NOT REACHED, CONTAINS: ~p~n", + [Limit, _Other]), + false + end; +status(_, _) -> + error. + + +%%------------------------------------------------------------ +%% function : gc_events_local +%% Arguments: DBRef +%% Returns : +%% Comment : This function is intended for "emergency" GC, i.e., +%% when the DB must discard events we should first try +%% to remove events with expired deadlines. +%%------------------------------------------------------------ +gc_events_local(_, _, false, _) -> + ok; +gc_events_local(_, _, _, 0) -> + ok; +gc_events_local(ORef, DRef, _, _) -> + gc_loop(ets:first(ORef), ORef, DRef). + +%%------------------------------------------------------------ +%% function : gc_events +%% Arguments: DBRef +%% Priority - 'low', 'medium' or 'high'; will determine +%% how important a fast gc is. +%% Returns : +%% Comment : This function is intended for background GC. +%%------------------------------------------------------------ +gc_events(DBRef, _Priority) when ?is_TimeoutNotUsed(DBRef) -> + ok; +gc_events(DBRef, _Priority) when ?is_StopTNotSupported(DBRef) -> + ok; +gc_events(DBRef, Priority) -> + {M,S,U} = now(), + case get(oe_GC_timestamp) of + Num when {M,S,U} > Num -> + put(oe_GC_timestamp, {M,S+?get_GCTime(DBRef),U}), + spawn_link(?MODULE, gc_start, [DBRef, Priority]); + _-> + ok + end. + + +%%------------------------------------------------------------ +%% function : gc_start +%% Arguments: +%% Returns : +%%------------------------------------------------------------ +gc_start(#dbRef{orderRef = ORef, discardRef = DRef}, Priority) -> + process_flag(priority, Priority), + gc_loop(ets:first(ORef), ORef, DRef). + +gc_loop('$end_of_table', _, _) -> + ok; +gc_loop(Key, ORef, DRef) -> + [{Keys,DL,_,_,_}]=ets:lookup(ORef, Key), + case check_deadline(DL) of + true when DRef == undefined -> + ets:delete(ORef, Key); + true -> + ets:delete(ORef, Key), + gc_discard_DB(Keys, DRef); + _ -> + ok + end, + gc_loop(ets:next(ORef, Key), ORef, DRef). + +gc_discard_DB({Key1, Key2}, DRef) -> + ets:delete(DRef, {Key2, Key1}); +gc_discard_DB({Key1, Key2, Key3}, DRef) -> + ets:delete(DRef, {Key3, Key2, Key1}). + +%%------------------------------------------------------------ +%% function : create_FIFO_Key +%% Arguments: +%% Returns : +%%------------------------------------------------------------ +create_FIFO_Key() -> + {M, S, U} = erlang:now(), + -M*1000000000000 - S*1000000 - U. + +%%------------------------------------------------------------ +%% function : convert_FIFO_Key +%% Arguments: +%% Returns : A now tuple +%% Comment : Used when we must reuse a timestamp, i.e., only +%% when we must reorder the DB. +%%------------------------------------------------------------ +convert_FIFO_Key(Key) -> + K = abs(Key), + Secs = trunc(K/1000000), + M = trunc(K/1000000000000), + S = Secs-M*1000000, + U = K - S*1000000-M*1000000000000, + {M, S, U}. + +%%------------------------------------------------------------ +%% function : extract_priority +%% Arguments: Event +%% Defalt Value +%% Mapping Filter Value +%% - false value not needed (depends on QoS type) +%% - undefined value needed but no filter associated. +%% Returns : +%%------------------------------------------------------------ +extract_priority(_, _, false) -> + false; +extract_priority(#'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {variable_header = VH}}, DefPriority, undefined) -> + extract_value(VH, ?not_Priority, DefPriority); +%% Maybe a unstructured event. +extract_priority(_, DefPriority, undefined) -> + DefPriority; +extract_priority(_, _, PriorityOverride) -> + %% Must have an associated MappingFilter for Priority. + PriorityOverride. + +%%------------------------------------------------------------ +%% function : extract_start_time +%% Arguments: +%% Returns : +%%------------------------------------------------------------ +extract_start_time(_, false, _) -> + false; +extract_start_time(#'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {variable_header = VH}}, _, TRef) -> + ST = case extract_value(VH, ?not_StartTime, undefined) of + UTC when is_record(UTC, 'TimeBase_UtcT') -> + UTC; + _ -> + false + end, + convert_time(ST, TRef, now()); +extract_start_time(_, _, _) -> + false. + +%%------------------------------------------------------------ +%% function : extract_deadline +%% Arguments: Structured Event +%% Default Timeout Value - TimeT or UtcT (see cosTime). +%% StopTSupported - boolean(). +%% TRef - reference to TimeService +%% Mapping Filter Value +%% - false eq. value not needed (depends on QoS type) +%% - undefined eq. value needed but no filter associated. +%% Now - used when we want to reuse old TimeStamp which +%% must be done when changing QoS. +%% Returns : A modified return from now(). +%%------------------------------------------------------------ +extract_deadline(_, _, _, _, false) -> + false; +extract_deadline(Event, DefaultT, StopTSupported, TRef, MappingVal) -> + extract_deadline(Event, DefaultT, StopTSupported, TRef, MappingVal, now()). + +extract_deadline(_, _, _, _, false, _) -> + false; +extract_deadline(#'CosNotification_StructuredEvent' + {header = #'CosNotification_EventHeader' + {variable_header = VH}}, DefaultT, StopTSupported, + TRef, undefined, Now) -> + DL = case extract_value(VH, ?not_Timeout, undefined) of + undefined when StopTSupported == true, TRef =/= undefined -> + case extract_value(VH, ?not_StopTime, undefined) of + undefined -> + DefaultT; + DefinedTime -> + DefinedTime + end; + undefined -> + DefaultT; + DefinedTime -> + DefinedTime + end, + convert_time(DL, TRef, Now); +%% Maybe a unstructured event. +extract_deadline(_, Time, _, TRef, undefined, Now) -> + convert_time(Time, TRef, Now); +extract_deadline(_, _, _, TRef, DOverride, Now) -> + %% Must have an associated MappingFilter defining a Deadline. + convert_time(DOverride, TRef, Now). + +convert_time(0, _, _) -> + false; +convert_time(UTC, TRef, {M,S,U}) when is_record(UTC, 'TimeBase_UtcT') -> + case catch get_time_diff(UTC, TRef) of + {'EXCEPTION', _} -> + false; + {'EXIT', _} -> + false; + DL -> + MicroSecs = round(DL/10), + Secs = round(MicroSecs/1000000), + MegaSecs = round(Secs/1000000), + {-M-MegaSecs, -S-Secs+MegaSecs, -U-MicroSecs+Secs} + end; +convert_time(DL, _, {M,S,U}) when is_integer(DL) -> + MicroSecs = round(DL/10), + Secs = round(MicroSecs/1000000), + MegaSecs = round(Secs/1000000), + {-M-MegaSecs, -S-Secs+MegaSecs, -U-MicroSecs+Secs}; +convert_time(_, _, _) -> + false. + + +get_time_diff(UTC, TRef) -> + UTO = 'CosTime_TimeService':universal_time(TRef), + UTO2 = 'CosTime_TimeService':uto_from_utc(TRef, UTC), + TIO = 'CosTime_UTO':time_to_interval(UTO, UTO2), + #'TimeBase_IntervalT'{lower_bound=LB, upper_bound = UB} = + 'CosTime_TIO':'_get_time_interval'(TIO), + UB-LB. + +check_deadline(DL) when is_tuple(DL) -> + {M,S,U} = now(), + DL >= {-M,-S,-U}; +check_deadline(_DL) -> + %% This case will cover if no timeout is set. + false. + +check_start_time(ST) when is_tuple(ST) -> + {M,S,U} = now(), + ST >= {-M,-S,-U}; +check_start_time(_ST) -> + %% This case will cover if no earliest delivery time is set. + true. + +%%------------------------------------------------------------ +%% function : extract_value +%% Arguments: A Property Sequence +%% ID - wanted property string() +%% Other - default-value. +%% Returns : Value associated with given ID or default value. +%%------------------------------------------------------------ +extract_value([], _, Other) -> + Other; +extract_value([#'CosNotification_Property'{name=ID, value=V}|_], ID, _) -> + any:get_value(V); +extract_value([_H|T], ID, Other) -> + extract_value(T, ID, Other). + +%%------------------------------------------------------------ +%% function : get_event +%% Arguments: +%% Returns : +%%------------------------------------------------------------ +get_event(DBRef) -> + get_event(DBRef, true). +get_event(DBRef, Delete) -> + case get_events(DBRef, 1, Delete) of + {[], false} -> + {[], false}; + {[], false, Keys} -> + {[], false, Keys}; + {[Event], Bool} -> + {Event, Bool}; + {[Event], Bool, Keys} -> + {Event, Bool, Keys} + end. + +%%------------------------------------------------------------ +%% function : get_events +%% Arguments: +%% Returns : A list of events (possibly empty) and a boolean +%% indicating if event found. +%% Comments : Try to extract Max events from the database. +%%------------------------------------------------------------ +get_events(#dbRef{orderRef = ORef, discardRef = DRef}, Max) -> + event_loop(ets:last(ORef), ORef, DRef, Max, [], [], true). + +get_events(#dbRef{orderRef = ORef, discardRef = DRef}, Max, Delete) -> + event_loop(ets:last(ORef), ORef, DRef, Max, [], [], Delete). + +event_loop('$end_of_table', _, _, _, [], _, true) -> + {[], false}; +event_loop('$end_of_table', _, _, _, [], [], _) -> + {[], false, []}; +event_loop('$end_of_table', _ORef, _, _, Accum, _Keys, true) -> + {lists:reverse(Accum), true}; +event_loop('$end_of_table', _ORef, _, _, Accum, Keys, _) -> + {lists:reverse(Accum), true, Keys}; +event_loop(_, _ORef, _, 0, [], _Keys, true) -> + %% Only possible if some tries to pull a sequence of 0 events. + %% Should we really test for this case? + {[], false}; +event_loop(_, _ORef, _, 0, [], Keys, _) -> + {[], false, Keys}; +event_loop(_, _ORef, _, 0, Accum, _Keys, true) -> + {lists:reverse(Accum), true}; +event_loop(_, _ORef, _, 0, Accum, Keys, _) -> + {lists:reverse(Accum), true, Keys}; +event_loop(Key, ORef, undefined, Left, Accum, Keys, Delete) -> + [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, Key), + case check_deadline(DL) of + true -> + ets:delete(ORef, Key), + event_loop(ets:prev(ORef, Key), ORef, undefined, + Left, Accum, Keys, Delete); + false -> + case check_start_time(ST) of + true when Delete == true -> + ets:delete(ORef, Key), + event_loop(ets:prev(ORef, Key), ORef, undefined, + Left-1, [Event|Accum], Keys, Delete); + true -> + event_loop(ets:prev(ORef, Key), ORef, undefined, + Left-1, [Event|Accum], [{ORef, Key}|Keys], Delete); + false -> + event_loop(ets:prev(ORef, Key), ORef, undefined, + Left, Accum, Keys, Delete) + end + end; +event_loop({Key1, Key2}, ORef, DRef, Left, Accum, Keys, Delete) -> + [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, {Key1, Key2}), + case check_deadline(DL) of + true -> + ets:delete(ORef, {Key1, Key2}), + ets:delete(DRef, {Key2, Key1}), + event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef, + Left, Accum, Keys, Delete); + false -> + case check_start_time(ST) of + true when Delete == true -> + ets:delete(ORef, {Key1, Key2}), + ets:delete(DRef, {Key2, Key1}), + event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef, + Left-1, [Event|Accum], Keys, Delete); + true -> + event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef, + Left-1, [Event|Accum], + [{ORef, {Key1, Key2}}, {DRef, {Key2, Key1}}|Keys], + Delete); + false -> + event_loop(ets:prev(ORef, {Key1, Key2}), ORef, DRef, + Left, Accum, Keys, Delete) + end + end; +event_loop({Key1, Key2, Key3}, ORef, DRef, Left, Accum, Keys, Delete) -> + [{_,DL,ST,_PO,Event}]=ets:lookup(ORef, {Key1, Key2, Key3}), + case check_deadline(DL) of + true -> + ets:delete(ORef, {Key1, Key2, Key3}), + ets:delete(DRef, {Key3, Key2, Key1}), + event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef, + Left, Accum, Keys, Delete); + false -> + case check_start_time(ST) of + true when Delete == true -> + ets:delete(ORef, {Key1, Key2, Key3}), + ets:delete(DRef, {Key3, Key2, Key1}), + event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef, + Left-1, [Event|Accum], Keys, Delete); + true -> + event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef, + Left-1, [Event|Accum], + [{ORef, {Key1, Key2, Key3}}, + {DRef, {Key3, Key2, Key1}}|Keys], Delete); + false -> + event_loop(ets:prev(ORef, {Key1, Key2, Key3}), ORef, DRef, + Left, Accum, Keys, Delete) + end + end. + +%%------------------------------------------------------------ +%% function : delete_events +%% Arguments: EventList - what's returned by get_event, get_events +%% and add_and_get_event. +%% Returns : +%% Comment : Shall be invoked when it's safe to premanently remove +%% the events found in the EventList. +%% +%%------------------------------------------------------------ +delete_events([]) -> + ok; +delete_events([{DB, Key}|T]) -> + ets:delete(DB, Key), + delete_events(T). + +%%------------------------------------------------------------ +%% function : update +%% Arguments: +%% Returns : +%% Comment : As default we shall deliver Events in Priority order. +%% Hence, if AnyOrder set we will still deliver in +%% Priority order. +%%------------------------------------------------------------ +update(undefined, _QoS) -> + ok; +update(DBRef, QoS) -> + update(DBRef, QoS, undefined, undefined). + +update(DBRef, QoS, LifeFilter, PrioFilter) -> + case updated_order(DBRef, ?not_GetOrderPolicy(QoS)) of + false -> + case updated_discard(DBRef, ?not_GetDiscardPolicy(QoS)) of + false -> + DBR2 = ?set_DefPriority(DBRef, ?not_GetPriority(QoS)), + DBR3 = ?set_MaxEvents(DBR2, ?not_GetMaxEventsPerConsumer(QoS)), + DBR4 = ?set_DefStopT(DBR3, ?not_GetTimeout(QoS)), + DBR5 = ?set_StartTsupport(DBR4, ?not_GetStartTimeSupported(QoS)), + DBR6 = ?set_StopTsupport(DBR5, ?not_GetStopTimeSupported(QoS)), + case ets:info(?get_OrderRef(DBR6), size) of + N when N =< ?get_MaxEvents(DBR6) -> + %% Even if the QoS MaxEvents have been changed + %% we don't reach the limit. + DBR6; + N -> + %% The QoS MaxEvents must have been decreased. + discard_events(DBR6, N-?get_MaxEvents(DBR6)), + DBR6 + end; + true -> + destroy_discard_db(DBRef), + NewDBRef = create_db(QoS, ?get_GCTime(DBRef), ?get_GCLimit(DBRef), + ?get_TimeRef(DBRef)), + move_events(DBRef, NewDBRef, ets:first(?get_OrderRef(DBRef)), + LifeFilter, PrioFilter) + end; + true -> + destroy_discard_db(DBRef), + NewDBRef = create_db(QoS, ?get_GCTime(DBRef), ?get_GCLimit(DBRef), + ?get_TimeRef(DBRef)), + move_events(DBRef, NewDBRef, ets:first(?get_OrderRef(DBRef)), + LifeFilter, PrioFilter) + end. + +updated_order(#dbRef{orderPolicy = Equal}, Equal) -> false; +updated_order(#dbRef{orderPolicy = ?not_PriorityOrder}, ?not_AnyOrder) -> false; +updated_order(#dbRef{orderPolicy = ?not_AnyOrder}, ?not_PriorityOrder) -> false; +updated_order(_, _) -> true. + +updated_discard(#dbRef{discardPolicy = Equal}, Equal) -> false; +updated_discard(#dbRef{discardPolicy = ?not_RejectNewEvents}, ?not_AnyOrder) -> false; +updated_discard(#dbRef{discardPolicy = ?not_AnyOrder}, ?not_RejectNewEvents) -> false; +updated_discard(_, _) -> true. + +move_events(DBRef, NewDBRef, '$end_of_table', _, _) -> + destroy_order_db(DBRef), + case ets:info(?get_OrderRef(NewDBRef), size) of + N when N =< ?get_MaxEvents(NewDBRef) -> + %% Even if the QoS MaxEvents have been changed + %% we don't reach the limit. + NewDBRef; + N -> + %% The QoS MaxEvents must have been decreased. + discard_events(DBRef, N-?get_MaxEvents(NewDBRef)), + NewDBRef + end; +move_events(DBRef, NewDBRef, Key, LifeFilter, PrioFilter) -> + [{Keys, DeadLine, StartTime, PriorityOverride, Event}] = + ets:lookup(?get_OrderRef(DBRef), Key), + case check_deadline(DeadLine) of + true -> + ok; + _-> + write_event(?get_OrderP(DBRef), + {Keys, DeadLine, StartTime, PriorityOverride, Event}, + DBRef, NewDBRef, Key, LifeFilter, PrioFilter) + end, + ets:delete(?get_OrderRef(DBRef), Key), + move_events(DBRef, NewDBRef, ets:next(?get_OrderRef(DBRef), Key), + LifeFilter, PrioFilter). + +%% We cannot use do_add_event directly since we MUST lookup the timestamp (TS). +write_event(?not_DeadlineOrder, {{_, TS, _Prio}, DL, ST, PO, Event}, _DBRef, NewDBRef, + _Key, _LifeFilter, _PrioFilter) -> + StartT = update_starttime(NewDBRef, Event, ST), + %% Deadline and Priority previously extracted. + do_add_event(NewDBRef, Event, TS, DL, StartT, PO); +write_event(?not_DeadlineOrder, {{_, TS}, DL, _ST, PO, Event}, _DBRef, NewDBRef, + _Key, _LifeFilter, PrioFilter) -> + %% Priority not previously extracted. + POverride = update_priority(NewDBRef, PrioFilter, Event, PO), + StartT = extract_start_time(Event, ?get_StartTsupport(NewDBRef), + ?get_TimeRef(NewDBRef)), + do_add_event(NewDBRef, Event, TS, DL, StartT, POverride); +write_event(?not_FifoOrder, {{TS, _PorD}, DL, ST, PO, Event}, _DBRef, NewDBRef, + _Key, LifeFilter, PrioFilter) -> + %% Priority or Deadline have been extracted before but we cannot tell which. + POverride = update_priority(NewDBRef, PrioFilter, Event, PO), + DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL), + StartT = update_starttime(NewDBRef, Event, ST), + do_add_event(NewDBRef, Event, TS, DeadL, StartT, POverride); +write_event(?not_FifoOrder, {TS, DL, ST, PO, Event}, _DBRef, NewDBRef, + _Key, LifeFilter, PrioFilter) -> + %% Priority and Deadline not extracetd before. Do it now. + POverride = update_priority(NewDBRef, PrioFilter, Event, PO), + DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL), + StartT = update_starttime(NewDBRef, Event, ST), + do_add_event(NewDBRef, Event, TS, DeadL, StartT, POverride); +%% Order Policy must be AnyOrder or PriorityOrder. +write_event(_, {{_Prio, TS}, DL, ST, PO, Event}, _DBRef, NewDBRef, + _Key, LifeFilter, _PrioFilter) -> + DeadL = update_deadline(NewDBRef, LifeFilter, Event, TS, DL), + StartT = update_starttime(NewDBRef, Event, ST), + do_add_event(NewDBRef, Event, TS, DeadL, StartT, PO); +write_event(_, {{_Prio, TS, DL}, DL, ST, PO, Event}, _DBRef, NewDBRef, _Key, _, _) -> + %% Both Deadline and Priority have been extracetd before. + StartT = update_starttime(NewDBRef, Event, ST), + do_add_event(NewDBRef, Event, TS, DL, StartT, PO). + + +%%------------------------------------------------------------ +%% function : update_priority +%% Arguments: +%% Returns : +%% Comment : The purpose with this function is to avoid +%% calling MappingFilter priority again, especially +%% deadline again (we especially want to avoid calling +%% since it may require intra-ORB communication. +%% Use only when doing an update. +%%------------------------------------------------------------ +update_priority(DBRef, PrioFilter, Event, OldPrio) when is_atom(OldPrio) -> + get_prio_mapping_value(DBRef, PrioFilter, Event); +update_priority(_DBRef, _PrioFilter, _Event, OldPrio) -> + OldPrio. + +%%------------------------------------------------------------ +%% function : update_deadline +%% Arguments: +%% Returns : +%% Comment : The purpose with this function is to avoid +%% calling MappingFilter or parsing the events for +%% deadline again (we especially want to avoid calling +%% the MappingFilter since it may require intra-ORB +%% communication. Use only when doing an update. +%%------------------------------------------------------------ +update_deadline(DBRef, _LifeFilter, _Event, _TS, _OldDeadL) when + ?get_DiscardP(DBRef) =/= ?not_DeadlineOrder, + ?get_OrderP(DBRef) =/= ?not_DeadlineOrder, + ?is_StopTNotSupported(DBRef) -> + %% We do not need to extract the Deadline since it will not be used. + false; +update_deadline(DBRef, LifeFilter, Event, TS, OldDeadL) when is_atom(OldDeadL) -> + %% We need the Deadline and it have not been extracetd before. + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + %% We must find out when the event was delivered; setting a deadline using + %% a new timestamp would not be accurate since we cannot tell for how long + %% the event have been waiting. + OldNow = convert_FIFO_Key(TS), + extract_deadline(Event, ?get_DefStopT(DBRef), ?get_StopTsupport(DBRef), + ?get_TimeRef(DBRef), DOverride, OldNow); +update_deadline(_DBRef, _LifeFilter, _Event, _TS, OldDeadL) -> + %% We need the Deadline and it have been extracetd before. + OldDeadL. + +%%------------------------------------------------------------ +%% function : update_starttime +%% Arguments: +%% Returns : +%% Comment : The purpose with this function is to avoid +%% parsing the events for starttime again. +%% Use only when doing an update. +%%------------------------------------------------------------ +update_starttime(DBRef, Event, OldStartT) when is_atom(OldStartT) -> + %% Probably not previously extracted; try to get it. + extract_start_time(Event, ?get_StartTsupport(DBRef), ?get_TimeRef(DBRef)); +update_starttime(_DBRef, _Event, OldStartT) -> + %% Previously extracted. + OldStartT. + +%%------------------------------------------------------------ +%% function : discard_events +%% Arguments: DBRef +%% N - number of events we must discard. +%% Returns : +%% Comment : As default we shall Reject New Events when the limit +%% is reached. Any discard order will do the same. +%% +%% This function can only be used for the discard policies +%% Fifo, Priority and Deadline. Any or RejectNewEvents +%% will not allow events to be stored at all, i.e., no events +%% to discard. Lifo will not be stored either since when +%% trying to add an event it is definitely the last event in. +%%------------------------------------------------------------ +%% Since no Discard DB must the same Order policy. +discard_events(#dbRef{orderRef = ORef, discardRef = undefined, + discardPolicy = ?not_DeadlineOrder}, N) -> + ?debug_print("Discarding ~p events Deadline Order.",[N]), + index_loop_backward(ets:last(ORef), undefined, ORef, N); +discard_events(#dbRef{orderRef = ORef, discardRef = DRef, + discardPolicy = ?not_DeadlineOrder}, N) -> + ?debug_print("Discarding ~p events Deadline Order.",[N]), + index_loop_backward(ets:last(DRef), DRef, ORef, N); +%% Fifo. +discard_events(#dbRef{orderRef = ORef, discardRef = undefined, + discardPolicy = ?not_FifoOrder}, N) -> + ?debug_print("Discarding ~p events Fifo Order.",[N]), + index_loop_backward(ets:last(ORef), undefined, ORef, N); +discard_events(#dbRef{orderRef = ORef, discardRef = DRef, + discardPolicy = ?not_FifoOrder}, N) -> + ?debug_print("Discarding ~p events Fifo Order.",[N]), + index_loop_backward(ets:last(DRef), DRef, ORef, N); +%% Lifo- or Priority-Order +discard_events(#dbRef{orderRef = ORef, discardRef = undefined}, N) -> + ?debug_print("Discarding ~p events Lifo- or Priority-Order.",[N]), + index_loop_forward(ets:first(ORef), undefined, ORef, N); +discard_events(#dbRef{orderRef = ORef, discardRef = DRef}, N) -> + ?debug_print("Discarding ~p events Lifo- or Priority-Order.",[N]), + index_loop_forward(ets:first(DRef), DRef, ORef, N). + + +index_loop_forward('$end_of_table', _, _, _Left) -> + ok; +index_loop_forward(_, _, _, 0) -> + ok; +index_loop_forward(Key, undefined, ORef, Left) -> + ets:delete(ORef, Key), + NewKey=ets:next(ORef, Key), + index_loop_forward(NewKey, undefined, ORef, Left-1); + +index_loop_forward({Key1, Key2, Key3}, DRef, ORef, Left) -> + ets:delete(DRef, {Key1, Key2, Key3}), + ets:delete(ORef, {Key3, Key2, Key1}), + NewKey=ets:next(DRef, {Key1, Key2, Key3}), + index_loop_forward(NewKey, DRef, ORef, Left-1); + +index_loop_forward({Key1, Key2}, DRef, ORef, Left) -> + ets:delete(DRef, {Key1, Key2}), + ets:delete(ORef, {Key2, Key1}), + NewKey=ets:next(DRef, {Key1, Key2}), + index_loop_forward(NewKey, DRef, ORef, Left-1). + +index_loop_backward('$end_of_table', _, _, _) -> + ok; +index_loop_backward(_, _, _, 0) -> + ok; +index_loop_backward(Key, undefined, ORef, Left) -> + ets:delete(ORef, Key), + NewKey=ets:prev(ORef, Key), + index_loop_backward(NewKey, undefined, ORef, Left-1); +index_loop_backward({Key1, Key2}, DRef, ORef, Left) -> + ets:delete(DRef, {Key1, Key2}), + ets:delete(ORef, {Key2, Key1}), + NewKey=ets:prev(DRef, {Key1, Key2}), + index_loop_backward(NewKey, DRef, ORef, Left-1); +index_loop_backward({Key1, Key2, Key3}, DRef, ORef, Left) -> + ets:delete(DRef, {Key1, Key2, Key3}), + ets:delete(ORef, {Key3, Key2, Key1}), + NewKey=ets:prev(DRef, {Key1, Key2, Key3}), + index_loop_backward(NewKey, DRef, ORef, Left-1). + +%%------------------------------------------------------------ +%% function : add_and_get_event +%% Arguments: DBRef and Event +%% Returns : {[], bool()} | {Event, bool()} +%% Comment : This function is a mixture of ad anf get events. +%% The intended use to avoid storing an event when +%% not necessary. +%%------------------------------------------------------------ +add_and_get_event(DBRef, Event) -> + add_and_get_event(DBRef, Event, undefined, undefined, true). + +add_and_get_event(DBRef, Event, Delete) -> + add_and_get_event(DBRef, Event, undefined, undefined, Delete). + +add_and_get_event(DBRef, Event, LifeFilter, PrioFilter) -> + add_and_get_event(DBRef, Event, LifeFilter, PrioFilter, true). + +add_and_get_event(DBRef, Event, LifeFilter, PrioFilter, Delete) -> + case ets:info(?get_OrderRef(DBRef), size) of + 0 when ?is_StartTNotSupported(DBRef), ?is_StopTNotSupported(DBRef), + Delete == true -> + %% No stored events and no timeouts used; just return the event. + {Event, false}; + 0 when ?is_StartTNotSupported(DBRef), ?is_StopTNotSupported(DBRef) -> + %% No stored events and no timeouts used; just return the event. + {Event, false, []}; + 0 when ?is_StartTNotSupported(DBRef) -> + %% Only deadline supported, lookup values and cehck if ok. + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef), + DOverride), + case check_deadline(DL) of + true when Delete == true -> + %% Expired, just discard the event. + {[], false}; + true -> + {[], false, []}; + _ when Delete == true -> + %% Not expired, we can safely return the event. + {Event, false}; + _ -> + %% Not expired, we can safely return the event. + {Event, false, []} + end; + 0 when ?is_StopTNotSupported(DBRef) -> + %% Only starttime allowed, test if we can deliver the event now. + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + case check_start_time(ST) of + false when Delete == true -> + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + POverride = get_prio_mapping_value(DBRef, PrioFilter, Event), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), + ?get_TimeRef(DBRef), DOverride), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride), + {[], true}; + false -> + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + POverride = get_prio_mapping_value(DBRef, PrioFilter, Event), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), + ?get_TimeRef(DBRef), DOverride), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride), + {[], true, []}; + _ when Delete == true -> + %% Starttime ok, just return the event. + {Event, false}; + _ -> + %% Starttime ok, just return the event. + {Event, false, []} + end; + _-> + %% Event already stored, just have to accept the overhead. + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + DOverride = get_life_mapping_value(DBRef, LifeFilter, Event), + POverride = get_prio_mapping_value(DBRef, PrioFilter, Event), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), + ?get_TimeRef(DBRef), DOverride), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride), + get_event(DBRef, Delete) + end. + +%%------------------------------------------------------------ +%% function : add_event +%% Arguments: DBRef and Event +%% Returns : true (or whatever 'ets:insert' returns) | +%% {'EXCEPTION', #'IMP_LIMIT'{}} +%% Comment : As default we shall deliver Events in Priority order. +%% Hence, if AnyOrder set we will still deliver in +%% Priority order. But we cannot use only the Priority +%% value since if "all" events have the same priority +%% there is a risk that some never will be delivered if +%% the EventDB always contain events. +%% +%% When discard and order policy is equal we only use one +%% DB since all we have to do is to "read from the other +%% end" to discard the correct event(s). +%% +%% In the discard DB we must also store keys necessary to +%% lookup the event in the order DB. +%% +%% If event limit reached 'IMPL_LIMIT' is raised if +%% the discard policy is RejectNewEvents or AnyOrder. +%% Theses two policies we currently define to be equal. +%%------------------------------------------------------------ + +add_event(DBRef, Event) -> + %% Save overhead by first checking if we really need to extract + %% Deadline and/or Priority. + Deadline = get_life_mapping_value(DBRef, undefined, Event), + Priority = get_prio_mapping_value(DBRef, undefined, Event), + add_event_helper(DBRef, Event, Deadline, Priority). + +add_event(DBRef, Event, LifeFilter, PrioFilter) -> + %% Save overhead by first checking if we really need to extract + %% Deadline and/or Priority. + Deadline = get_life_mapping_value(DBRef, LifeFilter, Event), + Priority = get_prio_mapping_value(DBRef, PrioFilter, Event), + add_event_helper(DBRef, Event, Deadline, Priority). + +add_event_helper(DBRef, Event, DOverride, POverride) -> + case ets:info(?get_OrderRef(DBRef), size) of + N when N < ?get_MaxEvents(DBRef), N > ?get_GCLimit(DBRef) -> + gc_events(DBRef, low), + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef), + DOverride), + case check_deadline(DL) of + true -> + true; + _ -> + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride) + end; + N when N < ?get_MaxEvents(DBRef) -> + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef), + DOverride), + case check_deadline(DL) of + true -> + true; + _ -> + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride) + end; + _N when ?get_DiscardP(DBRef) == ?not_RejectNewEvents -> + gc_events(DBRef, low), + corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO}); + _N when ?get_DiscardP(DBRef) == ?not_AnyOrder -> + gc_events(DBRef, low), + corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO}); + _N when ?get_DiscardP(DBRef) == ?not_LifoOrder -> + gc_events(DBRef, low), + corba:raise(#'IMP_LIMIT'{completion_status=?COMPLETED_NO}); + _N -> + gc_events(DBRef, low), + %% Other discard policy; we must first store the event + %% and the look up in the Discard DB which event we + %% should remove. + DL = extract_deadline(Event, ?get_DefStopT(DBRef), + ?get_StopTsupport(DBRef), ?get_TimeRef(DBRef), + DOverride), + case check_deadline(DL) of + true -> + true; + _ -> + ST = extract_start_time(Event, ?get_StartTsupport(DBRef), + ?get_TimeRef(DBRef)), + do_add_event(DBRef, Event, create_FIFO_Key(), DL, ST, POverride), + discard_events(DBRef, 1) + end + end. + + +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder, + discardRef = DRef, discardPolicy = ?not_PriorityOrder, + defPriority = DefPrio, defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{DL, Key, Prio}, DL, ST, PO, Event}), + ets:insert(DRef, {{Prio, Key, DL}}); +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder, + discardRef = DRef, discardPolicy = ?not_FifoOrder, + defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}), + ets:insert(DRef, {{Key, DL}}); +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder, + discardRef = DRef, discardPolicy = ?not_LifoOrder, + defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}), + ets:insert(DRef, {{Key, DL}}); +%% Either the same (DeadlineOrder), RejectNewEvents or AnyOrder. No need +%% to store anything in the discard policy, i.e., if the same we'll just +%% read "from the other end" and AnyOrder and RejectNewEvents is equal. +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_DeadlineOrder, + defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {{DL, Key}, DL, ST, PO, Event}); + + +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder, + discardRef = DRef, discardPolicy = ?not_DeadlineOrder, + defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {{Key, DL}, DL, ST, PO, Event}), + ets:insert(DRef, {{DL, Key}}); +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder, + discardRef = DRef, discardPolicy = ?not_PriorityOrder, + defPriority = DefPrio}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Key, Prio}, DL, ST, PO, Event}), + ets:insert(DRef, {{Prio, Key}}); +%% The discard policy must RejectNewEvents, AnyOrder, Fifo or Lifo order. +do_add_event(#dbRef{orderRef = ORef, orderPolicy = ?not_FifoOrder, + discardRef = _DRef}, Event, Key, DL, ST, PO) -> + ets:insert(ORef, {Key, DL, ST, PO, Event}); + +%% Order Policy must be AnyOrder or PriorityOrder. +do_add_event(#dbRef{orderRef = ORef, + discardRef = DRef, discardPolicy = ?not_DeadlineOrder, + defPriority = DefPrio, defStopT = _DefStopT}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Prio, Key, DL}, DL, ST, PO, Event}), + ets:insert(DRef, {{DL, Key, Prio}}); +do_add_event(#dbRef{orderRef = ORef, + discardRef = DRef, discardPolicy = ?not_FifoOrder, + defPriority = DefPrio}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}), + ets:insert(DRef, {{Key, Prio}}); + +do_add_event(#dbRef{orderRef = ORef, + discardRef = DRef, discardPolicy = ?not_LifoOrder, + defPriority = DefPrio}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}), + ets:insert(DRef, {{Key, Prio}}); + +%% Order Policy must be AnyOrder or PriorityOrder and Discard Policy must be +%% AnyOrder or RejectNewEvents +do_add_event(#dbRef{orderRef = ORef, defPriority = DefPrio}, Event, Key, DL, ST, PO) -> + Prio = extract_priority(Event, DefPrio, PO), + ets:insert(ORef, {{Prio, Key}, DL, ST, PO, Event}). + +%%------------------------------------------------------------ +%% function : destroy_db +%% Arguments: A DB reference +%% Returns : +%%------------------------------------------------------------ +destroy_db(#dbRef{orderRef = ORef, discardRef = undefined}) -> + ets:delete(ORef); +destroy_db(#dbRef{orderRef = ORef, discardRef = DRef}) -> + ets:delete(ORef), + ets:delete(DRef). + +%%------------------------------------------------------------ +%% function : destroy_discard_db +%% Arguments: A DB reference +%% Returns : +%%------------------------------------------------------------ +destroy_discard_db(#dbRef{discardRef = undefined}) -> + ok; +destroy_discard_db(#dbRef{discardRef = DRef}) -> + ets:delete(DRef). + +%%------------------------------------------------------------ +%% function : destroy_order_db +%% Arguments: A DB reference +%% Returns : +%%------------------------------------------------------------ +destroy_order_db(#dbRef{orderRef = ORef}) -> + ets:delete(ORef). + +%%------------------------------------------------------------ +%% function : create_db +%% Arguments: QoS (local representation). +%% Returns : A DB reference +%%------------------------------------------------------------ +create_db(QoS, GCTime, GCLimit, TimeRef) -> + DiscardRef = + case {?not_GetDiscardPolicy(QoS), ?not_GetOrderPolicy(QoS)} of + {Equal, Equal} -> + undefined; + {?not_PriorityOrder, ?not_AnyOrder} -> + %% NOTE: Any- and Priority-Order delivery policy is equal. + undefined; + {?not_RejectNewEvents, _} -> + undefined; + {?not_AnyOrder, _} -> + undefined; + {?not_LifoOrder, ?not_FifoOrder} -> + undefined; + _ -> + ets:new(oe_ets, [set, public, ordered_set]) + end, + DBRef = ?CreateRef(ets:new(oe_ets, [set, public, ordered_set]), + DiscardRef, + ?not_GetOrderPolicy(QoS), ?not_GetDiscardPolicy(QoS), + ?not_GetPriority(QoS), ?not_GetMaxEventsPerConsumer(QoS), + ?not_GetTimeout(QoS), ?not_GetStartTimeSupported(QoS), + ?not_GetStopTimeSupported(QoS), GCTime, GCLimit, TimeRef), + if + ?is_TimeoutNotUsed(DBRef), ?is_StopTNotSupported(DBRef) -> + ok; + true -> + {M,S,U} = now(), + put(oe_GC_timestamp, {M,S+GCTime,U}) + end, + DBRef. + +%%------------------------------------------------------------ +%% function : get_prio_mapping_value +%% Arguments: A MappingFilter reference | undefined +%% Event (Any or Structured) +%% Returns : undefined | Data +%%------------------------------------------------------------ +get_prio_mapping_value(DBRef, _, _) when ?get_DiscardP(DBRef) =/= ?not_PriorityOrder, + ?get_OrderP(DBRef) =/= ?not_AnyOrder, + ?get_OrderP(DBRef) =/= ?not_PriorityOrder -> + false; +get_prio_mapping_value(_, undefined, _) -> + undefined; +get_prio_mapping_value(_, MFilter, Event) when is_record(Event, 'any') -> + case catch 'CosNotifyFilter_MappingFilter':match(MFilter, Event) of + {false, DefVal} when is_record(DefVal, 'any') -> + any:get_value(DefVal); + {true, Matched} when is_record(Matched, 'any') -> + any:get_value(Matched); + _ -> + undefined + end; +get_prio_mapping_value(_, MFilter, Event) -> + case catch 'CosNotifyFilter_MappingFilter':match_structured(MFilter, Event) of + {false, DefVal} when is_record(DefVal, 'any') -> + any:get_value(DefVal); + {true, Matched} when is_record(Matched, 'any') -> + any:get_value(Matched); + _ -> + undefined + end. + +%%------------------------------------------------------------ +%% function : get_life_mapping_value +%% Arguments: A MappingFilter reference | undefined +%% Event (Any or Structured) +%% Returns : undefined | Data +%%------------------------------------------------------------ +get_life_mapping_value(DBRef, _, _) when ?get_DiscardP(DBRef) =/= ?not_DeadlineOrder, + ?get_OrderP(DBRef) =/= ?not_DeadlineOrder, + ?is_StopTNotSupported(DBRef) -> + false; +get_life_mapping_value(_, undefined, _) -> + undefined; +get_life_mapping_value(_, MFilter, Event) when is_record(Event, 'any') -> + case catch 'CosNotifyFilter_MappingFilter':match(MFilter, Event) of + {false, DefVal} when is_record(DefVal, 'any') -> + any:get_value(DefVal); + {true, Matched} when is_record(Matched, 'any') -> + any:get_value(Matched); + _ -> + undefined + end; +get_life_mapping_value(_, MFilter, Event) -> + case catch 'CosNotifyFilter_MappingFilter':match_structured(MFilter, Event) of + {false, DefVal} when is_record(DefVal, 'any') -> + any:get_value(DefVal); + {true, Matched} when is_record(Matched, 'any') -> + any:get_value(Matched); + _ -> + undefined + end. + +%%------------------------------------------------------------ +%% function : validate_event +%% Arguments: Subscribe data +%% A sequence of Events, 'structured' or an 'any' record +%% A list of filter references +%% Status, i.e., do we have to filter the events or just check subscr. +%% Returns : A tuple of two lists; list1 the events that passed +%% and list2 the events that didn't pass. +%%------------------------------------------------------------ +validate_event(true, Events, Filters, _, 'MATCH') -> + filter_events(Events, Filters, false); +validate_event(true, Events, _Filters, _, _) -> + {Events, []}; +validate_event({_Which, _WC}, Event, Filters, _, 'MATCH') when is_record(Event, any) -> + filter_events(Event, Filters, false); +validate_event({_Which, _WC}, Event, _Filters, _, _) when is_record(Event, any) -> + {Event, []}; +validate_event({Which, WC}, Events, Filters, DBRef, 'MATCH') -> + Passed=validate_event2(DBRef, Events, Which, WC, []), + filter_events(Passed, Filters, true); +validate_event({Which, WC}, Events, _Filters, DBRef, _) -> + Passed=validate_event2(DBRef, Events, Which, WC, []), + {lists:reverse(Passed), []}. + +validate_event2(_, [], _, _, []) -> + []; +validate_event2(_, [], _, _, Acc) -> + Acc; +validate_event2(DBRef, [Event|T], Which, WC, Acc) -> + ET = ((Event#'CosNotification_StructuredEvent'.header) + #'CosNotification_EventHeader'.fixed_header) + #'CosNotification_FixedEventHeader'.event_type, + CheckList = + case Which of + both -> + [ET]; + domain -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}]; + type -> + [ET, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}]; + _ -> + [ET, + ET#'CosNotification_EventType'{type_name=""}, + ET#'CosNotification_EventType'{type_name="*"}, + ET#'CosNotification_EventType'{domain_name=""}, + ET#'CosNotification_EventType'{domain_name="*"}] + end, + case check_subscription(DBRef, CheckList) of + true -> + validate_event2(DBRef, T, Which, WC, [Event|Acc]); + _-> + case catch cosNotification_Filter:match_types( + ET#'CosNotification_EventType'.domain_name, + ET#'CosNotification_EventType'.type_name, + WC) of + true -> + validate_event2(DBRef, T, Which, WC, [Event|Acc]); + _-> + validate_event2(DBRef, T, Which, WC, Acc) + end + end. + +check_subscription(_, []) -> + false; +check_subscription(DBRef, [H|T]) -> + case ets:lookup(DBRef, H) of + [] -> + check_subscription(DBRef, T); + _ -> + true + end. + + +%%------------------------------------------------------------ +%% function : filter_events +%% Arguments: A sequence of structured Events or #any +%% Returns : A tuple of two lists; list1 the events that passed +%% and list2 the events that didn't pass. +%%------------------------------------------------------------ + +filter_events(Events, []) -> + {Events, []}; +filter_events(Events, Filters) -> + filter_events(Events, Filters, [], [], false). + +filter_events(Events, [], false) -> + {Events, []}; +filter_events(Events, [], _) -> + {lists:reverse(Events), []}; +filter_events(Events, Filters, Reversed) -> + filter_events(Events, Filters, [], [], Reversed). + +filter_events([], _, AccPassed, AccFailed, false) -> + {lists:reverse(AccPassed), lists:reverse(AccFailed)}; +filter_events([], _, AccPassed, AccFailed, _) -> + {AccPassed, AccFailed}; +filter_events([H|T], Filters, AccPassed, AccFailed, Reversed) -> + case call_filters(Filters, H) of + true -> + filter_events(T, Filters, [H|AccPassed], AccFailed, Reversed); + _ -> + filter_events(T, Filters, AccPassed, [H|AccFailed], Reversed) + end; +filter_events(Any, Filters, _AccPassed, _AccFailed, _Reversed) -> + case call_filters(Filters, Any) of + true -> + {Any, []}; + _ -> + {[], Any} + end. + +call_filters([], _) -> + false; +call_filters([{_,H}|T], Event) when is_record(Event, any) -> + case catch 'CosNotifyFilter_Filter':match(H, Event) of + true -> + true; + _-> + call_filters(T, Event) + end; +call_filters([{_,H}|T], Event) when ?not_isConvertedAny(Event) -> + case catch 'CosNotifyFilter_Filter':match(H, + Event#'CosNotification_StructuredEvent'.remainder_of_body) of + true -> + true; + _-> + call_filters(T, Event) + end; +call_filters([{_,H}|T], Event) -> + case catch 'CosNotifyFilter_Filter':match_structured(H, Event) of + true -> + true; + _-> + call_filters(T, Event) + end. + + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk new file mode 100644 index 0000000..65f9812 --- /dev/null +++ b/lib/cosNotification/vsn.mk @@ -0,0 +1,11 @@ +COSNOTIFICATION_VSN = 1.1.12 + +TICKETS = OTP-8201 + +TICKETS_1.1.11 = OTP-7987 + +TICKETS_1.1.10 = OTP-7837 + +TICKETS_1.1.9 = OTP-7595 + +TICKETS_1.1.8 = OTP-7553 diff --git a/lib/cosProperty/AUTHORS b/lib/cosProperty/AUTHORS new file mode 100644 index 0000000..55d8059 --- /dev/null +++ b/lib/cosProperty/AUTHORS @@ -0,0 +1,4 @@ +Original Authors: +Niclas Eklund + +Contributors: diff --git a/lib/cosProperty/Makefile b/lib/cosProperty/Makefile new file mode 100644 index 0000000..e8ec803 --- /dev/null +++ b/lib/cosProperty/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(COSPROPERTY_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- +# SUB_DIRECTORIES = src test examples doc/src +# At the moment we don't have any example programs. +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/cosProperty/doc/html/.gitignore b/lib/cosProperty/doc/html/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosProperty/doc/man3/.gitignore b/lib/cosProperty/doc/man3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosProperty/doc/man6/.gitignore b/lib/cosProperty/doc/man6/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosProperty/doc/pdf/.gitignore b/lib/cosProperty/doc/pdf/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml new file mode 100644 index 0000000..75c7cb3 --- /dev/null +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml @@ -0,0 +1,95 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosPropertyService_­PropertiesIterator + ..._PropertiesIterator + + + + 2000-07-25 + 1.0 +
+ CosPropertyService_PropertiesIterator + This module implements the OMG CosPropertyService::PropertiesIterator interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosProperty/include/CosPropertyService.hrl").

+
+ + + reset(Iterator) -> ok + Reset the position to the first property + + Iterator = #objref + + +

This operation resets the position to the first property.

+
+
+ + next_one(Iterator) -> Reply + Return true if a Property exists at the current position and the out parameter is a valid Property. Otherwise false and a non-valid property + + Iterator = #objref + Reply = {boolean(), #'CosPropertyService_Property'{property_name = Name, property_value = Value}} + Name = string() + Value = #any + + +

This operation returns true . If false is returned the out + parameter is a non-valid Property.

+
+
+ + next_n(Iterator, HowMany) -> Reply + Return true if the requested number of properties can be delivered and there are additional properties. Otherwise false is returned and a sequence of max HowManyproperties + + Iterator = #objref + HowMany = long() + Reply = {boolean(), Properties} + Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}] + Name = string() + Value = #any + + +

This operation returns true if the requested number of properties can be + delivered and there are additional properties. If false is returned and a + sequence of max HowMany properties will be returned and no more + properties can be delivered.

+
+
+ + destroy(Iterator) -> ok + Terminate the target object + + Iterator = #objref + + +

This operation will terminate the Iterator and all subsequent calls + will fail.

+
+
+
+ +
+ diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml new file mode 100644 index 0000000..54e29a5 --- /dev/null +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml @@ -0,0 +1,97 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosPropertyService_­PropertyNamesIterator + ..._PropertyNamesIterator + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-07-25 + 1.0 +
+ CosPropertyService_PropertyNamesIterator + This module implements the OMG CosPropertyService::PropertyNamesIterator interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosProperty/include/CosPropertyService.hrl").

+
+ + + reset(Iterator) -> ok + Reset the position to the first property name + + Iterator = #objref + + +

This operation resets the position to the first property name.

+
+
+ + next_one(Iterator) -> Reply + Return true if a Property Name exists at the current position and the out parameter is a valid Property Name. Otherwise false and a non-valid Property Name + + Iterator = #objref + Reply = {boolean(), Name} + Name = string() + + +

This operation returns true if a Property Name exists at the current + position and the out parameter is a valid Property Name. + If false is returned the out parameter is a non-valid Property Name.

+
+
+ + next_n(Iterator, HowMany) -> Reply + Return HowManyProperty Names and a boolean which is true if additional Property Names exists + + Iterator = #objref + HowMany = long() + Reply = {boolean(), [Name]} + Name = string() + + +

This operation returns true if the requested number of Property Names can be + delivered and there are additional property names. If false is returned a + sequence of max HowMany property names will be returned and no + more Property Names can be delivered.

+
+
+ + destroy(Iterator) -> ok + Terminate the target object + + Iterator = #objref + + +

This operation will terminate the Iterator and all subsequent calls + will fail.

+
+
+
+ +
+ diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml new file mode 100644 index 0000000..4a2073d --- /dev/null +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml @@ -0,0 +1,201 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosPropertyService_­PropertySet + ..._PropertySet + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-07-25 + 1.0 +
+ CosPropertyService_PropertySet + This module implements the OMG CosPropertyService::PropertySet interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosProperty/include/CosPropertyService.hrl").

+
+ + + define_property(PropertySet, Name, Value) -> Reply + Add a new property to the target object + + PropertySet = #objref + Name = non-empty string() + Value = #any + Reply = ok | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} | {'EXCEPTION', #CosPropertyService_ConflictingProperty{}} | {'EXCEPTION', #CosPropertyService_UnsupportedTypeCode{}} | {'EXCEPTION', #CosPropertyService_UnsupportedProperty{}} | {'EXCEPTION', #CosPropertyService_ReadOnlyProperty{}} + + +

This operation adds a new property to the given object. Depending on + which initial arguments was supplied when starting the object several + exceptions may be raised.

+
+
+ + define_properties(PropertySet, Properties) -> Reply + Add new properties to the target object + + PropertySet = #objref + Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}] + Name = string() + Value = #any + Reply = ok | {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}} + Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}] + Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property + + +

This operation adds several new properties to the given object. Depending on + which initial arguments was supplied when starting the object an + exceptions may be raised listing the properties failing.

+
+
+ + get_number_of_properties(PropertySet) -> ulong() + Get the number of properties associated with the target object + + PropertySet = #objref + + +

This operation returns the number of properties associated with the target + object.

+
+
+ + get_all_property_names(PropertySet, Max) -> Reply + Get Maxproperty names. If the target object have additional associated properties they will be put in the returned Iterator + + PropertySet = NamesIterator = #objref + Max = ulong() + Reply = {ok, Names, NamesIterator} + Names = [string()] + + +

This operation returns up to Max property names. If the target + object have additional associated properties they will be put in the + returned Iterator, otherwise the Iterator will be a NIL object.

+
+
+ + get_property_value(PropertySet, Name) -> Reply + Return the property value associated with given name + + PropertySet = #objref + Name = string() + Reply = #any | {'EXCEPTION', #CosPropertyService_PropertyNotFound{}} | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} + + +

This operation returns the property value associated with given name. If no such property + exists or the given name is an empty string an exception will be raised.

+
+
+ + get_properties(PropertySet, Names) -> Reply + Return all properties associated with given names + + PropertySet = #objref + Names = [string()] + Reply = {boolean(), Properties} + Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}] + + +

This operation returns all properties associated with given names. If the + boolean flag is true all properties where retrieved correctly, otherwise, + all properties with the type tk_void was not found.

+
+
+ + get_all_properties(PropertySet, Max) -> Reply + Return a list Maxproperties or less. If more properties are associated with the target object they will be put in thePropertiesIterator. + + PropertySet = PropertiesIterator = #objref + Reply = {ok, Properties, PropertiesIterator} + Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}] + + +

This operation return a list Max properties or less. If more + properties are associated with the target object they will be put in the + PropertiesIterator. If the object had less than Max + associated properties the Iterator will be a NIL object.

+
+
+ + delete_property(PropertySet, Name) -> Reply + Delete the property with given Name + + PropertySet = #objref + Name = string() + Reply = ok | {'EXCEPTION', #CosPropertyService_FixedProperty{}} | {'EXCEPTION', #CosPropertyService_PropertyNotFound{}} | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} + + +

This operation tries to delete the property with given Name. An exception + which indicates why it failed is raised if so needed.

+
+
+ + delete_properties(PropertySet, Names) -> Reply + Delete all properties with given Names + + PropertySet = #objref + Names = [string()] + Reply = ok | {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}} + Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}] + Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property + + +

This operation tries to delete all given Properties. If one or more removal + fails an exception is raised which describe why.

+
+
+ + delete_all_properties(PropertySet) -> boolean() + Delete all properties + + PropertySet = #objref + + +

This operation deletes all properties. The boolean flag, if set to false, + indicates that it was not possible to remove one or more properties, e.g., + may be read only.

+
+
+ + is_property_defined(PropertySet, Name) -> Reply + Return true if the target have an associated property with given name + + PropertySet = #objref + Name = non-empty string() + Reply = boolean() | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} + + +

This operation returns true if the target have an associated property with + given name.

+
+
+
+ +
+ diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml new file mode 100644 index 0000000..7684998 --- /dev/null +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml @@ -0,0 +1,168 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosPropertyService_­PropertySetDef + ..._PropertySetDef + + + + 2000-07-25 + 1.0 +
+ CosPropertyService_PropertySetDef + This module implements the OMG CosPropertyService::PropertySetDef interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosProperty/include/CosPropertyService.hrl").

+

This module also exports the functions described in

+

CosPropertyService_PropertySet

+
+ + + get_allowed_property_types(PropertySetDef) -> Reply + Return allowed TypeCodes for the target object + + PropertySetDef = #objref + Reply = {ok, PropertyTypes} + PropertyTypes = [CORBA::TypeCode] + + +

This operation return the TypeCodes which we are allowed to use when adding + new properties.

+
+
+ + get_allowed_properties(PropertySetDef) -> Reply + Return a sequence of the allowed properties + + PropertySetDef = #objref + Reply = {ok, PropertyDefs} + PropertyDefs = [#'CosPropertyService_PropertyDef'{property_name = Name, property_value = Value, property_mode = Mode}] + Name = string() + Value = #any + Mode = normal | read_only | fixed_normal | fixed_readonly | undefined + + +

This operation a sequence of the allowed properties we may alter; depends on + which mode associated with a certain property.

+
+
+ + define_property_with_mode(PropertySetDef, Name, Value, Mode) -> Reply + Associate a new property with the target object + + PropertySetDef = #objref + Name = non-empty string() + Value = #any + Mode = normal | read_only | fixed_normal | fixed_readonly | undefined + Reply = ok | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} | {'EXCEPTION', #CosPropertyService_ConflictingProperty{}} | {'EXCEPTION', #CosPropertyService_UnsupportedTypeCode{}} | {'EXCEPTION', #CosPropertyService_UnsupportedProperty{}} | {'EXCEPTION', #CosPropertyService_UnsupportedMode{}} | {'EXCEPTION', #CosPropertyService_ReadOnlyProperty{}} + + +

This operation attempts to associate a new property with the target object. + If we fail to do so the appropriate exception is raised.

+
+
+ + define_properties_with_modes(PropertySetDef, PropertyDefs) -> Reply + Associate the given Property Definitions with the target object + + PropertySetDef = #objref + PropertyDefs = [#'CosPropertyService_PropertyDef'{property_name = Name, property_value = Value, property_mode = Mode}] + Name = string() + Value = #any + Mode = normal | read_only | fixed_normal | fixed_readonly | undefined + Reply = ok | {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}} + Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}] + Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property + + +

This operation attempts to associate the given Property Definitions with the + target object. If one or more attempts fail an exception is raised + describing which properties we where not able to create.

+
+
+ + get_property_mode(PropertySetDef, Name) -> Reply + Return the mode of the given property + + PropertySetDef = #objref + Name = string() + Reply = Mode | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} | {'EXCEPTION', #CosPropertyService_PropertyNotFound{}} + Mode = normal | read_only | fixed_normal | fixed_readonly | undefined + + +

This operation returns the type of the given property.

+
+
+ + get_property_modes(PropertySetDef, Names) -> Reply + Return the modes of the given properties + + PropertySetDef = #objref + Names = [string()] + Reply = {boolean(), PropertyModes} + PropertyModes = [#'CosPropertyService_PropertyMode'{property_name = Name, property_mode = Mode}] + Name = string() + Mode = normal | read_only | fixed_normal | fixed_readonly | undefined + + +

This operation returns the modes of the listed properties. If the boolean + flag is false, all properties with mode undefined this operation + failed to comply.

+
+
+ + set_property_mode(PropertySetDef, Name, Mode) -> Reply + Change the given property's mode + + PropertySetDef = #objref + Name = string() + Mode = normal | read_only | fixed_normal | fixed_readonly | undefined + Reply = ok | {'EXCEPTION', #CosPropertyService_InvalidPropertyName{}} | {'EXCEPTION', #CosPropertyService_UnsupportedMode{}} | {'EXCEPTION', #CosPropertyService_PropertyNotFound{}} + + +

This operation changes the given property's mode. Return the appropriate + exception if not able to fulfill the request.

+
+
+ + set_property_modes(PropertySetDef, PropertyModes) -> Reply + Change the listed properties mode's + + PropertySetDef = #objref + PropertyModes = [#'CosPropertyService_PropertyMode'{property_name = Name, property_mode = Mode}] + Name = string() + Mode = normal | read_only | fixed_normal | fixed_readonly | undefined + Reply = ok | {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}} + Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}] + Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property + + +

This operation attempts to update the listed properties mode's. Raises an + exception which describe which and why an operation failed.

+
+
+
+ +
+ diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml new file mode 100644 index 0000000..82c04e5 --- /dev/null +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml @@ -0,0 +1,95 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosPropertyService_­PropertySetDefFactory + ..._PropertySetDefFactory + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-07-25 + 1.0 +
+ CosPropertyService_PropertySetDefFactory + This module implements the OMG CosPropertyService::PropertySetDefFactory interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosProperty/include/CosPropertyService.hrl").

+
+ + + create_propertysetdef(Factory) -> + Create a new PropertySetDefwith no predefined settings + + Factory = PropertySetDef = #objref + + +

This operation creates a new PropertySetDef with no predefined + settings.

+
+
+ + create_constrained_propertysetdef(Factory, PropertyTypes, PropertyDefs) -> Reply + Create a new PropertySetDefwith specified constraints + + Factory = PropertySetDef = #objref + PropertyTypes = [CORBA::TypeCode] + PropertyDefs = [#'CosPropertyService_PropertyDef'{property_name = Name, property_value = Value, property_mode = Mode}] + Name = string() + Value = #any + Mode = normal | read_only | fixed_normal | fixed_readonly | undefined + Reply = {'EXCEPTION', #CosPropertyService_ConstraintNotSupported{}} | PropertySetDef + PropertySetDef = #objref + + +

This operation creates a new PropertySetDef with specific + constraints. PropertyTypes states allowed TypeCode's and PropertyDefs valid + CosPropertyService::PropertyDef data.

+
+
+ + create_initial_propertysetdef(Factory, PropertyDefs) -> Reply + Create a new PropertySetDefwith specified initial properties + + Factory = PropertySetDef = #objref + PropertyDefs = [#'CosPropertyService_PropertyDef'{property_name = Name, property_value = Value, property_mode = Mode}] + Name = string() + Value = #any + Mode = normal | read_only | fixed_normal | fixed_readonly | undefined + Reply = {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}} | PropertySetDef + Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}] + Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property + PropertySetDef = #objref + + +

This operation creates a new PropertySetDef with specific + initial properties.

+
+
+
+ +
+ diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml new file mode 100644 index 0000000..06b3d2b --- /dev/null +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml @@ -0,0 +1,93 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosPropertyService_­PropertySetFactory + ..._PropertySetFactory + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-07-25 + 1.0 +
+ CosPropertyService_PropertySetFactory + This module implements the OMG CosPropertyService::PropertySetFactory interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosProperty/include/CosPropertyService.hrl").

+
+ + + create_propertyset(Factory) -> PropertySet + Create a new PropertySet with no predefined properties + + Factory = PropertySet = #objref + + +

This operation creates a new PropertySet with no predefined + properties.

+
+
+ + create_constrained_propertyset(Factory, PropertyTypes, Properties) -> Reply + Create a new PropertySetwith specified constraints + + Factory = #objref + PropertyTypes = [CORBA::TypeCode] + Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}] + Name = string() + Value = #any + Reply = {'EXCEPTION', #CosPropertyService_ConstraintNotSupported{}} | PropertySet + PropertySet = #objref + + +

This operation creates a new PropertySet with specific constraints. + PropertyTypes states allowed TypeCode's and Properties valid + CosPropertyService::Property data.

+
+
+ + create_initial_propertyset(Factory, Properties) -> Reply + Create a new PropertySetwith specified initial properties + + Factory = #objref + Properties = [#'CosPropertyService_Property'{property_name = Name, property_value = Value}] + Name = string() + Value = #any + Reply = {'EXCEPTION', #CosPropertyService_MultipleExceptions{exceptions = Excs}} | PropertySet + Excs = [#'CosPropertyService_PropertyException{reason = Reason, failing_property_name = Name}] + Reason = invalid_property_name | conflicting_property | property_not_found | unsupported_type_code | unsupported_property | unsupported_mode | fixed_property | read_only_property + PropertySet = #objref + + +

This operation creates a new PropertySet with specific + initial properties.

+
+
+
+ +
+ diff --git a/lib/cosProperty/doc/src/Makefile b/lib/cosProperty/doc/src/Makefile new file mode 100644 index 0000000..126e05e --- /dev/null +++ b/lib/cosProperty/doc/src/Makefile @@ -0,0 +1,243 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(COSPROPERTY_VSN) +APPLICATION=cosProperty + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + cosProperty.xml \ + CosPropertyService_PropertySetFactory.xml \ + CosPropertyService_PropertySetDefFactory.xml \ + CosPropertyService_PropertySet.xml \ + CosPropertyService_PropertySetDef.xml \ + CosPropertyService_PropertiesIterator.xml \ + CosPropertyService_PropertyNamesIterator.xml + +XML_REF6_FILES = + +XML_PART_FILES = \ + part.xml \ + part_notes.xml +XML_CHAPTER_FILES = \ + ch_contents.xml \ + ch_introduction.xml \ + ch_install.xml \ + ch_example.xml \ + notes.xml + +BOOK_FILES = book.xml + +TECHNICAL_DESCR_FILES = + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif + +PS_FILES = + +# ---------------------------------------------------- + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info + +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_REF6_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) +MAN6_FILES = $(XML_REF6_FILES:%.xml=$(MAN6DIR)/%.6) + + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_REF6_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf + +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(INTERNAL_HTML_FILES) + +tex_users_guide: $(TEX_FILES_USERS_GUIDE) +tex_ref_man: $(TEX_FILES_REF_MAN) +tex: tex_users_guide tex_ref_man $(TEX_FILES_BOOK) + +$(DOCDIR)/latexlog: $(BOOK_FILES:%.xml=%.dvi) + -fgrep -i "latex warning" $(BOOK_FILES:%.xml=%.log) >$(DOCDIR)/latexlog + +clean_tex: + -rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + +clean: + rm -f ../html/* $(MAN3_FILES) $(MAN6_FILES) $(TEX_FILES_USERS_GUIDE) + rm -f *xmls_output *xmls_errs + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ $(LATEX_CLEAN) + +endif + +man: $(MAN3_FILES) $(MAN6_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +$(INDEX_TARGET): $(INDEX_SRC) + sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + +release_spec: + diff --git a/lib/cosProperty/doc/src/book.gif b/lib/cosProperty/doc/src/book.gif new file mode 100644 index 0000000000000000000000000000000000000000..94b38687920c5386f0d90df2cfc962d66f52fbce GIT binary patch literal 1081 zcmV-91jhSENk%v~VJrYQ0K@U3Z&d%1>*52OU z=jZ3|@9+2b_W%F@EC2ui04xAE000I5ARvxpX`Uh%Eez$Ma2!{|XMe{g?|T;9x5JA^ zG%bL@N^vRj5RkV9bLkO4ZPIBmas5oR#mf&V1Q#(0YhcjmXe*9~d=7a)?vMy(=-KE* z8yQRzT~`AL3l4P-3kL!Lf=d(yg_TGJLq#4K5D7Jwg%4&P850c&1Y@8d0)H_S5pFPj z7ZR$K4m$^o4iXXx39coCpaZff8wUU$784g63O)Mnh1d zM*Ony;LwB#3?8W4Fn~dfDxggNp6C!kf(B*{AQb3^!o#OZ2{2Ij__0FI3O->S0!o2G zg@f-96evKTsnY>a2Pj~$%K;+++!`!k(;yCksSK!^1M@%uPY44fe1t$i?MDI+c2ZbC za|F=4KrQICaN${m0^A%h5YV8o0a~3adU`fEQr`1qssBIw;^v!UF;k;yW-v@4+eo>JYd}fHVVU z5gLf*p9x%mVi^DlSTI8WPNw|_zy%J@^^O%t7;wu6|1F@62n+%+n+O+(7C~JYKp}tz zPXIAiOdhnDfD0a6fWQkLNGO6;!$2WQfj6jx)&W2YPymny2!Ox=N)36z-FBgSXr4c6dN%+LI-06;0gjrH4CDHEr=iiO;mnh?Fk3i5Wq1C#9AnbqG>3C zxFaCoE>b2iV1odev}UfA7}V< + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosProperty + Niclas Eklund + + 2000-06-07 + 1.0 +
+ + + cosProperty + + + + + + + + + + + + + + +
+ diff --git a/lib/cosProperty/doc/src/ch_contents.xml b/lib/cosProperty/doc/src/ch_contents.xml new file mode 100644 index 0000000..9b8a39c --- /dev/null +++ b/lib/cosProperty/doc/src/ch_contents.xml @@ -0,0 +1,74 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The cosProperty Application + Niclas Eklund + + 2000-06-07 + 1.0 + ch_contents.xml +
+ +
+ Content Overview +

The cosProperty documentation is divided into three sections: +

+ + +

PART ONE - The User's Guide +

+Description of the cosProperty Application including + services and a small tutorial demonstrating + the development of a simple service.

+
+ +

PART TWO - Release Notes +

+A concise history of cosProperty.

+
+ +

PART THREE - The Reference Manual +

+ A quick reference guide, including a + brief description, to all the functions available in cosProperty.

+
+
+
+ +
+ Brief description of the User's Guide +

The User's Guide contains the following parts:

+ + +

cosProperty overview

+
+ +

cosProperty installation

+
+ +

A tutorial example

+
+
+
+
+ diff --git a/lib/cosProperty/doc/src/ch_example.xml b/lib/cosProperty/doc/src/ch_example.xml new file mode 100644 index 0000000..3b5c616 --- /dev/null +++ b/lib/cosProperty/doc/src/ch_example.xml @@ -0,0 +1,75 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosProperty Examples + Niclas Eklund + + 2000-06-07 + A + ch_example.xml +
+ +
+ A tutorial on how to create a simple service + +
+ Initiate the application +

To use the cosProperty application Orber must be running.

+
+ +
+ How to run everything +

Below is a short transcript on how to run cosProperty.

+ + +%% Start Mnesia and Orber +mnesia:delete_schema([node()]), +mnesia:create_schema([node()]), +orber:install([node()]), +mnesia:start(), +orber:start(), + +%% Install Property Service in the IFR. +cosProperty:install(), + +%% Install Property Service in mnesia. +cosProperty:install_db(), + +%% Now start the application. +cosProperty:start(), + +%% To be able to create Property objects we must first a Factory +%% of our preferred type. +Fac = cosProperty:start_SetDefFactory(), + +%% Now we can create a Property object. +'CosPropertyService_PropertySetDefFactory': + create_propertysetdef(Fac), + +%% Now we can create any allowed properties. There are many +%% options which are all described further in the documentation. + +
+
+
+ diff --git a/lib/cosProperty/doc/src/ch_install.xml b/lib/cosProperty/doc/src/ch_install.xml new file mode 100644 index 0000000..33324a0 --- /dev/null +++ b/lib/cosProperty/doc/src/ch_install.xml @@ -0,0 +1,55 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Installing cosProperty + Niclas Eklund + + 2000-06-07 + + ch-install.xml +
+ +
+ Installation Process +

This chapter describes how to install + cosProperty in an Erlang Environment. +

+ +
+ Preparation +

Before starting the installation process for cosProperty, + the application Orber must be running.

+
+ +
+ Configuration +

First the cosProperty application must be installed by using + cosProperty:install() and, if requested, cosProperty:install_db(), + followed by cosProperty:start(). + Now we can start the desired Factory type by using either + cosProperty:start_SetFactory() or + cosProperty:start_SetDefFactory().

+
+
+
+ diff --git a/lib/cosProperty/doc/src/ch_introduction.xml b/lib/cosProperty/doc/src/ch_introduction.xml new file mode 100644 index 0000000..1f87311 --- /dev/null +++ b/lib/cosProperty/doc/src/ch_introduction.xml @@ -0,0 +1,53 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Introduction to cosProperty + Niclas Eklund + + 2000-06-07 + + ch_introduction.xml +
+ +
+ Overview +

The cosProperty application is compliant with the OMG + Service CosProperty Service. +

+ +
+ Purpose and Dependencies +

cosProperty is dependent on Orber, which provides CORBA functionality in an Erlang environment.

+
+ +
+ Prerequisites +

To fully understand the concepts presented in the + documentation, it is recommended that the user is familiar + with distributed programming, CORBA and the Orber application. +

+

Recommended reading includes CORBA, Fundamentals and Programming - Jon Siegel and Open Telecom Platform Documentation Set. It is also helpful to have read Concurrent Programming in Erlang.

+
+
+
+ diff --git a/lib/cosProperty/doc/src/cosProperty.xml b/lib/cosProperty/doc/src/cosProperty.xml new file mode 100644 index 0000000..4dbbbad --- /dev/null +++ b/lib/cosProperty/doc/src/cosProperty.xml @@ -0,0 +1,149 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosProperty + + + + 2000-06-07 + PA1 +
+ cosProperty + The main module of the cosProperty application + +

To get access to the record definitions for the structures use:

+-include_lib("cosProperty/include/*.hrl").

+

This module contains the functions for starting and stopping the application.

+
+ + + install() -> Return + Install the cosProperty application in the IFR + + Return = ok | {'EXIT', Reason} + + +

This operation installs the cosProperty application in the IFR.

+
+
+ + install_db() -> Return + Install data in mnesia necessary for running the cosProperty application + + Return = ok | {'EXIT', Reason} + + +

This operation installs data in mnesia necessary for running the + cosProperty application.

+
+
+ + uninstall() -> Return + Remove all data in the IFR related to the cosProperty application + + Return = ok | {'EXIT', Reason} + + +

This operation removes all data in the IFR related to the cosProperty + application.

+
+
+ + uninstall_db() -> Return + Remove all data from mnesia related to the cosProperty application + + Return = ok | {'EXIT', Reason} + + +

This operation removes all data from mnesia related to the cosProperty + application.

+
+
+ + start() -> Return + Start the cosProperty application + + Return = ok | {error, Reason} + + +

This operation starts the cosProperty application.

+
+
+ + start_SetDefFactory() -> Return + Start a PropertySetDef Factory + + Return = Factory | {'EXCEPTION', E} + Factory = CosPropertyService::PropertySetDefFactory reference. + + +

This operation starts a PropertySetDef Factory.

+
+
+ + start_SetFactory() -> Return + Start a PropertySet Factory + + Return = Factory | {'EXCEPTION', E} + Factory = CosPropertyService::PropertySetDefFactory reference. + + +

This operation starts a PropertySet Factory.

+
+
+ + stop_SetDefFactory(Factory) -> Return + Stop the given PropertySetDef Factory + + Factory = CosPropertyService::PropertySetDefFactory reference. + Return = ok | {'EXCEPTION', E} + + +

This operation stops the supplied PropertySetDef Factory.

+
+
+ + stop_SetFactory(Factory) -> Return + Stop the given PropertySet Factory + + Factory = CosPropertyService::PropertySetFactory reference. + Return = ok | {'EXCEPTION', E} + + +

This operation stops the supplied PropertySet Factory.

+
+
+ + stop() -> Return + Stop the cosProperty application + + Return = ok | {error, Reason} + + +

This operation stops the cosProperty application.

+
+
+
+ +
+ diff --git a/lib/cosProperty/doc/src/fascicules.xml b/lib/cosProperty/doc/src/fascicules.xml new file mode 100644 index 0000000..0678195 --- /dev/null +++ b/lib/cosProperty/doc/src/fascicules.xml @@ -0,0 +1,18 @@ + + + + + + User's Guide + + + Reference Manual + + + Release Notes + + + Off-Print + + + diff --git a/lib/cosProperty/doc/src/make.dep b/lib/cosProperty/doc/src/make.dep new file mode 100644 index 0000000..383af54 --- /dev/null +++ b/lib/cosProperty/doc/src/make.dep @@ -0,0 +1,26 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: CosPropertyService_PropertiesIterator.tex \ + CosPropertyService_PropertyNamesIterator.tex \ + CosPropertyService_PropertySet.tex CosPropertyService_PropertySetDef.tex \ + CosPropertyService_PropertySetDefFactory.tex \ + CosPropertyService_PropertySetFactory.tex \ + book.tex ch_contents.tex ch_example.tex ch_install.tex \ + ch_introduction.tex cosProperty.tex part.tex \ + ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + diff --git a/lib/cosProperty/doc/src/notes.gif b/lib/cosProperty/doc/src/notes.gif new file mode 100644 index 0000000000000000000000000000000000000000..e000cca26a383722eca87f4d87a5841292b0b8ea GIT binary patch literal 2005 zcmc(e`(I0c1HeD$>})&L($>wE%9*B;E}M!dPv>-9341YwWX&zf>scU1zfBrl=I{N9;r;i^$ ze)#ZVWMt(1`}gnOy?gui?eOsMn>TM>zkWS5H1z7#tHHs+fq?;|(fIP^%NH+RJb(WD z*|TR)pFVx^ogEz=?d|P)y}qrjt+lnarKLru(`mKZ=H_ONMx$1%@7%d_`}XZyw{G3MdGp4N z8%<43jg5^B4Gq_?U%z(k+SRL9>+9>UT)9$LS65qGTT@eW`SRsUmo8nrc=5u83+KckWzORn^(EXDcf!&zw1P`t<2jr%qK=RFs#Ot5m9!Cr_R@apL&#<7H)K$BrF4 zdi1DLsXTJzNNH(lNl8g@aq;29hl`4e3JVJr3dNyAhYlV*SWr-qpP!$XmzSHHo0F3x zm&-FUGSbu2Wir|R{rmUr+qZY`-n6u|)YR0Jl$1St_9Q1K@7}$8*REYVckbM=V@Fa_ zl0+iezI}UQV&b-K+Y%BIwr<_JdGqE?n>KCSxN*aV4Pvo4E-p?a60KjqJ~lRX-MV!# zF)?e`u3fWc&Fa;wSFKvLa^=buD^>`F!ez^r2?T=0ix)>lMMXwNMnpvL`TX$k@UXD3 zkdTnz;NYO3Ac7zQ0|OT>TD_t~>&yScf|nl;PS)z!tt#o5`J!{InNIkDMn48x{RpYG`B=-}XBZ*Mm zJ0_E9VPQd|(M(NEQ52<8sT2wYK@bv&1j8@{LE!(5`#%Ezya3Qi0HOB$8kHskwQ`Hm z*OY4y(48X7__Y-+c}(wwXZqSxZHKVn+_d2V9bX<;)o5v8$jlB{tz6vnwfvQAiMw6t z0IXVSedvhT17nJCGJ_XCYT%)5*?chw5R9s25QXlX!e_sd7hr)!eyKroJ4zhgi|iRe z9BRcDRXkmj&PH5Z1EswZP1Yik}bX?KQfDMotrhur?Z`l6 z9SHWUks6^bPWsX|jEswdY)vps%VI@IAvY7W9?a_N?~xI!M!5pm(Ry5JJ;$6wSb!Kw z1Ofz-ES$>6ni1O}ScWTvR$Wsm*pF-~}^QqIoOkG6>BJ?$;+XE5N4m%cOVTgl$q1H6Cj2CRZ#Cwk*Z+A1}6-ZGIOnZ zriKR6JwuHEr#89IP&lU0d>}f|iQ2(xTebl}Km=JKc>w~{On}kI=M0e4E*aE>B!t(` zz!7B(z}xLdevm2fNGl*)VFk@hhEN1isQ4%eVdfhlo64C^B-c26^Z?T#Tc$&!YL-EE zsr_sc%})?_z}$saj#x(bLnO=CUH5f1>6}R!!dMZ|W9GTgpb9n@*5fiBqnDrne~DCT zx&%mdn3ma=CO4$ZCjP+)Zks2RB*+Tt`QEtb2g6+n+RKF1oJqVMUCo0mdGDTz#3Q^?T4648gGi%gvvJ#j{AlN2b z`m?E;VM>mcPQBC_Y6=8kn9B=CL=o-QgXt_x2k`|YJusL&`b=Pj%+?u4tr>8h24sDX + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosProperty Release Notes + Niclas Eklund + + + + 2000-06-07 + A + notes.xml +
+ +
+ cosProperty 1.1.10 + +
+ Improvements and New Features + + +

+ The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.

+

+ Own Id: OTP-8201 Aux Id:

+
+
+
+
+ +
+ cosProperty 1.1.9 + +
+ Improvements and New Features + + +

Obsolete guards, e.g. record vs is_record, has been changed + to avoid compiler warnings.

+

Own id: OTP-7987

+
+
+
+
+ +
+ cosProperty 1.1.8 +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7837

+
+
+
+
+ +
+ cosProperty 1.1.7 +
+ Improvements and New Features + + +

Documentation source included in open source releases.

+

Own id: OTP-7595

+
+
+
+
+ +
+ cosProperty 1.1.6 +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7011

+
+
+
+
+ +
+ cosProperty 1.1.5 +
+ Improvements and New Features + + +

The documentation source has been converted from SGML to XML.

+

Own Id: OTP-6754 Aux Id:

+
+
+
+
+ +
+ cosProperty 1.1.4 +
+ Improvements and New Features + + +

Minor Makefile changes.

+

Own Id: OTP-6701 Aux Id:

+
+
+
+
+ +
+ cosProperty 1.1.3 + +
+ Fixed Bugs and Malfunctions + + +

The appup source file was missing a trailing newline.

+

Own id: OTP-6626

+
+
+
+
+ +
+ cosProperty 1.1.2 + +
+ Improvements and New Features + + +

Removed some unused code.

+

Own Id: OTP-6527 Aux Id:

+
+
+
+
+ +
+ cosProperty 1.1.1 + +
+ Fixed Bugs and Malfunctions + + +

The app-file contained duplicated modules.

+

Own id: OTP-4976

+
+
+
+
+ +
+ cosProperty 1.1 + +
+ Improvements and New Features + + +

The stub/skeleton-files generated by IC have been improved, + i.e., depending on the IDL-files, reduced the size of the + erl- and beam-files and decreased dependencies off Orber's + Interface Repository. It is necessary to re-compile all IDL-files + and use COS-applications, including Orber, compiled with + IC-4.2.

+

Own id: OTP-4576

+
+
+
+
+ +
+ cosProperty 1.0.1 + +
+ Improvements and New Features + + +

First release of the cosProperty application.

+

Own Id: -

+
+
+
+
+
+ diff --git a/lib/cosProperty/doc/src/part.xml b/lib/cosProperty/doc/src/part.xml new file mode 100644 index 0000000..210dad6 --- /dev/null +++ b/lib/cosProperty/doc/src/part.xml @@ -0,0 +1,39 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosProperty User's Guide + Niclas Eklund + + 2000-06-07 + 1.0 +
+ +

The cosProperty Application is an Erlang implementation of the OMG + CORBA Property Service.

+
+ + + + +
+ diff --git a/lib/cosProperty/doc/src/part_notes.xml b/lib/cosProperty/doc/src/part_notes.xml new file mode 100644 index 0000000..4e02ff4 --- /dev/null +++ b/lib/cosProperty/doc/src/part_notes.xml @@ -0,0 +1,36 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosProperty Release Notes + Niclas Eklund + + 2000-06-07 + 1.0 +
+ +

The cosProperty Application is an Erlang implementation of the OMG + CORBA Property Service.

+
+ +
+ diff --git a/lib/cosProperty/doc/src/ref_man.gif b/lib/cosProperty/doc/src/ref_man.gif new file mode 100644 index 0000000000000000000000000000000000000000..b13c4efd53ff30209e94a832b9b141aefa01373e GIT binary patch literal 1530 zcmdVZdppw$0KoB|UD(ZKjLpudxl|bD5*~BdW(#wPxjQR!4XwvDQJz|2?rd%yODG+} zTS?d`8$ziw@9efjcbb8~ZJV`F`NeQj-Rb#--RW#!YS zPs_{8OG`^1KYmEb&dp9*T_4@VeSFc{Z zeEIUlix(;Hhy1Lrh+M1f0n>TM(S67S0;;O2u%F4=$ii+~`^0Klrkw{chQc_%8TvSw4P*9Mc zpP!ePmz$fLlanJ52(q)YuU)&AnVEUz%9YEPFK1+AT)K4W;>C;U>FH@{X%{YBNKH*W zfBt+*N=kBaa#B)KVq#)KLPC6e{JC@Ics$E-3+>FMd= z;o5R+g5Q78Vv{ zGTGeR+|10()YOzjBAJ+&7#kZK85t3YL|t879UUD4fq=*3wY9ZzI2;y>)zZ?^)YQaa zFd7;fYHDh#s;Vj~D$2^rC=?2bL?RFfI2;ax!IYGg6crVrP$&cf0fWIH5J*8m0r;Os z`p^I03jpi@P=FC!+v{kk6S6LO_!Iu)95sCwBtcqW%*9y*G+T7kk6cw&i6X!~u9ub^ z(;p_fv9U$vWTl#^q0-1BITpV6n#M{a{we|K$qn8tF1dhi2#U)iChGwf%c>!EMdamI z$h@1HHE$AU0uQ06DJaKq=RDnzU^TZiOigaDbX?9sbbG2Mo zru2uhl#`IQgUVf0v!Xj-d%-$1xRm>;TQmHNwcAfcM=qjwu=nh zQh;0;RMT@!2!f)5xXw7CWD^X8atslf08f~GlvPC&!u3CIvJ6wy=4qhoBAlk74dDIc za5tv{OoL_(_?n6N^K=DFVPbx|J4#5`n`9n$heG9OfAim6K_sx=yuqZzUrzW~%(8B5(t!Xl{Hb0?L6-vF=+wDe8$ zTT`s`Dq0fpfEZM3+{q@m}*YWuf-$-b$k$LLWEZK;Ee|dK!!GAvHA;V z*1da#TyGWrnurc+>Z42^g}P$+dV8CLlZ-G3$5&lvmrHi*;me*Y^_v!=AL*c_d4sqi z`SWVr{)P|6KptK|>YQR5CUyjEppnvPJ-9YQBBMdn(+)quWG#%To7OvoyB^9=`#bkY st1M+qtZTt#!ZD6_9%~hW^bvUb7(Sl{bx5FV=!1r@;+Z6>KNX<-3tg&0LjV8( literal 0 HcmV?d00001 diff --git a/lib/cosProperty/doc/src/ref_man.xml b/lib/cosProperty/doc/src/ref_man.xml new file mode 100644 index 0000000..f69904e --- /dev/null +++ b/lib/cosProperty/doc/src/ref_man.xml @@ -0,0 +1,42 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosProperty Reference Manual + Niclas Eklund + + 2000-06-07 + 1.0 +
+ +

The cosProperty Application is an Erlang implementation of the OMG + CORBA Property Service.

+
+ + + + + + + +
+ diff --git a/lib/cosProperty/doc/src/summary.html.src b/lib/cosProperty/doc/src/summary.html.src new file mode 100644 index 0000000..87370c6 --- /dev/null +++ b/lib/cosProperty/doc/src/summary.html.src @@ -0,0 +1 @@ +Orber OMG Property Service. \ No newline at end of file diff --git a/lib/cosProperty/doc/src/user_guide.gif b/lib/cosProperty/doc/src/user_guide.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6275a803db46bc56df2b31240f80e68a4eb28b5 GIT binary patch literal 1581 zcmd6mi9gc|0Kk8njctY*W^QwCJ{HX#%4V)-y(i>aMOY|Iy@!%dZA6YGb49u7IpPyu zxpLn_avvd{2!$L^&hlRW#rysR-_Q5+`C8dn8X8V>k`j;wKQ1gR%+Jry&CSiu&d$utOixe0fB$}JYHD(Fa$;g)e0+Rt zY;1INbYx^?czAedXlQV7@ZGz20|Nv7{r!D?eZ9TCJRYy7r>DESyQ{0Kv$M0KqocjO zy{)aSwY9aSrKP#Kxv8nCv9YnCq2bM&H}&=Pb#-;MwY4=hHPzMCuV25es;a82tgNW0 zc=_^WSy|bO7cWXnOG`>hii?Yjii!#g3kwPg^7Hfa^73+Xb8~WXva_?Zva&KWGoL+s z_Vnq~jEs!*^z{(M&Qxg*t zV`JkpXU-TI85tTH>g((4>FMd}>gwp|kVqtLZEYmX?x|!eX(Kl9CtEE3!%>OGRc>9)Rn&SYM zj~Y~*8(l`PO4G;6R;FqaD@X#~VMifcR)pt=DvF{Q3(>@Ud>(7)(V4{v)PmxVK~kPo zjj~AEyr<1v8vx#~Tk98U5_J`0L}~fU>RjhaAKM=MUf{g5m?T z)+IHOf7l%`QALwKCeyDj6SLD45WBagBU?Fw4{df%%9E4Y2u)Wk*W$nyCUXV^5gf*w zJcTmdm_5ACzSYODr)n2;x_FnPc`B(M`LXIbz9g71J`3n))Gq$bQK+sRivkPkZkj>F zXejb80{#?f()6mQl&jOcTB0m7HQ)B0eJ!3!3LG1z5Dy4!8UDX&qmZHiEZH4hCN$qe z4*)g+{|y}64a+3k1Ar7VS%DkXnyczs>8pr>ch^qPgriJZarAD;X*)P0t_Uea!m)bj zekgBBW+6d2l7{g|`zZIq7r_Y&symb`GN>UKUQ)c!TxUa0r_Gumy9Jeti%E)uL##a# zMGizq*jB%VA7Ip@(A3hq9YH69qL7NjkWRA2q5;hU`xYmEN)bB>aqrz!?T?Ynv*X-7 zk5PfTmt$8kTF6UOKy_o?XHYzxtkg%ZbG*StHxDNDsyD5c2a>x5vWvVCApVgu@XNF$})`XD-pCH3`9zE-Lj6@!*TS9lwVaP}h|-H2`m~ItYQE$0z|a zt4=D`BBR~(5MZ;L{+LQk#4$5Kz`eloKZBK-7eFm?OlZCy;GH~%L;($J;|e#tww(~b et1Zl|+ha7@T8X2%4FJEoWS?mjDfbqXtih~yb literal 0 HcmV?d00001 diff --git a/lib/cosProperty/ebin/.gitignore b/lib/cosProperty/ebin/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosProperty/examples/.gitignore b/lib/cosProperty/examples/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosProperty/include/.gitignore b/lib/cosProperty/include/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosProperty/info b/lib/cosProperty/info new file mode 100644 index 0000000..67c56e9 --- /dev/null +++ b/lib/cosProperty/info @@ -0,0 +1,2 @@ +group: orb +short: Orber OMG Property Service diff --git a/lib/cosProperty/priv/.gitignore b/lib/cosProperty/priv/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosProperty/src/CosProperty.cfg b/lib/cosProperty/src/CosProperty.cfg new file mode 100644 index 0000000..f10bf84 --- /dev/null +++ b/lib/cosProperty/src/CosProperty.cfg @@ -0,0 +1,5 @@ +{this, "CosPropertyService::PropertySet"}. +{this, "CosPropertyService::PropertySetDef"}. +{this, "CosPropertyService::PropertySetDefFactory"}. +{this, "CosPropertyService::PropertySetFactory"}. + diff --git a/lib/cosProperty/src/CosProperty.idl b/lib/cosProperty/src/CosProperty.idl new file mode 100644 index 0000000..156fb37 --- /dev/null +++ b/lib/cosProperty/src/CosProperty.idl @@ -0,0 +1,192 @@ +#ifndef _COSPROPERTY_IDL +#define _COSPROPERTY_IDL + +#pragma prefix "omg.org" + +module CosPropertyService { + /*****************************************************/ + /* Data Types */ + /*****************************************************/ + typedef string PropertyName; + + struct Property { + PropertyName property_name; + any property_value; + }; + + enum PropertyModeType { + normal, read_only, fixed_normal, fixed_readonly, undefined }; + + struct PropertyDef { + PropertyName property_name; + any property_value; + PropertyModeType property_mode; + }; + + struct PropertyMode { + PropertyName property_name; + PropertyModeType property_mode; + }; + + typedef sequence PropertyNames; + typedef sequence Properties; + typedef sequence PropertyDefs; + typedef sequence PropertyModes; + typedef sequence PropertyTypes; + + interface PropertyNamesIterator; + interface PropertiesIterator; + interface PropertySetFactory; + interface PropertySetDef; + interface PropertySet; + + /*****************************************************/ + /* Exceptions */ + /*****************************************************/ + exception ConstraintNotSupported{}; + exception InvalidPropertyName {}; + exception ConflictingProperty {}; + exception PropertyNotFound {}; + exception UnsupportedTypeCode {}; + exception UnsupportedProperty {}; + exception UnsupportedMode {}; + exception FixedProperty {}; + exception ReadOnlyProperty {}; + + enum ExceptionReason { invalid_property_name, conflicting_property, + property_not_found, unsupported_type_code, + unsupported_property, unsupported_mode, + fixed_property, read_only_property }; + + struct PropertyException { + ExceptionReason reason; + PropertyName failing_property_name; + }; + + typedef sequence PropertyExceptions; + exception MultipleExceptions { PropertyExceptions exceptions; }; + + /*****************************************************/ + /* Interface Definitions */ + /*****************************************************/ + interface PropertySetFactory { + PropertySet create_propertyset(); + + PropertySet create_constrained_propertyset( in PropertyTypes allowed_property_types, + in Properties allowed_properties) + raises(ConstraintNotSupported); + + PropertySet create_initial_propertyset( in Properties initial_properties) + raises(MultipleExceptions); }; + + /*---------------------------------------------------*/ + interface PropertySetDefFactory { + PropertySetDef create_propertysetdef(); + + PropertySetDef create_constrained_propertysetdef( in PropertyTypes allowed_property_types, + in PropertyDefs allowed_property_defs) + raises(ConstraintNotSupported); + + PropertySetDef create_initial_propertysetdef( in PropertyDefs initial_property_defs) + raises(MultipleExceptions); + }; + + /*---------------------------------------------------*/ + interface PropertySet { + /* Support for defining and modifying properties */ + void define_property( in PropertyName property_name, in any property_value) + raises(InvalidPropertyName, ConflictingProperty, UnsupportedTypeCode, + UnsupportedProperty, ReadOnlyProperty); + + void define_properties( in Properties nproperties) + raises(MultipleExceptions); + + /* Support for Getting Properties and their Names */ + unsigned long get_number_of_properties(); + + void get_all_property_names( in unsigned long how_many, + out PropertyNames property_names, + out PropertyNamesIterator rest); + + any get_property_value( in PropertyName property_name) + raises(PropertyNotFound, InvalidPropertyName); + + boolean get_properties( in PropertyNames property_names, + out Properties nproperties); + + void get_all_properties( in unsigned long how_many, + out Properties nproperties, + out PropertiesIterator rest); + + /* Support for Deleting Properties */ + void delete_property( in PropertyName property_name) + raises(PropertyNotFound, InvalidPropertyName, FixedProperty); + + void delete_properties( in PropertyNames property_names) + raises(MultipleExceptions); + + boolean delete_all_properties(); + + /* Support for Existence Check */ + boolean is_property_defined( in PropertyName property_name) + raises(InvalidPropertyName); + }; + + /*---------------------------------------------------*/ + interface PropertySetDef:PropertySet { + /* Support for retrieval of PropertySet constraints*/ + void get_allowed_property_types( out PropertyTypes property_types); + + void get_allowed_properties( out PropertyDefs property_defs); + + /* Support for defining and modifying properties */ + void define_property_with_mode( in PropertyName property_name, + in any property_value, + in PropertyModeType property_mode) + raises(InvalidPropertyName, ConflictingProperty, UnsupportedTypeCode, + UnsupportedProperty, UnsupportedMode, ReadOnlyProperty); + + void define_properties_with_modes( in PropertyDefs property_defs) + raises(MultipleExceptions); + + /* Support for Getting and Setting Property Modes */ + PropertyModeType get_property_mode( in PropertyName property_name) + raises(PropertyNotFound, InvalidPropertyName); + + boolean get_property_modes( in PropertyNames property_names, + out PropertyModes property_modes); + + void set_property_mode( in PropertyName property_name, + in PropertyModeType property_mode) + raises(InvalidPropertyName, PropertyNotFound, UnsupportedMode); + + void set_property_modes( in PropertyModes property_modes) + raises(MultipleExceptions); + }; + + /*---------------------------------------------------*/ + interface PropertyNamesIterator{ + void reset(); + + boolean next_one( out PropertyName property_name); + + boolean next_n ( in unsigned long how_many, + out PropertyNames property_names); + + void destroy(); + }; + + /*---------------------------------------------------*/ + interface PropertiesIterator { + void reset(); + + boolean next_one( out Property aproperty); + + boolean next_n( in unsigned long how_many, + out Properties nproperties); + + void destroy(); + }; +}; + +#endif diff --git a/lib/cosProperty/src/CosPropertyService_PropertiesIterator_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertiesIterator_impl.erl new file mode 100644 index 0000000..a7769ce --- /dev/null +++ b/lib/cosProperty/src/CosPropertyService_PropertiesIterator_impl.erl @@ -0,0 +1,166 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosPropertyService_PropertiesIterator_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosPropertyService_PropertiesIterator_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). +-include("CosPropertyService.hrl"). +-include("cosProperty.hrl"). + + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +%% Mandatory server functions +-export([init/1, + terminate/2, + code_change/3]). + +-export([reset/1, + next_one/1, + next_n/2, + destroy/1]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([ + ]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {properties, counter=1, length}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +-define(CreateInitState(L), #state{properties = L, length = length(L)}). +-define(get_Properties(S), S#state.properties). +-define(get_Counter(S), S#state.counter). +-define(get_Length(S), S#state.length). + +-define(set_Properties(S, P), S#state{properties = P}). +-define(set_Counter(S, C), S#state{counter = C}). +-define(set_Length(S, L), S#state{length = L}). + +-define(increment_Counter(S), S#state{counter = S#state.counter+1}). +-define(decrement_Counter(S), S#state{counter = S#state.counter-1}). +-define(addto_Counter(S, N), S#state{counter = S#state.counter+N}). +-define(subfrom_Counter(S, N), S#state{counter = S#state.counter-N}). + + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Description: Initiates the server +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%%---------------------------------------------------------------------- +init(Properties) -> + {ok, ?CreateInitState(Properties)}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Description: Shutdown the server +%% Returns : any (ignored by gen_server) +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Description: Convert process state when code is changed +%% Returns : {ok, NewState} +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% Function : reset +%% Arguments : - +%% Description: +%% Returns : {ok, NewState} +%%---------------------------------------------------------------------- +reset(State) -> + {reply, ok, ?set_Counter(State, 1)}. + +%%---------------------------------------------------------------------- +%% Function : next_one +%% Arguments : - +%% Description: +%% Returns : {ok, {bool(), PropertyList}, NewState} +%%---------------------------------------------------------------------- +next_one(State) when ?get_Counter(State) > ?get_Length(State) -> + {reply, {false, + #'CosPropertyService_Property' + {property_name = "", + property_value = any:create(orber_tc:null(), null)}}, + State}; +next_one(State) -> + {reply, {true, lists:nth(?get_Counter(State), ?get_Properties(State))}, + ?set_Counter(State, 1+?get_Counter(State))}. + +%%---------------------------------------------------------------------- +%% Function : next_n +%% Arguments : N - how many properties we should return. +%% Description: +%% Returns : {ok, {bool(), PropertyList}, NewState} +%%---------------------------------------------------------------------- +next_n(State, N) -> + case lists:sublist(?get_Properties(State), + ?get_Counter(State), + N) of + Properties when N+?get_Counter(State) < ?get_Length(State) -> + {reply, {true, Properties}, ?set_Counter(State, N+?get_Counter(State))}; + Properties -> + {reply, {false, Properties}, ?set_Counter(State, ?get_Length(State))} + end. + +%%---------------------------------------------------------------------% +%% Function : destroy +%% Arguments : - +%% Description: Terminate the object +%% Returns : {ok, NewState} +%%---------------------------------------------------------------------- +destroy(State) -> + {stop, normal, ok, State}. + +%%====================================================================== +%% Internal functions +%%===================================================================== + +%%====================================================================== +%% END OF MODULE +%%====================================================================== + diff --git a/lib/cosProperty/src/CosPropertyService_PropertyNamesIterator_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertyNamesIterator_impl.erl new file mode 100644 index 0000000..fc5cddd --- /dev/null +++ b/lib/cosProperty/src/CosPropertyService_PropertyNamesIterator_impl.erl @@ -0,0 +1,158 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosPropertyService_PropertyNamesIterator_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosPropertyService_PropertyNamesIterator_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). +-include("CosPropertyService.hrl"). +-include("cosProperty.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +%% Mandatory server functions +-export([init/1, + terminate/2, + code_change/3]). + +-export([reset/1, + next_one/1, + next_n/2, + destroy/1]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([ + ]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {properties, counter=1, length}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +-define(CreateInitState(L), #state{properties = L, length = length(L)}). +-define(get_Properties(S), S#state.properties). +-define(get_Counter(S), S#state.counter). +-define(get_Length(S), S#state.length). + +-define(set_Properties(S, P), S#state{properties = P}). +-define(set_Counter(S, C), S#state{counter = C}). +-define(set_Length(S, L), S#state{length = L}). + +-define(increment_Counter(S), S#state{counter = S#state.counter+1}). +-define(decrement_Counter(S), S#state{counter = S#state.counter-1}). +-define(addto_Counter(S, N), S#state{counter = S#state.counter+N}). +-define(subfrom_Counter(S, N), S#state{counter = S#state.counter-N}). + + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Description: Initiates the server +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%%---------------------------------------------------------------------- +init(Properties) -> + {ok, ?CreateInitState(Properties)}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Description: Shutdown the server +%% Returns : any (ignored by gen_server) +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Description: Convert process state when code is changed +%% Returns : {ok, NewState} +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% Function : reset +%% Arguments : - +%% Description: +%% Returns : {ok, NewState} +%%---------------------------------------------------------------------- +reset(State) -> + {reply, ok, ?set_Counter(State, 1)}. + +%%---------------------------------------------------------------------% +%% Function : next_one +%% Arguments : - +%% Description: +%% Returns : {ok, {bool(), PropertyName}, NewState} +%%---------------------------------------------------------------------- +next_one(State) when ?get_Counter(State) > ?get_Length(State) -> + {reply, {false, ""}, State}; +next_one(State) -> + {reply, {true, lists:nth(?get_Counter(State), ?get_Properties(State))}, + ?set_Counter(State, 1+?get_Counter(State))}. + +%%---------------------------------------------------------------------% +%% Function : next_n +%% Arguments : N - how many properties we should return. +%% Description: +%% Returns : {ok, {bool(), PropertyNameList}, NewState} +%%---------------------------------------------------------------------- +next_n(State, N) -> + case lists:sublist(?get_Properties(State), ?get_Counter(State), N) of + Properties when N+?get_Counter(State) < ?get_Length(State) -> + {reply, {true, Properties}, ?set_Counter(State, N+?get_Counter(State))}; + Properties -> + {reply, {false, Properties}, ?set_Counter(State, ?get_Length(State))} + end. + +%%---------------------------------------------------------------------% +%% Function : destroy +%% Arguments : - +%% Description: Terminate the object +%% Returns : {ok, NewState} +%%---------------------------------------------------------------------- +destroy(State) -> + {stop, normal, ok, State}. + +%%====================================================================== +%% Internal functions +%%====================================================================== + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl new file mode 100644 index 0000000..b099026 --- /dev/null +++ b/lib/cosProperty/src/CosPropertyService_PropertySetDefFactory_impl.erl @@ -0,0 +1,179 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosPropertyService_PropertySetDefFactory_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosPropertyService_PropertySetDefFactory_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). +-include("CosPropertyService.hrl"). +-include("cosProperty.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3]). + +-export([create_propertysetdef/2, + create_constrained_propertysetdef/4, + create_initial_propertysetdef/3]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +-define(checkTCfun, fun(TC) -> orber_tc:check_tc(TC) end). + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([]) -> + {ok, #state{}}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% Function : create_propertysetdef +%% Arguments : +%% Returns : CosPropertyService::PropertySetDef reference. +%% Description: +%%---------------------------------------------------------------------- +create_propertysetdef(_OE_This, State) -> + {reply, + 'CosPropertyService_PropertySetDef': + oe_create({normal, [], [], [], ?PropertySetDef}, [{pseudo, true}]), + State}. + +%%---------------------------------------------------------------------% +%% Function : create_constrained_propertysetdef +%% Arguments : PropTypes - list of property types. +%% PropDefs - list of property defs. +%% Returns : CosPropertyService::PropertySetDef | +%% {'EXCEPTION', CosPropertyService::ConstraintNotSupported} +%% Description: +%%---------------------------------------------------------------------- +create_constrained_propertysetdef(_OE_This, State, PropTypes, PropDefs) -> + case lists:all(?checkTCfun, PropTypes) of + true -> + crosscheckTC(PropDefs, PropTypes), + {reply, + 'CosPropertyService_PropertySetDef': + oe_create({normal, PropTypes, PropDefs, [], ?PropertySetDef}, [{pseudo, true}]), + State}; + false -> + corba:raise(#'CosPropertyService_ConstraintNotSupported'{}) + end. + +crosscheckTC([], _) -> + ok; +crosscheckTC([#'CosPropertyService_PropertyDef' + {property_name = Name, + property_value = Value, + property_mode = _Mode}|T], TCs) -> + case lists:member(any:get_typecode(Value), TCs) of + true when Name =/= "" -> + crosscheckTC(T, TCs); + _ -> + corba:raise(#'CosPropertyService_ConstraintNotSupported'{}) + end. + +%%---------------------------------------------------------------------% +%% Function : create_initial_propertysetdef +%% Arguments : +%% Returns : CosPropertyService::PropertySetDef | +%% {'EXCEPTION', CosPropertyService::MultipleExceptions} +%% Description: +%%---------------------------------------------------------------------- +create_initial_propertysetdef(_OE_This, State, PropDefs) -> + InitProps = evaluate_propertysetdef(PropDefs), + {reply, + 'CosPropertyService_PropertySetDef': + oe_create({normal, [], [], InitProps, ?PropertySetDef}, [{pseudo, true}]), + State}. + +%%====================================================================== +%% Internal functions +%%====================================================================== +evaluate_propertysetdef(SetDefs) -> + evaluate_propertysetdef(SetDefs, [], []). +evaluate_propertysetdef([], NewProperties, []) -> + %% No exceptions found. + NewProperties; +evaluate_propertysetdef([], _, Exc) -> + corba:raise(#'CosPropertyService_MultipleExceptions'{exceptions = Exc}); +evaluate_propertysetdef([#'CosPropertyService_PropertyDef' + {property_name = Name, + property_value = Value, + property_mode = Mode}|T], X, Exc) -> + case orber_tc:check_tc(any:get_typecode(Value)) of + true -> + evaluate_propertysetdef(T, [{Name, Value, Mode}|X], Exc); + false -> + evaluate_propertysetdef(T, X, [#'CosPropertyService_PropertyException' + {reason = unsupported_type_code, + failing_property_name = Name}|Exc]) + end. + + + +%%====================================================================== +%% END OF MODULE +%%====================================================================== + diff --git a/lib/cosProperty/src/CosPropertyService_PropertySetDef_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertySetDef_impl.erl new file mode 100644 index 0000000..157b243 --- /dev/null +++ b/lib/cosProperty/src/CosPropertyService_PropertySetDef_impl.erl @@ -0,0 +1,1041 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: CosPropertyService_PropertySetDef_impl.erl +%% Modified: +%% +%%----------------------------------------------------------------- +%% README: +%% (1) The OMG specification states that a property name may not +%% be an empty string (""). We may restrict this further +%% but there is no reason for that. +%%----------------------------------------------------------------- +-module('CosPropertyService_PropertySetDef_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). +-include_lib("cosProperty/include/CosPropertyService.hrl"). +-include("cosProperty.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +%% Mandatory callbacks +-export([init/1, + terminate/2, + code_change/3]). + +%% Inherrit from CosPropertyService::PropertySet +-export([define_property/4, + define_properties/3, + get_number_of_properties/2, + get_all_property_names/3, + get_property_value/3, + get_properties/3, + get_all_properties/3, + delete_property/3, + delete_properties/3, + delete_all_properties/2, + is_property_defined/3]). + +%% CosPropertyService::PropertySetDef +-export([get_allowed_property_types/2, + get_allowed_properties/2, + define_property_with_mode/5, + define_properties_with_modes/3, + get_property_mode/3, + get_property_modes/3, + set_property_mode/4, + set_property_modes/3]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([dump/0]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {dbKey, defaultMode, okTypes, okProperties, myType}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +-define(create_InitState(K, D, AT, AP, MT), #state{dbKey = K, defaultMode = D, + okTypes = AT, okProperties = AP, + myType = MT}). +%% Selectors +-define(get_DBKey(S), S#state.dbKey). +-define(get_DefaultMode(S), S#state.defaultMode). +-define(get_okTypes(S), S#state.okTypes). +-define(get_okProperties(S), S#state.okProperties). +%% MISC +-define(is_NotSetDef(S), S#state.myType =/= ?PropertySetDef). +-define(no_PropertyLimits(S), S#state.okProperties == []). +-define(no_TypeLimits(S), S#state.okTypes == []). +-define(is_NotStatic(S), is_binary(S#state.dbKey)). + +%% Fun:s +-define(Local2Property, fun({N,V,_M}) -> + #'CosPropertyService_Property'{property_name = N, + property_value = V} + end). +-define(Local2Names, fun({N,_V,_M}) -> + N + end). +-define(MemberName(N), fun(R) -> + case R of + Property when is_record(R, 'CosPropertyService_Property') -> + Property#'CosPropertyService_Property'.property_name == N; + PropertyDef when is_record(R, 'CosPropertyService_PropertyDef') -> + PropertyDef#'CosPropertyService_PropertyDef'.property_name == N; + _-> + false + end + end). + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Description: Initiates the server +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%%---------------------------------------------------------------------- +init({DefMode, AllowedTypes, AllowedProperties, InitProperties, MyType}) -> + Key = term_to_binary({now(), node()}), + _F = ?write_function(#oe_CosPropertyService{key=Key, + properties=InitProperties}), + write_result(mnesia:transaction(_F)), + {ok, ?create_InitState(Key, DefMode, AllowedTypes, AllowedProperties, MyType)}; +init({static, DefMode, AllowedTypes, AllowedProperties, InitProperties, MyType}) -> + {ok, ?create_InitState(InitProperties, DefMode, AllowedTypes, + AllowedProperties, MyType)}. + +%%---------------------------------------------------------------------% +%% Function : terminate +%% Description: Shutdown the server +%% Returns : any (ignored by gen_server) +%%---------------------------------------------------------------------- +terminate(_Reason, State) when ?is_NotStatic(State) -> + _DF = ?delete_function({oe_CosPropertyService, ?get_DBKey(State)}), + catch write_result(mnesia:transaction(_DF)), + ok; +terminate(_Reason, _State) -> + ok. + +%%---------------------------------------------------------------------% +%% Function : code_change +%% Description: Convert process state when code is changed +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +%%---------------------------------------------------------------------- +%% Interface CosPropertyService::PropertySet +%%---------------------------------------------------------------------- +%%---------------------------------------------------------------------% +%% Function : define_property +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +define_property(_, _, "", _) -> + corba:raise(#'CosPropertyService_InvalidPropertyName'{}); +define_property(_OE_This, State, Name, Value) when ?is_NotStatic(State) -> + evaluate_property_data(State, Value, Name), + _DF = + fun() -> + case mnesia_read(State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + X -> + case catch update_property(X, Name, value, Value, + ?get_DefaultMode(State)) of + {'EXCEPTION', E} when + is_record(E, 'CosPropertyService_PropertyNotFound') -> + mnesia_write(State, [{Name, Value, ?get_DefaultMode(State)}|X]); + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + NewProperties -> + mnesia_write(State, NewProperties) + end + end + end, + {reply, mnesia_transaction(_DF), State}; +define_property(_OE_This, State, Name, Value) -> + evaluate_property_data(State, Value, Name), + X = ?get_DBKey(State), + case catch update_property(X, Name, value, Value, ?get_DefaultMode(State)) of + {'EXCEPTION', E} when is_record(E, 'CosPropertyService_PropertyNotFound') -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}); + {'EXCEPTION', E} -> + corba:raise(E); + _NewProperties -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + + +%%---------------------------------------------------------------------% +%% Function : get_property_value +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +get_property_value(_, _, "") -> + corba:raise(#'CosPropertyService_InvalidPropertyName'{}); +get_property_value(_OE_THIS, State, Name) -> + X = lookup_table(?get_DBKey(State)), + {reply, find_property(X, Name, value), State}. + +%%---------------------------------------------------------------------% +%% Function : delete_property +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +delete_property(_, _, "") -> + corba:raise(#'CosPropertyService_InvalidPropertyName'{}); +delete_property(_OE_THIS, State, Name) when ?is_NotStatic(State) -> + _DF = + fun() -> + case mnesia_read(State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + X -> + case catch remove_property(X, Name) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + NewProperties -> + mnesia_write(State, NewProperties) + end + end + end, + {reply, mnesia_transaction(_DF), State}; +delete_property(_OE_THIS, State, Name) -> + X = lookup_table(?get_DBKey(State)), + %% Check the properties; must raise an exception. + remove_property(X, Name), + %% Something is not correct. + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + + +%%---------------------------------------------------------------------% +%% Function : define_properties +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +define_properties(_OE_THIS, State, PropertySeq) when ?is_NotStatic(State) -> + {OKProperties, Exc} = evaluate_properties_data(State, PropertySeq), + _DF = + fun() -> + case mnesia_read(State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + X -> + case catch define_properties_helper(State, + OKProperties, X, Exc) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + NewProperties -> + mnesia_write(State, NewProperties) + end + end + end, + {reply, mnesia_transaction(_DF), State}; +define_properties(_OE_THIS, State, PropertySeq) -> + {OKProperties, Exc} = evaluate_properties_data(State, PropertySeq), + X = lookup_table(?get_DBKey(State)), + case define_properties_helper(State, OKProperties, X, Exc) of + {'EXCEPTION', E} -> + corba:raise(E); + _ -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +define_properties_helper(_State, [], NewProperties, []) -> + %% No exceptions, insert the properties. + NewProperties; +define_properties_helper(_State, [], _, MultipleExceptions) -> + {'EXCEPTION', #'CosPropertyService_MultipleExceptions'{exceptions = MultipleExceptions}}; +define_properties_helper(State, [#'CosPropertyService_Property' + {property_name = Name, + property_value = Value}|T], Properties, Exc) -> + case catch update_property(Properties, Name, value, Value, ?get_DefaultMode(State)) of + {'EXCEPTION', E} when is_record(E, 'CosPropertyService_PropertyNotFound') -> + define_properties_helper(State, T, [{Name, Value, ?get_DefaultMode(State)}|Properties], Exc); + {'EXCEPTION', E} -> + define_properties_helper(State, T, Properties, + [#'CosPropertyService_PropertyException' + {reason = remap_exception(E), + failing_property_name = Name}|Exc]); + NewProperties -> + define_properties_helper(State, T, NewProperties, Exc) + end. + +%%---------------------------------------------------------------------% +%% Function : get_number_of_properties +%% Arguments : - +%% Description: Returns the number of properties currently associated +%% with this object. +%% Returns : {ok, ulong(), State} +%%---------------------------------------------------------------------- +get_number_of_properties(_OE_THIS, State) -> + X = lookup_table(?get_DBKey(State)), + {reply, length(X), State}. + +%%---------------------------------------------------------------------% +%% Function : get_all_property_names +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +get_all_property_names(_OE_THIS, State, Max) -> + X = lookup_table(?get_DBKey(State)), + {reply, get_all_property_names_helper(X, [], Max), State}. + +get_all_property_names_helper([], Acc, _) -> + %% There are no more properties; return a nil-object refernce. + {ok, Acc, corba:create_nil_objref()}; +get_all_property_names_helper(Left, Acc, 0) -> + %% There are more properties; create Name Iterartor. + PropertyNames = lists:map(?Local2Names, Left), + {ok, Acc, cosProperty:start_PropertyNamesIterator(PropertyNames)}; +get_all_property_names_helper([{Name, _, _}|T], Acc, No) -> + get_all_property_names_helper(T, [Name|Acc], No-1). + + +%%---------------------------------------------------------------------% +%% Function : get_properties +%% Arguments : A list of property names, i.e., string() +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +get_properties(_OE_THIS, State, PropertyNames) -> + X = lookup_table(?get_DBKey(State)), + {reply, locate_names(PropertyNames, X, true, []), State}. + +locate_names([], _, AllOK, Acc) -> + {AllOK, Acc}; +locate_names([""|T], X, _AllOK, Acc) -> + locate_names(T, X, false, [#'CosPropertyService_Property' + {property_name = "", + property_value = + any:create(tk_void, ok)}|Acc]); +locate_names([H|T], X, AllOK, Acc) -> + case catch find_property(X, H, value) of + {'EXCEPTION', _} -> + locate_names(T, X, false, [#'CosPropertyService_Property' + {property_name = H, + property_value = + any:create(tk_void, ok)}|Acc]); + Val -> + locate_names(T, X, AllOK, [#'CosPropertyService_Property' + {property_name = H, + property_value = Val}|Acc]) + end. + +%%---------------------------------------------------------------------% +%% Function : get_all_properties +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +get_all_properties(_OE_THIS, State, Max) -> + X = lookup_table(?get_DBKey(State)), + {reply, get_all_properties_helper(X, [], Max), State}. + +get_all_properties_helper([], Acc, _) -> +%% There are no more properties; return a nil-object refernce. + {ok, Acc, corba:create_nil_objref()}; +get_all_properties_helper(Left, Acc, 0) -> + %% There are more properties; create Iterartor. + Properties = lists:map(?Local2Property, Left), + {ok, Acc, cosProperty:start_PropertiesIterator(Properties)}; +get_all_properties_helper([{Name, Val, _}|T], Acc, No) -> + get_all_properties_helper(T, [#'CosPropertyService_Property' + {property_name = Name, + property_value = Val}|Acc], No-1). + +%%---------------------------------------------------------------------% +%% Function : delete_properties +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +delete_properties(_OE_THIS, State, []) -> + {reply, ok, State}; +delete_properties(_OE_THIS, State, PropertyNames) when ?is_NotStatic(State) -> + _DF = + fun() -> + case mnesia_read(State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + X -> + case catch delete_properties_helper(X, [], [], + PropertyNames, State, + length(X)) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + {{'EXCEPTION', E}, NotDeleted} -> + ok = mnesia_write(State, NotDeleted), + {'EXCEPTION', E}; + {ok, NotDeleted} -> + mnesia_write(State, NotDeleted) + end + end + end, + {reply, mnesia_transaction(_DF), State}; +delete_properties(_OE_THIS, State, PropertyNames) -> + X = lookup_table(?get_DBKey(State)), + case delete_properties_helper(X, [], [], PropertyNames, State, length(X)) of + {'EXCEPTION', E} -> + corba:raise(E); + _-> + %% Not acceptable if it was possible to delete one or more Properties. + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +delete_properties_helper([], [], NotDeleted, [], _State, _Len) -> + %% Since there are no exceptions we have been able to delete all + %% properties. + {ok, NotDeleted}; +delete_properties_helper([], MultipleExc, NotDeleted, Names, _State, Len) -> + %% Write remaining events to DB. + case length(NotDeleted) of + Len -> + {'EXCEPTION', #'CosPropertyService_MultipleExceptions' + {exceptions = add_not_found(Names, MultipleExc)}}; + _-> + {{'EXCEPTION', #'CosPropertyService_MultipleExceptions' + {exceptions = add_not_found(Names, MultipleExc)}}, + NotDeleted} + end; +delete_properties_helper([{Name, Val, Mode}|T], MultipleExc, NotDeleted, + Names, State, Len) -> + case lists:member(Name, Names) of + true when Mode =/= fixed_normal, Mode =/= fixed_readonly -> + delete_properties_helper(T, MultipleExc, NotDeleted, + lists:delete(Name, Names), State, Len); + true -> + delete_properties_helper(T, [#'CosPropertyService_PropertyException' + {reason = fixed_property, + failing_property_name = Name}|MultipleExc], + [{Name, Val, Mode}|NotDeleted], + lists:delete(Name, Names), State, Len); + false -> + delete_properties_helper(T, MultipleExc, [{Name, Val, Mode}|NotDeleted], + Names, State, Len) + end. + +add_not_found([], MultipleExc) -> + MultipleExc; +add_not_found([Name|T], MultipleExc) -> + add_not_found(T, [#'CosPropertyService_PropertyException' + {reason = property_not_found, + failing_property_name = Name}|MultipleExc]). + + + +%%---------------------------------------------------------------------% +%% Function : delete_all_properties +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +delete_all_properties(_OE_THIS, State) when ?is_NotStatic(State) -> + _DF = + fun() -> + case mnesia_read(State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + X -> + case catch delete_all_properties_helper(X, [], State, + length(X)) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + true -> + ok = mnesia_write(State, []), + true; + false -> + false; + {false, NotDeleted} -> + ok = mnesia_write(State, NotDeleted), + false + end + end + end, + {reply, mnesia_transaction(_DF), State}; +delete_all_properties(_OE_THIS, State) -> + X = lookup_table(?get_DBKey(State)), + case delete_all_properties_helper(X, [], State, length(X)) of + false -> + {reply, false, State}; + _-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +delete_all_properties_helper([], [], _State, _) -> + %% Was able to delete all properties. + true; +delete_all_properties_helper([], NotDeleted, _State, Len) -> + %% Write remaining events to DB. + case length(NotDeleted) of + Len -> + false; + _-> + {false, NotDeleted} + end; +delete_all_properties_helper([{Name, Val, fixed_normal}|T], NotDeleted, State, Len) -> + delete_all_properties_helper(T, [{Name, Val, fixed_normal}|NotDeleted], State, Len); +delete_all_properties_helper([{Name, Val, fixed_readonly}|T], NotDeleted, State, Len) -> + delete_all_properties_helper(T, [{Name, Val, fixed_readonly}|NotDeleted], State, Len); +delete_all_properties_helper([_|T], NotDeleted, State, Len) -> + delete_all_properties_helper(T, NotDeleted, State, Len). + +%%---------------------------------------------------------------------% +%% Function : is_property_defined +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +is_property_defined(_, _, "") -> + corba:raise(#'CosPropertyService_InvalidPropertyName'{}); +is_property_defined(_OE_THIS, State, Name) -> + X = lookup_table(?get_DBKey(State)), + {reply, lists:keymember(Name, 1, X), State}. + +%%---------------------------------------------------------------------- +%% Interface CosPropertyService::PropertySetDef +%%---------------------------------------------------------------------- +%%---------------------------------------------------------------------% +%% Function : get_allowed_property_types +%% Arguments : - +%% Description: Returns the initially supplied restrictions. An empty +%% list means no restrictions. +%% Returns : {ok, TypeCodeList,State} +%%---------------------------------------------------------------------- +get_allowed_property_types(_OE_THIS, State) when ?is_NotSetDef(State) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}); +get_allowed_property_types(_OE_THIS, State) -> + {reply, {ok, ?get_okTypes(State)}, State}. + +%%---------------------------------------------------------------------% +%% Function : get_allowed_properties +%% Arguments : +%% Description: Returns the initially supplied restrictions. An empty +%% list means no restrictions. +%% Returns : {ok, PropertyDefList, State} +%%---------------------------------------------------------------------- +get_allowed_properties(_OE_THIS, State) when ?is_NotSetDef(State) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}); +get_allowed_properties(_OE_THIS, State) -> + {reply, {ok, ?get_okProperties(State)}, State}. + +%%---------------------------------------------------------------------% +%% Function : define_property_with_mode +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +define_property_with_mode(_OE_THIS, State, _, _, _) when ?is_NotSetDef(State) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}); +define_property_with_mode(_, _, "", _, _) -> + corba:raise(#'CosPropertyService_InvalidPropertyName'{}); +define_property_with_mode(_OE_THIS, State, Name, Value, Mode) + when ?is_NotStatic(State) -> + evaluate_property_data(State, Value, Name), + _DF = + fun() -> + case mnesia_read(State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + X -> + case catch update_property(X, Name, both, Value, Mode) of + {'EXCEPTION', E} + when is_record(E, 'CosPropertyService_PropertyNotFound') -> + mnesia_write(State, [{Name, Value, Mode}|X]); + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + NewProperties -> + mnesia_write(State, NewProperties) + end + end + end, + {reply, mnesia_transaction(_DF), State}; +define_property_with_mode(_OE_THIS, State, Name, Value, Mode) -> + evaluate_property_data(State, Value, Name), + X = lookup_table(?get_DBKey(State)), + case catch update_property(X, Name, both, Value, Mode) of + {'EXCEPTION', E} when is_record(E, 'CosPropertyService_PropertyNotFound') -> + %% Should get not allowed exception. + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}); + {'EXCEPTION', E} -> + corba:raise(E); + _ -> + %% Should be impossible. + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------% +%% Function : define_properties_with_modes +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +define_properties_with_modes(_OE_THIS, State, _) when ?is_NotSetDef(State) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}); +define_properties_with_modes(_OE_THIS, State, PropertyDefSeq) + when ?is_NotStatic(State)-> + {OKProperteDefs, Exc} = evaluate_properties_data(State, PropertyDefSeq), + _DF = + fun() -> + case mnesia_read(State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + X -> + case catch define_properties_with_modes_helper(OKProperteDefs, + X, Exc, State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + NewProperties -> + mnesia_write(State, NewProperties) + end + end + end, + {reply, mnesia_transaction(_DF), State}; +define_properties_with_modes(_OE_THIS, State, PropertyDefSeq) -> + {OKProperteDefs, Exc} = evaluate_properties_data(State, PropertyDefSeq), + X = lookup_table(?get_DBKey(State)), + case define_properties_with_modes_helper(OKProperteDefs, X, Exc, State) of + {'EXCEPTION', E} -> + corba:raise(E); + _ -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + + +define_properties_with_modes_helper([], NewPropertyDefs, [], _State) -> + %% No exceptions found. + NewPropertyDefs; +define_properties_with_modes_helper([], _, Exc, _) -> + {'EXCEPTION', #'CosPropertyService_MultipleExceptions'{exceptions = Exc}}; +define_properties_with_modes_helper([#'CosPropertyService_PropertyDef' + {property_name = Name, + property_value = Value, + property_mode = Mode}|T], X, Exc, State) -> + case catch update_property(X, Name, both, Value, Mode) of + {'EXCEPTION', E} when is_record(E, 'CosPropertyService_PropertyNotFound') -> + define_properties_with_modes_helper(T, [{Name, Value, Mode}|X], Exc, State); + {'EXCEPTION', E} -> + define_properties_with_modes_helper(T, X, + [#'CosPropertyService_PropertyException' + {reason = remap_exception(E), + failing_property_name = Name}|Exc], + State); + NewX -> + define_properties_with_modes_helper(T, NewX, Exc, State) + end. + +%%---------------------------------------------------------------------% +%% Function : get_property_mode +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +get_property_mode(_OE_THIS, State, _) when ?is_NotSetDef(State) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}); +get_property_mode(_, _, "") -> + corba:raise(#'CosPropertyService_InvalidPropertyName'{}); +get_property_mode(_OE_THIS, State, Name) -> + X = lookup_table(?get_DBKey(State)), + {reply, find_property(X, Name, mode), State}. + +%%---------------------------------------------------------------------% +%% Function : get_property_modes +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +get_property_modes(_OE_THIS, State, _) when ?is_NotSetDef(State) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}); +get_property_modes(_OE_THIS, State, PropertyNames) -> + X = lookup_table(?get_DBKey(State)), + {reply, get_property_modes_helper(PropertyNames, X, [], true), State}. + +get_property_modes_helper([], _, Acc, Bool) -> + {Bool, Acc}; +get_property_modes_helper([""|T], Properties, Acc, _) -> + get_property_modes_helper(T, Properties, + [#'CosPropertyService_PropertyMode' + {property_name = "", + property_mode = undefined}|Acc], false); +get_property_modes_helper([Name|T], Properties, Acc, Bool) -> + case lists:keysearch(Name, 1, Properties) of + {value, {Name, _, Mode}} -> + get_property_modes_helper(T, Properties, + [#'CosPropertyService_PropertyMode' + {property_name = Name, + property_mode = Mode}|Acc], Bool); + false -> + get_property_modes_helper(T, Properties, + [#'CosPropertyService_PropertyMode' + {property_name = Name, + property_mode = undefined}|Acc], false) + end. + +%%---------------------------------------------------------------------% +%% Function : set_property_mode +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +set_property_mode(_OE_THIS, State, _, _) when ?is_NotSetDef(State) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}); +set_property_mode(_, _, "", _) -> + corba:raise(#'CosPropertyService_InvalidPropertyName'{}); +set_property_mode(_OE_THIS, State, Name, Mode) when ?is_NotStatic(State) -> + _DF = + fun() -> + case mnesia_read(State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + X -> + case catch update_property(X, Name, mode, undefined, Mode) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + NewProperties -> + mnesia_write(State, NewProperties) + end + end + end, + {reply, mnesia_transaction(_DF), State}; +set_property_mode(_OE_THIS, State, Name, Mode) -> + X = lookup_table(?get_DBKey(State)), + update_property(X, Name, mode, undefined, Mode), + %% Something is not correct, shouldn't be allowed to update a property when + %% static. + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +%%---------------------------------------------------------------------% +%% Function : set_property_modes +%% Arguments : +%% Description: +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +set_property_modes(_OE_THIS, State, _) when ?is_NotSetDef(State) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_NO}); +set_property_modes(_OE_THIS, State, PropertyModes) when ?is_NotStatic(State) -> + _DF = + fun() -> + case mnesia_read(State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + X -> + case catch set_property_modes_helper(PropertyModes, X, [], + State) of + {'EXCEPTION', E} -> + {'EXCEPTION', E}; + NewProperties -> + mnesia_write(State, NewProperties) + end + end + end, + {reply, mnesia_transaction(_DF), State}; +set_property_modes(_OE_THIS, State, PropertyModes) -> + X = lookup_table(?get_DBKey(State)), + case set_property_modes_helper(PropertyModes, X, [], State) of + {'EXCEPTION', E} -> + corba:raise(E); + _ -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +set_property_modes_helper([], NewProperties, [], _State) -> + %% No exceptions, write to DB. + NewProperties; +set_property_modes_helper([], _, Exc, _) -> + {'EXCEPTION', #'CosPropertyService_MultipleExceptions'{exceptions = Exc}}; +set_property_modes_helper([#'CosPropertyService_PropertyMode' + {property_name = Name, + property_mode = Mode}|T], X, Exc, State) -> + case catch update_property(X, Name, mode, undefined, Mode) of + {'EXCEPTION', E} -> + set_property_modes_helper(T, X, + [#'CosPropertyService_PropertyException' + {reason = remap_exception(E), + failing_property_name = Name}|Exc], + State); + NewX -> + set_property_modes_helper(T, NewX, Exc, State) + end. + + +%%====================================================================== +%% Internal functions +%%====================================================================== + +remap_exception(#'CosPropertyService_ConflictingProperty'{}) -> conflicting_property; +remap_exception(#'CosPropertyService_FixedProperty'{}) -> fixed_property; +remap_exception(#'CosPropertyService_InvalidPropertyName'{}) -> invalid_property_name; +remap_exception(#'CosPropertyService_PropertyNotFound'{}) -> property_not_found; +remap_exception(#'CosPropertyService_UnsupportedTypeCode'{}) -> unsupported_type_code; +remap_exception(#'CosPropertyService_UnsupportedProperty'{}) -> unsupported_property; +remap_exception(#'CosPropertyService_ReadOnlyProperty'{}) -> read_only_property; +remap_exception(#'CosPropertyService_UnsupportedMode'{}) -> unsupported_mode. + +find_property([], _, _) -> + corba:raise(#'CosPropertyService_PropertyNotFound'{}); +find_property([{Name, Value, _}|_], Name, value) -> + Value; +find_property([{Name, _, Mode}|_], Name, mode) -> + Mode; +% Left out for now to avoid dialyzer warning. +%find_property([{Name, Value, Mode}|_], Name, all) -> +% {Name, Value, Mode}; +find_property([_|T], Name, Which) -> + find_property(T, Name, Which). + +remove_property(PropertList, Name) -> + remove_property(PropertList, Name, []). +remove_property([], _, _) -> + corba:raise(#'CosPropertyService_PropertyNotFound'{}); +remove_property([{Name, _, fixed_normal}|_T], Name, _) -> + corba:raise(#'CosPropertyService_FixedProperty'{}); +remove_property([{Name, _, fixed_readonly}|_T], Name, _) -> + corba:raise(#'CosPropertyService_FixedProperty'{}); +remove_property([{Name, _, _}|T], Name, Acc) -> + T++Acc; +remove_property([H|T], Name, Acc) -> + remove_property(T, Name, [H|Acc]). + + +update_property(_, "", _, _, _) -> + corba:raise(#'CosPropertyService_InvalidPropertyName'{}); +update_property(PropertyList, Name, Which, Value, Mode) -> + update_property(PropertyList, Name, Which, Value, Mode, []). + +update_property([], _, _, _, _, _) -> + corba:raise(#'CosPropertyService_PropertyNotFound'{}); +update_property([{Name, _, fixed_readonly}|_], Name, value, _, _, _) -> + corba:raise(#'CosPropertyService_FixedProperty'{}); +update_property([{Name, _, fixed_normal}|_], Name, both, _, _, _) -> + corba:raise(#'CosPropertyService_FixedProperty'{}); +update_property([{Name, _, fixed_readonly}|_], Name, both, _, _, _) -> + corba:raise(#'CosPropertyService_FixedProperty'{}); +update_property([{Name, #any{typecode = TC}, Mode}|T], Name, + value, #any{typecode = TC, value = Value}, _Mod, Acc) -> + [{Name, #any{typecode = TC, value = Value}, Mode}|T]++Acc; +update_property([{Name, #any{typecode = TC}, _Mode}|T], Name, + both, #any{typecode = TC, value = Value}, Mod, Acc) -> + [{Name, #any{typecode = TC, value = Value}, Mod}|T]++Acc; +update_property([{Name, _, _}|_], Name, value, _, _, _) -> + corba:raise(#'CosPropertyService_ConflictingProperty'{}); +update_property([{Name, _, _}|_], Name, both, _, _, _) -> + corba:raise(#'CosPropertyService_ConflictingProperty'{}); +%% Normally we don't need to raise an exception for the two following cases but +%% to be able to manage static Properties we must raise an exception. Well, +%% on the other hand, why should a user try to change a mode to the same value?! +%% But we have no other option. +update_property([{Name, _Value, fixed_normal}|_T], Name, mode, _, fixed_normal, _Acc) -> + corba:raise(#'CosPropertyService_FixedProperty'{}); +update_property([{Name, _Value, fixed_readonly}|_T], Name, mode, _, fixed_readonly, _Acc) -> + corba:raise(#'CosPropertyService_FixedProperty'{}); +update_property([{Name, _Value, fixed_normal}|_T], Name, mode, _, _Mode, _Acc) -> + corba:raise(#'CosPropertyService_UnsupportedMode'{}); +update_property([{Name, _Value, fixed_readonly}|_T], Name, mode, _, _Mode, _Acc) -> + corba:raise(#'CosPropertyService_UnsupportedMode'{}); +update_property([{Name, Value, _}|T], Name, mode, _, Mode, Acc) -> + [{Name, Value, Mode}|T]++Acc; +update_property([H|T], Name, Which, Value, Mode, Acc) -> + update_property(T, Name, Which, Value, Mode, [H|Acc]). + + +lookup_table(Key) when is_binary(Key) -> + _RF = ?read_function({oe_CosPropertyService, Key}), + case mnesia:transaction(_RF) of + {atomic, [#oe_CosPropertyService{properties=Properties}]} -> + Properties; + {atomic, []} -> + corba:raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO}); + _Other -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +lookup_table(Key) when is_list(Key) -> + Key; +lookup_table(_) -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +mnesia_transaction(Fun) -> + case mnesia:transaction(Fun) of + {atomic, {'EXCEPTION', E}} -> + corba:raise(E); + {atomic, ok} -> + ok; + {atomic, Reply} -> + Reply; + _Other -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +mnesia_read(State) -> + case mnesia:wread({oe_CosPropertyService, ?get_DBKey(State)}) of + [#oe_CosPropertyService{properties = X}] -> + X; + {atomic, []} -> + {'EXCEPTION', #'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO}}; + _Other -> + {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}} + end. + +mnesia_write(State, X) -> + mnesia:write(#oe_CosPropertyService{key = ?get_DBKey(State), properties = X}). + +%% Check a write transaction +write_result({atomic,ok}) -> ok; +write_result(_Foo) -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + +evaluate_properties_data(State, PropertySeq) -> + evaluate_properties_data(State, PropertySeq, [], []). + +evaluate_properties_data(_State, [], OKProperties, Exc) -> + {OKProperties, Exc}; + +evaluate_properties_data(State, [#'CosPropertyService_Property' + {property_name = Name, + property_value = Value}|T], Acc, Exc) -> + case catch evaluate_property_data(State, Value, Name) of + ok -> + evaluate_properties_data(State, T, [#'CosPropertyService_Property' + {property_name = Name, + property_value = Value}|Acc], Exc); + {'EXCEPTION', E} when is_record(E, 'CosPropertyService_UnsupportedTypeCode') -> + evaluate_properties_data(State, T, Acc, + [#'CosPropertyService_PropertyException' + {reason = unsupported_type_code, + failing_property_name = Name}|Exc]); + {'EXCEPTION', E} when is_record(E, 'CosPropertyService_UnsupportedProperty') -> + evaluate_properties_data(State, T, Acc, + [#'CosPropertyService_PropertyException' + {reason = unsupported_property, + failing_property_name = Name}|Exc]) + end; +evaluate_properties_data(State, [#'CosPropertyService_PropertyDef' + {property_name = Name, + property_value = Value, + property_mode = Mode}|T], Acc, Exc) -> + case catch evaluate_property_data(State, Value, Name) of + ok -> + evaluate_properties_data(State, T, [#'CosPropertyService_PropertyDef' + {property_name = Name, + property_value = Value, + property_mode = Mode}|Acc], Exc); + {'EXCEPTION', E} when is_record(E, 'CosPropertyService_UnsupportedTypeCode') -> + evaluate_properties_data(State, T, Acc, + [#'CosPropertyService_PropertyException' + {reason = unsupported_type_code, + failing_property_name = Name}|Exc]); + {'EXCEPTION', E} when is_record(E, 'CosPropertyService_UnsupportedProperty') -> + evaluate_properties_data(State, T, Acc, + [#'CosPropertyService_PropertyException' + {reason = unsupported_property, + failing_property_name = Name}|Exc]) + end; +evaluate_properties_data(_, _, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +evaluate_property_data(State, _, _) when ?no_PropertyLimits(State), + ?no_TypeLimits(State) -> + ok; +evaluate_property_data(State, Value, _Name) when ?no_PropertyLimits(State) -> + case lists:member(any:get_typecode(Value), ?get_okTypes(State)) of + true -> + ok; + _ -> + corba:raise(#'CosPropertyService_UnsupportedTypeCode'{}) + end; +evaluate_property_data(State, _Value, Name) when ?no_TypeLimits(State) -> + case lists:any(?MemberName(Name), ?get_okProperties(State)) of + true -> + ok; + _ -> + corba:raise(#'CosPropertyService_UnsupportedProperty'{}) + end; +evaluate_property_data(State, Value, Name) -> + case lists:any(?MemberName(Name), ?get_okProperties(State)) of + true -> + case lists:member(any:get_typecode(Value), ?get_okTypes(State)) of + true -> + ok; + _ -> + corba:raise(#'CosPropertyService_UnsupportedTypeCode'{}) + end; + _ -> + corba:raise(#'CosPropertyService_UnsupportedProperty'{}) + end. + + +%%---------------------------------------------------------------------- +%% Debugging functions +%%---------------------------------------------------------------------- +dump() -> + case catch mnesia:dirty_first('oe_CosPropertyService') of + {'EXIT', R} -> + io:format("Exited with ~p\n",[R]); + Key -> + dump_print(Key), + dump_loop(Key) + end. + +dump_loop(PreviousKey) -> + case catch mnesia:dirty_next('oe_CosPropertyService', PreviousKey) of + {'EXIT', R} -> + io:format("Exited with ~p\n",[R]); + '$end_of_table' -> + ok; + Key -> + dump_print(Key), + dump_loop(Key) + end. + +dump_print(Key) -> + case catch mnesia:dirty_read({'oe_CosPropertyService', Key}) of + {'EXIT', R} -> + io:format("Exited with ~p\n",[R]); + [{_,_,X}] -> + io:format("Property: ~p~n", [X]); + _ -> + ok + end. + + +%%-------------------------- END OF MODULE ----------------------------- diff --git a/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl b/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl new file mode 100644 index 0000000..ad3cdb6 --- /dev/null +++ b/lib/cosProperty/src/CosPropertyService_PropertySetFactory_impl.erl @@ -0,0 +1,176 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosPropertyService_PropertySetFactory_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosPropertyService_PropertySetFactory_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). +-include("CosPropertyService.hrl"). +-include("cosProperty.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3]). + +-export([create_propertyset/2, + create_constrained_propertyset/4, + create_initial_propertyset/3]). + + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +-define(checkTCfun, fun(TC) -> orber_tc:check_tc(TC) end). + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([]) -> + {ok, #state{}}. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------- +%% Function : create_propertyset +%% Arguments : +%% Returns : CosPropertyService::PropertySet reference. +%% Description: +%%---------------------------------------------------------------------- +create_propertyset(_OE_This, State) -> + {reply, + 'CosPropertyService_PropertySetDef': + oe_create({normal, [], [], [], ?PropertySet}, [{pseudo, true}]), + State}. + +%%---------------------------------------------------------------------- +%% Function : create_constrained_propertyset +%% Arguments : PropTypes - list of property types. +%% Properties - list of properties. +%% Returns : CosPropertyService::PropertySet | +%% {'EXCEPTION', CosPropertyService::ConstraintNotSupported} +%% Description: +%%---------------------------------------------------------------------- +create_constrained_propertyset(_OE_This, State, PropTypes, Properties) -> + case lists:all(?checkTCfun, PropTypes) of + true -> + crosscheckTC(Properties, PropTypes), + {reply, + 'CosPropertyService_PropertySetDef': + oe_create({normal, PropTypes, Properties, [], ?PropertySet}, + [{pseudo, true}]), + State}; + false -> + corba:raise(#'CosPropertyService_ConstraintNotSupported'{}) + end. + +crosscheckTC([], _) -> + ok; +crosscheckTC([#'CosPropertyService_Property' + {property_name = Name, + property_value = Value}|T], TCs) -> + case lists:member(any:get_typecode(Value), TCs) of + true when Name =/= "" -> + crosscheckTC(T, TCs); + _ -> + corba:raise(#'CosPropertyService_ConstraintNotSupported'{}) + end. + +%%---------------------------------------------------------------------- +%% Function : create_initial_propertyset +%% Arguments : Properties - list of properties. +%% Returns : CosPropertyService::PropertySetDef | +%% {'EXCEPTION', CosPropertyService::MultipleExceptions} +%% Description: +%%---------------------------------------------------------------------- +create_initial_propertyset(_OE_This, State, Properties) -> + InitProps = evaluate_propertyset(Properties), + {reply, + 'CosPropertyService_PropertySetDef': + oe_create({normal, [], [], InitProps, ?PropertySet}, [{pseudo, true}]), + State}. + +%%====================================================================== +%% Internal functions +%%====================================================================== +evaluate_propertyset(Sets) -> + evaluate_propertyset(Sets, [], []). +evaluate_propertyset([], NewProperties, []) -> + %% No exceptions found. + NewProperties; +evaluate_propertyset([], _, Exc) -> + corba:raise(#'CosPropertyService_MultipleExceptions'{exceptions = Exc}); +evaluate_propertyset([#'CosPropertyService_Property' + {property_name = Name, + property_value = Value}|T], X, Exc) -> + case orber_tc:check_tc(any:get_typecode(Value)) of + true -> + evaluate_propertyset(T, [{Name, Value, normal}|X], Exc); + false -> + evaluate_propertyset(T, X, [#'CosPropertyService_PropertyException' + {reason = unsupported_type_code, + failing_property_name = Name}|Exc]) + end. + +%%====================================================================== +%% END OF MODULE +%%====================================================================== diff --git a/lib/cosProperty/src/Makefile b/lib/cosProperty/src/Makefile new file mode 100644 index 0000000..1d2119d --- /dev/null +++ b/lib/cosProperty/src/Makefile @@ -0,0 +1,183 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug -W +endif + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(COSPROPERTY_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/cosProperty-$(VSN) + +EXTERNAL_INC_PATH = ../include + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + cosProperty \ + CosPropertyService_PropertySetDefFactory_impl \ + CosPropertyService_PropertySetDef_impl \ + CosPropertyService_PropertySetFactory_impl \ + CosPropertyService_PropertiesIterator_impl \ + CosPropertyService_PropertyNamesIterator_impl + + +ERL_FILES = $(MODULES:%=%.erl) +HRL_FILES = \ + cosProperty.hrl \ + +GEN_ERL_FILES = \ + oe_CosProperty.erl \ + CosPropertyService_ConflictingProperty.erl \ + CosPropertyService_ConstraintNotSupported.erl \ + CosPropertyService_FixedProperty.erl \ + CosPropertyService_InvalidPropertyName.erl \ + CosPropertyService_MultipleExceptions.erl \ + CosPropertyService_Properties.erl \ + CosPropertyService_PropertiesIterator.erl \ + CosPropertyService_Property.erl \ + CosPropertyService_PropertyDef.erl \ + CosPropertyService_PropertyDefs.erl \ + CosPropertyService_PropertyException.erl \ + CosPropertyService_PropertyExceptions.erl \ + CosPropertyService_PropertyMode.erl \ + CosPropertyService_PropertyModes.erl \ + CosPropertyService_PropertyNames.erl \ + CosPropertyService_PropertyNamesIterator.erl \ + CosPropertyService_PropertyNotFound.erl \ + CosPropertyService_PropertySet.erl \ + CosPropertyService_PropertySetDef.erl \ + CosPropertyService_PropertySetDefFactory.erl \ + CosPropertyService_PropertySetFactory.erl \ + CosPropertyService_PropertyTypes.erl \ + CosPropertyService_ReadOnlyProperty.erl \ + CosPropertyService_UnsupportedMode.erl \ + CosPropertyService_UnsupportedProperty.erl \ + CosPropertyService_UnsupportedTypeCode.erl + +LOCAL_HRL_FILES = \ + oe_CosProperty.hrl \ + CosPropertyService.hrl \ + CosPropertyService_PropertiesIterator.hrl \ + CosPropertyService_PropertyNamesIterator.hrl \ + CosPropertyService_PropertySet.hrl \ + CosPropertyService_PropertySetDef.hrl \ + CosPropertyService_PropertySetDefFactory.hrl \ + CosPropertyService_PropertySetFactory.hrl + +GEN_HRL_FILES = $(LOCAL_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_FILES = \ + $(GEN_HRL_FILES) \ + $(GEN_ERL_FILES) + +TARGET_FILES = \ + $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +IDL_FILES = \ + CosProperty.idl + +APPUP_FILE = cosProperty.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + +APP_FILE = cosProperty.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosProperty/ebin \ + -pa $(ERL_TOP)/lib/ic/ebin\ + -pa $(ERL_TOP)/lib/orber/ebin + +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -pa $(ERL_TOP)/lib/orber/include \ + -pa $(ERL_TOP)/lib/cosProperty/include \ + -I$(ERL_TOP)/lib/cosProperty/include \ + -I$(ERL_TOP)/lib/orber/include \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,"cosProperty_$(COSPROPERTY_VSN)"}' + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + +debug: + @${MAKE} TYPE=debug opt + +cleanb: + rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +clean: + rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +$(GEN_ERL_FILES) $(GEN_HRL_FILES): CosProperty.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosProperty.cfg"}' CosProperty.idl + mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH) + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include + +release_docs_spec: diff --git a/lib/cosProperty/src/cosProperty.app.src b/lib/cosProperty/src/cosProperty.app.src new file mode 100644 index 0000000..3099e90 --- /dev/null +++ b/lib/cosProperty/src/cosProperty.app.src @@ -0,0 +1,45 @@ +{application, cosProperty, + [{description, "The Erlang CosProperty application"}, + {vsn, "%VSN%"}, + {modules, + [ + 'cosProperty', + 'CosPropertyService_PropertySetDefFactory_impl', + 'CosPropertyService_PropertySetDef_impl', + 'CosPropertyService_PropertySetFactory_impl', + 'CosPropertyService_PropertiesIterator_impl', + 'CosPropertyService_PropertyNamesIterator_impl', + 'oe_CosProperty', + 'CosPropertyService_ConflictingProperty', + 'CosPropertyService_ConstraintNotSupported', + 'CosPropertyService_FixedProperty', + 'CosPropertyService_InvalidPropertyName', + 'CosPropertyService_MultipleExceptions', + 'CosPropertyService_Properties', + 'CosPropertyService_PropertiesIterator', + 'CosPropertyService_Property', + 'CosPropertyService_PropertyDef', + 'CosPropertyService_PropertyDefs', + 'CosPropertyService_PropertyException', + 'CosPropertyService_PropertyExceptions', + 'CosPropertyService_PropertyMode', + 'CosPropertyService_PropertyModes', + 'CosPropertyService_PropertyNames', + 'CosPropertyService_PropertyNamesIterator', + 'CosPropertyService_PropertyNotFound', + 'CosPropertyService_PropertySet', + 'CosPropertyService_PropertySetDef', + 'CosPropertyService_PropertySetDefFactory', + 'CosPropertyService_PropertySetFactory', + 'CosPropertyService_PropertyTypes', + 'CosPropertyService_ReadOnlyProperty', + 'CosPropertyService_UnsupportedMode', + 'CosPropertyService_UnsupportedProperty', + 'CosPropertyService_UnsupportedTypeCode' + ] + }, + {registered, [oe_cosPropertySup]}, + {applications, [orber, stdlib, kernel]}, + {env, []}, + {mod, {cosProperty, []}} +]}. diff --git a/lib/cosProperty/src/cosProperty.appup.src b/lib/cosProperty/src/cosProperty.appup.src new file mode 100644 index 0000000..f3eead4 --- /dev/null +++ b/lib/cosProperty/src/cosProperty.appup.src @@ -0,0 +1,6 @@ +{"%VSN%", + [ + ], + [ + ] +}. diff --git a/lib/cosProperty/src/cosProperty.erl b/lib/cosProperty/src/cosProperty.erl new file mode 100644 index 0000000..2368ee3 --- /dev/null +++ b/lib/cosProperty/src/cosProperty.erl @@ -0,0 +1,414 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosProperty.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module(cosProperty). + +%%--------------- INCLUDES ----------------------------------- +-include("cosProperty.hrl"). +-include_lib("cosProperty/include/CosPropertyService.hrl"). + +%%--------------- EXPORTS------------------------------------- +%% cosProperty API external +-export([start/0, + start_SetDefFactory/0, + start_SetFactory/0, + stop_SetDefFactory/1, + stop_SetFactory/1, + stop/0, + install/0, + install/1, + install_db/0, + install_db/1, + install_db/2, + uninstall/0, + uninstall/1, + uninstall_db/0]). + +%% cosProperty API internal +-export([create_link/3, + get_option/3, + type_check/2, + query_result/1, + start_PropertiesIterator/1, + start_PropertyNamesIterator/1, + create_static_SetDef/2]). + +%% Application callbacks +-export([start/2, init/1, stop/1]). + +%%--------------- DEFINES ------------------------------------ + +-define(SUPERVISOR_NAME, oe_cosPropertySup). +-define(SUP_FLAG, {simple_one_for_one,50,10}). +-define(SUP_PROP_SPEC(T,I), + ['CosPropertyService_PropertiesIterator',I, + [{sup_child, true}, {regname, {global, T}}]]). +-define(SUP_NAMES_SPEC(T,I), + ['CosPropertyService_PropertyNamesIterator',I, + [{sup_child, true}, {regname, {global, T}}]]). +-define(SUP_CHILD, + {"oe_PropertyChild", + {cosProperty,create_link, []}, + transient,100000,worker, + []}). + +%%------------------------------------------------------------ +%% function : install +%% Arguments: - +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ +install() -> + install([]). +install(_Options) -> + case catch oe_CosProperty:'oe_register'() of + ok -> + ok; + {'EXIT',{unregistered,App}} -> + ?write_ErrorMsg("Unable to register cosProperty; application ~p not registered.~n", + [App]), + exit({unregistered,App}); + {'EXCEPTION',_} -> + ?write_ErrorMsg("Unable to register cosProperty; propably already registered. +You are adviced to confirm this.~n", []), + exit({error, "Register in the IFR failed."}); + Reason -> + ?write_ErrorMsg("Unable to register cosProperty; reason ~p", [Reason]), + exit({error, "Register in the IFR failed."}) + end. + +%%------------------------------------------------------------ +%% function : install_db +%% Arguments: - +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ +install_db() -> + install_db(infinity, []). +install_db(Timeout) -> + install_db(Timeout, []). +install_db(Timeout, Options) -> + case install_table(Timeout, Options) of + ok -> + ok; + {error, [DB_tables_created, Wait]} -> + ?write_ErrorMsg("Able to register cosProperty but failed adding table in mnesia (~p, ~p)", + [DB_tables_created, Wait]), + exit({error, "Adding data in mnesia failed."}); + Why -> + ?write_ErrorMsg("Able to register cosProperty but failed adding table in mnesia with reason ~p", + [Why]), + exit({error, "Adding data in mnesia failed."}) + end. + +%%------------------------------------------------------------ +%% function : install_table +%% Arguments: - +%% Returns : ok | {error, Data} +%% Effect : Install necessary data in mnesia +%%------------------------------------------------------------ +install_table(Timeout, Options) -> + %% Fetch a list of the defined tables to see if 'oe_CosPropertyService' + %% is defined. + AllTabs = mnesia:system_info(tables), + DB_tables_created = + case lists:member('oe_CosPropertyService', AllTabs) of + true -> + case lists:member({local_content, true}, + Options) of + true-> + mnesia:add_table_copy('oe_CosPropertyService', + node(), + ram_copies); + _-> + mnesia:create_table('oe_CosPropertyService',[{attributes, + record_info(fields, + 'oe_CosPropertyService')} + |Options]) + end; + _ -> + mnesia:create_table('oe_CosPropertyService',[{attributes, + record_info(fields, + 'oe_CosPropertyService')} + |Options]) + end, + Wait = mnesia:wait_for_tables(['oe_CosPropertyService'], Timeout), + %% Check if any error has occured yet. If there are errors, return them. + if + DB_tables_created == {atomic, ok}, + Wait == ok -> + ok; + true -> + {error, [DB_tables_created, Wait]} + end. + + +%%------------------------------------------------------------ +%% function : query_result +%% Arguments: - +%% Returns : error | Data +%% Effect : Check a read transaction +%%------------------------------------------------------------ +query_result(Qres) -> + case Qres of + {atomic, [Hres]} -> + Hres#oe_CosPropertyService.properties; + {atomic, [_Hres | _Tres]} -> + error; + {atomic, []} -> + error; + _Other -> + error + end. + +%%------------------------------------------------------------ +%% function : uninstall +%% Arguments: - +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosProperty from the IFR DB +%%------------------------------------------------------------ +uninstall() -> + uninstall([]). +uninstall(_Options) -> + application:stop(cosProperty), + oe_CosProperty:oe_unregister(). + +%%------------------------------------------------------------ +%% function : uninstall +%% Arguments: - +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosProperty from the IFR DB +%%------------------------------------------------------------ +uninstall_db() -> + application:stop(cosProperty), + case mnesia:delete_table('oe_CosPropertyService') of + {atomic, ok} -> + ok; + {aborted, _Reason} -> + exit({error, "Removing data from mnesia failed."}) + end. + +%%------------------------------------------------------------ +%% function : create_static_SetDef +%% Arguments: +%% Returns : +%% Effect : Starts or stops the cosProperty application. +%%------------------------------------------------------------ +create_static_SetDef(PropTypes, PropDefs) -> + InitProps = propertyDef2local(PropDefs, []), + 'CosPropertyService_PropertySetDef':oe_create({static, fixed_readonly, PropTypes, + PropDefs, InitProps, + ?PropertySetDef}, + [{pseudo, true}]). +propertyDef2local([#'CosPropertyService_PropertyDef' + {property_name = Name, + property_value = Value, + property_mode = fixed_readonly}|T], Acc) -> + propertyDef2local(T, [{Name, Value, fixed_readonly}|Acc]); +propertyDef2local([], Acc) -> + Acc; +propertyDef2local(_, _) -> + exit({error, "Bad Mode type supplied. Must be fixed_readonly"}). + +%%------------------------------------------------------------ +%% function : start/stop +%% Arguments: +%% Returns : +%% Effect : Starts or stops the cosProperty application. +%%------------------------------------------------------------ +start() -> + application:start(cosProperty). +stop() -> + application:stop(cosProperty). + + + +%%-----------------------------------------------------------% +%% function : start_SetDefFactory +%% Arguments: - +%% Returns : A PropertySetDefFactory reference. +%% Effect : +%%------------------------------------------------------------ +start_SetDefFactory() -> + 'CosPropertyService_PropertySetDefFactory':oe_create([], [{pseudo, true}]). + +%%-----------------------------------------------------------% +%% function : start_SetFactory +%% Arguments: - +%% Returns : A PropertySetFactory reference. +%% Effect : +%%------------------------------------------------------------ +start_SetFactory() -> + 'CosPropertyService_PropertySetFactory':oe_create([], [{pseudo, true}]). + +%%-----------------------------------------------------------% +%% function : stop_SetDefFactory +%% Arguments: Factory - A PropertySetDefFactory reference. +%% Returns : +%% Effect : +%%------------------------------------------------------------ +stop_SetDefFactory(Factory) -> + corba:dispose(Factory). + +%%-----------------------------------------------------------% +%% function : stop_SetFactory +%% Arguments: Factory - A PropertySetFactory reference. +%% Returns : +%% Effect : +%%------------------------------------------------------------ +stop_SetFactory(Factory) -> + corba:dispose(Factory). + +%%------------------------------------------------------------ +%% function : start +%% Arguments: Type - see module application +%% Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ +start(_, _) -> + supervisor:start_link({local, ?SUPERVISOR_NAME}, cosProperty, app_init). + + +%%------------------------------------------------------------ +%% function : stop +%% Arguments: Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ +stop(_) -> + ok. + +%%-----------------------------------------------------------% +%% function : init +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ +%% Starting using create_factory/X +init(own_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}; +%% When starting as an application. +init(app_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}. + +%%-----------------------------------------------------------% +%% function : create_link +%% Arguments: Module - which Module to call +%% Env/ArgList - ordinary oe_create arguments. +%% Returns : +%% Exception: +%% Effect : Necessary since we want the supervisor to be a +%% 'simple_one_for_one'. Otherwise, using for example, +%% 'one_for_one', we have to call supervisor:delete_child +%% to remove the childs startspecification from the +%% supervisors internal state. +%%------------------------------------------------------------ +create_link(Module, Env, ArgList) -> + Module:oe_create_link(Env, ArgList). + +%%-----------------------------------------------------------% +%% function : start_PropertiesIterator +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +start_PropertiesIterator(Args) -> + Name = create_name(propertiesIterator), + case supervisor:start_child(?SUPERVISOR_NAME, ?SUP_PROP_SPEC(Name, Args)) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + _Other-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%-----------------------------------------------------------% +%% function : start_PropertyNamesIterator +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +start_PropertyNamesIterator(Args) -> + Name = create_name(propertiesIterator), + case supervisor:start_child(?SUPERVISOR_NAME, ?SUP_NAMES_SPEC(Name, Args)) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + _Other-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + + +%%-----------------------------------------------------------% +%% function : get_option +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +get_option(Key, OptionList, DefaultList) -> + case lists:keysearch(Key, 1, OptionList) of + {value,{Key,Value}} -> + Value; + _ -> + case lists:keysearch(Key, 1, DefaultList) of + {value,{Key,Value}} -> + Value; + _-> + {error, "Invalid option"} + end + end. + +%%-----------------------------------------------------------% +%% function : type_check +%% Arguments: Obj - objectrefernce to test. +%% Mod - Module which contains typeID/0. +%% Returns : 'ok' or raises exception. +%% Effect : +%%------------------------------------------------------------ +type_check(Obj, Mod) -> + case catch corba_object:is_a(Obj,Mod:typeID()) of + true -> + ok; + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end. + + +%%-----------------------------------------------------------% +%% function : create_name/1 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ +create_name(Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',MSec, '_', Sec, '_', USec]). + +%%--------------- END OF MODULE ------------------------------ + + diff --git a/lib/cosProperty/src/cosProperty.hrl b/lib/cosProperty/src/cosProperty.hrl new file mode 100644 index 0000000..2755b89 --- /dev/null +++ b/lib/cosProperty/src/cosProperty.hrl @@ -0,0 +1,81 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosProperty.hrl +%% Purpose : +%%---------------------------------------------------------------------- + + +%%--------------- INCLUDES ----------------------------------- +%% External +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). + +%%----------------------------------------------------------------- +%% Mnesia Table definition record +%%----------------------------------------------------------------- +-record('oe_CosPropertyService', {key, properties}). + +%%----------------------------------------------------------------- +%% Macros +%%----------------------------------------------------------------- +-define(PropertySet, 0). +-define(PropertySetDef, 1). + +%% This macro returns a read fun suitable for evaluation in a transaction +-define(read_function(Objkey), + fun() -> + mnesia:read(Objkey) + end). + +%% This macro returns a write fun suitable for evaluation in a transaction +-define(write_function(R), + fun() -> + mnesia:write(R) + end). + +%% This macro returns a delete fun suitable for evaluation in a transaction +-define(delete_function(R), + fun() -> + mnesia:delete(R) + end). + +-define(query_check(Q_res), {atomic, Q_res}). + + +-define(write_ErrorMsg(Txt, Arg), +error_logger:error_msg("================ CosProperty ==============~n" + Txt + "===========================================~n", + Arg)). + + + +-ifdef(debug). +-define(debug_print(F,A), + io:format("[LINE: ~p MODULE: ~p] "++F,[?LINE, ?MODULE]++A)). +-define(property_TypeCheck(O,M), 'cosProperty':type_check(O,M)). +-else. +-define(debug_print(F,A), ok). +-define(property_TypeCheck(O,I), ok). +-endif. + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosProperty/vsn.mk b/lib/cosProperty/vsn.mk new file mode 100644 index 0000000..0e55352 --- /dev/null +++ b/lib/cosProperty/vsn.mk @@ -0,0 +1,9 @@ +COSPROPERTY_VSN = 1.1.10 + +TICKETS = OTP-8201 + +TICKETS_1.1.9 = OTP-7987 + +TICKETS_1.1.8 = OTP-7837 + +TICKETS_1.1.7 = OTP-7595 diff --git a/lib/cosTime/AUTHORS b/lib/cosTime/AUTHORS new file mode 100644 index 0000000..55d8059 --- /dev/null +++ b/lib/cosTime/AUTHORS @@ -0,0 +1,4 @@ +Original Authors: +Niclas Eklund + +Contributors: diff --git a/lib/cosTime/Makefile b/lib/cosTime/Makefile new file mode 100644 index 0000000..b8628ac --- /dev/null +++ b/lib/cosTime/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(COSTIME_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- +# SUB_DIRECTORIES = src test examples doc/src +# At the moment we don't have any example programs. +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/cosTime/doc/html/.gitignore b/lib/cosTime/doc/html/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTime/doc/man3/.gitignore b/lib/cosTime/doc/man3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTime/doc/man6/.gitignore b/lib/cosTime/doc/man6/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTime/doc/pdf/.gitignore b/lib/cosTime/doc/pdf/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTime/doc/src/CosTime_TIO.xml b/lib/cosTime/doc/src/CosTime_TIO.xml new file mode 100644 index 0000000..91aa34d --- /dev/null +++ b/lib/cosTime/doc/src/CosTime_TIO.xml @@ -0,0 +1,108 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosTime_TIO + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosTime_TIO + This module implements the OMG CosTime::TIO interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTime/include/*.hrl").

+
+ + + '_get_time_interval'(TIO) -> TimeInterval + Return the interval associated with the target object + + TIO = #objref + TimeInterval = #'TimeBase_IntervalT{lower_bound, upper_bound} + lower_bound = upper_bound = ulonglong + + +

This operation returns the interval associated with the target object.

+
+
+ + spans(TIO, UTO) -> Reply + Return an OverlapType which describe how the interval in the target object and the timerange represented by the UTO object overlap + + TIO = UTO = OtherTIO = #objref + Reply = {OverlapType, OtherTIO} + OverlapType = 'OTContainer' | 'OTContained' | 'OTOverlap' | 'OTNoOverlap' + + +

This operation returns a OverlapType depending on how the interval + in the target object and the timerange represented by the UTO object + overlap. If the OverlapType is 'OTNoOverlap' the out parameter represents + the gap between the two intervals. If OverlapType is one of the others, the + out parameter represents the overlap interval. + The definitions of the OverlapType's are:

+

+ + 'OTContainer' - target objects lower and upper limits are, + respectively, less or equal to and greater or equal to given object's. + 'OTContained' - target objects lower and upper limits are, + respectively, greater or equal to and less or equal to given object's. + 'OTOverlap' - target objects interval overlap given object's. + 'OTNoOverlap' - target objects interval do not overlap given object's. + +
+
+ + overlaps(TIO, OtherTIO) -> Reply + Return an OverlapType which describe how the interval in the target object and the timerange represented by the TIO object overlap + + TIO = OtherTIO = AnotherTIO = #objref + Reply = {OverlapType, AnotherTIO} + OverlapType = 'OTContainer' | 'OTContained' | 'OTOverlap' | 'OTNoOverlap' + + +

This operation returns a OverlapType depending on how the interval + in the target object and the timerange represented by the TIO object + overlap. The OverlapType's are described under spans/2.

+
+
+ + time(TIO) -> UTO + Return a UTO in which the interval equals the time interval in the target object and time value is the midpoint of the interval + + TIO = UTO = #objref + + +

This operation returns a UTO in which the interval equals the time interval + in the target object and time value is the midpoint of the interval.

+
+
+
+ +
+ diff --git a/lib/cosTime/doc/src/CosTime_TimeService.xml b/lib/cosTime/doc/src/CosTime_TimeService.xml new file mode 100644 index 0000000..9b20f24 --- /dev/null +++ b/lib/cosTime/doc/src/CosTime_TimeService.xml @@ -0,0 +1,103 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosTime_TimeService + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosTime_TimeService + This module implements the OMG CosTime::TimeService interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTime/include/*.hrl").

+
+ + + universal_time(TimeService) -> Reply + Return the current time and the Inaccuracy given when starting this application in a UTO + + TimeService = #objref + Reply = UTO | {'EXCEPTION", #'TimerService_TimeUnavailable'{}} + UTO = #objref + + +

This operation returns the current time and the Inaccuracy given + when starting this application in a UTO. The time base is + 15 october 1582 00:00. Comparing two time objects which use + different time base is, by obvious reasons, pointless.

+
+
+ + new_universal_time(TimeService, Time, Inaccuracy, Tdf) -> UTO + Create a new UTO object representing the time parameters given + + TimeService = UTO = #objref + Time = Inaccuracy = ulonglong() + Tdf = short() + + +

This operation creates a new UTO object representing the time + parameters given. This is the only way to create a UTO with an + arbitrary time from its components. This is useful when using the + Timer Event Service.

+
+
+ + uto_from_utc(TimeService, Utc) -> UTO + Create a UTO representing the given time in Utc form + + TimeService = UTO = #objref + Utc = #'TimeBase_UtcT'{time, inacclo, inacchi, tdf} + time = ulonglong() + inacclo = ulong() + inacchi = ushort() + tdf = short() + + +

This operation is used to create a UTO given a time in the Utc form.

+
+
+ + new_interval(TimeService, Lower, Upper) -> TIO + Create a new TIO object representing the input parameters + + TimeService = TIO = #objref + Lower = Upper = ulonglong() + + +

This operation is used to create a new TIO object, representing + the input parameters. If Lower is greater than Upper + BAD_PARAM is raised.

+
+
+
+ +
+ diff --git a/lib/cosTime/doc/src/CosTime_UTO.xml b/lib/cosTime/doc/src/CosTime_UTO.xml new file mode 100644 index 0000000..73784e5 --- /dev/null +++ b/lib/cosTime/doc/src/CosTime_UTO.xml @@ -0,0 +1,155 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosTime_UTO + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosTime_UTO + This module implements the OMG CosTime::UTO interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTime/include/*.hrl").

+
+ + + '_get_time'(UTO) -> ulonglong() + Return the time associated with the target object + + UTO = #objref + + +

This operation returns the time associated with the target object.

+
+
+ + '_get_inaccuracy'(UTO) -> ulonglong() + Return the inaccuracy associated with the target object + + UTO = #objref + + +

This operation returns the inaccuracy associated with the target object.

+
+
+ + '_get_tdf'(UTO) -> short() + Return the time displacement factor associated with the target object + + UTO = #objref + + +

This operation returns the time displacement factor associated with + the target object.

+
+
+ + '_get_utc_time'(UTO) -> UtcT + Return the data associated with the target object in Utc form + + UTO = #objref + Utc = #'TimeBase_UtcT'{time, inacclo, inacchi, tdf} + time = ulonglong() + inacclo = ulong() + inacchi = ushort() + tdf = short() + + +

This operation returns the data associated with the target object in + Utc form.

+
+
+ + absolute_time(UTO) -> OtherUTO + Create a new UTO object representing the time in the target object added to current time (UTC) + + UTO = OtherUTO = #objref + + +

This operation create a new UTO object representing the time in the target + object added to current time (UTC). The time base is + 15 october 1582 00:00. Comparing two time objects which use + different time base is, by obvious reasons, pointless. + Raises DATA_CONVERSION if causes an overflow. This operation is only useful + if the target object represents a relative time.

+
+
+ + compare_time(UTO, ComparisonType, OtherUTO) -> Reply + Compare the time associated with the target object and the given UTO object + + UTO = OtherUTO = #objref + ComparisonType = 'IntervalC' | 'MidC' + Reply = 'TCEqualTo' | 'TCLessThan' | 'TCGreaterThan' | 'TCIndeterminate' + + +

This operation compares the time associated with the target object and the + given UTO object. The different ComparisonType are:

+

+ + 'MidC' - only compare the time represented by each object. Furthermore, + the target object is always used as the first parameter in the + comparison, i.e., if the target object's time is larger + 'TCGreaterThan' will be returned. + 'IntervalC' - also takes the inaccuracy into consideration, i.e., + if the two objects interval overlaps 'TCIndeterminate' is returned, + otherwise the as for 'MidC'. + +
+
+ + time_to_interval(UTO, OtherUTO) -> TIO + Create a TIO representing the interval between the target object and the given UTO midpoint times + + UTO = OtherUTO = TIO = #objref + + +

This operation returns a TIO representing the interval between the target + object and the given UTO midpoint times. The inaccuracy in the objects are + not taken into consideration.

+
+
+ + interval(UTO) -> TIO + Create a TIO object representing the error interval around the time value represented by the target object + + UTO = TIO = #objref + + +

This operation creates a TIO object representing the error interval + around the time value represented by the target object, i.e., + TIO.upper_bound = UTO.time+UTO.inaccuracy and + TIO.lower_bound = UTO.time-UTO.inaccuracy.

+
+
+
+ +
+ diff --git a/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml b/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml new file mode 100644 index 0000000..bc1ef39 --- /dev/null +++ b/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml @@ -0,0 +1,125 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosTimerEvent_­TimerEventHandler + ..._TimerEventHandler + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosTimerEvent_TimerEventHandler + This module implements the OMG CosTimerEvent::TimerEventHandler interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTime/include/*.hrl").

+
+ + + '_get_status'(TimerEventHandler) -> Reply + Return the status of the target object + + TimerEventHandler = #objref + Reply = 'ESTimeSet' | 'ESTimeCleared' | 'ESTriggered' | 'ESFailedTrigger' + + +

This operation returns the status of the target object.

+ + 'ESTimeSet' - timer is set to trigger event(s). + 'ESTimeCleared' - no time set or the timer have been reset. + 'ESTriggered' - event has already been sent. + 'ESFailedTrigger' - tried to, but failed, sending the event. + +

If the target object is of type 'TTPeriodic' the status value + 'ESTriggered' is not valid.

+
+
+ + time_set(TimerEventHandler) -> Reply + Return trueif the time has been set for an event that is yet to be triggered, falseotherwise. The outparameter represents the current time value of the target object + + TimerEventHandler = #objref + Reply = {boolean(), UTO} + UTO = #objref + + +

This operation returns true if the time has been set for an event that + is yet to be triggered, false otherwise. The outparameter represents + the current time value of the target object.

+
+
+ + set_timer(TimerEventHandler, TimeType, TriggerTime) -> void() + Terminate terminate any previous set trigger, and set a new trigger specified by the TimeTypeand UTOobjects + + TimerEventHandler = #objref + TimeType = 'TTAbsolute' | 'TTRelative' | 'TTPeriodic' + TriggerTime = UTO + UTO = #objref + + +

This operation terminates any previous set trigger, and set a new trigger + specified by the TimeType and UTO objects.

+

The relation between the UTO object and the TimeTypes are:

+ + 'TTAbsolute' - the UTO object must represent absolute time, i.e., + number of 100 nanoseconds passed since 15 october + 1582 00:00. + 'TTRelative' - the UTO object must represent the from now until when + the event should be triggered, e.g., within 30*10^7 nanoseconds. + 'TTPeriodic' - the same as for 'TTRelative', but this option + will trigger an event periodically until timer cancelled. + +
+
+ + cancel_timer(TimerEventHandler) -> boolean() + Cancel, if possible, triggering of event(s). Returntrueif an event is actually cancelled, falseotherwise + + TimerEventHandler = #objref + + +

This operation cancel, if possible, the triggering of event(s). Returns + true if an event is actually cancelled, false otherwise.

+
+
+ + set_data(TimerEventHandler, EventData) -> ok + Change the event data sent when triggered + + TimerEventHandler = #objref + EventData = #any + + +

This operation changes the event data sent when triggered.

+
+
+
+ +
+ diff --git a/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml b/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml new file mode 100644 index 0000000..90eeb5b --- /dev/null +++ b/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml @@ -0,0 +1,84 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosTimerEvent_­TimerEventService + ..._TimerEventService + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-02-01 + 1.0 +
+ CosTimerEvent_TimerEventService + This module implements the OMG CosTimerEvent::TimerEventService interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTime/include/*.hrl").

+
+ + + register(TimerEventService, CosEventCommPushConsumer, Data) -> TimerEventHandler + Create a new TimerEventHandlerobject which push the givenDatato given CosEventCommPushConsumerafter the timer have been set + + TimerEventService = CosEventCommPushConsumer = TimerEventHandler = #objref + Data = #any + + +

This operation will create a new TimerEventHandler object which + will push given Data to given CosEventCommPushConsumer after + the timer have been set.

+
+
+ + unregister(TimerEventService, TimerEventHandler) -> ok + Terminate the target TimerEventHandler object + + TimerEventService = TimerEventHandler = #objref + + +

This operation will terminate the given TimerEventHandler.

+
+
+ + event_time(TimerEventService, TimerEvent) -> UTO + Return a UTO containing the time at which the associated event was triggered + + TimerEventService = #objref + TimerEvent = #'CosTimerEvent_TimerEvent'{utc, event_data} + utc = + event_data = #any} + UTO = #objref + + +

This operation returns a UTO containing the time at which the associated + event was triggered.

+
+
+
+ +
+ diff --git a/lib/cosTime/doc/src/Makefile b/lib/cosTime/doc/src/Makefile new file mode 100644 index 0000000..568e2cd --- /dev/null +++ b/lib/cosTime/doc/src/Makefile @@ -0,0 +1,225 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(COSTIME_VSN) +APPLICATION=cosTime + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + cosTime.xml \ + CosTime_TIO.xml \ + CosTime_TimeService.xml \ + CosTime_UTO.xml \ + CosTimerEvent_TimerEventHandler.xml \ + CosTimerEvent_TimerEventService.xml \ + +XML_PART_FILES = \ + part.xml \ + part_notes.xml +XML_CHAPTER_FILES = \ + ch_contents.xml \ + ch_introduction.xml \ + ch_install.xml \ + ch_example.xml \ + notes.xml + +BOOK_FILES = book.xml + +TECHNICAL_DESCR_FILES = + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif + +PS_FILES = + +# ---------------------------------------------------- + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf + +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(INTERNAL_HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTML_FILES) $(MAN3_FILES) + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) + +endif + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +$(INDEX_TARGET): $(INDEX_SRC) + sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + +release_spec: + diff --git a/lib/cosTime/doc/src/book.gif b/lib/cosTime/doc/src/book.gif new file mode 100644 index 0000000000000000000000000000000000000000..94b38687920c5386f0d90df2cfc962d66f52fbce GIT binary patch literal 1081 zcmV-91jhSENk%v~VJrYQ0K@U3Z&d%1>*52OU z=jZ3|@9+2b_W%F@EC2ui04xAE000I5ARvxpX`Uh%Eez$Ma2!{|XMe{g?|T;9x5JA^ zG%bL@N^vRj5RkV9bLkO4ZPIBmas5oR#mf&V1Q#(0YhcjmXe*9~d=7a)?vMy(=-KE* z8yQRzT~`AL3l4P-3kL!Lf=d(yg_TGJLq#4K5D7Jwg%4&P850c&1Y@8d0)H_S5pFPj z7ZR$K4m$^o4iXXx39coCpaZff8wUU$784g63O)Mnh1d zM*Ony;LwB#3?8W4Fn~dfDxggNp6C!kf(B*{AQb3^!o#OZ2{2Ij__0FI3O->S0!o2G zg@f-96evKTsnY>a2Pj~$%K;+++!`!k(;yCksSK!^1M@%uPY44fe1t$i?MDI+c2ZbC za|F=4KrQICaN${m0^A%h5YV8o0a~3adU`fEQr`1qssBIw;^v!UF;k;yW-v@4+eo>JYd}fHVVU z5gLf*p9x%mVi^DlSTI8WPNw|_zy%J@^^O%t7;wu6|1F@62n+%+n+O+(7C~JYKp}tz zPXIAiOdhnDfD0a6fWQkLNGO6;!$2WQfj6jx)&W2YPymny2!Ox=N)36z-FBgSXr4c6dN%+LI-06;0gjrH4CDHEr=iiO;mnh?Fk3i5Wq1C#9AnbqG>3C zxFaCoE>b2iV1odev}UfA7}V< + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTime + Niclas Eklund + + 2000-01-31 + 1.0 +
+ + + cosTime + + + + + + + + + + + + + + +
+ diff --git a/lib/cosTime/doc/src/ch_contents.xml b/lib/cosTime/doc/src/ch_contents.xml new file mode 100644 index 0000000..1e223f2 --- /dev/null +++ b/lib/cosTime/doc/src/ch_contents.xml @@ -0,0 +1,74 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The cosTime Application + Niclas Eklund + + 2000-01-31 + 1.0 + ch_contents.xml +
+ +
+ Content Overview +

The cosTime documentation is divided into three sections: +

+ + +

PART ONE - The User's Guide +

+Description of the cosTime Application including + services and a small tutorial demonstrating + the development of a simple service.

+
+ +

PART TWO - Release Notes +

+A concise history of cosTime.

+
+ +

PART THREE - The Reference Manual +

+ A quick reference guide, including a + brief description, to all the functions available in cosTime.

+
+
+
+ +
+ Brief Description of the User's Guide +

The User's Guide contains the following parts:

+ + +

cosTime overview

+
+ +

cosTime installation

+
+ +

A tutorial example

+
+
+
+
+ diff --git a/lib/cosTime/doc/src/ch_example.xml b/lib/cosTime/doc/src/ch_example.xml new file mode 100644 index 0000000..9664331 --- /dev/null +++ b/lib/cosTime/doc/src/ch_example.xml @@ -0,0 +1,112 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTime Examples + Niclas Eklund + + 2000-01-31 + A + ch_example.xml +
+ +
+ A Tutorial on How to Create a Simple Service + +
+ Initiate the Application +

To use the complete cosTime application Time and Timer Event Services + must be installed. The application is then started by using + cosTime:start(). To get access to Time Service or Timer Event Service, + use start_time_service/2 or start_timerevent_service/1.

+

The Time Service are global, i.e., there may only exist one instance per + Orber domain.

+

The Timer Event Service is locally registered, i.e., there may only exist + one instance per node.

+ +

The Time and Timer Event Service use the time base + 15 october 1582 00:00. Performing operations using other time + bases will not yield correct result. Furthermore, time and inaccuracy + must be expressed in 100 nano seconds.

+
+
+ +
+ How to Run Everything +

Below is a short transcript on how to run cosTime.

+ + +%% Start Mnesia and Orber +mnesia:delete_schema([node()]), +mnesia:create_schema([node()]), +orber:install([node()]), +mnesia:start(), +orber:start(), + +%% Install Time Service in the IFR. +cosTime:install_time(), + +%% Install Timer Event Service in the IFR. Which, require +%% the Time Service and cosEvent or cosNotification +%% application to be installed. +cosNotification:install(), +cosTime:install_timerevent(), + +%% Now start the application and necessary services. +cosTime:start(), +%% Tdf == Time displacement factor +%% Inaccuracy measured in 100 nano seconds +TS=cosTime:start_time_service(TDF, Inaccuracy), +TES=cosTime:start_timerevent_service(TS), + +%% Access a cosNotification Proxy Push Consumer. How this is +%% done is implementation specific. +ProxyPushConsumer = .... + +%% How we construct the event is also implementation specific. +AnyEvent = .... + +%% Create a new relative universal time. +%% Time measured in 100 nano seconds. +UTO='CosTime_TimeService': + new_universal_time(TS, Time, Inaccuracy, TDF), +EH='CosTimerEvent_TimerEventService': + register(TES, ProxyPushConsumer, AnyEvent), + +%% If we want to trigger one event Time*10^-7 seconds from now: +'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTRelative', UTO), + +%% If we want to trigger an event every Time*10^-7 seconds, starting +%% Time*10^-7 seconds from now: +'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTPeriodic', UTO), + +%% If we want to use absolute time we must retrieve such an object. +%% One way is to convert the one we got, UTO, by using: +UTO2='CosTime_UTO':absolute_time(UTO), +%% If any other way is used, the correct time base MUST be used, i.e., +%% 15 october 1582 00:00. +'CosTimerEvent_TimerEventHandler':set_timer(EH, 'TTAbsolute', UTO2), + +
+
+
+ diff --git a/lib/cosTime/doc/src/ch_install.xml b/lib/cosTime/doc/src/ch_install.xml new file mode 100644 index 0000000..fe2b25c --- /dev/null +++ b/lib/cosTime/doc/src/ch_install.xml @@ -0,0 +1,55 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Installing cosTime + Niclas Eklund + + 2000-01-31 + + ch_install.xml +
+ +
+ Installation Process +

This chapter describes how to install + cosTime in an Erlang Environment. +

+ +
+ Preparation +

Before starting the installation process for cosTime, + the application Orber must be running.

+
+ +
+ Configuration +

When using both the Time and TimerEvent Services the cosTime application + first must be installed using cosTime:install_time() and + cosTime:install_timerevent(), followed by cosTime:start(). + Now we can choose which can start the servers by using + cosTime:start_time_service(Tdf, Inaccuracy) + and cosTime:start_timerevent_service(TimeService).

+
+
+
+ diff --git a/lib/cosTime/doc/src/ch_introduction.xml b/lib/cosTime/doc/src/ch_introduction.xml new file mode 100644 index 0000000..ca23168 --- /dev/null +++ b/lib/cosTime/doc/src/ch_introduction.xml @@ -0,0 +1,58 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Introduction to cosTime + Niclas Eklund + + 2000-01-31 + + ch_introduction.xml +
+ +
+ Overview +

The cosTime application is Time and TimerEvent Services compliant with the OMG + Services CosTime and CosTimerEvent. +

+ +
+ Purpose and Dependencies +

This application use calender:now_to_universal_time(Now) to create a + UTC. Hence, the underlying OS must deliver a correct result when calling + erlang:now().

+

cosTime is dependent on Orber, which provides CORBA functionality in an Erlang environment.

+

cosTimerEvent is dependent on Orber and cosNotification, + which provides CORBA functionality and Event handling in an Erlang environment.

+
+ +
+ Prerequisites +

To fully understand the concepts presented in the + documentation, it is recommended that the user is familiar + with distributed programming, CORBA, the Orber and cosNotification applications. +

+

Recommended reading includes CORBA, Fundamentals and Programming - Jon Siegel and Open Telecom Platform Documentation Set. It is also helpful to have read Concurrent Programming in Erlang.

+
+
+
+ diff --git a/lib/cosTime/doc/src/cosTime.xml b/lib/cosTime/doc/src/cosTime.xml new file mode 100644 index 0000000..8bc80f2 --- /dev/null +++ b/lib/cosTime/doc/src/cosTime.xml @@ -0,0 +1,174 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + cosTime + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 2000-01-31 + PA1 +
+ cosTime + The main module of the cosTime application + +

To get access to the record definitions for the structures use:

+-include_lib("cosTime/include/*.hrl").

+

This module contains the functions for starting and stopping the application.

+

This application use the time base 15 october 1582 00:00. + Performing operations using other time bases will not yield correct result.

+

The OMG CosTime specification defines the operation + secure_universal_time. As of today we cannot provide this functionality + considering the criteria demanded to fulfill the OMG specification.

+

When using this application, time and inaccuracy supplied by the user must + be given in number of 100 nano seconds. The + Time Displacement Factor is positive east of the meridian, while + those to the west are negative.

+

This application use calender:now_to_universal_time(Now) to create a + UTC. Hence, the underlying OS must deliver a correct result when calling + erlang:now().

+

When determining the inaccuracy of the system, the user should consider the + way the time objects will be used. Communicating with other ORB's, add a + substantial overhead and should be taken into consideration.

+
+ + + install_time() -> Return + Install the cosTime Time Service part application + + Return = ok | {'EXIT', Reason} + + +

This operation installs the cosTime Time Service part application.

+
+
+ + uninstall_time() -> Return + Uninstall the cosTime Time Service part application + + Return = ok | {'EXIT', Reason} + + +

This operation uninstalls the cosTime Time Service part application.

+
+
+ + install_timerevent() -> Return + Install the cosTime Timer Event Service part application + + Return = ok | {'EXIT', Reason} + + +

This operation installs the cosTime Timer Event Service part application.

+ +

The Timer Event Service part requires Time Service part and + cosEvent or the cosNotification application to be installed + first.

+
+
+
+ + uninstall_timerevent() -> Return + Uninstall the cosTime Timer Event Service part application + + Return = ok | {'EXIT', Reason} + + +

This operation uninstalls the cosTime Timer Event Service part application.

+
+
+ + start() -> Return + Start the cosTime application + + Return = ok | {error, Reason} + + +

This operation starts the cosTime application.

+
+
+ + stop() -> Return + Stop the cosTime application + + Return = ok | {error, Reason} + + +

This operation stops the cosTime application.

+
+
+ + start_time_service(Tdf, Inaccuracy) -> Return + Start a Time Service object + + Tdf = short() + Inaccuracy = ulonglong(), eq. #100 nano seconds + Return = ok | {'EXCEPTION', #'BAD_PARAM'{}} + + +

This operation starts a Time Service server. Please note that there + may only be exactly one Time Service active at a time. The Inaccuracy + parameter defines the inaccuracy the underlying OS will introduce. Remember + to take into account latency when passing time object between nodes.

+
+
+ + stop_time_service(TimeService) -> ok + Stop the target Time Service object + + TimeService = #objref + + +

This operation stops the Time Service object.

+
+
+ + start_timerevent_service(TimeService) -> ok + Start a Timer Event Service object + + TimeService = #objref + + +

This operation starts a Timer Event Service server. Please note that there + may only be exactly one Timer Event Service per node active at a time. The + supplied TimeServcie reference will be the object Timer Event Service + contacts to get access to a new UTC.

+
+
+ + stop_timerevent_service(TimerEventService) -> ok + Stop the target Timer Event Service object + + TimerEventService = #objref + + +

This operation stops the Timer Event Service object.

+
+
+
+ +
+ diff --git a/lib/cosTime/doc/src/fascicules.xml b/lib/cosTime/doc/src/fascicules.xml new file mode 100644 index 0000000..0678195 --- /dev/null +++ b/lib/cosTime/doc/src/fascicules.xml @@ -0,0 +1,18 @@ + + + + + + User's Guide + + + Reference Manual + + + Release Notes + + + Off-Print + + + diff --git a/lib/cosTime/doc/src/make.dep b/lib/cosTime/doc/src/make.dep new file mode 100644 index 0000000..69a584a --- /dev/null +++ b/lib/cosTime/doc/src/make.dep @@ -0,0 +1,22 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: CosTime_TIO.tex CosTime_TimeService.tex CosTime_UTO.tex \ + CosTimerEvent_TimerEventHandler.tex CosTimerEvent_TimerEventService.tex \ + book.tex ch_contents.tex ch_example.tex ch_install.tex \ + ch_introduction.tex cosTime.tex part.tex ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + diff --git a/lib/cosTime/doc/src/notes.gif b/lib/cosTime/doc/src/notes.gif new file mode 100644 index 0000000000000000000000000000000000000000..e000cca26a383722eca87f4d87a5841292b0b8ea GIT binary patch literal 2005 zcmc(e`(I0c1HeD$>})&L($>wE%9*B;E}M!dPv>-9341YwWX&zf>scU1zfBrl=I{N9;r;i^$ ze)#ZVWMt(1`}gnOy?gui?eOsMn>TM>zkWS5H1z7#tHHs+fq?;|(fIP^%NH+RJb(WD z*|TR)pFVx^ogEz=?d|P)y}qrjt+lnarKLru(`mKZ=H_ONMx$1%@7%d_`}XZyw{G3MdGp4N z8%<43jg5^B4Gq_?U%z(k+SRL9>+9>UT)9$LS65qGTT@eW`SRsUmo8nrc=5u83+KckWzORn^(EXDcf!&zw1P`t<2jr%qK=RFs#Ot5m9!Cr_R@apL&#<7H)K$BrF4 zdi1DLsXTJzNNH(lNl8g@aq;29hl`4e3JVJr3dNyAhYlV*SWr-qpP!$XmzSHHo0F3x zm&-FUGSbu2Wir|R{rmUr+qZY`-n6u|)YR0Jl$1St_9Q1K@7}$8*REYVckbM=V@Fa_ zl0+iezI}UQV&b-K+Y%BIwr<_JdGqE?n>KCSxN*aV4Pvo4E-p?a60KjqJ~lRX-MV!# zF)?e`u3fWc&Fa;wSFKvLa^=buD^>`F!ez^r2?T=0ix)>lMMXwNMnpvL`TX$k@UXD3 zkdTnz;NYO3Ac7zQ0|OT>TD_t~>&yScf|nl;PS)z!tt#o5`J!{InNIkDMn48x{RpYG`B=-}XBZ*Mm zJ0_E9VPQd|(M(NEQ52<8sT2wYK@bv&1j8@{LE!(5`#%Ezya3Qi0HOB$8kHskwQ`Hm z*OY4y(48X7__Y-+c}(wwXZqSxZHKVn+_d2V9bX<;)o5v8$jlB{tz6vnwfvQAiMw6t z0IXVSedvhT17nJCGJ_XCYT%)5*?chw5R9s25QXlX!e_sd7hr)!eyKroJ4zhgi|iRe z9BRcDRXkmj&PH5Z1EswZP1Yik}bX?KQfDMotrhur?Z`l6 z9SHWUks6^bPWsX|jEswdY)vps%VI@IAvY7W9?a_N?~xI!M!5pm(Ry5JJ;$6wSb!Kw z1Ofz-ES$>6ni1O}ScWTvR$Wsm*pF-~}^QqIoOkG6>BJ?$;+XE5N4m%cOVTgl$q1H6Cj2CRZ#Cwk*Z+A1}6-ZGIOnZ zriKR6JwuHEr#89IP&lU0d>}f|iQ2(xTebl}Km=JKc>w~{On}kI=M0e4E*aE>B!t(` zz!7B(z}xLdevm2fNGl*)VFk@hhEN1isQ4%eVdfhlo64C^B-c26^Z?T#Tc$&!YL-EE zsr_sc%})?_z}$saj#x(bLnO=CUH5f1>6}R!!dMZ|W9GTgpb9n@*5fiBqnDrne~DCT zx&%mdn3ma=CO4$ZCjP+)Zks2RB*+Tt`QEtb2g6+n+RKF1oJqVMUCo0mdGDTz#3Q^?T4648gGi%gvvJ#j{AlN2b z`m?E;VM>mcPQBC_Y6=8kn9B=CL=o-QgXt_x2k`|YJusL&`b=Pj%+?u4tr>8h24sDX + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTime Release Notes + Niclas Eklund + Niclas Eklund + + + + 2000-01-31 + A + notes.xml +
+ +
+ cosTime 1.1.7 + +
+ Improvements and New Features + + +

+ The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.

+

+ Own Id: OTP-8201 Aux Id:

+
+
+
+
+ +
+ cosTime 1.1.6 + +
+ Improvements and New Features + + +

Obsolete guards, e.g. record vs is_record, has been changed + to avoid compiler warnings.

+

Own id: OTP-7987

+
+
+
+
+ +
+ cosTime 1.1.5 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7837

+
+
+
+
+ +
+ cosTime 1.1.4 + +
+ Improvements and New Features + + +

Documentation source included in open source releases.

+

Own id: OTP-7595

+
+
+
+
+ +
+ cosTime 1.1.3 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7011

+
+
+
+
+ +
+ cosTime 1.1.2 + +
+ Improvements and New Features + + +

The documentation source has been converted from SGML to XML.

+

Own id: OTP-6754

+
+
+
+
+ +
+ cosTime 1.1.1 + +
+ Improvements and New Features + + +

Minor Makefile changes.

+

Own id: OTP-6701

+
+
+
+
+ +
+ cosTime 1.1 + +
+ Improvements and New Features + + +

The stub/skeleton-files generated by IC have been improved, + i.e., depending on the IDL-files, reduced the size of the + erl- and beam-files and decreased dependencies off Orber's + Interface Repository. It is necessary to re-compile all IDL-files + and use COS-applications, including Orber, compiled with + IC-4.2.

+

Own id: OTP-4576

+
+
+
+
+ +
+ cosTime 1.0.1.1 + +
+ Incompatibilities + + +

An includepath in CosTimerEvent.idl have been + changed. Hence, if you include this file you should check + your include paths for your IDL-file(s), i.e., add + the path to CosEventComm.idl.

+

Own Id: OTP-4093

+
+
+
+
+ +
+ cosTime 1.0.1 + +
+ Improvements and New Features + + +

First release of the cosTime application.

+

Own Id: -

+
+
+
+
+
+ diff --git a/lib/cosTime/doc/src/part.xml b/lib/cosTime/doc/src/part.xml new file mode 100644 index 0000000..fe6a50c --- /dev/null +++ b/lib/cosTime/doc/src/part.xml @@ -0,0 +1,39 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTime User's Guide + Niclas Eklund + + 2000-01-31 + 1.0 +
+ +

The cosTime application is an Erlang implementation of the OMG + CORBA Time and TimerEvent Services.

+
+ + + + +
+ diff --git a/lib/cosTime/doc/src/part_notes.xml b/lib/cosTime/doc/src/part_notes.xml new file mode 100644 index 0000000..3f45a11 --- /dev/null +++ b/lib/cosTime/doc/src/part_notes.xml @@ -0,0 +1,36 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTime Release Notes + Niclas Eklund + + 2000-01-31 + 1.0 +
+ +

The cosTime Application is an Erlang implementation of the OMG + CORBA Time and TimerEvent Services.

+
+ +
+ diff --git a/lib/cosTime/doc/src/ref_man.gif b/lib/cosTime/doc/src/ref_man.gif new file mode 100644 index 0000000000000000000000000000000000000000..b13c4efd53ff30209e94a832b9b141aefa01373e GIT binary patch literal 1530 zcmdVZdppw$0KoB|UD(ZKjLpudxl|bD5*~BdW(#wPxjQR!4XwvDQJz|2?rd%yODG+} zTS?d`8$ziw@9efjcbb8~ZJV`F`NeQj-Rb#--RW#!YS zPs_{8OG`^1KYmEb&dp9*T_4@VeSFc{Z zeEIUlix(;Hhy1Lrh+M1f0n>TM(S67S0;;O2u%F4=$ii+~`^0Klrkw{chQc_%8TvSw4P*9Mc zpP!ePmz$fLlanJ52(q)YuU)&AnVEUz%9YEPFK1+AT)K4W;>C;U>FH@{X%{YBNKH*W zfBt+*N=kBaa#B)KVq#)KLPC6e{JC@Ics$E-3+>FMd= z;o5R+g5Q78Vv{ zGTGeR+|10()YOzjBAJ+&7#kZK85t3YL|t879UUD4fq=*3wY9ZzI2;y>)zZ?^)YQaa zFd7;fYHDh#s;Vj~D$2^rC=?2bL?RFfI2;ax!IYGg6crVrP$&cf0fWIH5J*8m0r;Os z`p^I03jpi@P=FC!+v{kk6S6LO_!Iu)95sCwBtcqW%*9y*G+T7kk6cw&i6X!~u9ub^ z(;p_fv9U$vWTl#^q0-1BITpV6n#M{a{we|K$qn8tF1dhi2#U)iChGwf%c>!EMdamI z$h@1HHE$AU0uQ06DJaKq=RDnzU^TZiOigaDbX?9sbbG2Mo zru2uhl#`IQgUVf0v!Xj-d%-$1xRm>;TQmHNwcAfcM=qjwu=nh zQh;0;RMT@!2!f)5xXw7CWD^X8atslf08f~GlvPC&!u3CIvJ6wy=4qhoBAlk74dDIc za5tv{OoL_(_?n6N^K=DFVPbx|J4#5`n`9n$heG9OfAim6K_sx=yuqZzUrzW~%(8B5(t!Xl{Hb0?L6-vF=+wDe8$ zTT`s`Dq0fpfEZM3+{q@m}*YWuf-$-b$k$LLWEZK;Ee|dK!!GAvHA;V z*1da#TyGWrnurc+>Z42^g}P$+dV8CLlZ-G3$5&lvmrHi*;me*Y^_v!=AL*c_d4sqi z`SWVr{)P|6KptK|>YQR5CUyjEppnvPJ-9YQBBMdn(+)quWG#%To7OvoyB^9=`#bkY st1M+qtZTt#!ZD6_9%~hW^bvUb7(Sl{bx5FV=!1r@;+Z6>KNX<-3tg&0LjV8( literal 0 HcmV?d00001 diff --git a/lib/cosTime/doc/src/ref_man.xml b/lib/cosTime/doc/src/ref_man.xml new file mode 100644 index 0000000..18de68a --- /dev/null +++ b/lib/cosTime/doc/src/ref_man.xml @@ -0,0 +1,41 @@ + + + + +
+ + 20002009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTime Reference Manual + Niclas Eklund + + 2000-01-31 + 1.0 +
+ +

The cosTime application is an Erlang implementation of the OMG + CORBA Time and TimerEvent Services.

+
+ + + + + + +
+ diff --git a/lib/cosTime/doc/src/summary.html.src b/lib/cosTime/doc/src/summary.html.src new file mode 100644 index 0000000..78e383d --- /dev/null +++ b/lib/cosTime/doc/src/summary.html.src @@ -0,0 +1 @@ +Orber OMG Timer and TimerEvent Services. diff --git a/lib/cosTime/doc/src/user_guide.gif b/lib/cosTime/doc/src/user_guide.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6275a803db46bc56df2b31240f80e68a4eb28b5 GIT binary patch literal 1581 zcmd6mi9gc|0Kk8njctY*W^QwCJ{HX#%4V)-y(i>aMOY|Iy@!%dZA6YGb49u7IpPyu zxpLn_avvd{2!$L^&hlRW#rysR-_Q5+`C8dn8X8V>k`j;wKQ1gR%+Jry&CSiu&d$utOixe0fB$}JYHD(Fa$;g)e0+Rt zY;1INbYx^?czAedXlQV7@ZGz20|Nv7{r!D?eZ9TCJRYy7r>DESyQ{0Kv$M0KqocjO zy{)aSwY9aSrKP#Kxv8nCv9YnCq2bM&H}&=Pb#-;MwY4=hHPzMCuV25es;a82tgNW0 zc=_^WSy|bO7cWXnOG`>hii?Yjii!#g3kwPg^7Hfa^73+Xb8~WXva_?Zva&KWGoL+s z_Vnq~jEs!*^z{(M&Qxg*t zV`JkpXU-TI85tTH>g((4>FMd}>gwp|kVqtLZEYmX?x|!eX(Kl9CtEE3!%>OGRc>9)Rn&SYM zj~Y~*8(l`PO4G;6R;FqaD@X#~VMifcR)pt=DvF{Q3(>@Ud>(7)(V4{v)PmxVK~kPo zjj~AEyr<1v8vx#~Tk98U5_J`0L}~fU>RjhaAKM=MUf{g5m?T z)+IHOf7l%`QALwKCeyDj6SLD45WBagBU?Fw4{df%%9E4Y2u)Wk*W$nyCUXV^5gf*w zJcTmdm_5ACzSYODr)n2;x_FnPc`B(M`LXIbz9g71J`3n))Gq$bQK+sRivkPkZkj>F zXejb80{#?f()6mQl&jOcTB0m7HQ)B0eJ!3!3LG1z5Dy4!8UDX&qmZHiEZH4hCN$qe z4*)g+{|y}64a+3k1Ar7VS%DkXnyczs>8pr>ch^qPgriJZarAD;X*)P0t_Uea!m)bj zekgBBW+6d2l7{g|`zZIq7r_Y&symb`GN>UKUQ)c!TxUa0r_Gumy9Jeti%E)uL##a# zMGizq*jB%VA7Ip@(A3hq9YH69qL7NjkWRA2q5;hU`xYmEN)bB>aqrz!?T?Ynv*X-7 zk5PfTmt$8kTF6UOKy_o?XHYzxtkg%ZbG*StHxDNDsyD5c2a>x5vWvVCApVgu@XNF$})`XD-pCH3`9zE-Lj6@!*TS9lwVaP}h|-H2`m~ItYQE$0z|a zt4=D`BBR~(5MZ;L{+LQk#4$5Kz`eloKZBK-7eFm?OlZCy;GH~%L;($J;|e#tww(~b et1Zl|+ha7@T8X2%4FJEoWS?mjDfbqXtih~yb literal 0 HcmV?d00001 diff --git a/lib/cosTime/ebin/.gitignore b/lib/cosTime/ebin/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTime/examples/.gitignore b/lib/cosTime/examples/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTime/include/.gitignore b/lib/cosTime/include/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTime/info b/lib/cosTime/info new file mode 100644 index 0000000..7820f3f --- /dev/null +++ b/lib/cosTime/info @@ -0,0 +1,12 @@ +group: orb +short: Orber OMG Timer and TimerEvent Services + + + + + + + + + + diff --git a/lib/cosTime/priv/.gitignore b/lib/cosTime/priv/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTime/src/CosTime.cfg b/lib/cosTime/src/CosTime.cfg new file mode 100644 index 0000000..1aad9eb --- /dev/null +++ b/lib/cosTime/src/CosTime.cfg @@ -0,0 +1,6 @@ +{this, "CosTime::UTO"}. +{{handle_info, "CosTime::UTO"}, true}. +{this, "CosTime::TIO"}. +{{handle_info, "CosTime::TIO"}, true}. +{this, "CosTime::TimeService"}. +{{handle_info, "CosTime::TimeService"}, true}. diff --git a/lib/cosTime/src/CosTime.idl b/lib/cosTime/src/CosTime.idl new file mode 100644 index 0000000..2bf3268 --- /dev/null +++ b/lib/cosTime/src/CosTime.idl @@ -0,0 +1,59 @@ +#ifndef _COS_TIME_IDL_ +#define _COS_TIME_IDL_ + +#pragma prefix "omg.org" + +#include + +module CosTime { + enum TimeComparison { + TCEqualTo, + TCLessThan, + TCGreaterThan, + TCIndeterminate + }; + enum ComparisonType{ + IntervalC, + MidC }; + enum OverlapType { + OTContainer, + OTContained, + OTOverlap, + OTNoOverlap + }; + + exception TimeUnavailable {}; + interface TIO; // forward declaration + + interface UTO { + readonly attribute TimeBase::TimeT time; + readonly attribute TimeBase::InaccuracyT inaccuracy; + readonly attribute TimeBase::TdfT tdf; + readonly attribute TimeBase::UtcT utc_time; + + UTO absolute_time(); + TimeComparison compare_time( in ComparisonType comparison_type, in UTO uto ); + TIO time_to_interval( in UTO uto ); + TIO interval(); + }; + + interface TIO { + readonly attribute TimeBase::IntervalT time_interval; + + OverlapType spans ( in UTO time, out TIO overlap ); + OverlapType overlaps ( in TIO interval, out TIO overlap ); + UTO time (); + }; + + interface TimeService { + UTO universal_time() + raises(TimeUnavailable ); + UTO secure_universal_time() + raises(TimeUnavailable ); + UTO new_universal_time( in TimeBase::TimeT time, in TimeBase::InaccuracyT inaccuracy, in TimeBase::TdfT tdf ); + UTO uto_from_utc( in TimeBase::UtcT utc ); + TIO new_interval( in TimeBase::TimeT lower, in TimeBase::TimeT upper ); + }; +}; + +#endif diff --git a/lib/cosTime/src/CosTime_TIO_impl.erl b/lib/cosTime/src/CosTime_TIO_impl.erl new file mode 100644 index 0000000..d6d4ee8 --- /dev/null +++ b/lib/cosTime/src/CosTime_TIO_impl.erl @@ -0,0 +1,200 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosTime_TIO_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('CosTime_TIO_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include("cosTimeApp.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%% Attributes (external) +-export(['_get_time_interval'/2]). + +%% Interface functions +-export([spans/3, overlaps/3, time/2]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + + +%% Data structures +-record(state, {interval, + tdf, + timer}). +%% Data structures constructors +-define(get_InitState(I,T,TO), + #state{interval = I, + tdf = T, + timer = TO}). + +%% Data structures selectors +-define(get_IntervalT(S), S#state.interval). +-define(get_Lower(S), (S#state.interval)#'TimeBase_IntervalT'.lower_bound). +-define(get_Upper(S), (S#state.interval)#'TimeBase_IntervalT'.upper_bound). +-define(get_Tdf(S), S#state.tdf). +-define(get_TimerObj(S), S#state.timer). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +handle_info(_Info, State) -> + {noreply, State}. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([Interval, Tdf, Timer]) -> + {ok, ?get_InitState(Interval, Tdf, Timer)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------------------------ attributes ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_time_interval' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_time_interval'(_OE_THIS, State) -> + {reply, ?get_IntervalT(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : spans +%% Arguments: Time - UTO +%% Returns : CosTime::OverLapType - enum() +%% TIO - out-parameter. +%%----------------------------------------------------------- +spans(_OE_THIS, State, Time) -> + ?time_TypeCheck(Time, 'CosTime_UTO'), + case catch 'CosTime_UTO':'_get_utc_time'(Time) of + #'TimeBase_UtcT'{time = Btime, inacclo = InaccL, inacchi=InaccH} -> + Inaccuarcy = ?concat_TimeT(InaccH, InaccL), + BL = Btime - Inaccuarcy, + BU = Btime + Inaccuarcy, + L = ?get_Lower(State), + U = ?get_Upper(State), + {Type, NewL, NewU} = + if + L==BU -> + {'OTContainer',BL,BU}; + L>=BL, U= + {'OTContained',L,U}; + L=BL -> + {'OTOverlap',BL,U}; + L>=BL, L=BU -> + {'OTOverlap',L,BU}; + L>BU -> + {'OTNoOverlap',BU,L}; + true -> + {'OTNoOverlap',U,BL} + end, + {reply, + {Type, + 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=NewL, + upper_bound=NewU}, + ?get_Tdf(State), + ?get_TimerObj(State)], + [{pseudo,true}|?CREATE_OPTS])}, + State}; + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end. + + +%%----------------------------------------------------------% +%% function : overlaps +%% Arguments: Interval - TIO +%% Returns : CosTime::OverLapType - enum() +%% TIO - out-parameter. +%%----------------------------------------------------------- +overlaps(_OE_THIS, State, Interval) -> + ?time_TypeCheck(Interval, 'CosTime_TIO'), + case catch 'CosTime_TIO':'_get_time_interval'(Interval) of + #'TimeBase_IntervalT'{lower_bound=BL, upper_bound=BU} -> + L = ?get_Lower(State), + U = ?get_Upper(State), + {Type, NewL, NewU} = + if + L==BU -> + {'OTContainer',BL,BU}; + L>=BL, U= + {'OTContained',L,U}; + L=BL -> + {'OTOverlap',BL,U}; + L>=BL, L=BU -> + {'OTOverlap',L,BU}; + L>BU -> + {'OTNoOverlap',BU,L}; + true -> + {'OTNoOverlap',U,BL} + end, + {reply, + {Type, + 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=NewL, + upper_bound=NewU}, + ?get_Tdf(State), + ?get_TimerObj(State)], + [{pseudo,true}|?CREATE_OPTS])}, + State}; + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : time +%% Arguments: - +%% Returns : UTO +%%----------------------------------------------------------- +time(_OE_THIS, State) -> + L = ?get_Lower(State), + H = ?get_Upper(State), + Utc = #'TimeBase_UtcT'{time=(erlang:trunc(((H-L)/2))+L), + inacclo=L, + inacchi=H, + tdf=?get_Tdf(State)}, + {reply, + 'CosTime_UTO':oe_create([Utc, ?get_TimerObj(State)], [{pseudo,true}|?CREATE_OPTS]), + State}. + + +%%--------------- LOCAL FUNCTIONS ---------------------------- + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosTime/src/CosTime_TimeService_impl.erl b/lib/cosTime/src/CosTime_TimeService_impl.erl new file mode 100644 index 0000000..bac4ae0 --- /dev/null +++ b/lib/cosTime/src/CosTime_TimeService_impl.erl @@ -0,0 +1,180 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosTime_TimeService_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('CosTime_TimeService_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include("cosTimeApp.hrl"). + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%% Interface functions +-export([universal_time/2, secure_universal_time/2, new_universal_time/5]). +-export([uto_from_utc/3, new_interval/4]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + + +%% Data structures +-record(state, + {tdf, + inaccuracy}). +%% Data structures constructors +-define(get_InitState(T,I), + #state{tdf = T, + inaccuracy = I}). + +%% Data structures selectors +-define(get_Inaccuracy(S), S#state.inaccuracy). +-define(get_Tdf(S), S#state.tdf). + +%% Data structures modifiers + +%% MISC + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(_Info, State) -> + ?debug_print("INFO: ~p~n", [_Info]), + {noreply, State}. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([Tdf, Inaccuracy]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(Tdf, Inaccuracy)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : universal_time +%% Arguments: - +%% Returns : CosTime::UTO | +%% {'EXCEPTION", #'CosTime_TimeUnavailable'{}} +%% NOTE : cosTime:create_universal_time will raise the correct +%% exception. +%%----------------------------------------------------------- +universal_time(OE_THIS, State) -> + {ok, Time} = create_universal_time(), + Inaccuracy = ?get_Inaccuracy(State), + Utc = #'TimeBase_UtcT'{time=Time, inacclo = ?low_TimeT(Inaccuracy), + inacchi = ?high_TimeT(Inaccuracy), + tdf = ?get_Tdf(State)}, + {reply, 'CosTime_UTO':oe_create([Utc, OE_THIS], [{pseudo,true}|?CREATE_OPTS]), State}. + +%%----------------------------------------------------------% +%% function : secure_universal_time +%% Arguments: +%% Returns : {'EXCEPTION", #'CosTime_TimeUnavailable'{}} +%%----------------------------------------------------------- +secure_universal_time(_OE_THIS, _State) -> + corba:raise(#'CosTime_TimeUnavailable'{}). + +%%----------------------------------------------------------% +%% function : new_universal_time +%% Arguments: Time - TimeBase::TimeT +%% Inaccuracy - TimeBase::InaccuracyT inaccuracy +%% Tdf - TimeBase::TdfT +%% Returns : CosTime::UTO +%%----------------------------------------------------------- +new_universal_time(OE_THIS, State, Time, Inaccuracy, Tdf) when + is_integer(Time) andalso is_integer(Inaccuracy) andalso is_integer(Tdf) andalso + Tdf=<12 andalso Inaccuracy= + Utc = #'TimeBase_UtcT'{time=Time, inacclo = ?low_TimeT(Inaccuracy), + inacchi = ?high_TimeT(Inaccuracy), tdf = Tdf}, + {reply, 'CosTime_UTO':oe_create([Utc, OE_THIS], [{pseudo,true}|?CREATE_OPTS]), State}; +new_universal_time(_, _, _, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : uto_from_utc +%% Arguments: Utc - TimeBase::UtcT +%% Returns : CosTime::UTO +%%----------------------------------------------------------- +uto_from_utc(OE_THIS, State, Utc) when is_record(Utc, 'TimeBase_UtcT') -> + {reply, 'CosTime_UTO':oe_create([Utc, OE_THIS],[{pseudo,true}|?CREATE_OPTS]),State}; +uto_from_utc(_, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : new_interval +%% Arguments: Lower - TimeBase::TimeT +%% Upper - TimeBase::TimeT +%% Returns : CosTime::TIO +%%----------------------------------------------------------- +new_interval(OE_THIS, State, Lower, Upper) when is_integer(Lower) andalso is_integer(Upper) andalso + Lower= + {reply, 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=Lower, + upper_bound=Upper}, + ?get_Tdf(State), + OE_THIS], + [{pseudo,true}|?CREATE_OPTS]), State}; +new_interval(_, _, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%--------------- LOCAL FUNCTIONS ---------------------------- +%%-----------------------------------------------------------% +%% function : create_universal_utc +%% Arguments: - +%% Returns : TimeT or raises exception. +%% Effect : Creates a universal time; if time unavailable we +%% must raise CosTime_TimeUnavailable. +%% NOTE : 'datetime_to_gregorian_seconds' use year 0 as time +%% base. We want to use 15 october 1582, 00:00 as base. +%%------------------------------------------------------------ + +create_universal_time() -> + %% Time is supposed to be #100 nano-secs passed. + %% We add micro secs for a greater precision. + {MS,S,US} = now(), + case catch calendar:datetime_to_gregorian_seconds( + calendar:now_to_universal_time({MS,S,US})) of + Secs when is_integer(Secs) -> + {ok, (Secs-?ABSOLUTE_TIME_DIFF)*10000000 + US*10}; + _ -> + corba:raise(#'CosTime_TimeUnavailable'{}) + end. + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ + diff --git a/lib/cosTime/src/CosTime_UTO_impl.erl b/lib/cosTime/src/CosTime_UTO_impl.erl new file mode 100644 index 0000000..b35e215 --- /dev/null +++ b/lib/cosTime/src/CosTime_UTO_impl.erl @@ -0,0 +1,241 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosTime_UTO_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('CosTime_UTO_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include("cosTimeApp.hrl"). + + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%% Attributes (external) +-export(['_get_time'/2, + '_get_inaccuracy'/2, + '_get_tdf'/2, + '_get_utc_time'/2]). + +%% Interface functions +-export([absolute_time/2, compare_time/4]). +-export([time_to_interval/3, interval/2]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + + +%% Data structures +-record(state, {timer, utc}). +%% Data structures constructors +-define(get_InitState(U, T), #state{timer = T, utc = U}). + +%% Data structures selectors +-define(get_Time(S), (S#state.utc)#'TimeBase_UtcT'.time). +-define(get_Inaccuracy(S), ?concat_TimeT((S#state.utc)#'TimeBase_UtcT'.inacchi, + (S#state.utc)#'TimeBase_UtcT'.inacclo)). +-define(get_Tdf(S), (S#state.utc)#'TimeBase_UtcT'.tdf). +-define(get_Utc(S), S#state.utc). +-define(get_TimeObj(S), S#state.timer). + + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +handle_info(_Info, State) -> + {noreply, State}. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([Utc, TimeObj]) -> + {ok, ?get_InitState(Utc, TimeObj)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------------------------ attributes ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_time' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_time'(_OE_THIS, State) -> + {reply, ?get_Time(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_inaccuracy' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_inaccuracy'(_OE_THIS, State) -> + {reply, ?get_Inaccuracy(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_tdf' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_tdf'(_OE_THIS, State) -> + {reply, ?get_Tdf(State), State}. + +%%----------------------------------------------------------% +%% Attribute: '_get_utc_time' +%% Type : readonly +%% Returns : +%%----------------------------------------------------------- +'_get_utc_time'(_OE_THIS, State) -> + {reply, ?get_Utc(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : absolute_time +%% Arguments: - +%% Returns : UTO +%% NOTE : Return the base time to the relative time in the object. +%%----------------------------------------------------------- +absolute_time(_OE_THIS, State) -> + case catch 'CosTime_UTO':'_get_time'( + 'CosTime_TimeService':universal_time(?get_TimeObj(State)))+ + ?get_Time(State) of + UniTime when is_integer(UniTime) andalso UniTime =< ?max_TimeT -> + Utc=?get_Utc(State), + {reply, 'CosTime_UTO':oe_create([Utc#'TimeBase_UtcT'{time=UniTime}, + ?get_TimeObj(State)], + [{pseudo,true}|?CREATE_OPTS]), State}; + UniTime when is_integer(UniTime) -> + %% Oopss, overflow! + corba:raise(#'DATA_CONVERSION'{completion_status=?COMPLETED_NO}); + _ -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : compare_time +%% Arguments: Comparison_type - CosTime::ComparisonType +%% Uto - ObjRef +%% Returns : TimeComparison - 'TCEqualTo' | 'TCLessThan' | +%% 'TCGreaterThan' | 'TCIndeterminate' +%%----------------------------------------------------------- +compare_time(_OE_THIS, State, 'IntervalC', Uto) -> + ?time_TypeCheck(Uto, 'CosTime_UTO'), + case catch {'CosTime_UTO':'_get_time'(Uto), + 'CosTime_UTO':'_get_inaccuracy'(Uto)} of + {Time,Inaccuracy} when is_integer(Time) andalso is_integer(Inaccuracy) -> + OwnInacc = ?get_Inaccuracy(State), + if + ?get_Time(State)+OwnInacc < Time-Inaccuracy -> + {reply, 'TCLessThan', State}; + ?get_Time(State)-OwnInacc > Time+Inaccuracy -> + {reply, 'TCGreaterThan', State}; + ?get_Time(State) == Time, Inaccuracy==0, OwnInacc==0 -> + %% TimeService specification (july 1997, p14-7:2) states + %% that they are only equal if both UTO's Inaccuracy + %% equals zero. + {reply, 'TCEqualTo', State}; + true -> + {reply, 'TCIndeterminate', State} + end; + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +compare_time(_OE_THIS, State, 'MidC', Uto) -> + ?time_TypeCheck(Uto, 'CosTime_UTO'), + case catch 'CosTime_UTO':'_get_time'(Uto) of + Time when is_integer(Time) -> + if + ?get_Time(State) < Time -> + {reply, 'TCLessThan', State}; + ?get_Time(State) > Time -> + {reply, 'TCGreaterThan', State}; + true -> + {reply, 'TCEqualTo', State} + end; + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end; +compare_time(_OE_THIS, _State, _, _) -> + %% Comparison_type given not correct?! + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : time_to_interval +%% Arguments: +%% Returns : TIO +%%----------------------------------------------------------- +time_to_interval(_OE_THIS, State, Uto) -> + ?time_TypeCheck(Uto, 'CosTime_UTO'), + case catch 'CosTime_UTO':'_get_time'(Uto) of + Time when is_integer(Time) -> + OwnTime = ?get_Time(State), + if + Time > OwnTime -> + {reply, 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=OwnTime, + upper_bound=Time}, + ?get_Tdf(State), + ?get_TimeObj(State)], + [{pseudo,true}|?CREATE_OPTS]), State}; + true -> + {reply, 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=Time, + upper_bound=OwnTime}, + ?get_Tdf(State), + ?get_TimeObj(State)], + [{pseudo,true}|?CREATE_OPTS]), State} + end; + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end. + +%%----------------------------------------------------------% +%% function : interval +%% Arguments: +%% Returns : TIO +%%----------------------------------------------------------- +interval(_OE_THIS, State) -> + Lower = ?get_Time(State) - ?get_Inaccuracy(State), + Upper = ?get_Time(State) + ?get_Inaccuracy(State), + {reply, 'CosTime_TIO':oe_create([#'TimeBase_IntervalT'{lower_bound=Lower, + upper_bound=Upper}, + ?get_Tdf(State), + ?get_TimeObj(State)], + [{pseudo,true}|?CREATE_OPTS]), State}. + + +%%--------------- LOCAL FUNCTIONS ---------------------------- + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ + diff --git a/lib/cosTime/src/CosTimerEvent.cfg b/lib/cosTime/src/CosTimerEvent.cfg new file mode 100644 index 0000000..7f16197 --- /dev/null +++ b/lib/cosTime/src/CosTimerEvent.cfg @@ -0,0 +1,4 @@ +{this, "CosTimerEvent::TimerEventHandler"}. +{{handle_info, "CosTimerEvent::TimerEventHandler"}, true}. +{this, "CosTimerEvent::TimerEventService"}. +{{handle_info, "CosTimerEvent::TimerEventService"}, true}. diff --git a/lib/cosTime/src/CosTimerEvent.idl b/lib/cosTime/src/CosTimerEvent.idl new file mode 100644 index 0000000..b845862 --- /dev/null +++ b/lib/cosTime/src/CosTimerEvent.idl @@ -0,0 +1,45 @@ +#ifndef _COS_TIMEREVENT_IDL_ +#define _COS_TIMEREVENT_IDL_ + +#pragma prefix "omg.org" + +#include"CosEventComm.idl" +#include +#include + +module CosTimerEvent{ + + enum TimeType { + TTAbsolute, + TTRelative, + TTPeriodic + }; + enum EventStatus { + ESTimeSet, + ESTimeCleared, + ESTriggered, + ESFailedTrigger + }; + + struct TimerEventT { + TimeBase::UtcT utc; + any event_data; + }; + + interface TimerEventHandler { + readonly attribute EventStatus status; + boolean time_set( out CosTime::UTO uto ); + void set_timer( in TimeType time_type, in CosTime::UTO trigger_time ); + boolean cancel_timer(); + void set_data( in any event_data ); + }; + + interface TimerEventService { + + TimerEventHandler register( in CosEventComm::PushConsumer event_interface, in any data ); + void unregister( in TimerEventHandler timer_event_handler ); + CosTime::UTO event_time( in TimerEventT timer_event ); + }; +}; + +#endif diff --git a/lib/cosTime/src/CosTimerEvent_TimerEventHandler_impl.erl b/lib/cosTime/src/CosTimerEvent_TimerEventHandler_impl.erl new file mode 100644 index 0000000..5885691 --- /dev/null +++ b/lib/cosTime/src/CosTimerEvent_TimerEventHandler_impl.erl @@ -0,0 +1,304 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosTimerEvent_TimerEventHandler_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('CosTimerEvent_TimerEventHandler_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include("cosTimeApp.hrl"). + + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%% Attributes (external) +-export(['_get_status'/2]). +%% Interface functions +-export([time_set/2, set_timer/4]). +-export([cancel_timer/2, set_data/3]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + + +%% Data structures +-record(state, {parent, + parentPid, + event, + status = 'ESTimeCleared', + timer, + time, + timeObj, + myType, + pushConsumer, + uto}). +%% Data structures constructors +-define(get_InitState(P,PP,E,PC,TO), + #state{parent=P, + parentPid=PP, + event=E, + pushConsumer=PC, + timeObj=TO}). + +%% Data structures selectors +-define(get_Status(S), S#state.status). +-define(get_ParentPid(S), S#state.parentPid). +-define(get_Parent(S), S#state.parent). +-define(get_Event(S), S#state.event). +-define(get_Timer(S), S#state.timer). +-define(get_Time(S), S#state.time). +-define(get_TimeObj(S), S#state.timeObj). +-define(get_MyType(S), S#state.myType). +-define(get_PushConsumer(S), S#state.pushConsumer). +-define(get_Uto(S), S#state.uto). + +%% Data structures modifiers +-define(set_Status(S,V), S#state{status=V}). +-define(set_ParentPid(S,PP), S#state{parentPid=PP}). +-define(set_Parent(S,P), S#state{parent=P}). +-define(set_Event(S,E), S#state{event=E}). +-define(set_Timer(S,T), S#state{timer=T}). +-define(set_Time(S,T), S#state{time=T}). +-define(set_MyType(S,Ty), S#state{myType=Ty}). +-define(set_PushConsumer(S,P), S#state{pushConsumer=P}). +-define(set_Uto(S,U,Type), S#state{uto=U, myType=Type}). +-define(set_TimeData(S,U,Ty,Ti),S#state{uto=U, myType=Ty, time=Ti}). + +%% MISC +-define(not_Cancelled(S), S#state.status =/= 'ESTimeCleared'). +-define(is_TimeSet(S), S#state.status == 'ESTimeSet'). +-define(is_UtoSet(S), S#state.uto =/= undefined). +-define(is_NotAbsolute(S), S#state.myType =/= 'TTAbsolute'). + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(Info, State) -> + ?debug_print("INFO: ~p~n", [Info]), + case Info of + {'EXIT', Pid, _Reason} when Pid == ?get_ParentPid(State) -> + ?debug_print("PARENT TERMINATED with reason: ~p~n",[_Reason]), + {noreply, State}; + oe_event when ?not_Cancelled(State) -> + %% Push event + case catch 'CosEventComm_PushConsumer':push(?get_PushConsumer(State), + ?get_Event(State)) of + ok -> + ?debug_print("PUSHED: ~p~n", [?get_Event(State)]), + {noreply, ?set_Status(State, 'ESTriggered')}; + _Other-> + ?debug_print("FAILED PUSH: ~p ~p~n", [?get_Event(State), _Other]), + {noreply, ?set_Status(State, 'ESFailedTrigger')} + end; + oe_periodic_event when ?not_Cancelled(State) -> + %% Push event + catch 'CosEventComm_PushConsumer':push(?get_PushConsumer(State), + ?get_Event(State)), + {noreply, State}; + _ -> + {noreply, State} + end. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([Parent, ParentPid, PushConsumer, Event, TimeObj]) -> + process_flag(trap_exit, true), + {ok, ?get_InitState(Parent, ParentPid, Event, PushConsumer, TimeObj)}. + +terminate(_Reason, State) -> + clear_timer(State), + ok. + +%%----------------------------------------------------------- +%%------------------------ attributes ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% Attribute: '_get_status' +%% Type : readonly +%% Returns : 'ESTimeSet' | 'ESTimeCleared' | 'ESTriggered' | +%% 'ESFailedTrigger' +%%----------------------------------------------------------- +'_get_status'(_OE_THIS, State) -> + {reply, ?get_Status(State), State}. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : time_set +%% Arguments: - +%% Returns : {boolean(), CosTime::UTO} +%%----------------------------------------------------------- +time_set(_OE_THIS, State) when ?is_UtoSet(State) -> + {reply, {?is_TimeSet(State), ?get_Uto(State)}, State}; +time_set(_OE_THIS, State) -> + Utc = #'TimeBase_UtcT'{time=0, inacclo = 0,inacchi = 0, tdf = 0}, + {reply, + {?is_TimeSet(State), + 'CosTime_UTO':oe_create([Utc, ?get_TimeObj(State)], [{pseudo,true}|?CREATE_OPTS])}, + State}. + + +%%----------------------------------------------------------- +%% function : set_timer +%% Arguments: TimeType - 'TTAbsolute' | 'TTRelative' | 'TTPeriodic' +%% TriggerTime - CosTime::UTO +%% Returns : ok +%%----------------------------------------------------------- +set_timer(_OE_THIS, State, 'TTAbsolute', TriggerTime) -> + NewState = clear_timer(State), + ?time_TypeCheck(TriggerTime, 'CosTime_UTO'), + case catch {'CosTime_UTO':'_get_time'(TriggerTime), + 'CosTime_UTO':'_get_time'( + 'CosTime_TimeService':universal_time(?get_TimeObj(State)))} of + {Time, CurrentTime} when is_integer(Time) andalso is_integer(CurrentTime) andalso + Time > CurrentTime -> + %% Set a timer to send a message in (Time-CurrentTime)*10^-7 secs. + case timer:send_after(?convert_TimeT2TimerT(Time-CurrentTime), oe_event) of + {ok, TRef} -> + NewState1 = ?set_Timer(NewState, TRef), + NewState2 = ?set_Uto(NewState1, TriggerTime, 'TTAbsolute'), + ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(Time-CurrentTime)]), + {reply, ok, ?set_Status(NewState2, 'ESTimeSet')}; + _-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; + {Time, CurrentTime} when is_integer(Time) andalso is_integer(CurrentTime) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}); + _-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +set_timer(_OE_THIS, State, 'TTRelative', TriggerTime) -> + NewState = clear_timer(State), + ?time_TypeCheck(TriggerTime, 'CosTime_UTO'), + case catch {'CosTime_UTO':'_get_time'(TriggerTime), ?get_Time(State)} of + {0,OldTime} when ?is_NotAbsolute(NewState) andalso is_integer(OldTime) -> + %% Set a timer to send a message within Time*10^-7 secs + case timer:send_after(OldTime, oe_event) of + {ok, TRef} -> + NewState1 = ?set_Timer(NewState, TRef), + NewState2 = ?set_Uto(NewState1, TriggerTime, 'TTRelative'), + ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(OldTime)]), + {reply, ok, ?set_Status(NewState2, 'ESTimeSet')}; + _-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; + {UtoTime,_} when is_integer(UtoTime) -> + %% Set a timer to send a message within Time*10^-7 secs + Time = ?convert_TimeT2TimerT(UtoTime), + case timer:send_after(Time, oe_event) of + {ok, TRef} -> + NewState1 = ?set_Timer(NewState, TRef), + NewState2 = ?set_TimeData(NewState1, TriggerTime, + 'TTRelative', Time), + ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(Time)]), + {reply, ok, ?set_Status(NewState2, 'ESTimeSet')}; + _-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; + + _-> + {reply, {'EXCEPTION', #'BAD_PARAM'{completion_status=?COMPLETED_NO}}, NewState} + end; +set_timer(_OE_THIS, State, 'TTPeriodic', TriggerTime) -> + NewState = clear_timer(State), + ?time_TypeCheck(TriggerTime, 'CosTime_UTO'), + case catch {'CosTime_UTO':'_get_time'(TriggerTime), ?get_Time(State)} of + {0,OldTime} when ?is_NotAbsolute(NewState) andalso is_integer(OldTime) -> + %% Set a timer to send a message within Time*10^-7 secs + case timer:send_interval(OldTime, oe_periodic_event) of + {ok, TRef} -> + NewState1 = ?set_Timer(NewState, TRef), + NewState2 = ?set_Uto(NewState1, TriggerTime, 'TTPeriodic'), + ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(OldTime)]), + {reply, ok, ?set_Status(NewState2, 'ESTimeSet')}; + _-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; + {UtoTime,_} when is_integer(UtoTime) -> + %% Set a timer to send a message within Time*10^-7 secs + Time = ?convert_TimeT2TimerT(UtoTime), + case timer:send_interval(Time, oe_periodic_event) of + {ok, TRef} -> + NewState1 = ?set_Timer(NewState, TRef), + NewState2 = ?set_TimeData(NewState1, TriggerTime, + 'TTPeriodic', Time), + ?debug_print("TIMER SET: ~p~n", [?convert_TimeT2TimerT(Time)]), + {reply, ok, ?set_Status(NewState2, 'ESTimeSet')}; + _-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; + + _-> + {reply, {'EXCEPTION', #'BAD_PARAM'{completion_status=?COMPLETED_NO}}, NewState} + end; +set_timer(_OE_THIS, _State, _, _) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +%%----------------------------------------------------------% +%% function : cancel_timer +%% Arguments: - +%% Returns : boolean() +%%----------------------------------------------------------- +cancel_timer(_OE_THIS, State) -> + NewState=clear_timer(State), + case ?get_Status(NewState) of + 'ESTriggered' -> + {reply, false, NewState}; + 'ESFailedTrigger' -> + {reply, false, NewState}; + _ -> + {reply, true, ?set_Status(NewState, 'ESTimeCleared')} + end. + +%%----------------------------------------------------------% +%% function : set_data +%% Arguments: EventData - any# +%% Returns : ok +%%----------------------------------------------------------- +set_data(_OE_THIS, State, EventData) when is_record(EventData, any) -> + {reply, ok, ?set_Event(State, EventData)}; +set_data(_OE_THIS, _State, _EventData) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%--------------- LOCAL FUNCTIONS ---------------------------- +clear_timer(State) when ?get_Timer(State) == undefined -> + State; +clear_timer(State) -> + catch timer:cancel(?get_Timer(State)), + ?set_Timer(State, undefined). + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosTime/src/CosTimerEvent_TimerEventService_impl.erl b/lib/cosTime/src/CosTimerEvent_TimerEventService_impl.erl new file mode 100644 index 0000000..b324ecb --- /dev/null +++ b/lib/cosTime/src/CosTimerEvent_TimerEventService_impl.erl @@ -0,0 +1,118 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosTimerEvent_TimerEventService_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('CosTimerEvent_TimerEventService_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include("cosTimeApp.hrl"). + + +%%--------------- EXPORTS ------------------------------------ +%%--------------- External ----------------------------------- +%% Interface functions +-export([register/4, unregister/3, event_time/3]). + +%%--------------- gen_server specific exports ---------------- +-export([handle_info/2, code_change/3]). +-export([init/1, terminate/2]). + + +%% Data structures +-record(state, {timer}). +%% Data structures constructors +-define(get_InitState(T), + #state{timer=T}). + +%% Data structures selectors +-define(get_TimerObj(S), S#state.timer). + +%% Data structures modifiers + +%% MISC + +%%-----------------------------------------------------------% +%% function : handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_info(_Info, State) -> + ?debug_print("INFO: ~p~n", [_Info]), + {noreply, State}. + +%%----------------------------------------------------------% +%% function : init, terminate +%% Arguments: +%%----------------------------------------------------------- + +init([Timer]) -> + process_flag(trap_exit, true), + timer:start(), + {ok, ?get_InitState(Timer)}. + +terminate(_Reason, _State) -> + ok. + +%%----------------------------------------------------------- +%%------- Exported external functions ----------------------- +%%----------------------------------------------------------- +%%----------------------------------------------------------% +%% function : register +%% Arguments: EventInterface - CosEventComm::PushConsumer +%% Data - #any +%% Returns : TimerEventHandler - objref# +%%----------------------------------------------------------- +register(OE_THIS, State, EventInterface, Data) -> + {reply, + cosTime:start_event_handler([OE_THIS, self(),EventInterface, Data, + ?get_TimerObj(State)]), + State}. + +%%----------------------------------------------------------% +%% function : unregister +%% Arguments: TimerEventHandler - objref# +%% Returns : ok +%%----------------------------------------------------------- +unregister(_OE_THIS, State, TimerEventHandler) -> + catch corba:dispose(TimerEventHandler), + {reply, ok, State}. + +%%----------------------------------------------------------% +%% function : event_time +%% Arguments: TimerEvent - #'CosTimerEvent_TimerEventT'{utc, event_data} +%% Returns : CosTime::UTO +%%----------------------------------------------------------- +event_time(_OE_THIS, State, #'CosTimerEvent_TimerEventT'{utc=Utc}) -> + {reply, 'CosTime_UTO':oe_create([Utc],[{pseudo,true}]), State}. + + +%%--------------- LOCAL FUNCTIONS ---------------------------- + +%%--------------- MISC FUNCTIONS, E.G. DEBUGGING ------------- +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosTime/src/Makefile b/lib/cosTime/src/Makefile new file mode 100644 index 0000000..3b6f7ba --- /dev/null +++ b/lib/cosTime/src/Makefile @@ -0,0 +1,205 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug -W +endif + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(COSTIME_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/cosTime-$(VSN) + +EXTERNAL_INC_PATH = ../include + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + cosTime \ + CosTime_TIO_impl \ + CosTime_TimeService_impl \ + CosTime_UTO_impl \ + CosTimerEvent_TimerEventHandler_impl \ + CosTimerEvent_TimerEventService_impl \ + +ERL_FILES = $(MODULES:%=%.erl) +HRL_FILES = \ + cosTimeApp.hrl \ + +GEN_TIMEBASE_ERL_FILES = \ + oe_TimeBase.erl \ + TimeBase_IntervalT.erl \ + TimeBase_UtcT.erl + +GEN_COSTIME_ERL_FILES = \ + oe_CosTime.erl \ + CosTime_TIO.erl \ + CosTime_TimeService.erl \ + CosTime_TimeUnavailable.erl \ + CosTime_UTO.erl \ + +GEN_COSTIMEREVENT_ERL_FILES = \ + oe_CosTimerEvent.erl \ + CosTimerEvent_TimerEventHandler.erl \ + CosTimerEvent_TimerEventService.erl \ + CosTimerEvent_TimerEventT.erl \ + +GEN_TIMEBASE_HRL_FILES = \ + oe_TimeBase.hrl \ + TimeBase.hrl \ + +EXTERNAL_TIMEBASE_HRL_FILES = $(GEN_TIMEBASE_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_COSTIME_HRL_FILES = \ + oe_CosTime.hrl \ + CosTime.hrl \ + CosTime_TIO.hrl \ + CosTime_TimeService.hrl \ + CosTime_UTO.hrl + +EXTERNAL_COSTIME_HRL_FILES = $(GEN_COSTIME_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_COSTIMEREVENT_HRL_FILES = \ + oe_CosTimerEvent.hrl \ + CosTimerEvent.hrl \ + CosTimerEvent_TimerEventHandler.hrl \ + CosTimerEvent_TimerEventService.hrl \ + +EXTERNAL_COSTIMEREVENT_HRL_FILES = $(GEN_COSTIMEREVENT_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + + +GEN_ERL_FILES = \ + $(GEN_TIMEBASE_ERL_FILES) \ + $(GEN_COSTIME_ERL_FILES) \ + $(GEN_COSTIMEREVENT_ERL_FILES) + +GEN_HRL_FILES = \ + $(EXTERNAL_TIMEBASE_HRL_FILES) \ + $(EXTERNAL_COSTIME_HRL_FILES) \ + $(EXTERNAL_COSTIMEREVENT_HRL_FILES) \ + +GEN_FILES = \ + $(GEN_HRL_FILES) \ + $(GEN_ERL_FILES) + +TARGET_FILES = \ + $(GEN_TIMEBASE_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(GEN_COSTIME_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(GEN_COSTIMEREVENT_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +IDL_FILES = \ + TimeBase.idl \ + CosTime.idl \ + CosTimerEvent.idl + +APPUP_FILE = cosTime.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + +APP_FILE = cosTime.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosTime/ebin \ + -pa $(ERL_TOP)/lib/ic/ebin\ + -pa $(ERL_TOP)/lib/orber/ebin \ + -I$(ERL_TOP)/lib/cosEvent/src + +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -pa $(ERL_TOP)/lib/orber/include \ + -pa $(ERL_TOP)/lib/cosTime/include \ + -I$(ERL_TOP)/lib/cosTime/include \ + -I$(ERL_TOP)/lib/orber/include \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,"cosTime_$(COSTIME_VSN)"}' + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + +debug: + @${MAKE} TYPE=debug opt + +cleanb: + rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +clean: + rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +$(GEN_TIMEBASE_ERL_FILES) $(EXTERNAL_TIMEBASE_HRL_FILES): TimeBase.idl + erlc $(ERL_IDL_FLAGS) TimeBase.idl + mv $(GEN_TIMEBASE_HRL_FILES) $(EXTERNAL_INC_PATH) + +$(GEN_COSTIME_ERL_FILES) $(EXTERNAL_COSTIME_HRL_FILES): CosTime.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTime.cfg"}' CosTime.idl + mv $(GEN_COSTIME_HRL_FILES) $(EXTERNAL_INC_PATH) + +$(GEN_COSTIMEREVENT_ERL_FILES) $(EXTERNAL_COSTIMEREVENT_HRL_FILES): CosTimerEvent.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTimerEvent.cfg"}' CosTimerEvent.idl + mv $(GEN_COSTIMEREVENT_HRL_FILES) $(EXTERNAL_INC_PATH) + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(GEN_FILES) $(IDL_FILES) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DATA) $(GEN_HRL_FILES) $(RELSYSDIR)/include + +release_docs_spec: diff --git a/lib/cosTime/src/TimeBase.idl b/lib/cosTime/src/TimeBase.idl new file mode 100644 index 0000000..92a0c65 --- /dev/null +++ b/lib/cosTime/src/TimeBase.idl @@ -0,0 +1,22 @@ +#ifndef _TIMEBASE_IDL_ +#define _TIMEBASE_IDL_ + +#pragma prefix "omg.org" + +module TimeBase { + typedef unsigned long long TimeT; + typedef TimeT InaccuracyT; + typedef short TdfT; + struct UtcT { + TimeT time; // 8 octets + unsigned long inacclo; // 4 octets + unsigned short inacchi; // 2 octets + TdfT tdf; // 2 octets // total 16 octets. + }; + struct IntervalT { + TimeT lower_bound; + TimeT upper_bound; + }; +}; + +#endif diff --git a/lib/cosTime/src/cosTime.app.src b/lib/cosTime/src/cosTime.app.src new file mode 100644 index 0000000..191ee5f --- /dev/null +++ b/lib/cosTime/src/cosTime.app.src @@ -0,0 +1,30 @@ +{application, cosTime, + [{description, "The Erlang CosTime application"}, + {vsn, "%VSN%"}, + {modules, + [ + 'cosTime', + 'oe_TimeBase', + 'oe_CosTime', + 'oe_CosTimerEvent', + 'CosTime_TIO', + 'CosTime_TimeService', + 'CosTime_TimeUnavailable', + 'CosTime_UTO', + 'CosTimerEvent_TimerEventHandler', + 'CosTimerEvent_TimerEventService', + 'CosTimerEvent_TimerEventT', + 'TimeBase_IntervalT', + 'TimeBase_UtcT', + 'CosTime_TIO_impl', + 'CosTime_TimeService_impl', + 'CosTime_UTO_impl', + 'CosTimerEvent_TimerEventHandler_impl', + 'CosTimerEvent_TimerEventService_impl' + ] + }, + {registered, [oe_cosTimeSup, oe_cosTimerEventService]}, + {applications, [orber, stdlib, kernel]}, + {env, []}, + {mod, {cosTime, []}} +]}. diff --git a/lib/cosTime/src/cosTime.appup.src b/lib/cosTime/src/cosTime.appup.src new file mode 100644 index 0000000..f3eead4 --- /dev/null +++ b/lib/cosTime/src/cosTime.appup.src @@ -0,0 +1,6 @@ +{"%VSN%", + [ + ], + [ + ] +}. diff --git a/lib/cosTime/src/cosTime.erl b/lib/cosTime/src/cosTime.erl new file mode 100644 index 0000000..f4e6757 --- /dev/null +++ b/lib/cosTime/src/cosTime.erl @@ -0,0 +1,321 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosTime.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module(cosTime). + +%%--------------- INCLUDES ----------------------------------- +-include("cosTimeApp.hrl"). + +%%--------------- EXPORTS------------------------------------- +%% cosTime API external +-export([start/0, stop/0, + install_time/0, uninstall_time/0, + install_timerevent/0, uninstall_timerevent/0, + start_time_service/2, start_timerevent_service/1, stop_timerevent_service/1, + stop_time_service/1]). + +%% cosTime API internal +-export([create_link/3, get_option/3, type_check/2, start_event_handler/1]). + +%% Application callbacks +-export([start/2, init/1, stop/1]). + +%%--------------- DEFINES ------------------------------------ +-define(IDL_TIME_MODULES, ['oe_TimeBase', + 'oe_CosTime']). +-define(IDL_TIMEREVENT_MODULES, ['oe_CosTimerEvent']). +-define(SUPERVISOR_NAME, oe_cosTimeSup). +-define(SUP_FLAG, {simple_one_for_one,50,10}). +-define(SUP_TIMESERVICE_SPEC(T,I), + ['CosTime_TimeService',[T, I], + [{sup_child, true}, {regname, {global, "oe_cosTimeService"}}]]). +-define(SUP_TIMEREVENTSERVICE_SPEC(Args), + ['CosTimerEvent_TimerEventService', Args, + [{sup_child, true}, {regname, {local, 'oe_cosTimerEventService'}}]]). +-define(SUP_TIMEREVENTHANDLER_SPEC(Name, Args), + ['CosTimerEvent_TimerEventHandler',Args, + [{sup_child, true}, {regname, {global, Name}}]]). +-define(SUP_CHILD, + {"oe_TimeChild", + {cosTime,create_link, []}, + transient,100000,worker, + []}). + +%%------------------------------------------------------------ +%% function : install_*/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Install necessary data in the IFR DB +%%------------------------------------------------------------ + +install_time() -> + install_loop(?IDL_TIME_MODULES,[]). + +install_timerevent() -> + install_loop(?IDL_TIMEREVENT_MODULES,[]). + +install_loop([], _) -> + ok; +install_loop([H|T], Accum) -> + case catch H:'oe_register'() of + {'EXIT',{unregistered,App}} -> + ?write_ErrorMsg("Unable to register '~p'; application ~p not registered. +Trying to unregister ~p~n", [H,App,Accum]), + uninstall_loop(Accum, {exit, register}); + {'EXCEPTION',_} -> + ?write_ErrorMsg("Unable to register '~p'; propably already registered. +You are adviced to confirm this. +Trying to unregister ~p~n", [H,Accum]), + uninstall_loop(Accum, {exit, register}); + ok -> + install_loop(T, [H|Accum]); + _ -> + ?write_ErrorMsg("Unable to register '~p'; reason unknown. +Trying to unregister ~p~n", [H,Accum]), + uninstall_loop(Accum, {exit, register}) + end. + +%%------------------------------------------------------------ +%% function : uninstall_*/X +%% Arguments: - | Time (seconds) +%% Returns : ok | EXIT | EXCEPTION +%% Effect : Remove data related to cosTime from the IFR DB +%%------------------------------------------------------------ + +uninstall_time() -> + uninstall_loop(lists:reverse(?IDL_TIME_MODULES),ok). + +uninstall_timerevent() -> + uninstall_loop(lists:reverse(?IDL_TIMEREVENT_MODULES),ok). + +uninstall_loop([],ok) -> + ok; +uninstall_loop([],{exit, register}) -> + exit({?MODULE, "oe_register failed"}); +uninstall_loop([],{exit, unregister}) -> + exit({?MODULE, "oe_unregister failed"}); +uninstall_loop([],{exit, both}) -> + exit({?MODULE, "oe_register and, for some of those already registered, oe_unregister failed"}); +uninstall_loop([H|T], Status) -> + case catch H:'oe_unregister'() of + ok -> + uninstall_loop(T, Status); + _ when Status == ok -> + ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered. +You are adviced to confirm this.~n",[H]), + uninstall_loop(T, {exit, unregister}); + _ -> + ?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered. +You are adviced to confirm this.~n",[H]), + uninstall_loop(T, {exit, both}) + end. + +%%------------------------------------------------------------ +%% function : start/stop +%% Arguments: +%% Returns : +%% Effect : Starts or stops the cosTime application. +%%------------------------------------------------------------ + +start() -> + application:start(cosTime). +stop() -> + application:stop(cosTime). + +%%------------------------------------------------------------ +%% function : start +%% Arguments: Type - see module application +%% Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +start(_, _) -> + supervisor:start_link({local, ?SUPERVISOR_NAME}, cosTime, app_init). + + +%%------------------------------------------------------------ +%% function : stop +%% Arguments: Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +stop(_) -> + ok. + +%%------------------------------------------------------------ +%% function : start_time_service +%% Arguments: Tdf - time difference to UTC +%% Inaccuracy - ulonglong +%% Upper - inaccuracy high +%% Returns : +%% Effect : +%%------------------------------------------------------------ +start_time_service(Tdf, Inaccuracy) when is_integer(Tdf) andalso is_integer(Inaccuracy) -> + case supervisor:start_child(?SUPERVISOR_NAME, + ?SUP_TIMESERVICE_SPEC(Tdf, Inaccuracy)) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + _Other-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +start_time_service(_Tdf, _Inaccuracy) -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + + +%%------------------------------------------------------------ +%% function : stop_time_service +%% Arguments: Obj - TimeService objref +%% Returns : +%% Effect : +%%------------------------------------------------------------ +stop_time_service(Obj) -> + corba:dispose(Obj). + +%%------------------------------------------------------------ +%% function : start_timerevent_service +%% Arguments: Timer - Timer Service Reference +%% Returns : +%% Effect : +%%------------------------------------------------------------ +start_timerevent_service(Timer) -> + case supervisor:start_child(?SUPERVISOR_NAME, + ?SUP_TIMEREVENTSERVICE_SPEC([Timer])) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + _Other-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + +%%-----------------------------------------------------------% +%% function : stop_timerevent_service +%% Arguments: Obj - TimerEventService objref +%% Returns : +%% Effect : +%%------------------------------------------------------------ +stop_timerevent_service(Obj) -> + corba:dispose(Obj). + +%%-----------------------------------------------------------% +%% function : init +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%% Starting using create_factory/X +init(own_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}; +%% When starting as an application. +init(app_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}. + +%%-----------------------------------------------------------% +%% function : create_link +%% Arguments: Module - which Module to call +%% Env/ArgList - ordinary oe_create arguments. +%% Returns : +%% Exception: +%% Effect : Necessary since we want the supervisor to be a +%% 'simple_one_for_one'. Otherwise, using for example, +%% 'one_for_one', we have to call supervisor:delete_child +%% to remove the childs startspecification from the +%% supervisors internal state. +%%------------------------------------------------------------ +create_link(Module, Env, ArgList) -> + Module:oe_create_link(Env, ArgList). + +%%-----------------------------------------------------------% +%% function : start_event_handler +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +start_event_handler(Args) -> + Name = create_name(eventhandler), + case supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TIMEREVENTHANDLER_SPEC(Name,Args)) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + _Other-> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end. + + +%%-----------------------------------------------------------% +%% function : get_option +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +get_option(Key, OptionList, DefaultList) -> + case lists:keysearch(Key, 1, OptionList) of + {value,{Key,Value}} -> + Value; + _ -> + case lists:keysearch(Key, 1, DefaultList) of + {value,{Key,Value}} -> + Value; + _-> + {error, "Invalid option"} + end + end. + +%%-----------------------------------------------------------% +%% function : type_check +%% Arguments: Obj - objectrefernce to test. +%% Mod - Module which contains typeID/0. +%% Returns : 'ok' or raises exception. +%% Effect : +%%------------------------------------------------------------ + +type_check(Obj, Mod) -> + case catch corba_object:is_a(Obj,Mod:typeID()) of + true -> + ok; + _ -> + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}) + end. + + +%%-----------------------------------------------------------% +%% function : create_name/1 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +create_name(Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',MSec, '_', Sec, '_', USec]). + +%%--------------- END OF MODULE ------------------------------ + + diff --git a/lib/cosTime/src/cosTimeApp.hrl b/lib/cosTime/src/cosTimeApp.hrl new file mode 100644 index 0000000..f308281 --- /dev/null +++ b/lib/cosTime/src/cosTimeApp.hrl @@ -0,0 +1,76 @@ +%%---------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosTimeApp.hrl +%% Purpose : +%%---------------------------------------------------------------------- + + +%%--------------- INCLUDES ----------------------------------- +%% External +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). + +%% Local +-include("CosTimerEvent.hrl"). +-include("CosTime.hrl"). +-include("CosTimerEvent.hrl"). +-include("TimeBase.hrl"). + +-define(CREATE_OPTS, [{no_security, orber:partial_security()}]). + +-define(max_Inaccuracy, 281474976710655). +-define(max_TimeT, 18446744073709551616). + +%% The calendar module uses year 0 as base for gregorian functions. +%% 'ABSOULTE_TIME_DIFF' is #seconfs from year 0 until 15 october 1582, 00:00. +-define(ABSOLUTE_TIME_DIFF, 49947926400). +%% As above but diff year 0 to 00:00 GMT, January 1, 1970 +-define(STANDARD_TIME_DIFF, 62167219200). + +-define(split_TimeT(T), {((T band 16#0000ffff00000000) bsr 32), + (T band 16#00000000ffffffff)}). + +-define(high_TimeT(T), ((T band 16#0000ffff00000000) bsr 32)). +-define(low_TimeT(T), (T band 16#00000000ffffffff)). + +-define(concat_TimeT(H,L), ((H bsl 32) + L)). + +-define(convert_TimeT2TimerT(N), erlang:trunc(N*1.0e-4)). + +-define(write_ErrorMsg(Txt, Arg), +error_logger:error_msg("================ CosTime ==================~n" + Txt + "===========================================~n", + Arg)). + + + +-ifdef(debug). +-define(debug_print(F,A), + io:format("[LINE: ~p MODULE: ~p] "++F,[?LINE, ?MODULE]++A)). +-define(time_TypeCheck(O,M), 'cosTime':type_check(O,M)). +-else. +-define(debug_print(F,A), ok). +-define(time_TypeCheck(O,I), ok). +-endif. + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosTime/vsn.mk b/lib/cosTime/vsn.mk new file mode 100644 index 0000000..ac5e99a --- /dev/null +++ b/lib/cosTime/vsn.mk @@ -0,0 +1,9 @@ +COSTIME_VSN = 1.1.7 + +TICKETS = OTP-8201 + +TICKETS_1.1.6 = OTP-7987 + +TICKETS_1.1.5 = OTP-7837 + +TICKETS_1.1.4 = OTP-7595 diff --git a/lib/cosTransactions/AUTHORS b/lib/cosTransactions/AUTHORS new file mode 100644 index 0000000..6d03df4 --- /dev/null +++ b/lib/cosTransactions/AUTHORS @@ -0,0 +1,4 @@ +Original Authors: +Niclas Eklund + +Contributors: diff --git a/lib/cosTransactions/Makefile b/lib/cosTransactions/Makefile new file mode 100644 index 0000000..fddfa63 --- /dev/null +++ b/lib/cosTransactions/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(COSTRANSACTIONS_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- +# SUB_DIRECTORIES = src test examples doc/src +# At the moment we don't have any example programs. +SUB_DIRECTORIES = src doc/src + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/cosTransactions/doc/html/.gitignore b/lib/cosTransactions/doc/html/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTransactions/doc/man3/.gitignore b/lib/cosTransactions/doc/man3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTransactions/doc/man6/.gitignore b/lib/cosTransactions/doc/man6/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTransactions/doc/pdf/.gitignore b/lib/cosTransactions/doc/pdf/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTransactions/doc/src/CosTransactions_Control.xml b/lib/cosTransactions/doc/src/CosTransactions_Control.xml new file mode 100644 index 0000000..f4d9a38 --- /dev/null +++ b/lib/cosTransactions/doc/src/CosTransactions_Control.xml @@ -0,0 +1,73 @@ + + + + +
+ + 1999 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosTransactions_Control + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 1999-04-12 + PA1 +
+ CosTransactions_Control + This module implements the OMG CosTransactions::Control interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/include/CosTransactions.hrl").

+
+ + + get_coordinator(Control) -> Return + Return the Coordinator object associated with the target object + + Control = #objref + Return = Coordinator | {'EXCEPTION', E} + Coordinator = #objref + E = #'CosTransactions_Unavailable' {} + + +

This operation returns the Coordinator object associated with the target object. + The Coordinator supports operations for termination of a transaction.

+
+
+ + get_terminator(Control) -> Return + Return the Terminator object associated with the target object + + Control = #objref + Return = Terminator | {'EXCEPTION', E} + Terminator = #objref + E = #'CosTransactions_Unavailable' {} + + +

This operation returns the Terminator object associated with the target object. + The Terminator supports operations for termination of a transaction.

+
+
+
+ +
+ diff --git a/lib/cosTransactions/doc/src/CosTransactions_Coordinator.xml b/lib/cosTransactions/doc/src/CosTransactions_Coordinator.xml new file mode 100644 index 0000000..e172951 --- /dev/null +++ b/lib/cosTransactions/doc/src/CosTransactions_Coordinator.xml @@ -0,0 +1,229 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosTransactions_Coordinator + + + + 1999-04-12 + PA1 +
+ CosTransactions_Coordinator + This module implements the OMG CosTransactions::Coordinator interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/include/CosTransactions.hrl").

+
+ + + create_subtransaction(Coordinator) -> Control + Create a new subtransaction. + + Coordinator = #objref + Control = #objref + + +

A new subtransaction is created whose parent is the Coordinator argument.

+

Raises exception:

+ + 'SubtransactionsUnavailable' - if nested transactions are not supported. + 'Inactive' - if target transaction has already been prepared. + +
+
+ + get_transaction_name(Coordinator) -> Name + Return the name associated with the object. + + Coordinator = #objref + Name = string() of type "oe_name@machine_type_timestamp" + + +

Returns a printable string, which describe the transaction. The main purpose is to support debugging.

+
+
+ + get_parent_status(Coordinator) -> Status + Return the status of the parent transaction. + + Coordinator = #objref + Status = atom() + + +

Returns the status of the parent transaction + associated with the target object. If the target object is a top-level + transaction this operation is equivalent to get_status/1 operation.

+

Possible Status replies:

+ + 'StatusCommitted' + 'StatusCommitting' + 'StatusMarkedRollback' + 'StatusRollingBack' + 'StatusRolledBack' + 'StatusActive' + 'StatusPrepared' + 'StatusUnknown' + 'StatusNoTransaction' + 'StatusPreparing' + +
+
+ + get_status(Coordinator) -> Status + Return the status of the transaction associated with the target object + + Coordinator = #objref + Status = atom() + + +

Returns the status of the transaction associated with the target object.

+
+
+ + get_top_level_status(Coordinator) -> Status + Return the status of the top-level transaction associated with the target object + + Coordinator = #objref + Status = atom() + + +

Returns the status of the top-level transaction associated with the target object.

+
+
+ + hash_top_level_tran(Coordinator) -> Return + Return a hash code for the top-level transaction associated with the target object + + Coordinator = #objref + Return = integer() + + +

Returns a hash code for the top-level transaction + associated with the target object. Equals the operation + hash_transaction/1 if the target object is a top-level transaction.

+
+
+ + hash_transaction(Coordinator) -> Return + Return a hash code for the transaction associated with the target object. + + Coordinator = #objref + Return = integer() + + +

Returns a hash code for the transaction associated with the target object.

+
+
+ + is_descendant_transaction(Coordinator, OtherCoordinator) -> Return + Return a boolean which indicates whether the transaction associated with the target object is a descendant of the transaction associated with the parameter object + + Coordinator = #objref + OtherCoordinator = #objref + Return = Boolean + + +

Returns true if the transaction associated with the target object is a + descendant of the transaction associated with the parameter object.

+
+
+ + is_same_transaction(Coordinator, OtherCoordinator) -> Return + Return true if the transaction associated with the target object is related to the transaction associated with the parameter object + + Coordinator = #objref + OtherCoordinator = #objref + Return = Boolean + + +

Returns true if the transaction associated with the target object is + related to the transaction associated with the parameter object.

+
+
+ + is_top_level_transaction(Coordinator) -> Return + Return true if the transaction associated with the target object is a top-level transaction + + Coordinator = #objref + Return = Boolean + + +

Returns true if the transaction associated with the target object is + a top-level transaction.

+
+
+ + register_resource(Coordinator, Resource) -> RecoveryCoordinator + Register the parameter Resourceobject as a participant in the transaction associated with the target object + + Coordinator = #objref + Resource = #objref + RecoveryCoordinator = #objref + + +

This operation registers the parameter Resource object as a participant in the + transaction associated with the target object. The RecoveryCoordinator returned + by this operation can be used by this Resource during recovery.

+ +

The Resources will be called in FIFO-order when preparing or committing. + Hence, be sure to register the Resources in the correct order.

+
+

Raises exception:

+ + 'Inactive' - if target transaction has already been prepared. + +
+
+ + register_subtran_aware(Coordinator, SubtransactionAwareResource) -> Return + Register the parameter SubtransactionAwareResourceobject such that it will be notified when the transaction, associated wit the target object, has committed or rolled back + + Coordinator = #objref + Return = ok + + +

This operation registers the parameter SubtransactionAwareResource object such that + it will be notified when the transaction, associated wit the target object, + has committed or rolled back.

+ +

The Resources will be called in FIFO-order. + Hence, be sure to register the Resources in the correct order.

+
+
+
+ + rollback_only(Coordinator) -> Return + Modify the transaction associated with the target object so the only possible outcome is to rollback the transaction + + Coordinator = #objref + Return = ok + + +

The transaction associated with the target object is modified so the only + possible outcome is to rollback the transaction.

+
+
+
+ +
+ diff --git a/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml b/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml new file mode 100644 index 0000000..4b870f4 --- /dev/null +++ b/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml @@ -0,0 +1,82 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosTransactions_­RecoveryCoordinator + ..._RecoveryCoordinator + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 1999-04-12 + PA1 +
+ CosTransactions_RecoveryCoordinator + This module implements the OMG CosTransactions::RecoveryCoordinator interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/include/CosTransactions.hrl").

+
+ + + replay_completion(RecoveryCoordinator, Timeout, Resource) -> Return + Return the current status of the transaction + + RecoveryCoordinator = #objref + Timeout = integer(), milliseconds | 'infinity' + Resource = #objref + Return = Status | {'EXCEPTION', E} + E = #'CosTransactions_NotPrepared'{} + Status = atom() + + +

The RecoveryCoordinator object is returned by the operation + CosTransactions_Coordinator:register_resource/3. The replay_completion/2 + may only be used by the registered Resource and returns the current status + of the transaction. The operation is used when recovering after a failure.

+

Possible Status replies:

+ + 'StatusCommitted' + 'StatusCommitting' + 'StatusMarkedRollback' + 'StatusRollingBack' + 'StatusRolledBack' + 'StatusActive' + 'StatusPrepared' + 'StatusUnknown' + 'StatusNoTransaction' + 'StatusPreparing' + + +

replay_completion/3 is blocking and may cause dead-lock if a child + calls this function at the same time as its parent invokes an operation + on the child. Dead-lock will not occur if the timeout has any value except 'infinity'.

+

If the call is external incoming (intra-ORB) the timeout will not be activated. + Hence, similar action must be taken if the Resource resides on another vendors ORB.

+
+
+
+
+ +
+ diff --git a/lib/cosTransactions/doc/src/CosTransactions_Resource.xml b/lib/cosTransactions/doc/src/CosTransactions_Resource.xml new file mode 100644 index 0000000..1f091a5 --- /dev/null +++ b/lib/cosTransactions/doc/src/CosTransactions_Resource.xml @@ -0,0 +1,128 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosTransactions_Resource + + + + 1999-04-12 + PA1 +
+ CosTransactions_Resource + This module implements the OMG CosTransactions::Resource interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/include/CosTransactions.hrl").

+
+ + + commit(Resource) -> Return + Instruct the target object to commit the transaction + + Resource = #objref + Return = ok | {'EXCEPTION', E} + E = #'CosTransactions_NotPrepared'{} | #'CosTransactions_HeuristicRollback'{} | #'CosTransactions_HeuristicMixed'{} | #'CosTransactions_HeuristicHazard'{} + + +

This operation instructs the Resource to commit all changes made as a part of the transaction.

+

The Resource can raise:

+ + Heuristic Exception - if a Heuristic decision is made which differ + from the true outcome of the transaction. The Resource must remember + the Heuristic outcome until the forget operation is performed. + +
+
+ + commit_one_phase(Resource) -> Return + Instruct the target object to commit the transaction + + Resource = #objref + Return = ok | {'EXCEPTION', E} + E = #'CosTransactions_HeuristicHazard'{} | #'CosTransactions_TransactionRolledBack'{} + + +

If possible, the Resource should commit all changes made as part of the transaction, + else it should raise the TRANSACTION_ROLLEDBACK exception. + This operation can only be used if the Resource is the only child of its parent.

+
+
+ + forget(Resource) -> Return + Instruct the target object to forget any heuristic decisions + + Resource = #objref + Return = ok + + +

This operation informs the Resource that it is safe to forget any Heuristic + decisions and the knowledge of the transaction.

+
+
+ + prepare(Resource) -> Return + Instruct the target object to begin the two-phase commit protocol + + Resource = #objref + Return = Vote | {'EXCEPTION', E} + Vote = 'VoteReadOnly' | 'VoteCommit' | 'VoteRollback' + E = #'CosTransactions_HeuristicMixed'{} | #'CosTransactions_HeuristicHazard'{} + + +

This operation is invoked on the Resource to begin the two-phase commit protocol.

+

The Resource can reply:

+ + 'VoteReadOnly' - if no persistent data has been modified by the transaction. + The Resource can forget all knowledge of the transaction. + 'VoteCommit' - if the Resource has been prepared and is able to write all the + data needed to commit the transaction to stable storage. + 'VoteRollback' - under any circumstances but must do so if none of the alternatives above + are applicable. + Heuristic Exception - if a Heuristic decision is made which differ + from the true outcome of the transaction. The Resource must remember + the Heuristic outcome until the forget operation is performed. + +
+
+ + rollback(Resource) -> Return + Instruct the target object to rollback the transaction + + Resource = #objref + Return = ok | {'EXCEPTION', E} + E = #'CosTransactions_HeuristicCommit'{} | #'CosTransactions_HeuristicMixed'{} | #'CosTransactions_HeuristicHazard'{} + + +

This operation instructs the Resource to rollback all changes made as a part of the transaction.

+

The Resource can raise:

+ + Heuristic Exception - if a Heuristic decision is made which differ + from the true outcome of the transaction. The Resource must remember + the Heuristic outcome until the forget operation is performed. + +
+
+
+ +
+ diff --git a/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml b/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml new file mode 100644 index 0000000..2c7b6b5 --- /dev/null +++ b/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml @@ -0,0 +1,75 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosTransactions_­SubtransactionAwareResource + ..._SubtransactionAwareResource + + + + 1999-04-12 + PA1 +
+ CosTransactions_SubtransactionAwareResource + This module implements the OMG CosTransactions::SubtransactionAwareResource interface. + +

This interface inherits the CosTransactions::Resource interface. Hence, + it must also support all operations defined in the Resource interface.

+

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/include/CosTransactions.hrl").

+
+ + + commit_subtransaction(SubtransactionAwareResource, Coordinator) -> Return + Notify the target object that the transaction has committed + + SubtransactionAwareResource = #objref + Coordinator = #objref + Return = ok + + +

If the SubtransactionAwareResource have been registered with a subtransaction + using the operation CosTransactions_Coordinator:register_subtran_aware/2, + it will be notified when the transaction has committed.

+ +

The results of a committed subtransaction are relative to the completion of its ancestor + transactions, that is, these results can be undone if any ancestor transaction is rolled back.

+
+
+
+ + rollback_subtransaction(SubtransactionAwareResource) -> Return + Notify the target object that the transaction has been rolled back + + SubtransactionAwareResource = #objref + Return = ok + + +

If the SubtransactionAwareResource have been registered with a transactions + using the operation CosTransactions_Coordinator:register_subtran_aware/2 + it will be notified when the transaction has rolled back.

+
+
+
+ +
+ diff --git a/lib/cosTransactions/doc/src/CosTransactions_Synchronization.xml b/lib/cosTransactions/doc/src/CosTransactions_Synchronization.xml new file mode 100644 index 0000000..62d19fe --- /dev/null +++ b/lib/cosTransactions/doc/src/CosTransactions_Synchronization.xml @@ -0,0 +1,69 @@ + + + + +
+ + 1999 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosTransactions_Synchronization + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 1999-04-12 + PA1 +
+ CosTransactions_Synchronization + This module implements the OMG CosTransactions::Synchronization interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/CosTransactions.hrl").

+
+ + + before_completion(Synchronization) -> Return + Notify the target object that the transaction is about to enter the prepare phase + + Synchronization = #objref + Return = ok + + +

If the target object is a transaction using the operation register_synchronization/2 + it will be notified to perform necessary processing prior to the prepare phase.

+
+
+ + after_completion(Synchronization) -> Return + Notify the target object that the transaction is completed + + Synchronization = #objref + Return = ok + + +

If the target object is a transaction using the operation register_synchronization/2 + it will be notified to perform necessary processing after terminating the transaction.

+
+
+
+ +
+ diff --git a/lib/cosTransactions/doc/src/CosTransactions_Terminator.xml b/lib/cosTransactions/doc/src/CosTransactions_Terminator.xml new file mode 100644 index 0000000..0a8ebe6 --- /dev/null +++ b/lib/cosTransactions/doc/src/CosTransactions_Terminator.xml @@ -0,0 +1,72 @@ + + + + +
+ + 1999 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosTransactions_Terminator + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 1999-04-12 + PA1 +
+ CosTransactions_Terminator + This module implements the OMG CosTransactions::Terminator interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/include/CosTransactions.hrl").

+
+ + + commit(Terminator, ReportHeuristics) -> Return + Try to commit a transaction + + Terminator = #objref + ReportHeuristics = boolean() + Return = ok | {'EXCEPTION', E} + E = #'CosTransactions_HeuristicMixed'{} | #'CosTransactions_HeuristicHazrd'{} | #'CosTransactions_TransactionRolledBack'{} + + +

This operation initiates the two-phase commit protocol. If the transaction has not been marked + 'rollback only' and all the participants agree to commit, the operation terminates normally. Otherwise, + the TransactionRolledBack is raised. If the parameter ReportHeuristics is true and inconsistent + outcomes by raising an Heuristic Exception.

+
+
+ + rollback(Terminator) -> Return + Rollback a transaction + + Terminator = #objref + Return = ok + + +

This operation roles back the transaction.

+
+
+
+ +
+ diff --git a/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml b/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml new file mode 100644 index 0000000..181801c --- /dev/null +++ b/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml @@ -0,0 +1,64 @@ + + + + +
+ + 1999 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosTransactions_­TransactionFactory + ..._TransactionFactory + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 1999-04-12 + PA1 +
+ CosTransactions_TransactionFactory + This module implements the OMG CosTransactions::TransactionFactory interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/include/CosTransactions.hrl").

+
+ + + create(TransactionFactory, Timeout) -> Control + Create a new top-level transaction + + TransactionFactory = #objref + Timeout = integer() + Control = #objref + + +

This operation creates a new top-level transaction.

+

The Timeout argument can be:

+ + 0 - no timeout. + N (integer() > 0) - the transaction will be subject to being rolled back + if it does not complete before N seconds have elapsed. + +
+
+
+ +
+ diff --git a/lib/cosTransactions/doc/src/CosTransactions_TransactionalObject.xml b/lib/cosTransactions/doc/src/CosTransactions_TransactionalObject.xml new file mode 100644 index 0000000..0e836f5 --- /dev/null +++ b/lib/cosTransactions/doc/src/CosTransactions_TransactionalObject.xml @@ -0,0 +1,42 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosTransactions_TransactionalObject + + + + 1999-04-12 + PA1 +
+ CosTransactions_TransactionalObject + This module implements the OMG CosTransactions::TransactionalObject interface. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/CosTransactions.hrl").

+

The TransactionalObject interface is used by an object to indicate that it is transactional. + By supporting this interface, an object indicates that it wants the transaction context associated with + the client to be associated with all operation on its interface. No operations are defined.

+
+ +
+ diff --git a/lib/cosTransactions/doc/src/Makefile b/lib/cosTransactions/doc/src/Makefile new file mode 100644 index 0000000..eab52d3 --- /dev/null +++ b/lib/cosTransactions/doc/src/Makefile @@ -0,0 +1,229 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(COSTRANSACTIONS_VSN) +APPLICATION=cosTransactions + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + cosTransactions.xml \ + CosTransactions_Control.xml \ + CosTransactions_Coordinator.xml \ + CosTransactions_RecoveryCoordinator.xml \ + CosTransactions_Resource.xml \ + CosTransactions_SubtransactionAwareResource.xml \ + CosTransactions_Terminator.xml \ + CosTransactions_TransactionFactory.xml +# CosTransactions_Synchronization.xml + +XML_PART_FILES = \ + part.xml \ + part_notes.xml +XML_CHAPTER_FILES = \ + ch_contents.xml \ + ch_introduction.xml \ + ch_install.xml \ + ch_example.xml \ + ch_skeletons.xml \ + notes.xml + +BOOK_FILES = book.xml + +TECHNICAL_DESCR_FILES = + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif + +PS_FILES = + +# ---------------------------------------------------- + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf + +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(INTERNAL_HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTML_FILES) $(MAN3_FILES) + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) + +endif + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +$(INDEX_TARGET): $(INDEX_SRC) + sed -e 's;%VSN%;$(VSN);' $(INDEX_SRC) > $(INDEX_TARGET) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + +release_spec: + diff --git a/lib/cosTransactions/doc/src/book.gif b/lib/cosTransactions/doc/src/book.gif new file mode 100644 index 0000000000000000000000000000000000000000..94b38687920c5386f0d90df2cfc962d66f52fbce GIT binary patch literal 1081 zcmV-91jhSENk%v~VJrYQ0K@U3Z&d%1>*52OU z=jZ3|@9+2b_W%F@EC2ui04xAE000I5ARvxpX`Uh%Eez$Ma2!{|XMe{g?|T;9x5JA^ zG%bL@N^vRj5RkV9bLkO4ZPIBmas5oR#mf&V1Q#(0YhcjmXe*9~d=7a)?vMy(=-KE* z8yQRzT~`AL3l4P-3kL!Lf=d(yg_TGJLq#4K5D7Jwg%4&P850c&1Y@8d0)H_S5pFPj z7ZR$K4m$^o4iXXx39coCpaZff8wUU$784g63O)Mnh1d zM*Ony;LwB#3?8W4Fn~dfDxggNp6C!kf(B*{AQb3^!o#OZ2{2Ij__0FI3O->S0!o2G zg@f-96evKTsnY>a2Pj~$%K;+++!`!k(;yCksSK!^1M@%uPY44fe1t$i?MDI+c2ZbC za|F=4KrQICaN${m0^A%h5YV8o0a~3adU`fEQr`1qssBIw;^v!UF;k;yW-v@4+eo>JYd}fHVVU z5gLf*p9x%mVi^DlSTI8WPNw|_zy%J@^^O%t7;wu6|1F@62n+%+n+O+(7C~JYKp}tz zPXIAiOdhnDfD0a6fWQkLNGO6;!$2WQfj6jx)&W2YPymny2!Ox=N)36z-FBgSXr4c6dN%+LI-06;0gjrH4CDHEr=iiO;mnh?Fk3i5Wq1C#9AnbqG>3C zxFaCoE>b2iV1odev}UfA7}V< + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTransactions + Niclas Eklund + + 1999-04-14 + 2.0 +
+ + + cosTransactions + + + + + + + + + + + + + + +
+ diff --git a/lib/cosTransactions/doc/src/ch_contents.xml b/lib/cosTransactions/doc/src/ch_contents.xml new file mode 100644 index 0000000..21cefda --- /dev/null +++ b/lib/cosTransactions/doc/src/ch_contents.xml @@ -0,0 +1,74 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The cosTransactions Application + Niclas Eklund + + 1999-04-14 + B + ch_contents.xml +
+ +
+ Content Overview +

The cosTransactions documentation is divided into three sections: +

+ + +

PART ONE - The User's Guide +

+Description of the cosTransactions Application including + services and a small tutorial demonstrating + the development of a simple service.

+
+ +

PART TWO - Release Notes +

+A concise history of cosTransactions.

+
+ +

PART THREE - The Reference Manual +

+ A quick reference guide, including a + brief description, to all the functions available in cosTransactions.

+
+
+
+ +
+ Brief Description of the User's Guide +

The User's Guide contains the following parts:

+ + +

cosTransactions overview

+
+ +

cosTransactions installation

+
+ +

A tutorial example

+
+
+
+
+ diff --git a/lib/cosTransactions/doc/src/ch_example.xml b/lib/cosTransactions/doc/src/ch_example.xml new file mode 100644 index 0000000..6535016 --- /dev/null +++ b/lib/cosTransactions/doc/src/ch_example.xml @@ -0,0 +1,280 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTransactions Examples + + + 1999-04-27 + A + ch_example.xml +
+ +
+ A Tutorial on How to Create a Simple Service + +
+ Interface design +

To use the cosTransactions application participants must be implemented. + There are two types of participants:

+ + CosTransactions_Resource - operations used to commit or rollback resources. + CosTransactions_SubtransactionAwareResource - + operations used when the resources want to be notified when a subtransaction commits. + This interface inherits the CosTransactions_Resource + +

The interfaces for these participants are defined in CosTransactions.idl

+
+ +
+ Generating a Participant Interface +

We start by creating an interface which inherits from CosTransactions::Resource. Hence, + we must also implement all operations defined in the Resource interface. The IDL-file could look like:

+ + +module ownResourceImpl { + + interface ownInterface:CosTransactions::Resource { + + void ownFunctions(in any NeededArguments) + raises(Systemexceptions,OwnExceptions); + + }; +}; + +#endif + ]]> +

Run the IDL compiler on this file by calling the ic:gen/1 function. + This will produce the API named ownResourceImpl_ownInterface.erl. + After generating the API stubs and the server skeletons it is time to + implement the servers and if no special options are sent + to the IDl compiler the file name is ownResourceImpl_ownInterface_impl.erl.

+
+ +
+ Implementation of Participant interface +

If the participant is intended to be a plain Resource, we must implement the following operations:

+ + prepare/1 - this operation is invoked on the Resource to begin the two-phase commit protocol. + rollback/1 - this operation instructs the Resource to rollback all changes made as a part of the transaction. + commit/1 - this operation instructs the Resource to commit all changes made as a part of the transaction. + commit_one_phase/1 - if possible, the Resource should commit all changes made as part of the transaction. + This operation can only be used if the Resource is the only child of its parent. + forget/1 - this operation informs the Resource that it is safe to forget any + Heuristic decisions is a unilateral decision by a participant to commit or rollback without receiving the true outcome of the transaction from its parents coordinator.and the knowledge of the transaction. + ownFunctions - all application specific operations. + +

If the participant wants to be notified when a subtransaction commits, we must also implement the following operations + (besides the operations above):

+ + commit_subtransaction/2 - if the SubtransactionAwareResource have been registered + with a transactions using the operation CosTransactions_Coordinator:register_subtran_aware/2 it will + be notified when the transaction has + committed. + rollback_subtransaction/1 - if the SubtransactionAwareResource have been registered + with a transactions using the operation CosTransactions_Coordinator:register_subtran_aware/2 + it will be notified when the transaction has + rolled back. + + +

The results of a committed subtransaction are relative to the completion of its ancestor transactions, + that is, these results can be undone if any ancestor transaction is rolled back.

+
+
+ +
+ Participant Operations Behavior +

Each application participant must behave in a certain way to ensure that the two-phase commit protocol + can complete the transactions correctly.

+ +
+ prepare +

This operation ask the participant to vote on the outcome of the transaction. Possible replies are:

+ + 'VoteReadOnly' - if no data associated with the transaction has been modified VoteReadOnly may be returned. + The Resource can forget all knowledge of the transaction and terminate. + 'VoteCommit' - if the Resource is able to write all the data needed to commit the transaction to a stable storage, + VoteCommit may be returned. The Resource will then wait until it is informed of the outcome of the transaction. + The Resource may, however, make a unilateral decision (Heuristic) to commit or rollback changes associated + with the transaction. When the Resource is informed of the true outcome (rollback/commit) and it is equal to + the Heuristic decision the Resource just return 'ok'. But, if there is a mismatch and the commit-operation is irreversible, + the Resource must raise a Heuristic Exception and wait + until the forget operation is invoked. The Heuristic Decision must be recorded in stable storage. + 'VoteRollback' - the Resource may vote VoteRollback under any circumstances. + The Resource can forget all knowledge of the transaction and terminate. + + +

Before replying to the prepare operation, the Resource must record the prepare state, the reference of its + superior RecoveryCoordinator in stable storage. + The RecoveryCoordinator is obtained when registering as a participant in a transaction.

+
+
+ +
+ rollback +

The Resource should, if necessary, rollback all changes made as part of the transaction. If the Resource is not aware of the + transaction it should do nothing, e.g., recovered after a failure and have no data in stable storage. Heuristic Decisions + must be handled as described above.

+
+ +
+ commit +

The Resource should, if necessary, commit all changes made as part of the transaction. If the Resource is not aware of the + transaction it should do nothing, e.g., recovered after a failure and have no data in stable storage. Heuristic Decisions + must be handled as described above.

+
+ +
+ commit_one_phase +

If possible, the Resource should commit all changes made as part of the transaction. If it cannot, it should raise the + TRANSACTION_ROLLEDBACK exception. This operation can only be used if the Resource is the only child of its parent. + If a failure occurs the completion of the operation must be retried when the failure is repaired. Heuristic Decisions + must be handled as described above.

+
+ +
+ forget +

If the Resource raised a Heuristic Exception to commit, rollback or commit_one_phase this operation + will be performed. The Resource can forget all knowledge of the transaction and terminate.

+
+ +
+ commit_subtransaction +

If the SubtransactionAwareResource have been registered with a subtransaction + using the operation CosTransactions_Coordinator:register_subtran_aware/2 + it will be notified when the transaction has committed. The Resource may raise the exception + 'TRANSACTION_ROLLEDBACK'.

+ +

The result of a committed subtransaction is relative to the completion of its ancestor + transactions, that is, these results can be undone if any ancestor transaction is rolled back.

+
+
+ +
+ rollback_subtransaction +

If the SubtransactionAwareResource have been registered with a subtransaction + using the operation CosTransactions_Coordinator:register_subtran_aware/2 + it will be notified when the subtransaction has rolled back.

+
+
+ +
+ How to Run Everything +

Below is a short transcript on how to run cosTransactions.

+ + +%% Start Mnesia and Orber +mnesia:delete_schema([node()]), +mnesia:create_schema([node()]), +orber:install([node()]), +application:start(mnesia), +application:start(orber), + +%% Register CosTransactions in the IFR. +'oe_CosTransactions':'oe_register'(), + +%% Register the application specific Resource implementations +%% in the IFR. +'oe_ownResourceImpl':'oe_register'(), + +%%-- Set parameters -- +%% Timeout can be either 0 (no timeout) or an integer N > 0. +%% The later state that the transaction should be rolled +%% back if the transaction have not completed within N seconds. +TimeOut = 0, + +%% Do we want the transaction to report Heuristic Exceptions? +%% This variable must be boolean and indicates the way the +%% Terminator should behave. +Heuristics = true, + +%% Start the cosTransactions application. +cosTransactions:start(), %% or application:start(cosTransactions), + +%% Start a factory using the default configuration +TrFac = cosTransactions:start_factory(), +%% ... or use configuration parameters. +TrFac = cosTransactions:start_factory([{typecheck, false}, {hash_max, 3013}]), + +%% Create a new top-level transaction. +Control = 'CosTransactions_TransactionFactory':create(TrFac, TimeOut), + +%% Retrieve the Coordinator and Terminator object references from +%% the Control Object. +Term = 'CosTransactions_Control':get_terminator(Control), +Coord = 'CosTransactions_Control':get_coordinator(Control), + +%% Create two SubTransactions with the root-Coordinator as parent. +SubCont1 = 'CosTransactions_Coordinator':create_subtransaction(Coord), +SubCont2 = 'CosTransactions_Coordinator':create_subtransaction(Coord), + +%% Retrieve the Coordinator references from the Control Objects. +SubCoord1 = 'CosTransactions_Control':get_coordinator(SubCont1), +SubCoord2 = 'CosTransactions_Control':get_coordinator(SubCont2), + +%% Create application Resources. We can, for example, start the Resources +%% our selves or look them up in the naming service. This is application +%% specific. +Res1 = ... +Res2 = ... +Res3 = ... +Res4 = ... + +%% Register Resources with respective Coordinator. Each call returns +%% a RecoveryCoordinator object reference. +RC1 = 'CosTransactions_Coordinator':register_resource(SubCoord1, Res1), +RC2 = 'CosTransactions_Coordinator':register_resource(SubCoord1, Res2), +RC3 = 'CosTransactions_Coordinator':register_resource(SubCoord2, Res3), +RC4 = 'CosTransactions_Coordinator':register_resource(SubCoord2, Res4), + +%% Register Resource 4 with SubCoordinator 1 so that the Resource will be +%% informed when the SubCoordinator commits or roll-back. +'CosTransactions_Coordinator':register_subtran_aware(SubCoord1, Res4), + +%% We are now ready to try to commit the transaction. The second argument +%% must be a boolean +Outcome = (catch 'CosTransactions_Terminator':commit(Term, Heuristics)), + + +

For the cosTransaction application to be able to recognize if a Resource is + dead or in the process of restarting the Resource must be started as persistent, + e.g., 'OwnResource':oe_create_link(Env, [{regname, {global, RegName}}, {persistent, true}]). + For more information see the Orber documentation.

+
+

The outcome of the transaction can be:

+ + ok - the transaction was successfully committed. + {'EXCEPTION', HeuristicExc} - at least one participant made a + Heuristic decision or, due to a failure, one or more participants + where unreachable. + {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}} - + the transaction was successfully rolled back. + Any system exception - + the transaction failed with unknown reason. + +
+
+
+ diff --git a/lib/cosTransactions/doc/src/ch_install.xml b/lib/cosTransactions/doc/src/ch_install.xml new file mode 100644 index 0000000..d4b64d3 --- /dev/null +++ b/lib/cosTransactions/doc/src/ch_install.xml @@ -0,0 +1,103 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Installing cosTransactions + + + 1999-04-20 + + ch_install.xml +
+ +
+ Installation Process +

This chapter describes how to install + cosTransactions + in an Erlang Environment. +

+ +
+ Preparation +

Before starting the installation process for cosTransactions, + the application Orber must be running.

+

The cosTransactions application must be able to log progress to disk. The log files are + created in the current directory as "oe_name@machine_type_timestamp". Hence, read and + write rights must be granted. If the transaction completes in an orderly fashion the + logfiles are removed, but not if an error, which demands human intervention, occur.

+
+ +
+ Configuration +

When using the Transaction Service the cosTransactions application + must be started using either cosTransactions:start() or + application:start(cosTransactions). +

+

The following application configuration parameters exist:

+ + maxRetries - default is 40 times, i.e., if a transaction participant is unreachable + the application will retry to contact it N times. Reaching the maximum is considered to be a disaster. + comFailWait - default is 5000 milliseconds, i.e., before the application + retries to contact unreachable transaction participants the application wait Time milliseconds. + +

Then the Transaction Factory + must be started:

+ + cosTransactions:start_factory() - starts and returns a reference to a factory using default configuration parameters. + cosTransactions:start_factory(Options) - starts and returns a reference to a factory using given configuration parameters. + +

The following options exist: +

+ + {hash_max, HashValue} - + This value denotes the upper bound of the hash value the Coordinator uses. + Default is 1013. HashValue must be an integer. + {allow_subtr, Boolean} - + If set to true it is possible to create subtransactions. + Default is true. + {typecheck, Boolean} - + If set to to true all transaction operation's arguments will be type-checked. + Default is true. + {tty, Boolean} - + Enables or disables error printouts to the tty. + If Flag is false, all text that the error logger would have sent to the terminal is discarded. + If Flag is true, error messages are sent to the terminal screen. + {logfile, FileName} - + This function makes it possible to store all system information in FileName (string()). + It can be used in combination with the tty(false) item to have a silent system, + where all system information are logged to a file. + As default no logfile is used. + {maxRetries, Integer} - + default is 40 times, i.e., if a transaction participant is unreachable the application will + retry to contact it N times. Reaching the maximum is considered to be a disaster. + This option overrides the application configuration parameter. + {comFailWait, Integer} - + default is 5000 milliseconds, i.e., before the application retries to contact unreachable + transaction participants the application wait Time milliseconds. + This option overrides the application configuration parameter. + +

The Factory is now ready to use. For a more detailed description see Examples. +

+
+
+
+ diff --git a/lib/cosTransactions/doc/src/ch_introduction.xml b/lib/cosTransactions/doc/src/ch_introduction.xml new file mode 100644 index 0000000..b0e58c5 --- /dev/null +++ b/lib/cosTransactions/doc/src/ch_introduction.xml @@ -0,0 +1,64 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Introduction to cosTransactions + Niclas Eklund + + 1999-04-26 + + ch_introduction.xml +
+ +
+ Overview +

The cosTransactions application is a Transaction Service compliant with the OMG + Transaction Service CosTransactions 1.1. +

+ +
+ Purpose and Dependencies +

cosTransactions is dependent on Orber version 3.0.1 or later(see the Orber + documentation), which provides CORBA functionality in an Erlang environment.

+

cosTransactions is dependent on supervisor/stdlib-1.7 or later.

+

Basically, cosTransaction implements a two-phase commit protocol and allows objects running + on different platforms to participate in a transaction.

+
+ +
+ Prerequisites +

To fully understand the concepts presented in the + documentation, it is recommended that the user is familiar + with distributed programming, CORBA and the Orber application. +

+

Recommended reading includes CORBA, Fundamentals and Programming - Jon Siegel and Open Telecom Platform Documentation Set. It is also helpful to have read + Concurrent Programming in Erlang and, for example, Transaction Processing: concepts and techniques - Jim Gray, Andreas Reuter.

+ +

The cosTransaction application is compliant with the OMG CosTransactions specification 1.1. Using + other vendors transaction service, compliant with the OMG CosTransactions specification 1.0, may + not work since the 'TRANSACTION_REQUIRED', 'TRANSACTION_ROLLEDBACK' and 'INVALID_TRANSACTION' + exceptions have been redefined to be system exceptions, i.e., used to be transaction-specific ('CosTransactions_Exc').

+
+
+
+
+ diff --git a/lib/cosTransactions/doc/src/ch_skeletons.xml b/lib/cosTransactions/doc/src/ch_skeletons.xml new file mode 100644 index 0000000..a6dd41f --- /dev/null +++ b/lib/cosTransactions/doc/src/ch_skeletons.xml @@ -0,0 +1,213 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Resource Skeletons + Niclas Eklund + + 1999-04-29 + + ch_skeletons.xml +
+ +
+ Resource Skeletons +

This chapter provides a skeleton for application Resources. For more information + see the Orber documentation.

+ +%%%----------------------------------------------------------- +%%% File : Module_Interface_impl.erl +%%% Author : +%%% Purpose : +%%% Created : +%%%----------------------------------------------------------- + +-module('Module_Interface_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("cosTransactions/include/CosTransactions.hrl"). + +%%--------------- EXPORTS------------------------------------- +%%- Inherit from CosTransactions::Resource ------------------- +-export([prepare/2, + rollback/2, + commit/2, + commit_one_phase/2, + forget/2]). + +%%- Inherit from CosTransactions::SubtransactionAwareResource +-export([commit_subtransaction/3, + rollback_subtransaction/2]). + +%%--------------- gen_server specific ------------------------ +-export([init/1, terminate/2, code_change/3, handle_info/2]). + +%%------------------------------------------------------------ +%% function : gen_server specific +%%------------------------------------------------------------ +init(Env) -> + %% 'trap_exit' optional + process_flag(trap_exit,true), + + %%--- Possible replies --- + %% Reply and await next request + {ok, State}. + + %% Reply and if no more requests within Time the special + %% timeout message should be handled in the + %% Module_Interface_impl:handle_info/2 call-back function (use the + %% IC option {{handle_info, "Module::Interface"}, true}). + {ok, State, TimeOut}. + + %% Return ignore in order to inform the parent, especially if it is a + %% supervisor, that the server, as an example, did not start in + %% accordance with the configuration data. + ignore. + + %% If the initializing procedure fails, the reason + %% is supplied as StopReason. + {stop, StopReason}. + + +terminate(Reason, State) -> + ok. + +code_change(OldVsn, State, Extra) -> + {ok, NewState}. + +%% If use IC option {{handle_info, "Module::Interface"}, true} +handle_info(Info, State) -> + %%--- Possible replies --- + %% Await the next invocation. + {noreply, State}. + %% Stop with Reason. + {stop, Reason, State}. + + +%%- Inherit from CosTransactions::Resource ------------------- +prepare(State) -> + + %%% Do application specific actions here %%% + + %%-- Reply: -- + %% If no data related to the transaction changed. + {reply, 'VoteReadOnly', State} + %% .. or (for example): + {stop, normal, 'VoteReadOnly', State}. + + %% If able to commit + {reply, 'VoteCommit', State} + + %% If not able to commit + {reply, 'VoteRollback', State} + %% .. or (for example): + {stop, normal, 'VoteRollback', State}. + +rollback(State) -> + + %%% Do application specific actions here %%% + + %%-- Reply: -- + %% If able to rollback successfully + {reply, ok, State} + %% .. or (for example): + {stop, normal, ok, State}. + + %% If Heuristic Decision. Raise exception: + corba:raise(#'CosTransactions_HeuristicMixed' {}) + corba:raise(#'CosTransactions_HeuristicHazard' {}) + corba:raise(#'CosTransactions_HeuristicCommit'{}) + + +commit(State) -> + + %%% Do application specific actions here %%% + + %%-- Reply: -- + %% If able to commit successfully + {reply, ok, State} + %% .. or (for example): + {stop, normal, ok, State}. + + %% If the prepare operation never been invoked: + corba:raise(#'CosTransactions_NotPrepared'{}) + + %% If Heuristic Decision. Raise exception: + corba:raise(#'CosTransactions_HeuristicMixed' {}) + corba:raise(#'CosTransactions_HeuristicHazard' {}) + corba:raise(#'CosTransactions_HeuristicRollback'{}) + + +commit_one_phase(State) -> + + %%% Do application specific actions here %%% + + %%-- Reply: -- + %% If able to commit successfully + {reply, ok, State} + %% .. or (for example): + {stop, normal, ok, State}. + + %% If fails. Raise exception: + corba:raise(#'CosTransactions_HeuristicHazard' {}) + + %% If able to rollback successfully + corba:raise(#'CosTransactions_TransactionRolledBack' {}) + + +forget(State) -> + + %%% Do application specific actions here %%% + + %%-- Reply: -- + {reply, ok, State}. + %% .. or (for example): + {stop, normal, ok, State}. + + + +%%%%%% If the Resource is also supposed to be a %%%%%% +%%%%%% SubtransactionAwareResource implement these. %%%%%% + +%%- Inherit from CosTransactions::SubtransactionAwareResource +commit_subtransaction(State, Parent) -> + %%% Do application specific actions here %%% + + %%-- Reply: -- + {reply, ok, State}. + %% .. or (for example): + {stop, normal, ok, State}. + +rollback_subtransaction(State) -> + %%% Do application specific actions here %%% + + %%-- Reply: -- + {reply, ok, State}. + %% .. or (for example): + {stop, normal, ok, State}. + +%%--------------- END OF MODULE ------------------------------ + +
+
+ diff --git a/lib/cosTransactions/doc/src/cosTransactions.xml b/lib/cosTransactions/doc/src/cosTransactions.xml new file mode 100644 index 0000000..8365069 --- /dev/null +++ b/lib/cosTransactions/doc/src/cosTransactions.xml @@ -0,0 +1,141 @@ + + + + +
+ + 1999 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + cosTransactions + Niclas Eklund + Niclas Eklund + + Niclas Eklund + + 1999-04-23 + PA1 +
+ cosTransactions + The main module of the cosTransactions application. + +

To get access to the record definitions for the structures use:

+-include_lib("cosTransactions/include/CosTransactions.hrl").

+

This module contains the functions for starting and stopping the application. + If the application is started using application:start(cosTransactions) the + default configuration is used (see listing below). The Factory reference is stored using the CosNaming Service + under the id "oe_cosTransactionsFac_IPNo".

+

The following application configuration parameters exist:

+ + maxRetries - default is 40 times, i.e., if a transaction participant is unreachable + the application will retry to contact it N times. Reaching the maximum is considered to be a disaster. + comFailWait - default is 5000 milliseconds, i.e., before the application + retries to contact unreachable transaction participants the application wait Time milliseconds. + +
+ + + start() -> Return + Start the cosTransactions application + + Return = ok | {error, Reason} + + +

This operation starts the cosTransactions application.

+
+
+ + stop() -> Return + Stop the cosTransactions application + + Return = ok | {error, Reason} + + +

This operation stops the cosTransactions application.

+
+
+ + start_factory() -> TransactionFactory + Start a Transaction Factory + + TransactionFactory = #objref + + +

This operation creates a Transaction Factory. + The Factory is used to create a new top-level transaction using default options (see listing below).

+
+
+ + start_factory(FacDef) -> TransactionFactory + Start a Transaction Factorywith given options + + FacDef = [Options], see Option listing below. + TransactionFactory = #objref + + +

This operation creates a Transaction Factory. + The Factory is used to create a new top-level transaction.

+

The FacDef list must be a list of {Item, Value} tuples, + where the following values are allowed:

+ + {hash_max, HashValue} - + This value denotes the upper bound of the hash value the + Coordinator uses. + Default is 1013. HashValue must be an integer. + {allow_subtr, Boolean} - + If set to true it is possible to create subtransactions. + Default is true. + {typecheck, Boolean} - + If set to to true all transaction operation's arguments will be type-checked. + Default is true. + {tty, Boolean} - + Enables or disables error printouts to the tty. + If Flag is false, all text that the error logger would have sent to the terminal is discarded. + If Flag is true, error messages are sent to the terminal screen. + {logfile, FileName} - + This function makes it possible to store all system information in FileName (string()). + It can be used in combination with the tty(false) item in to have a silent system, + where all system information are logged to a file. + As default no logfile is used. + {maxRetries, Integer} - + default is 40 times, i.e., if a transaction participant is unreachable the application will + retry to contact it N times. Reaching the maximum is considered to be a disaster. + This option overrides the application configuration parameter. + {comFailWait, Integer} - + default is 5000 milliseconds, i.e., before the application retries to contact unreachable + transaction participants the application wait Time milliseconds. + This option overrides the application configuration parameter. + +
+
+ + stop_factory(TransactionFactory) -> Reply + Terminate the target object + + TransactionFactory = #objref + Reply = ok | {'EXCEPTION', E} + + +

This operation stop the target transaction factory.

+
+
+
+ +
+ diff --git a/lib/cosTransactions/doc/src/fascicules.xml b/lib/cosTransactions/doc/src/fascicules.xml new file mode 100644 index 0000000..0678195 --- /dev/null +++ b/lib/cosTransactions/doc/src/fascicules.xml @@ -0,0 +1,18 @@ + + + + + + User's Guide + + + Reference Manual + + + Release Notes + + + Off-Print + + + diff --git a/lib/cosTransactions/doc/src/make.dep b/lib/cosTransactions/doc/src/make.dep new file mode 100644 index 0000000..bd45aea --- /dev/null +++ b/lib/cosTransactions/doc/src/make.dep @@ -0,0 +1,27 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: CosTransactions_Control.tex CosTransactions_Coordinator.tex \ + CosTransactions_RecoveryCoordinator.tex CosTransactions_Resource.tex \ + CosTransactions_SubtransactionAwareResource.tex \ + CosTransactions_Terminator.tex CosTransactions_TransactionFactory.tex \ + book.tex ch_contents.tex ch_example.tex ch_install.tex \ + ch_introduction.tex ch_skeletons.tex cosTransactions.tex \ + part.tex ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + +ch_example.tex: ../../../../system/doc/definitions/term.defs + diff --git a/lib/cosTransactions/doc/src/notes.gif b/lib/cosTransactions/doc/src/notes.gif new file mode 100644 index 0000000000000000000000000000000000000000..e000cca26a383722eca87f4d87a5841292b0b8ea GIT binary patch literal 2005 zcmc(e`(I0c1HeD$>})&L($>wE%9*B;E}M!dPv>-9341YwWX&zf>scU1zfBrl=I{N9;r;i^$ ze)#ZVWMt(1`}gnOy?gui?eOsMn>TM>zkWS5H1z7#tHHs+fq?;|(fIP^%NH+RJb(WD z*|TR)pFVx^ogEz=?d|P)y}qrjt+lnarKLru(`mKZ=H_ONMx$1%@7%d_`}XZyw{G3MdGp4N z8%<43jg5^B4Gq_?U%z(k+SRL9>+9>UT)9$LS65qGTT@eW`SRsUmo8nrc=5u83+KckWzORn^(EXDcf!&zw1P`t<2jr%qK=RFs#Ot5m9!Cr_R@apL&#<7H)K$BrF4 zdi1DLsXTJzNNH(lNl8g@aq;29hl`4e3JVJr3dNyAhYlV*SWr-qpP!$XmzSHHo0F3x zm&-FUGSbu2Wir|R{rmUr+qZY`-n6u|)YR0Jl$1St_9Q1K@7}$8*REYVckbM=V@Fa_ zl0+iezI}UQV&b-K+Y%BIwr<_JdGqE?n>KCSxN*aV4Pvo4E-p?a60KjqJ~lRX-MV!# zF)?e`u3fWc&Fa;wSFKvLa^=buD^>`F!ez^r2?T=0ix)>lMMXwNMnpvL`TX$k@UXD3 zkdTnz;NYO3Ac7zQ0|OT>TD_t~>&yScf|nl;PS)z!tt#o5`J!{InNIkDMn48x{RpYG`B=-}XBZ*Mm zJ0_E9VPQd|(M(NEQ52<8sT2wYK@bv&1j8@{LE!(5`#%Ezya3Qi0HOB$8kHskwQ`Hm z*OY4y(48X7__Y-+c}(wwXZqSxZHKVn+_d2V9bX<;)o5v8$jlB{tz6vnwfvQAiMw6t z0IXVSedvhT17nJCGJ_XCYT%)5*?chw5R9s25QXlX!e_sd7hr)!eyKroJ4zhgi|iRe z9BRcDRXkmj&PH5Z1EswZP1Yik}bX?KQfDMotrhur?Z`l6 z9SHWUks6^bPWsX|jEswdY)vps%VI@IAvY7W9?a_N?~xI!M!5pm(Ry5JJ;$6wSb!Kw z1Ofz-ES$>6ni1O}ScWTvR$Wsm*pF-~}^QqIoOkG6>BJ?$;+XE5N4m%cOVTgl$q1H6Cj2CRZ#Cwk*Z+A1}6-ZGIOnZ zriKR6JwuHEr#89IP&lU0d>}f|iQ2(xTebl}Km=JKc>w~{On}kI=M0e4E*aE>B!t(` zz!7B(z}xLdevm2fNGl*)VFk@hhEN1isQ4%eVdfhlo64C^B-c26^Z?T#Tc$&!YL-EE zsr_sc%})?_z}$saj#x(bLnO=CUH5f1>6}R!!dMZ|W9GTgpb9n@*5fiBqnDrne~DCT zx&%mdn3ma=CO4$ZCjP+)Zks2RB*+Tt`QEtb2g6+n+RKF1oJqVMUCo0mdGDTz#3Q^?T4648gGi%gvvJ#j{AlN2b z`m?E;VM>mcPQBC_Y6=8kn9B=CL=o-QgXt_x2k`|YJusL&`b=Pj%+?u4tr>8h24sDX + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTransactions Release Notes + Niclas Eklund + Niclas Eklund + + + + 99-04-14 + A + notes.xml +
+ +
+ cosTransactions 1.2.8 + +
+ Improvements and New Features + + +

+ The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.

+

+ Own Id: OTP-8201 Aux Id:

+
+
+
+
+ +
+ cosTransactions 1.2.7 + +
+ Improvements and New Features + + +

Obsolete guards, e.g. record vs is_record, has been changed + to avoid compiler warnings.

+

Own id: OTP-7987

+
+
+
+
+ +
+ cosTransactions 1.2.6 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7837

+
+
+
+
+ +
+ cosTransactions 1.2.5 + +
+ Improvements and New Features + + +

Documentation source included in open source releases.

+

Own id: OTP-7595

+
+
+
+
+ +
+ cosTransactions 1.2.4 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7011

+
+
+
+
+ +
+ cosTransactions 1.2.3 + +
+ Improvements and New Features + + +

The documentation source has been converted from SGML to XML.

+

Own id: OTP-6754 Aux Id:

+
+
+
+
+ +
+ cosTransactions 1.2.2 + +
+ Improvements and New Features + + +

Minor Makefile changes.

+

Own id: OTP-6701 Aux Id:

+
+
+
+
+ +
+ cosTransactions 1.2.1 + +
+ Improvements and New Features + + +

Removed some unused code.

+

Own id: OTP-6527 Aux Id:

+
+
+
+
+ +
+ cosTransactions 1.2 + +
+ Improvements and New Features + + +

The stub/skeleton-files generated by IC have been improved, + i.e., depending on the IDL-files, reduced the size of the + erl- and beam-files and decreased dependencies off Orber's + Interface Repository. It is necessary to re-compile all IDL-files + and use COS-applications, including Orber, compiled with + IC-4.2.

+

Own id: OTP-4576

+
+
+
+
+ +
+ cosTransactions 1.1.2 + +
+ Improvements and New Features + + +

To avoid un-necessary Heuristic decisions cosTransactions now + recognize more systems exceptions.

+

Own Id: OTP-4485

+
+
+
+
+ +
+ cosTransactions 1.1.1.1 + +
+ Improvements and New Features + + +

Updated internal documentation.

+
+
+
+
+ +
+ cosTransactions 1.1.1 + +
+ Improvements and New Features + + +

cosTransactions is now able to handle upgrade properly.

+

Own Id: -

+
+ +

The cosTransactions factory now accepts maxRetries and + comFailWait options, which overrides the configuration parameters.

+

Own Id: -

+
+
+
+ +
+ Incompatibilities + + +

The configuration parameters comm_failure_wait and max_retries + changed to maxRetries and comFailWait. The default value for + maxRetries have been raised from 20 to 40.

+

Own Id: -

+
+
+
+
+ +
+ cosTransactions 1.1 + +
+ Improvements and New Features + + +

First release of the cosTransactions application.

+

Own Id: OTP-1741

+
+
+
+
+
+ diff --git a/lib/cosTransactions/doc/src/part.xml b/lib/cosTransactions/doc/src/part.xml new file mode 100644 index 0000000..b5a8397 --- /dev/null +++ b/lib/cosTransactions/doc/src/part.xml @@ -0,0 +1,40 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTransactions User's Guide + Niclas Eklund + + 1999-04-20 + 2.2 +
+ +

The cosTransactions application is an Erlang implementation + of the OMG CORBA Transaction Service.

+
+ + + + + +
+ diff --git a/lib/cosTransactions/doc/src/part_notes.xml b/lib/cosTransactions/doc/src/part_notes.xml new file mode 100644 index 0000000..16e1968 --- /dev/null +++ b/lib/cosTransactions/doc/src/part_notes.xml @@ -0,0 +1,36 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTransactions Release Notes + + + 1999-04-14 + 2.0 +
+ +

The cosTransactions Application is an Erlang implementation of the OMG + CORBA Transaction Service.

+
+ +
+ diff --git a/lib/cosTransactions/doc/src/ref_man.gif b/lib/cosTransactions/doc/src/ref_man.gif new file mode 100644 index 0000000000000000000000000000000000000000..b13c4efd53ff30209e94a832b9b141aefa01373e GIT binary patch literal 1530 zcmdVZdppw$0KoB|UD(ZKjLpudxl|bD5*~BdW(#wPxjQR!4XwvDQJz|2?rd%yODG+} zTS?d`8$ziw@9efjcbb8~ZJV`F`NeQj-Rb#--RW#!YS zPs_{8OG`^1KYmEb&dp9*T_4@VeSFc{Z zeEIUlix(;Hhy1Lrh+M1f0n>TM(S67S0;;O2u%F4=$ii+~`^0Klrkw{chQc_%8TvSw4P*9Mc zpP!ePmz$fLlanJ52(q)YuU)&AnVEUz%9YEPFK1+AT)K4W;>C;U>FH@{X%{YBNKH*W zfBt+*N=kBaa#B)KVq#)KLPC6e{JC@Ics$E-3+>FMd= z;o5R+g5Q78Vv{ zGTGeR+|10()YOzjBAJ+&7#kZK85t3YL|t879UUD4fq=*3wY9ZzI2;y>)zZ?^)YQaa zFd7;fYHDh#s;Vj~D$2^rC=?2bL?RFfI2;ax!IYGg6crVrP$&cf0fWIH5J*8m0r;Os z`p^I03jpi@P=FC!+v{kk6S6LO_!Iu)95sCwBtcqW%*9y*G+T7kk6cw&i6X!~u9ub^ z(;p_fv9U$vWTl#^q0-1BITpV6n#M{a{we|K$qn8tF1dhi2#U)iChGwf%c>!EMdamI z$h@1HHE$AU0uQ06DJaKq=RDnzU^TZiOigaDbX?9sbbG2Mo zru2uhl#`IQgUVf0v!Xj-d%-$1xRm>;TQmHNwcAfcM=qjwu=nh zQh;0;RMT@!2!f)5xXw7CWD^X8atslf08f~GlvPC&!u3CIvJ6wy=4qhoBAlk74dDIc za5tv{OoL_(_?n6N^K=DFVPbx|J4#5`n`9n$heG9OfAim6K_sx=yuqZzUrzW~%(8B5(t!Xl{Hb0?L6-vF=+wDe8$ zTT`s`Dq0fpfEZM3+{q@m}*YWuf-$-b$k$LLWEZK;Ee|dK!!GAvHA;V z*1da#TyGWrnurc+>Z42^g}P$+dV8CLlZ-G3$5&lvmrHi*;me*Y^_v!=AL*c_d4sqi z`SWVr{)P|6KptK|>YQR5CUyjEppnvPJ-9YQBBMdn(+)quWG#%To7OvoyB^9=`#bkY st1M+qtZTt#!ZD6_9%~hW^bvUb7(Sl{bx5FV=!1r@;+Z6>KNX<-3tg&0LjV8( literal 0 HcmV?d00001 diff --git a/lib/cosTransactions/doc/src/ref_man.xml b/lib/cosTransactions/doc/src/ref_man.xml new file mode 100644 index 0000000..b662f30 --- /dev/null +++ b/lib/cosTransactions/doc/src/ref_man.xml @@ -0,0 +1,43 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + cosTransactions Reference Manual + Niclas Eklund + + 1999-04-14 + 2.0 +
+ +

The cosTransactions application is an Erlang implementation + of the OMG CORBA Transaction Service.

+
+ + + + + + + + +
+ diff --git a/lib/cosTransactions/doc/src/summary.html.src b/lib/cosTransactions/doc/src/summary.html.src new file mode 100644 index 0000000..8fb7d6e --- /dev/null +++ b/lib/cosTransactions/doc/src/summary.html.src @@ -0,0 +1 @@ +Orber OMG Transaction Service \ No newline at end of file diff --git a/lib/cosTransactions/doc/src/user_guide.gif b/lib/cosTransactions/doc/src/user_guide.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6275a803db46bc56df2b31240f80e68a4eb28b5 GIT binary patch literal 1581 zcmd6mi9gc|0Kk8njctY*W^QwCJ{HX#%4V)-y(i>aMOY|Iy@!%dZA6YGb49u7IpPyu zxpLn_avvd{2!$L^&hlRW#rysR-_Q5+`C8dn8X8V>k`j;wKQ1gR%+Jry&CSiu&d$utOixe0fB$}JYHD(Fa$;g)e0+Rt zY;1INbYx^?czAedXlQV7@ZGz20|Nv7{r!D?eZ9TCJRYy7r>DESyQ{0Kv$M0KqocjO zy{)aSwY9aSrKP#Kxv8nCv9YnCq2bM&H}&=Pb#-;MwY4=hHPzMCuV25es;a82tgNW0 zc=_^WSy|bO7cWXnOG`>hii?Yjii!#g3kwPg^7Hfa^73+Xb8~WXva_?Zva&KWGoL+s z_Vnq~jEs!*^z{(M&Qxg*t zV`JkpXU-TI85tTH>g((4>FMd}>gwp|kVqtLZEYmX?x|!eX(Kl9CtEE3!%>OGRc>9)Rn&SYM zj~Y~*8(l`PO4G;6R;FqaD@X#~VMifcR)pt=DvF{Q3(>@Ud>(7)(V4{v)PmxVK~kPo zjj~AEyr<1v8vx#~Tk98U5_J`0L}~fU>RjhaAKM=MUf{g5m?T z)+IHOf7l%`QALwKCeyDj6SLD45WBagBU?Fw4{df%%9E4Y2u)Wk*W$nyCUXV^5gf*w zJcTmdm_5ACzSYODr)n2;x_FnPc`B(M`LXIbz9g71J`3n))Gq$bQK+sRivkPkZkj>F zXejb80{#?f()6mQl&jOcTB0m7HQ)B0eJ!3!3LG1z5Dy4!8UDX&qmZHiEZH4hCN$qe z4*)g+{|y}64a+3k1Ar7VS%DkXnyczs>8pr>ch^qPgriJZarAD;X*)P0t_Uea!m)bj zekgBBW+6d2l7{g|`zZIq7r_Y&symb`GN>UKUQ)c!TxUa0r_Gumy9Jeti%E)uL##a# zMGizq*jB%VA7Ip@(A3hq9YH69qL7NjkWRA2q5;hU`xYmEN)bB>aqrz!?T?Ynv*X-7 zk5PfTmt$8kTF6UOKy_o?XHYzxtkg%ZbG*StHxDNDsyD5c2a>x5vWvVCApVgu@XNF$})`XD-pCH3`9zE-Lj6@!*TS9lwVaP}h|-H2`m~ItYQE$0z|a zt4=D`BBR~(5MZ;L{+LQk#4$5Kz`eloKZBK-7eFm?OlZCy;GH~%L;($J;|e#tww(~b et1Zl|+ha7@T8X2%4FJEoWS?mjDfbqXtih~yb literal 0 HcmV?d00001 diff --git a/lib/cosTransactions/ebin/.gitignore b/lib/cosTransactions/ebin/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTransactions/examples/Makefile b/lib/cosTransactions/examples/Makefile new file mode 100644 index 0000000..24cd122 --- /dev/null +++ b/lib/cosTransactions/examples/Makefile @@ -0,0 +1,157 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk + +EBIN= ../ebin + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(COSTRANSACTIONS_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/cosTransactions-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +INETRC_EXAMPLE = \ +# inetrc + +IDL_FILES = \ +# hotel.idl \ +# travelAgency.idl + +GEN_ERL_MODULES = \ +# oe_travelAgency \ +# travelAgency_book \ + +MODULES= \ +# travelAgency_book_impl \ + +GEN_HRL_FILES = \ +# oe_travelAgency.hrl \ +# travelAgency_book.hrl + +HRL_FILES= + +ERL_FILES= $(MODULES:%=%.erl) + +JAVA_CLASSES = \ +# HotelResource + +JAVA_FILES= $(JAVA_CLASSES:%=%.java) +CLASS_FILES= $(JAVA_CLASSES:%=%.class) + +TARGET_FILES = \ + $(GEN_ERL_MODULES:%=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + + +ifeq ($(findstring sparc-sun-solaris2, $(TARGET)),sparc-sun-solaris2) + JAVA_TARGET=java +endif + +# ---------------------------------------------------- +# PROGRAMS +# ---------------------------------------------------- +JAVA_IDL = idl +LOCAL_CLASSPATH = $(ERL_TOP)/lib/cosTransactions/priv:$(ERL_TOP)/lib/cosTransactions/examples/java_output:$(ERL_TOP)/lib/cosTransactions/src:$(ERL_TOP)/lib/cosTransactions/examples:$(ERL_TOP)/lib/cosTransactions/examples/java_output/hotel + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += -pa /clearcase/otp/libraries/cosTransactions/ebin -pa /clearcase/otp/libraries/ic/ebin +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -pa /clearcase/otp/libraries/cosTransactions -I/clearcase/otp/libraries/cosTransactions +YRL_FLAGS = + +JAVA_OPTIONS = -classpath ../priv:/opt/local/pgm/OrbixWeb2.0.1 + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +tests debug opt: $(TARGET_FILES) $(JAVA_TARGET) + +java: java_costransactions_idl java_objects +# java_hotel_idl + +clean: + rm -f $(TARGET_FILES) $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES) $(CLASS_FILES) + rm -rf java_costransactions_idl + rm -rf java_output/* + rm -f errs core *~ +# rm -rf java_hotel_idl + +docs: + +java_costransactions_idl: + $(JAVA_IDL) ../src/CosTransactions.idl + @if [ -d java_output ]; then \ + echo "compiling java classes for CosTransactions ... This will take a while!!"; \ + CLASSPATH="${CLASSPATH}:${LOCAL_CLASSPATH}"; \ + export CLASSPATH;\ + (cd java_output/CosTransactions; $(JAVA) *.java;); \ + fi + @touch java_costransactions_idl + +#java_hotel_idl: +# $(JAVA_IDL) hotel.idl +# @if [ -d java_output ]; then \ +# echo "compiling java classes for hotel ..."; \ +# CLASSPATH="${CLASSPATH}:${LOCAL_CLASSPATH}"; \ +# export CLASSPATH;\ +# (cd java_output/hotel; $(JAVA) *.java;); \ +# fi +# @touch java_hotel_idl + +#java_objects: +# @if [ -d java_output ]; then \ +# echo "compiling java example files ..."; \ +# CLASSPATH="${CLASSPATH}:${LOCAL_CLASSPATH}"; \ +# export CLASSPATH;\ +# $(JAVA) *.java; \ +# fi +# @touch java_hotel_resource + +#oe_travelAgency.erl: travelAgency.idl +# erlc $(ERL_IDL_FLAGS) travelAgency.idl + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/examples + $(INSTALL_DATA) $(ERL_FILES) $(JAVA_FILES) $(IDL_FILES) $(RELSYSDIR)/examples + $(INSTALL_DATA) $(INETRC_EXAMPLE) $(RELSYSDIR)/examples + @tar cf - java_output | (cd $(RELSYSDIR); tar xf -) + +release_docs_spec: diff --git a/lib/cosTransactions/include/.gitignore b/lib/cosTransactions/include/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTransactions/info b/lib/cosTransactions/info new file mode 100644 index 0000000..e5d7c53 --- /dev/null +++ b/lib/cosTransactions/info @@ -0,0 +1,2 @@ +group: orb +short: Orber OMG Transaction Service diff --git a/lib/cosTransactions/priv/.gitignore b/lib/cosTransactions/priv/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/cosTransactions/src/CosTransactions.cfg b/lib/cosTransactions/src/CosTransactions.cfg new file mode 100644 index 0000000..05709d2 --- /dev/null +++ b/lib/cosTransactions/src/CosTransactions.cfg @@ -0,0 +1,15 @@ +{this, "CosTransactions::Coordinator"}. +{this, "CosTransactions::RecoveryCoordinator"}. +{this, "CosTransactions::Terminator"}. +{this, "CosTransactions::Control"}. +{this, "CosTransactions::Resource"}. +{this, "CosTransactions::TransactionFactory"}. +{{handle_info, "CosTransactions::Terminator"}, true}. +{{handle_info, "CosTransactions::TransactionFactory"}, true}. +{this, "ETraP::Server"}. +{{handle_info, "ETraP::Server"}, true}. +{{impl, "CosTransactions::Coordinator"}, "ETraP_Server_impl"}. +{{impl, "CosTransactions::RecoveryCoordinator"}, "ETraP_Server_impl"}. +{{impl, "CosTransactions::Control"}, "ETraP_Server_impl"}. +{{impl, "CosTransactions::Resource"}, "ETraP_Server_impl"}. +{timeout,"CosTransactions::RecoveryCoordinator"}. diff --git a/lib/cosTransactions/src/CosTransactions.idl b/lib/cosTransactions/src/CosTransactions.idl new file mode 100644 index 0000000..11ec5cb --- /dev/null +++ b/lib/cosTransactions/src/CosTransactions.idl @@ -0,0 +1,193 @@ +#ifndef _COSTRANSACTIONS_IDL +#define _COSTRANSACTIONS_IDL + +#pragma prefix "omg.org" + +module CosTransactions { + +// DATATYPES + enum Status { + StatusActive, + StatusMarkedRollback, + StatusPrepared, + StatusCommitted, + StatusRolledBack, + StatusUnknown, + StatusNoTransaction, + StatusPreparing, + StatusCommitting, + StatusRollingBack + }; + + enum Vote { + VoteCommit, + VoteRollback, + VoteReadOnly + }; + + // Forward references for interfaces defined later in module + interface Control; + interface Terminator; + interface Coordinator; + interface Resource; + interface RecoveryCoordinator; + interface SubtransactionAwareResource; + interface TransactionFactory; + interface TransactionalObject; + // interface Synchronization; + + // Structure definitions + struct otid_t { + long formatID; /*format identifier. 0 is OSI TP */ + long bqual_length; + sequence tid; + }; + struct TransIdentity { + Coordinator coord; + Terminator term; + otid_t otid; + }; + struct PropagationContext { + unsigned long timeout; + TransIdentity current; + sequence parents; + any implementation_specific_data; + }; + // interface Current; + + // Standard exceptions + // Defined in orber/include/corba.hrl + // exception TransactionRequired {}; + // exception TransactionRolledBack {}; + // exception InvalidTransaction {}; + + // Heuristic exceptions + exception HeuristicRollback {}; + exception HeuristicCommit {}; + exception HeuristicMixed {}; + exception HeuristicHazard {}; + + // Exception from Orb operations + exception WrongTransaction {}; + + // Other transaction-specific exceptions + exception SubtransactionsUnavailable {}; + exception NotSubtransaction {}; + exception Inactive {}; + exception NotPrepared {}; + exception NoTransaction {}; + exception InvalidControl {}; + exception Unavailable {}; + exception SynchronizationUnavailable {}; + + interface TransactionFactory { + Control create(in unsigned long time_out); + Control recreate(in PropagationContext ctx); + }; + + interface Control { + Terminator get_terminator() + raises(Unavailable); + Coordinator get_coordinator() + raises(Unavailable); + }; + + interface Terminator { + void commit(in boolean report_heuristics) + raises( HeuristicMixed, + HeuristicHazard ); + void rollback(); + }; + + interface Coordinator { + + Status get_status(); + Status get_parent_status(); + Status get_top_level_status(); + + boolean is_same_transaction(in Coordinator tc); + boolean is_related_transaction(in Coordinator tc); + boolean is_ancestor_transaction(in Coordinator tc); + boolean is_descendant_transaction(in Coordinator tc); + boolean is_top_level_transaction(); + + unsigned long hash_transaction(); + unsigned long hash_top_level_tran(); + + RecoveryCoordinator register_resource(in Resource r) + raises(Inactive); + +// void register_synchronization (in Synchronization sync) +// raises(Inactive, SynchronizationUnavailable); + + void register_subtran_aware(in SubtransactionAwareResource r) + raises(Inactive, NotSubtransaction); + + void rollback_only() + raises(Inactive); + + string get_transaction_name(); + Control create_subtransaction() + raises(SubtransactionsUnavailable, Inactive); + + PropagationContext get_txcontext () + raises(Unavailable); + }; + + + interface RecoveryCoordinator { + Status replay_completion(in Resource r) + raises(NotPrepared); + }; + + interface Resource { + Vote prepare() + raises(HeuristicMixed, + HeuristicHazard); + void rollback() + raises( HeuristicCommit, + HeuristicMixed, + HeuristicHazard ); + void commit() + raises( NotPrepared, + HeuristicRollback, + HeuristicMixed, + HeuristicHazard ); + void commit_one_phase() + raises( HeuristicHazard, + HeuristicRollback, + HeuristicMixed); + void forget(); + }; + +// interface TransactionalObject { +// }; + +// interface Synchronization : TransactionalObject { +// void before_completion(); +// void after_completion(in CosTransactions::Status status); +// }; + + interface SubtransactionAwareResource : Resource { + void commit_subtransaction(in Coordinator parent); + void rollback_subtransaction(); + }; + +}; // End of CosTransactions Module + +module ETraP { + + // interface Server + interface Server : + CosTransactions::Coordinator, CosTransactions::Resource, + CosTransactions::RecoveryCoordinator, CosTransactions::Control { + }; +// interface Server : +// CosTransactions::Coordinator, CosTransactions::Resource, +// CosTransactions::RecoveryCoordinator, CosTransactions::Control, +// CosTransactions::Synchronization { +// }; + +}; // End of ETraP Module + +#endif diff --git a/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl b/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl new file mode 100644 index 0000000..768e639 --- /dev/null +++ b/lib/cosTransactions/src/CosTransactions_Terminator_impl.erl @@ -0,0 +1,362 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosTransactions_Terminator_impl.erl +%% Purpose : Support operations to commit or roll-back a transaction. +%%---------------------------------------------------------------------- + +-module('CosTransactions_Terminator_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +%% Local +-include_lib("ETraP_Common.hrl"). +-include_lib("CosTransactions.hrl"). + +%%--------------- IMPORTS------------------------------------- +-import(etrap_logmgr, [log_safe/2, get_next/2]). + +%%--------------- EXPORTS------------------------------------- +%%-compile(export_all). +-export([commit/3, rollback/2]). +-export([init/1, terminate/2]). +-export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]). + +%%--------------- LOCAL DATA --------------------------------- +%-record(terminator, {reg_resources, rollback_only, regname, coordinator}). + +%%------------------------------------------------------------ +%% function : init, terminate +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the module ic. Used to initiate +%% and terminate a gen_server. +%%------------------------------------------------------------ + +init(State) -> + process_flag(trap_exit,true), + case catch start_object(State) of + {'EXIT', Reason} -> + %% Happens when, for example, we encounter an + %% error when reading from the log file. + {stop, Reason}; + Other -> + Other + end. + +start_object(State) -> + case catch file:read_file_info(?tr_get_terminator(State)) of + {error, enoent} -> + %% File does not exist. It's the first time. No restart. + ?debug_print("Terminator:init(~p)~n", [?tr_get_terminator(State)]), + etrap_logmgr:start(?tr_get_terminator(State)), + {ok, State, ?tr_get_timeout(State)}; + {error, Reason} -> % File exist but error occurred. + ?tr_error_msg("CosTransactions_Terminator( ~p ) Cannot open log file: ~p~n", + [?tr_get_terminator(State), Reason]), + {stop, {error, "unable_to_open_log"}}; + _ -> % File exists, perform restart. + etrap_logmgr:start(?tr_get_terminator(State)), + ?debug_print("RESTART Terminator:init(~p)~n", + [?tr_get_terminator(State)]), + do_restart(State, get_next(?tr_get_terminator(State), start), init) + end. + + +terminate(Reason, State) -> + ?debug_print("STOP ~p ~p~n", [?tr_get_terminator(State), Reason]), + case Reason of + normal -> + %% normal termination. Transaction completed. + log_safe(?tr_get_terminator(State), done), + etrap_logmgr:stop(?tr_get_terminator(State)), + file:delete(?tr_get_terminator(State)), + ok; + _ -> + ok + end. + +%%------------------------------------------------------------ +%% function : handle_call, handle_cast, handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the module ic. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_call(_,_, State) -> + {noreply, State}. + + +handle_cast(_, State) -> + {noreply, State}. + + +handle_info(Info, State) -> + ?debug_print("Terminator:handle_info(~p)~n", [Info]), + Pid = self(), + case Info of + timeout -> + ?tr_error_msg("Object( ~p ) timeout. Rolling back.~n", + [?tr_get_terminator(State)]), + {stop, normal, State}; + {suicide, Pid} -> + {stop, normal, State}; + _-> + {noreply, State} + end. + +%%------------------------------------------------------------ +%% function : commit +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Heuristics - boolean; report heuristic decisions? +%% Returns : ok - equal to void +%% Effect : +%% Exception: HeuristicMixed - Highest priority +%% HeuristicHazard - Lowest priority +%%------------------------------------------------------------ + +commit(_Self, State, _Heuristics) when ?tr_is_retransmit(State) -> + ?debug_print("Terminator:commit() recalled.~n", []), + {stop, normal, ?tr_get_reportH(State), State}; +commit(Self, State, Heuristics) -> + ?debug_print("Terminator:commit() called.~n", []), + NewState = ?tr_set_reportH(State, Heuristics), + log_safe(?tr_get_terminator(NewState), {init_commit, NewState}), + transmit(Self, NewState, Heuristics). + + +transmit(Self, State, Heuristics) -> + case catch 'ETraP_Common':try_timeout(?tr_get_alarm(State)) of + false -> +% catch 'ETraP_Server':before_completion(?tr_get_etrap(State)), + case catch 'CosTransactions_Resource':prepare(?tr_get_etrap(State)) of + 'VoteCommit' -> + evaluate_answer(Self, State, Heuristics, + 'ETraP_Common':try_timeout(?tr_get_alarm(State))); + 'VoteRollback' -> + {stop, normal, + {'EXCEPTION', + #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + State}; + 'VoteReadOnly' -> + {stop, normal, ok, State}; + {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicMixed'), + Heuristics==true-> + catch 'ETraP_Server':forget(?tr_get_etrap(State)), + {stop, normal, {'EXCEPTION', E}, State}; + {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicHazard'), + Heuristics==true-> + catch 'ETraP_Server':forget(?tr_get_etrap(State)), + {stop, normal, {'EXCEPTION', E}, State}; + {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicMixed') -> + catch 'ETraP_Server':forget(?tr_get_etrap(State)), + {stop, normal, + {'EXCEPTION',#'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + State}; + {'EXCEPTION', E} when is_record(E,'CosTransactions_HeuristicHazard') -> + catch 'ETraP_Server':forget(?tr_get_etrap(State)), + {stop, normal, + {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + State}; + Other -> + ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n", + [?tr_get_etrap(State), Other]), + {stop, normal, + {'EXCEPTION', + #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + State} + end; + _ -> + %% Timeout, rollback. + log_safe(?tr_get_terminator(State), rolled_back), + catch 'ETraP_Server':rollback(?tr_get_etrap(State)), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusRolledBack'), + {stop, normal, + {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + State} + end. + +evaluate_answer(Self, State, Heuristics, false) -> + evaluate_answer(Self, State, Heuristics, commit); +evaluate_answer(Self, State, Heuristics, true) -> + evaluate_answer(Self, State, Heuristics, rollback); +evaluate_answer(_Self, State, Heuristics, Vote) -> + case catch 'ETraP_Common':send_stubborn('ETraP_Server', Vote, + ?tr_get_etrap(State), + ?tr_get_maxR(State), + ?tr_get_maxW(State)) of + ok -> + ?eval_debug_fun({_Self, commit_ok1}, State), + log_safe(?tr_get_terminator(State), committed), + ?eval_debug_fun({_Self, commit_ok2}, State), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusCommitted'), + {stop, normal, ok, State}; + {'EXCEPTION', E} when Heuristics == true andalso + is_record(E,'CosTransactions_HeuristicMixed') -> + log_safe(?tr_get_terminator(State), {heuristic, State, E}), + ?eval_debug_fun({_Self, commit_heuristic1}, State), + catch 'ETraP_Server':forget(?tr_get_etrap(State)), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusRolledBack'), + {stop, normal, {'EXCEPTION', E}, State}; + {'EXCEPTION', E} when Heuristics == true andalso + is_record(E, 'CosTransactions_HeuristicHazard') -> + log_safe(?tr_get_terminator(State), {heuristic, State, E}), + catch 'ETraP_Server':forget(?tr_get_etrap(State)), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusRolledBack'), + {stop, normal, {'EXCEPTION', E}, State}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + log_safe(?tr_get_terminator(State), rolled_back), + {stop, normal, {'EXCEPTION', ?tr_hazard}, State}; + {'EXCEPTION', E} when is_record(E, 'TRANSACTION_ROLLEDBACK') -> + log_safe(?tr_get_terminator(State), rolled_back), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusRolledBack'), + {stop, normal, {'EXCEPTION', E}, State}; + {'EXCEPTION', E} when is_record(E, 'CosTransactions_HeuristicCommit') -> + catch 'ETraP_Server':forget(?tr_get_etrap(State)), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusRolledBack'), + {stop, normal, ok, State}; + {'EXCEPTION', E} when is_record(E, 'CosTransactions_HeuristicRollback') -> + catch 'ETraP_Server':forget(?tr_get_etrap(State)), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusCommitted'), + {stop, normal, + {'EXCEPTION', + #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + State}; + _Other when Heuristics == true -> + log_safe(?tr_get_terminator(State), rolled_back), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusRolledBack'), + {stop, normal, {'EXCEPTION', ?tr_hazard}, State}; + _Other -> + log_safe(?tr_get_terminator(State), rolled_back), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusRolledBack'), + {stop, normal, ok, State} + end. + +%%-----------------------------------------------------------% +%% function : rollback +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : ok - equal to void +%% Effect : +%%------------------------------------------------------------ + +rollback(_Self, State) -> + ?debug_print("Terminator:rollback() called.~n", []), + log_safe(?tr_get_terminator(State), rolled_back), + catch 'ETraP_Server':rollback(?tr_get_etrap(State)), + {stop, normal, ok, State}. + +%%-----------------------------------------------------------% +%% function : do_restart +%% Arguments: State - server context +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%% No data in file. Commit never initiated so we rollback (presumed rollback. +do_restart(State, eof, init) -> + log_safe(?tr_get_terminator(State), rolled_back), + catch 'ETraP_Server':rollback(?tr_get_etrap(State)), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), 'StatusRolledBack'), + self() ! {suicide, self()}, + {ok, State}; + +do_restart(State, {error, Reason}, _) -> + ?tr_error_msg("CosTransactions_Terminator (~p) failed. Cannot read log file: ~p~n", + [?tr_get_terminator(State), Reason]), + {stop, Reason}; +do_restart(State, eof, Phase) -> + ?debug_print("Terminator:do_restart(~p)~n", [Phase]), + case Phase of + committed -> + {ok, ?tr_set_reportH(State, ok)}; + rolled_back -> + self() ! {suicide, self()}, + {ok, State}; + init_commit -> + case catch corba_object:non_existent(?tr_get_etrap(State)) of + true -> + self() ! {suicide, self()}, + {ok, State}; + _-> + case transmit(false, State, ?tr_get_reportH(State)) of + {stop, normal, ok, NewState} -> + {ok, NewState}; + {stop, normal, + {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + NewState} -> + self() ! {suicide, self()}, + {ok, NewState}; + {stop, normal, {'EXCEPTION', Exc}, NewState} -> + if + ?tr_dont_reportH(State) -> + self() ! {suicide, self()}, + {ok, NewState}; + true -> + {ok, ?tr_set_reportH(NewState, Exc)} + end + end + end; + {heuristic, Exc} -> + catch 'ETraP_Server':forget(?tr_get_etrap(State)), +% catch 'ETraP_Server':after_completion(?tr_get_etrap(State), +% 'StatusRolledBack'), + if + ?tr_dont_reportH(State) -> + self() ! {suicide, self()}, + {ok, State}; + true -> + {ok, ?tr_set_reportH(State, {'EXCEPTION',Exc})} + end + end; +%% All done. +do_restart(State, {done, _Cursor}, _Phase) -> + ?debug_print("Terminator:do_restart(~p)~n", [_Phase]), + self() ! {suicide, self()}, + {ok, State}; +do_restart(State, {rolled_back, Cursor}, _Phase) -> + ?debug_print("Terminator:do_restart(~p)~n", [_Phase]), + do_restart(State, get_next(?tr_get_terminator(State), Cursor), rolled_back); +do_restart(State, {committed, Cursor}, _Phase) -> + ?debug_print("Terminator:do_restart(~p)~n", [_Phase]), + do_restart(State, get_next(?tr_get_terminator(State), Cursor), committed); +do_restart(State, {{heuristic, SavedState, Exc}, Cursor}, _Phase) -> + ?debug_print("Terminator:do_restart(~p)~n", [_Phase]), + do_restart(SavedState, get_next(?tr_get_terminator(State), Cursor), + {heuristic, Exc}); +do_restart(State, {{init_commit, SavedState}, Cursor}, _) -> + ?debug_print("Terminator:do_restart(~p)~n", [init_commit]), + do_restart(SavedState, get_next(?tr_get_terminator(State), Cursor), init_commit). + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl b/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl new file mode 100644 index 0000000..36e37e2 --- /dev/null +++ b/lib/cosTransactions/src/CosTransactions_TransactionFactory_impl.erl @@ -0,0 +1,178 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosTransactions_TransactionFactory_impl.erl +%% Purpose : Is provided to allow the transaction originator to begin +%% a transaction. +%%---------------------------------------------------------------------- + +-module('CosTransactions_TransactionFactory_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). + +%% Local +-include_lib("ETraP_Common.hrl"). +-include_lib("CosTransactions.hrl"). +%%--------------- IMPORTS------------------------------------- +-import('ETraP_Common', [get_option/3]). + +%%--------------- EXPORTS------------------------------------- +-export([create/3, recreate/3, init/1, terminate/2]). +-export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]). + +%%--------------- LOCAL DATA --------------------------------- +-record(factory, {hashMax, subtrOK, typeCheck, maxRetries, comFailWait}). + +%%--------------- LOCAL DEFINITIONS -------------------------- + +%%------------------------------------------------------------ +%% function : init +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the module ic. Used to initiate +%% a gen_server. +%%------------------------------------------------------------ + +init(Options) when is_list(Options) -> + ?debug_print("Factory:init(~p)~n", [Options]), + process_flag(trap_exit,true), + DefaultValues = [{maxRetries, ?tr_max_retries}, + {comFailWait, ?tr_comm_failure_wait}|?tr_FAC_DEF], + Hash = get_option(hash_max, Options, DefaultValues), + SubtrOK = get_option(allow_subtr, Options, DefaultValues), + TypeCheck = get_option(typecheck, Options, DefaultValues), + TTY = get_option(tty, Options, DefaultValues), + LogFile = get_option(logfile, Options, DefaultValues), + MaxRetries = get_option(maxRetries, Options, DefaultValues), + ComFailWait = get_option(comFailWait, Options, DefaultValues), + error_logger:tty(TTY), + case LogFile of + false -> + ok; + _-> + error_logger:logfile({open, LogFile}) + end, + {ok, #factory{typeCheck = TypeCheck, hashMax = Hash, subtrOK = SubtrOK, + maxRetries = MaxRetries, comFailWait = ComFailWait}}; + +init(Options) -> + ?tr_error_msg("TransactionFactory~nBad argument: ~p~n", [Options]), + corba:raise(?tr_badparam). + + +%%------------------------------------------------------------ +%% function : terminate +%% Arguments: +%% Returns : +%% Effect : Function demanded by the module ic. Used to +%% terminate a gen_server. +%%------------------------------------------------------------ + +terminate(_Reason, _State) -> + ?debug_print("Factory:terminate(~p)~n", [_Reason]), + ok. + +%%------------------------------------------------------------ +%% function : handle_call, handle_cast, handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the module ic. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_call(_,_, State) -> + {noreply, State}. + + +handle_cast(_, State) -> + {noreply, State}. + + +handle_info({'EXIT',_From,shutdown}, State) -> + ?debug_print("Factory:handle_info(~p)~n", [shutdown]), + {stop, shutdown, State}; +handle_info(_Info, State) -> + ?debug_print("Factory:handle_info(~p)~n", [_Info]), + {noreply, State}. + +%%------------------------------------------------------------ +%% function : create +%% Arguments: TimeOut - rollback the transaction after TimeOut +%% seconds. If 0 no timeout. +%% Returns : a Control object +%% Effect : Creates a new top-level transaction. The Control +%% can be used to manage or control participation +%% in the new transaction. Used for direct context +%% management. +%%------------------------------------------------------------ + +create(_Self, State, TimeOut) when is_integer(TimeOut) -> + %% Generate objectnames. + ETraPName = 'ETraP_Common':create_name("root"), + TermName = 'ETraP_Common':create_name("term"), + EState = ?tr_create_context(ETraPName, TermName, + State#factory.typeCheck, + State#factory.hashMax, + State#factory.subtrOK, + State#factory.maxRetries, + State#factory.comFailWait), + + case TimeOut of + 0 -> + ETraP = ?tr_start_child(?SUP_ETRAP(EState)), + {reply, ETraP, State}; + _ -> + if + TimeOut > 0 -> + {MegaSecs, Secs, _Microsecs} = erlang:now(), + EState2 = ?tr_set_alarm(EState, MegaSecs*1000000+Secs+TimeOut), + EState3 = ?tr_set_timeout(EState2, TimeOut*1000), + ETraP = ?tr_start_child(?SUP_ETRAP(EState3)), + {reply, ETraP, State}; + true -> + ?tr_error_msg("TransactionFactory:create( Integer >= 0 )~nBad argument. Not an integer.~n", []), + corba:raise(?tr_badparam) + end + end; + +create(_Self, _State, _TimeOut) -> + ?tr_error_msg("TransactionFactory:create( Integer >= 0 )~nBad argument. Not an integer.~n", []), + corba:raise(?tr_badparam). + + +%%------------------------------------------------------------ +%% function : recreate +%% Arguments: PropagationContext +%% Returns : a Control object +%% Effect : +%%------------------------------------------------------------ + +recreate(_Self, _State, #'CosTransactions_PropagationContext'{current = _C}) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}). +%recreate(Self, State, #'CosTransactions_PropagationContext'{current = C}) -> +% {reply, C#'CosTransactions_TransIdentity'.coord, State}. + + +%%--------------- END OF MODULE ------------------------------ + diff --git a/lib/cosTransactions/src/ETraP_Common.erl b/lib/cosTransactions/src/ETraP_Common.erl new file mode 100644 index 0000000..dd68e9b --- /dev/null +++ b/lib/cosTransactions/src/ETraP_Common.erl @@ -0,0 +1,185 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : ETraP_Common.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module('ETraP_Common'). + +%%--------------- INCLUDES ---------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +%% Local +-include_lib("ETraP_Common.hrl"). +-include_lib("CosTransactions.hrl"). + +%%--------------- EXPORTS ----------------------------------- +-export([try_timeout/1, + get_option/3, + create_name/2, + create_name/1, + is_debug_compiled/0, + send_stubborn/5, + create_link/3]). + +%%--------------- DEFINITIONS OF CONSTANTS ------------------ +%%------------------------------------------------------------ +%% function : create_link +%% Arguments: Module - which Module to call +%% Env/ARgList - ordinary oe_create arguments. +%% Returns : +%% Exception: +%% Effect : Necessary since we want the supervisor to be a +%% 'simple_one_for_one'. Otherwise, using for example, +%% 'one_for_one', we have to call supervisor:delete_child +%% to remove the childs startspecification from the +%% supervisors internal state. +%%------------------------------------------------------------ +create_link(Module, Env, ArgList) -> + Module:oe_create_link(Env, ArgList). + +%%------------------------------------------------------------ +%% function : get_option +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +get_option(Key, OptionList, DefaultList) -> + case lists:keysearch(Key, 1, OptionList) of + {value,{Key,Value}} -> + Value; + _ -> + case lists:keysearch(Key, 1, DefaultList) of + {value,{Key,Value}} -> + Value; + _-> + {error, "Invalid option"} + end + end. +%%------------------------------------------------------------ +%% function : create_name/2 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +create_name(Name,Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',Name,'_',MSec, '_', Sec, '_', USec]). + +%%------------------------------------------------------------ +%% function : create_name/1 +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +create_name(Type) -> + {MSec, Sec, USec} = erlang:now(), + lists:concat(['oe_',node(),'_',Type,'_',MSec, '_', Sec, '_', USec]). + +%%------------------------------------------------------------ +%% function : try_timeout +%% Arguments: Id - name of the timeoutSrv server. +%% Returns : Boolean +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +try_timeout(TimeoutAt) -> + case TimeoutAt of + infinity -> + false; + _-> + {MegaSecs, Secs, _Microsecs} = erlang:now(), + Time = MegaSecs*1000000+Secs, + if + Time < TimeoutAt -> + false; + true -> + true + end + end. + +%%------------------------------------------------------------ +%% function : send_stubborn +%% Arguments: M - module +%% F - function +%% A - arguments +%% MaxR - Maximum no retries +%% Wait - sleep Wait seconds before next try. +%% Returns : see effect +%% Exception: +%% Effect : Retries repeatedly until anything else besides +%% 'EXIT', 'COMM_FAILURE' or 'OBJECT_NOT_EXIST' +%%------------------------------------------------------------ + +send_stubborn(M, F, A, MaxR, Wait) when is_list(A) -> + send_stubborn(M, F, A, MaxR, Wait, 0); +send_stubborn(M, F, A, MaxR, Wait) -> + send_stubborn(M, F, [A], MaxR, Wait, 0). +send_stubborn(M, F, A, MaxR, _Wait, MaxR) -> + ?tr_error_msg("~p:~p( ~p ) failed!! Tried ~p times.~n", [M,F,A,MaxR]), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}); +send_stubborn(M, F, A, MaxR, Wait, Times) -> + ?debug_print("~p:~p(~p) # of retries: ~p~n", [M,F,A, Times]), + case catch apply(M,F,A) of + {'EXCEPTION', E} when is_record(E, 'COMM_FAILURE')-> + NewTimes = Times +1, + timer:sleep(Wait), + send_stubborn(M, F, A, MaxR, Wait, NewTimes); + {'EXCEPTION', E} when is_record(E, 'TRANSIENT')-> + NewTimes = Times +1, + timer:sleep(Wait), + send_stubborn(M, F, A, MaxR, Wait, NewTimes); + {'EXCEPTION', E} when is_record(E, 'TIMEOUT')-> + NewTimes = Times +1, + timer:sleep(Wait), + send_stubborn(M, F, A, MaxR, Wait, NewTimes); + {'EXIT', _} -> + NewTimes = Times +1, + timer:sleep(Wait), + send_stubborn(M, F, A, MaxR, Wait, NewTimes); + Other -> + ?debug_print("~p:~p(~p) Resulted in: ~p~n", [M,F,A, Other]), + Other + end. + +%%------------------------------------------------------------ +%% function : is_debug_compiled +%% Arguments: +%% Returns : +%% Exception: +%% Effect : +%%------------------------------------------------------------ + +-ifdef(debug). + is_debug_compiled() -> true. +-else. + is_debug_compiled() -> false. +-endif. + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosTransactions/src/ETraP_Common.hrl b/lib/cosTransactions/src/ETraP_Common.hrl new file mode 100644 index 0000000..5082282 --- /dev/null +++ b/lib/cosTransactions/src/ETraP_Common.hrl @@ -0,0 +1,340 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%--------------------------------------------------------------------- +%% File : ETraP_Common.hrl +%% Purpose : +%%--------------------------------------------------------------------- + +-ifndef(ETRAP_COMMON_HRL). +-define(ETRAP_COMMON_HRL, true). + +%%--------------- INCLUDES --------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("cosTransactions/include/CosTransactions.hrl"). + +%%-------- CONSTANTS --------------------------------------------------- +%% Timeouts +-define(tr_comm_failure_wait, + case catch application:get_env(cosTransactions, comFailWait) of + {ok, _Time} when is_integer(_Time) -> + _Time; + _ -> + 5000 + end). + +-define(tr_max_retries, + case catch application:get_env(cosTransactions, maxRetries) of + {ok, _Max} when is_integer(_Max) -> + _Max; + _ -> + 40 + end). + +%% Exceptions +% Heuristic +-define(tr_mixed, + #'CosTransactions_HeuristicMixed' {}). +-define(tr_hazard, + #'CosTransactions_HeuristicHazard' {}). +-define(tr_commit, + #'CosTransactions_HeuristicCommit' {}). +-define(tr_rollback, + #'CosTransactions_HeuristicRollback' {}). +%% Standard +-define(tr_subunavailable, + #'CosTransactions_SubtransactionsUnavailable' {}). +-define(tr_unavailable, + #'CosTransactions_Unavailable' {}). +-define(tr_unprepared, + #'CosTransactions_NotPrepared' {}). +-define(tr_inactive, + #'CosTransactions_Inactive' {}). +-define(tr_nosync, + #'CosTransactions_SynchronizationUnavailable' {}). +-define(tr_badparam, + #'BAD_PARAM'{completion_status=?COMPLETED_NO}). +-define(tr_NotSubtr, + #'CosTransactions_NotSubtransaction' {}). + +%% TypeID:s +-define(tr_Terminator, + 'CosTransactions_Terminator':typeID()). +-define(tr_Coordinator, + 'CosTransactions_Coordinator':typeID()). +-define(tr_Control, + 'CosTransactions_Control':typeID()). +-define(tr_RecoveryCoordinator, + 'CosTransactions_RecoveryCoordinator':typeID()). +-define(tr_SubtransactionAwareResource, + 'CosTransactions_SubtransactionAwareResource':typeID()). +-define(tr_Synchronization, + 'CosTransactions_Synchronization':typeID()). +-define(tr_Resource, + 'CosTransactions_Resource':typeID()). +-define(tr_ETraP, + 'ETraP_Server':typeID()). +-define(tr_TransactionalObject, + 'CosTransactions_TransactionalObject':typeID()). + + +%%-------- MISC -------------------------------------------------------- + +-define(tr_error_msg(Txt, Arg), +error_logger:error_msg("============ CosTransactions ==============~n" + Txt + "===========================================~n", + Arg)). + + +-define(tr_NIL_OBJ_REF, corba:create_nil_objref()). + +-define(tr_FAC_DEF, [{hash_max, 1013}, + {allow_subtr, true}, + {typecheck, true}, + {tty, false}, + {logfile, false}]). + + +%%-------- Supervisor child-specs ------------------------------------ +-define(FACTORY_NAME, oe_cosTransactionsFactory). +-define(SUPERVISOR_NAME, cosTransactions_sup). +-define(SUP_FLAG, {simple_one_for_one,50,10}). + +-define(SUP_FAC(Env), + ['CosTransactions_TransactionFactory',Env, + [{sup_child, true}, {regname, {local, ?FACTORY_NAME}}]]). + +-define(SUP_ETRAP(Env), + ['ETraP_Server', Env, + [{sup_child, true}, {persistent, true}, + {regname, {global, ?tr_get_etrap(Env)}}]]). + +-define(SUP_TERMINATOR(Env), + ['CosTransactions_Terminator', Env, + [{sup_child, true}, {persistent, true}, + {regname, {global, ?tr_get_etrap(Env)}}]]). + +-define(SUP_CHILD, + {"oe_child", + {'ETraP_Common',create_link, []}, + transient,100000,worker, + ['ETraP_Common', + 'ETraP_Server_impl', + 'ETraP_Server', + 'CosTransactions_Terminator_impl', + 'CosTransactions_Terminator', + 'CosTransactions_TransactionFactory_impl', + 'CosTransactions_TransactionFactory']}). + + +-define(tr_start_child(SPEC), + case supervisor:start_child(?SUPERVISOR_NAME, SPEC) of + {ok, Pid, Obj} when is_pid(Pid) -> + Obj; + _Other-> + corba:raise(?tr_badparam) + end). + +-define(tr_start_child_pid(SPEC), + supervisor:start_child(?SUPERVISOR_NAME, SPEC)). + +-define(tr_terminate_child(Child), + supervisor:terminate_child(?SUPERVISOR_NAME, Child)). + +-define(tr_delete_child(Child), + supervisor:delete_child(?SUPERVISOR_NAME, Child)). + +%%-------- DATASTRUCTURES ---------------------------------------------- +%% tr_*_* +-record(context, {terminator, etrap, recCoord, alarm = infinity, + timeout = infinity, parents=[], trid, typeCheck, + sub_tr_allowed, hashMax, local, rollback=false, + reportH, maxRetries, comFailWait}). + + +%%-------- FUNS -------------------------------------------------------- +-define(tr_IS_MEMBER(Obj), + fun(X) -> + case catch corba_object:is_equivalent(Obj, X) of + true -> + true; + _ -> + false + end + end). + +%% Managing conditional debug functions +-define(is_debug_compiled, 'ETraP_Common':is_debug_compiled()). +-define(set_debug_context(L, C), + etrap_test_lib:set_debug_context(L, C, ?FILE, ?LINE)). + + +-ifdef(debug). +-define(put_debug_data(Key, Data), erlang:put(Key, Data)). +-define(get_debug_data(Key), erlang:get(Key)). +-define(eval_debug_fun(I, E), + etrap_test_lib:eval_debug_fun(I, E, ?FILE, ?LINE)). +-define(activate_debug_fun(I, F, C), + etrap_test_lib:activate_debug_fun(I, F, C, ?FILE, ?LINE)). +-define(deactivate_debug_fun(I), + etrap_test_lib:deactivate_debug_fun(I, ?FILE, ?LINE)). +-define(debug_print(F,A), + io:format("[LINE: ~p] "++F,[?LINE]++A)). +-define(scratch_debug_fun, + etrap_test_lib:scratch_debug_fun()). +-else. +-define(put_debug_data(Key, Data), ok). +-define(get_debug_data(Key), ok). +-define(eval_debug_fun(I, E), ok). +-define(activate_debug_fun(I, F, C), ok). +-define(deactivate_debug_fun(I), ok). +-define(debug_print(F,A), ok). +-define(scratch_debug_fun, ok). +-endif. + + +%%-------- CONSTRUCTORS ------------------------------------------------ + +-define(tr_create_context(ETraP, Terminator, TypeCheck, HM, SubtrOK, MaxRetries, + ComFailWait), + #context{etrap = ETraP, terminator = Terminator, typeCheck = TypeCheck, + hashMax = HM, sub_tr_allowed = SubtrOK, maxRetries = MaxRetries, + comFailWait = ComFailWait}). + + +%%-------- MISC -------------------------------------------------------- +-define(tr_notimeout(Context), + 'ETraP_Common':try_timeout(Context#context.alarm) == false). +-define(tr_is_root(Context), Context#context.parents == []). +-define(tr_dont_reportH(Context), Context#context.reportH == false). +-define(tr_is_retransmit(Context), + Context#context.reportH =/= undefined, + Context#context.reportH =/= true, + Context#context.reportH =/= false). + +%%-------- SELECTORS --------------------------------------------------- + +-define(tr_get_reportH(Context), + Context#context.reportH). + +-define(tr_get_rollback(Context), + Context#context.rollback). + +-define(tr_get_subTraOK(Context), + Context#context.sub_tr_allowed). + +-define(tr_get_hashMax(Context), + Context#context.hashMax). + +-define(tr_get_local(Context), + Context#context.local). + +-define(tr_get_trid(Context), + Context#context.trid). + +-define(tr_get_typeCheck(Context), + Context#context.typeCheck). + +-define(tr_get_recCoord(Context), + Context#context.recCoord). + +-define(tr_get_alarm(Context), + Context#context.alarm). + +-define(tr_get_timeout(Context), + Context#context.timeout). + +-define(tr_get_etrap(Context), + Context#context.etrap). + +-define(tr_get_terminator(Context), + Context#context.terminator). + +-define(tr_get_id(Context), + Context#context.self). + +-define(tr_get_maxW(Context), + Context#context.comFailWait). + +-define(tr_get_maxR(Context), + Context#context.maxRetries). + +-define(tr_get_parents(Context), + Context#context.parents). + +-define(tr_get_parent(Context), + lists:nth(1, Context#context.parents)). + +%%-------- MODIFIERS --------------------------------------------------- + +-define(tr_set_reportH(Context, Bool), + Context#context{reportH = Bool}). + +-define(tr_set_rollback(Context, Bool), + Context#context{rollback = Bool}). + +-define(tr_set_subTraOK(Context, Bool), + Context#context{sub_tr_allowed = Bool}). + +-define(tr_set_hashMax(Context, HM), + Context#context{hashMax = HM}). + +-define(tr_reset_local(Context), + Context#context{local = undefined}). + +-define(tr_set_local(Context, Local), + Context#context{local = Local}). + +-define(tr_set_trid(Context, TRID), + Context#context{trid = TRID}). + +-define(tr_set_typeCheck(Context, Bool), + Context#context{typeCheck = Bool}). + +-define(tr_set_id(Context, ID), + Context#context{self = ID}). + +-define(tr_set_parents(Context, Parents), + Context#context{parents = Parents). + +-define(tr_add_parent(Context, Parent), + Context#context{parents = [Parent] ++ Context#context.parents}). + +-define(tr_set_recCoord(Context, R), + Context#context{recCoord = R}). + +-define(tr_set_alarm(Context, EC), + Context#context{alarm = EC}). + +-define(tr_set_timeout(Context, T), + Context#context{timeout = T}). + +-define(tr_set_etrap(Context, ETraP), + Context#context{etrap = ETraP}). + +-define(tr_set_terminator(Context, T), + Context#context{terminator = T}). + +-endif. + +%%-------------- EOF --------------------------------------------------- + + diff --git a/lib/cosTransactions/src/ETraP_Server_impl.erl b/lib/cosTransactions/src/ETraP_Server_impl.erl new file mode 100644 index 0000000..e2c5d88 --- /dev/null +++ b/lib/cosTransactions/src/ETraP_Server_impl.erl @@ -0,0 +1,1739 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : ETraP_Server_impl.erl +%% Purpose : +%%---------------------------------------------------------------------- +%% GENERAL CODE COMMENTS: +%% ###################### +%% TypeChecking incoming arguments: +%% -------------------------------- +%% We allow the user to configure the system so that external calls +%% (not CosTransactions calls) may be typechecked or not when calling +%% for example 'replay_completion'. With typecheck the user will get +%% instant feedback. But since 'is_a' add quiet a lot extra overhead +%% if the object is located on a remote ORB. Hence, it is up to the +%% user to decide; speed vs. "safety". +%% +%% Log behavior +%% ------------ +%% Log files are created in the current directory, which is why the +%% application requires read/write rights for current directory. The +%% file name looks like: +%% "oe_nonode@nohost_subc_939_383117_295538" (the last part is now()) +%% It is equal to what the object is started as, i.e., {regname, {global, X}}. +%% +%% If the application is unable to read the log it will exit and the +%% supervisor definitions (found in ETraP_Common.hrl) determines how +%% many times we will retry. If it's impossible to read the log it's +%% considered as a disaster, i.e., user intervention is needed. +%% +%% If an Object is unreachable when a Coordinator is trying to inform +%% of the true outcome of the transaction the application will retry N +%% times with T seconds wait in between. If it's still impossible to +%% reach the object it's considered as a disaster, i.e., user +%% intervention is needed. +%% +%%---------------------------------------------------------------------- + +-module('ETraP_Server_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). + +%% Local +-include_lib("cosTransactions/src/ETraP_Common.hrl"). +-include_lib("cosTransactions/include/CosTransactions.hrl"). + + +%%--------------- IMPORTS------------------------------------- +-import('ETraP_Common', [try_timeout/1]). + +%%--------------- EXPORTS------------------------------------- +%%--------------- Inherit from CosTransactions::Resource ---- +-export([prepare/2, + rollback/2, + commit/2, + commit_one_phase/2, + forget/2]). + +%%--------------- Inherit from CosTransactions::Control ----- +-export([get_terminator/2, + get_coordinator/2]). + +%%----- Inherit from CosTransactions::RecoveryCoordinator --- +-export([replay_completion/3]). + +%%--------------- Inherit from CosTransactions::Coordinator - +-export([create_subtransaction/2, + get_txcontext/2, + get_transaction_name/2, + get_parent_status/2, + get_status/2, + get_top_level_status/2, + hash_top_level_tran/2, + hash_transaction/2, + is_ancestor_transaction/3, + is_descendant_transaction/3, + is_related_transaction/3, + is_same_transaction/3, + is_top_level_transaction/2, + register_resource/3, + register_subtran_aware/3, + register_synchronization/3, + rollback_only/2]). + +%%--------- Inherit from CosTransactions::Synchronization --- +%-export([before_completion/2, +% after_completion/3]). + + +%%--------------- gen_server specific ------------------------ +-export([init/1, terminate/2]). +-export([handle_call/3, handle_cast/2, handle_info/2, code_change/3]). + + + +%%--------------- LOCAL DATA --------------------------------- +-record(exc, + {rollback = false, + mixed = false, + hazard = false, + unprepared = false, + commit = false}). + +%%--------------- LOCAL DEFINITIONS -------------------------- + +%%--------------- MISC MACROS -------------------------------- +-define(etr_log(Log, Data), etrap_logmgr:log_safe(Log, Data)). +-define(etr_read(Log, Cursor), etrap_logmgr:get_next(Log, Cursor)). + +-record(coord, + {status, %% Status of the transaction. + members = [], %% List of registred resources. + votedCommit = [], %% List of the ones that voted commit. + raisedHeuristic = [], %% The members which raised an Heur. exc. + subAw = [], %% Resorces which want to be informed of outcome. + sync = [], + exc = void, + self, + etsR}). + +%% Selectors +-define(etr_get_status(L), L#coord.status). +-define(etr_get_members(L), lists:reverse(L#coord.members)). +-define(etr_get_vc(L), lists:reverse(L#coord.votedCommit)). +-define(etr_get_raisedH(L), lists:reverse(L#coord.raisedHeuristic)). +-define(etr_get_exc(L), L#coord.exc). +-define(etr_get_subAw(L), lists:reverse(L#coord.subAw)). +-define(etr_get_sync(L), lists:reverse(L#coord.sync)). +-define(etr_get_self(L), L#coord.self). +-define(etr_get_etsR(L), L#coord.etsR). +-define(etr_get_init(Env), #coord{}). +-define(etr_get_exc_init(), #exc{}). +%% Modifiers +-define(etr_set_status(L, D), L#coord{status = D}). +-define(etr_set_members(L, D), L#coord{members = D}). +-define(etr_add_member(L, D), L#coord{members = [D|L#coord.members]}). +-define(etr_set_vc(L, D), L#coord{votedCommit = D}). +-define(etr_add_vc(L, D), L#coord{votedCommit = [D|L#coord.votedCommit]}). +-define(etr_remove_vc(L, D), L#coord{votedCommit = + lists:delete(D, ?etr_get_vc(L))}). +-define(etr_set_raisedH(L, D), L#coord{raisedHeuristic = [D]}). +-define(etr_add_raisedH(L, D), L#coord{raisedHeuristic = + [D|L#coord.raisedHeuristic]}). +-define(etr_remove_raisedH(L, D), L#coord{raisedHeuristic = + lists:delete(D, ?etr_get_raisedH(L))}). +-define(etr_set_exc(L, D), L#coord{exc = D}). +-define(etr_set_subAw(L, D), L#coord{subAw = [D]}). +-define(etr_add_subAw(L, D), L#coord{subAw = [D|L#coord.subAw]}). +-define(etr_remove_subAw(L, D), L#coord{subAw = + lists:delete(D,?etr_get_subAw(L))}). +-define(etr_set_sync(L, D), L#coord{sync = [D]}). +-define(etr_add_sync(L, D), L#coord{sync = [D|L#coord.sync]}). +-define(etr_remove_sync(L, D), L#coord{sync = lists:delete(D,?etr_get_sync(L))}). +-define(etr_set_self(L, D), L#coord{self = D}). +-define(etr_set_etsR(L, D), L#coord{etsR = D}). + + +%%------------------------------------------------------------ +%% function : init, terminate +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the module ic. +%%------------------------------------------------------------ + +init(Env) -> + process_flag(trap_exit,true), + case catch start_object(Env) of + {'EXIT', Reason} -> + %% Happens when, for example, we encounter an + %% error when reading from the log file. + {stop, Reason}; + {'EXCEPTION', E} -> + self() ! {suicide, self()}, + corba:raise(E); + Other -> + Other + end. + + + +terminate(Reason, {Env, _Local}) -> + ?debug_print("STOP ~p ~p~n", [?tr_get_etrap(Env), Reason]), + case Reason of + normal -> + %% normal termination. Transaction completed. + etrap_logmgr:stop(?tr_get_etrap(Env)), + file:delete(?tr_get_etrap(Env)), + ok; + _ -> + ?tr_error_msg("Object(~p) terminated abnormal.~n",[?tr_get_etrap(Env)]), + ok + end. + + +%%------------------------------------------------------------ +%% function : handle_call, handle_cast, handle_info, code_change +%% Arguments: +%% Returns : +%% Effect : Functions demanded by the gen_server module. +%%------------------------------------------------------------ + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +handle_call(_,_, State) -> + {noreply, State}. + +handle_cast(_, State) -> + {noreply, State}. + + +handle_info(Info, {Env, Local}) -> + ?debug_print("ETraP_Server:handle_info(~p)~n", [Info]), + Pid = self(), + case Info of + timeout -> + ?tr_error_msg("Object( ~p ) timeout. Rolling back.~n", + [?tr_get_etrap(Env)]), + {stop, normal, {Env, Local}}; + {suicide, Pid} -> + {stop, normal, {Env, Local}}; + _-> + {noreply, {Env, Local}} + end. + + +%%--------------- Inherit from CosTransactions::Control ----- +%%-----------------------------------------------------------% +%% function : get_terminator +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : a Terminator object reference. +%% Effect : Supports operations for termination of a transaction +%%------------------------------------------------------------ + +get_terminator(Self, {Env, Local}) -> + %% Only allows the root-coordinator to export the termonator. + %% The reason for this is that only the root-coordinator is allowed + %% to initiate termination of a transaction. This is however possible + %% to change and add restictions elsewhere, i.e. to verify if the + %% commit or rollback call is ok. + case catch ?tr_get_parents(Env) of + [] -> % No parents, it's a root-coordinator. + % Create terminators environment. + TEnv = ?tr_set_etrap(Env, Self), + T = ?tr_start_child(?SUP_TERMINATOR(TEnv)), + {reply, T, {Env, Local}, ?tr_get_timeout(TEnv)}; + _ -> + corba:raise(?tr_unavailable) + end. + +%%-----------------------------------------------------------% +%% function : get_coordinator +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : a Coordinator object reference. The OMG specification +%% states that a object reference must be returned. +%% Effect : Supports operations needed by resources to participate +%% in the transaction. +%%------------------------------------------------------------ + +get_coordinator(Self, State) -> + {reply, Self, State}. + +%%----- Inherit from CosTransactions::RecoveryCoordinator --- +%%-----------------------------------------------------------% +%% function : replay_completion +%% Arguments: +%% Returns : Status +%% Effect : Provides a hint to the Coordinator that the commit +%% or rollback operations have not been performed on +%% the resource. +%%------------------------------------------------------------ + +replay_completion(_Self, {Env, Local}, Resource) -> + type_check(?tr_get_typeCheck(Env), ?tr_Resource, + "RecoveryCoordinator:replay_completion", Resource), + case ?etr_get_status(Local) of + 'StatusActive' -> + corba:raise(?tr_unprepared); + Status -> + case lists:any(?tr_IS_MEMBER(Resource), ?etr_get_members(Local)) of + true -> + {reply, Status, {Env, Local}}; + _ -> + corba:raise(#'NO_PERMISSION'{completion_status=?COMPLETED_YES}) + end + end. + +%%--------------- Inherit from CosTransactions::Resource ---- +%%-----------------------------------------------------------% +%% function : prepare +%% Arguments: +%% Returns : a Vote +%% Effect : Is invoked to begin the two-phase-commit on the +%% resource. +%%------------------------------------------------------------ + +prepare(_Self, {Env, Local}) -> + %% Set status as prepared. No new Resources are allowed to register. + NewL = ?etr_set_status(Local, 'StatusPrepared'), + + ?eval_debug_fun({?tr_get_etrap(Env), root_delay}, Env), + + case catch send_prepare(?etr_get_members(NewL), + ?tr_get_alarm(Env)) of + readOnly -> + %% All voted ReadOnly, done. No need to log. + {stop, normal, 'VoteReadOnly', {Env, NewL}}; + %% Replace the reply above if allow synchronization +% case ?etr_get_sync(Local) of +% [] -> +% {stop, normal, 'VoteReadOnly', {Env, NewL}}; +% _ -> +% {reply, 'VoteReadOnly', {Env, NewL}} +% end; + {commit, VC} -> + %% All voted Commit. + NewL2 = ?etr_set_vc(NewL, VC), + case catch try_timeout(?tr_get_alarm(Env)) of + false -> + case ?etr_log(?tr_get_etrap(Env), {pre_vote, commit, NewL2}) of + ok -> + ?eval_debug_fun({?tr_get_etrap(Env), prepare1}, Env), + {reply, 'VoteCommit', {Env, NewL2}}; + _-> + %% Cannot log. Better to be safe than sorry; do rollback. + %% However, try to log rollback. + ?etr_log(?tr_get_etrap(Env),{pre_vote, rollback, NewL2}), + send_decision({Env, NewL2}, 'VoteRollback', rollback) + end; + _-> + ?etr_log(?tr_get_etrap(Env), + {pre_vote, rollback, NewL2}), + %% timeout, reply rollback. + send_decision({Env, NewL2}, 'VoteRollback', rollback) + end; + {rollback, VC} -> + %% Rollback vote received. + %% Send rollback to commit voters. + N2 = ?etr_set_vc(NewL, VC), + NewL2 = ?etr_set_status(N2,'StatusRolledBack'), + ?etr_log(?tr_get_etrap(Env), {pre_vote, rollback, NewL2}), + send_decision({Env, NewL2}, 'VoteRollback', rollback); + {'EXCEPTION', E, VC, Obj} -> + NewL2 = case is_heuristic(E) of + true -> + N2 = ?etr_set_vc(NewL, VC), + N3 = ?etr_set_exc(N2, E), + ?etr_set_raisedH(N3, Obj); + _-> + ?etr_set_vc(NewL, VC) + end, + ?etr_log(?tr_get_etrap(Env),{pre_vote,rollback, NewL2}), + ?eval_debug_fun({?tr_get_etrap(Env), prepare2}, Env), + send_decision({Env, NewL2}, {'EXCEPTION', E}, rollback); + {failed, VC} -> + NewL2 = ?etr_set_vc(NewL, VC), + ?etr_log(?tr_get_etrap(Env),{pre_vote, rollback, NewL2}), + send_decision({Env, NewL2}, + {'EXCEPTION', ?tr_hazard}, rollback) + end. + + +%%-----------------------------------------------------------% +%% function : rollback +%% Arguments: Self - the servers own objref. +%% {Env, Local} - the servers internal state. +%% Returns : ok +%% Effect : Rollback the transaction. If its status is +%% "StatusRolledBack", this is not the first +%% rollback call to this server. Might occur if +%% the parent coordinator just recoeverd from a crasch. +%% Exception: HeuristicCommit, HeuristicMixed, HeuristicHazard +%%------------------------------------------------------------ + +rollback(Self, {Env, Local}) -> + case ?etr_get_status(Local) of + 'StatusRolledBack' -> + case ?etr_get_exc(Local) of + void -> + {stop, normal, ok, {Env, Local}}; + %% Replace the reply above if allow synchronization + %% Rolled back successfullly earlier. +% case ?etr_get_sync(Local) of +% [] -> +% {stop, normal, ok, {Env, Local}}; +% _ -> +% {reply, ok, {Env, Local}} +% end; + E -> + %% Already rolledback with heuristic decision + corba:raise(E) + end; + 'StatusPrepared' -> + NewL = ?etr_set_status(Local, 'StatusRolledBack'), + ?eval_debug_fun({?tr_get_etrap(Env), rollback}, Env), + ?etr_log(?tr_get_etrap(Env), rollback), + ?eval_debug_fun({?tr_get_etrap(Env), rollback2}, Env), + send_decision({Env, NewL}, ok, rollback); + 'StatusActive' -> + NewL = ?etr_set_status(Local, 'StatusRolledBack'), + ?etr_log(?tr_get_etrap(Env), {rollback, NewL}), + send_info(?etr_get_members(NewL), 'CosTransactions_Resource', rollback), + notify_subtrAware(rollback, ?etr_get_subAw(NewL), Self), + {stop, normal, ok, {Env, NewL}} +%% Replace the reply above if allow synchronization +% case ?etr_get_sync(Local) of +% [] -> +% {stop, normal, ok, {NewEnv, NewL}}; +% _ -> +% {reply, ok, {NewEnv, NewL}} +% end; + end. + + +%%-----------------------------------------------------------% +%% function : commit +%% Arguments: Self - the servers own objref. +%% {Env, Local} - the servers internal state. +%% Returns : ok +%% Effect : Commit the transaction. +%% Exception: HeuristicRollback, HeuristicMixed, HeuristicHazard, +%% NotPrepared +%%------------------------------------------------------------ + +commit(_Self, {Env, Local}) -> + case ?etr_get_status(Local) of + 'StatusPrepared' -> + ?eval_debug_fun({?tr_get_etrap(Env), commit}, Env), + NewL = ?etr_set_status(Local, 'StatusCommitted'), + ?etr_log(?tr_get_etrap(Env),commit), + ?eval_debug_fun({?tr_get_etrap(Env), commit2}, Env), + send_decision({Env, NewL}, ok, commit); + 'StatusCommitted' -> + case ?etr_get_exc(Local) of + void -> + {stop, normal, ok, {Env, Local}}; + %% Replace the reply above if allow synchronization +% case ?etr_get_sync(Local) of +% [] -> +% {stop, normal, ok, {Env, Local}}; +% _ -> +% {reply, ok, {Env, Local}} +% end; + E-> + corba:raise(E) + end; + _ -> + corba:raise(?tr_unprepared) + end. + +%%-----------------------------------------------------------% +%% function : commit_one_phase +%% Arguments: Self - the servers own objref. +%% {Env, Local} - the servers internal state. +%% Returns : ok +%% Effect : Commit the transaction using one-phase commit. +%% Use ONLY when there is only one registered Resource. +%% Exception: HeuristicRollback, HeuristicMixed, HeuristicHazard, +%% TRANSACTION_ROLLEDBACK +%%------------------------------------------------------------ + +commit_one_phase(_Self, {Env, Local}) -> + case ?etr_get_members(Local) of + [Resource] -> + case ?etr_get_status(Local) of + 'StatusActive' -> + %% Set status as prepared. No new Resources are allowed to register. + NewL = ?etr_set_status(Local, 'StatusPrepared'), + ?eval_debug_fun({?tr_get_etrap(Env), onePC}, Env), + case try_timeout(?tr_get_alarm(Env)) of + false -> + case catch 'CosTransactions_Resource':prepare(Resource) of + 'VoteCommit' -> + case try_timeout(?tr_get_alarm(Env)) of + false -> + send_decision({Env, NewL}, ok, commit, [Resource]); + _-> + %% Timeout, rollback. + send_decision({Env, NewL}, + {'EXCEPTION', + #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + rollback, [Resource]) + end; + 'VoteRollback' -> + {stop, normal, + {'EXCEPTION', + #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + {Env, NewL}}; + 'VoteReadOnly' -> + {stop, normal, ok, {Env, NewL}}; + {'EXCEPTION', E} + when is_record(E, 'CosTransactions_HeuristicMixed') -> + {reply, {'EXCEPTION', E}, {Env, NewL}}; + {'EXCEPTION', E} + when is_record(E, 'CosTransactions_HeuristicHazard') -> + {reply, {'EXCEPTION', E}, {Env, NewL}}; + Other -> + ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n", + [Resource, Other]), + {stop, normal, + {'EXCEPTION', + #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + {Env, NewL}} + end; + _-> + NewL2 = ?etr_set_status(NewL, 'StatusRolledBack'), + send_info(Resource, 'CosTransactions_Resource', rollback), + {stop, normal, + {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + {Env, NewL2}} + %% Replace the reply above if allow synchronization +% case ?etr_get_sync(NewL2) of +% [] -> +% send_info(Resource, 'CosTransactions_Resource', rollback), +% {stop, normal, +% {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, +% {Env, NewL2}}; +% _ -> +% send_info(Resource, 'CosTransactions_Resource', rollback), +% {reply, +% {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, +% {Env, NewL2}} +% end + end; + _ -> + case evaluate_status(?etr_get_status(Local)) of + commit -> + test_exc(set_exception(?etr_get_exc_init(), + ?etr_get_exc(Local)), + commit, ok, {Env, Local}); + _-> + test_exc(set_exception(?etr_get_exc_init(), + ?etr_get_exc(Local)), + rollback, + {'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}}, + {Env, Local}) + end + end; + _-> + {reply, {'EXCEPTION', #'NO_PERMISSION'{completion_status=?COMPLETED_NO}}, + {Env, Local}} + end. + +%%-----------------------------------------------------------% +%% function : forget +%% Arguments: Self - the servers own objref. +%% State - the servers internal state. +%% Returns : ok +%% Effect : The resource can forget all knowledge about the +%% transaction. Terminate this server. +%%------------------------------------------------------------ + +forget(_Self, {Env, Local}) -> + ?etr_log(?tr_get_etrap(Env), forget_phase), + send_forget(?etr_get_raisedH(Local), ?tr_get_etrap(Env)), + {stop, normal, ok, {Env, ?etr_set_exc(Local, void)}}. +%% Replace the reply above if allow synchronization +% case ?etr_get_sync(Local) of +% [] -> +% {stop, normal, ok, {Env, ?etr_set_exc(Local, void)}}; +% _ -> +% {reply, ok, {Env, ?etr_set_exc(Local, void)}} +% end. + +%%--------------- Inherrit from CosTransactions::Coordinator - + +%%-----------------------------------------------------------% +%% function : get_status +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : Status +%% Effect : Returns the status of the transaction associated +%% with the target object. +%%------------------------------------------------------------ + +get_status(_Self, {Env, Local}) -> + {reply, ?etr_get_status(Local), {Env, Local}}. + + +%%-----------------------------------------------------------% +%% function : get_parent_status +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : Status +%% Effect : Returns the status of the parent transaction +%% associated with the target object. If top-level +%% transaction equal to get_status. +%%------------------------------------------------------------ + +get_parent_status(_Self, {Env, Local}) -> + case catch ?tr_get_parents(Env) of + [] -> + {reply, ?etr_get_status(Local), {Env, Local}}; + [Parent|_] -> + case catch 'CosTransactions_Coordinator':get_status(Parent) of + {'EXCEPTION', _E} -> + corba:raise(?tr_unavailable); + {'EXIT', _} -> + corba:raise(?tr_unavailable); + Status -> + {reply, Status, {Env, Local}} + end + end. + + +%%-----------------------------------------------------------% +%% function : get_top_level_status +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : Status +%% Effect : Returns the status of the top-level transaction +%% associated with the target object. If top-level +%% transaction equal to get_status. +%%------------------------------------------------------------ + +get_top_level_status(_Self, {Env, Local}) -> + case catch ?tr_get_parents(Env) of + [] -> + {reply, ?etr_get_status(Local), {Env, Local}}; + Ancestrors -> + case catch 'CosTransactions_Coordinator':get_status(lists:last(Ancestrors)) of + {'EXCEPTION', _E} -> + corba:raise(?tr_unavailable); + {'EXIT', _} -> + corba:raise(?tr_unavailable); + Status -> + {reply, Status, {Env, Local}} + end + end. + + +%%-----------------------------------------------------------% +%% function : is_same_transaction +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Coordinator object reference +%% Returns : boolean +%% Effect : +%%------------------------------------------------------------ + +is_same_transaction(Self, {Env, Local}, Coordinator) -> + type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, + "Coordinator:is_same_transaction", Coordinator), + {reply, corba_object:is_equivalent(Self, Coordinator), {Env, Local}}. + +%%------------------------------------------------------------ +%% function : is_related_transaction +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Coordinator object reference +%% Returns : boolean +%% Effect : +%%------------------------------------------------------------ + +is_related_transaction(_Self, {_Env, _Local}, _Coordinator) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}). +% type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, +% "Coordinator:is_related_transaction", Coordinator), +% {reply, false, {Env, Local}}. + + +%%------------------------------------------------------------ +%% function : is_ancestor_transaction +%% Coordinator object reference +%% Returns : boolean +%% Effect : +%%------------------------------------------------------------ + +is_ancestor_transaction(_Self, {_Env, _Local}, _Coordinator) -> + corba:raise(#'NO_IMPLEMENT'{completion_status=?COMPLETED_YES}). +% type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, +% "Coordinator:is_ancestor_transaction", Coordinator), +% {reply, false, {Env, Local}}. + + +%%-----------------------------------------------------------% +%% function : is_descendant_transaction +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Coordinator object reference +%% Returns : boolean +%% Effect : +%%------------------------------------------------------------ + +is_descendant_transaction(Self, {Env, Local}, Coordinator) -> + type_check(?tr_get_typeCheck(Env), ?tr_Coordinator, + "Coordinator:is_descendant_transaction", Coordinator), + {reply, + lists:any(?tr_IS_MEMBER(Coordinator), [Self|?tr_get_parents(Env)]), + {Env, Local}}. + +%%-----------------------------------------------------------% +%% function : is_top_level_transaction +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : boolean +%% Effect : +%%------------------------------------------------------------ + +is_top_level_transaction(_Self, {Env, Local}) -> + case catch ?tr_get_parents(Env) of + [] -> + {reply, true, {Env, Local}}; + _ -> + {reply, false, {Env, Local}} + end. + +%%-----------------------------------------------------------% +%% function : hash_transaction +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : hash code +%% Effect : Returns a hash code for the transaction associated +%% with the target object. +%%------------------------------------------------------------ + +hash_transaction(Self, {Env, Local}) -> + {reply, corba_object:hash(Self, ?tr_get_hashMax(Env)), {Env, Local}}. + + +%%-----------------------------------------------------------% +%% function : hash_top_level_tran +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : hash code +%% Effect : Returns a hash code for the top-level transaction +%% associated with the target object. Equals +%% hash_transaction if it's a top-level transaction. +%%------------------------------------------------------------ + +hash_top_level_tran(Self, {Env, Local}) -> + case ?tr_get_parents(Env) of + [] -> + {reply, + corba_object:hash(Self, ?tr_get_hashMax(Env)), + {Env, Local}}; + Ancestrors -> + case catch corba_object:hash(lists:last(Ancestrors), + ?tr_get_hashMax(Env)) of + {'EXCEPTION', _E} -> + corba:raise(?tr_unavailable); + Hash -> + {reply, Hash, {Env, Local}} + end + end. + + + +%%-----------------------------------------------------------% +%% function : register_resource +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Resource object reference +%% Returns : RecoveryCoordinator (can be used during recovery) +%% Effect : Registers the specified resource as as participant +%% in the transaction associated with the target object. +%% Exception: Inactive - Is prepared or terminated. +%%------------------------------------------------------------ + +register_resource(Self, {Env, Local}, Resource) -> + type_check(?tr_get_typeCheck(Env), ?tr_Resource, + "Coordinator:register_resource", Resource), + case ?etr_get_status(Local) of + 'StatusActive' -> % ok to register the Resource. + NewLocal = ?etr_add_member(Local, Resource), + RecoveryCoord = corba:create_subobject_key(Self, ?tr_get_etrap(Env)), + {reply, RecoveryCoord, {Env, NewLocal}, ?tr_get_timeout(Env)}; + _-> % Not active anymore. New members not ok. + corba:raise(?tr_inactive) + end. + + + +%%-----------------------------------------------------------% +%% function : register_subtran_aware +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% SubTransactionAwareResource object reference +%% Returns : - +%% Effect : Registers the specified object such that it +%% will be notified when the subtransaction has +%% commited or rolled back. +%%------------------------------------------------------------ + +register_subtran_aware(Self, {Env, Local}, SubTrAwareResource) -> + case ?tr_get_parents(Env) of + [] -> + corba:raise(?tr_NotSubtr); + _-> + type_check(?tr_get_typeCheck(Env), ?tr_SubtransactionAwareResource, + "Coordinator:register_subtran_aware", SubTrAwareResource), + NewL = ?etr_add_subAw(Local, SubTrAwareResource), + {reply, ok, {Env, ?etr_set_self(NewL, Self)}, + ?tr_get_timeout(Env)} + end. + +%%-----------------------------------------------------------% +%% function : register_synchronization +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Synchronization +%% Returns : - +%% Effect : +%%------------------------------------------------------------ + +register_synchronization(_Self, {_Env, _Local}, _Synchronization) -> + corba:raise(#'CosTransactions_SynchronizationUnavailable'{}). + +%register_synchronization(Self, {Env, Local}, Synchronization) -> +% type_check(?tr_get_typeCheck(Env), ?tr_Synchronization, +% "Coordinator:register_synchronization", Synchronization), +% case ?etr_get_status(Local) of +% 'StatusActive' -> +% case catch ?tr_get_parents(Env) of +% [] -> +% {reply, ok, {Env, ?etr_add_sync(Local, Synchronization)}, +% ?tr_get_timeout(Env)}; +% [Parent|_] -> +% case catch 'ETraP_Server':register_synchronization(Parent, Self) of +% {'EXCEPTION', E} -> +% corba:raise(E); +% ok -> +% {reply, ok, {Env, ?etr_add_sync(Local, Synchronization)}, +% ?tr_get_timeout(Env)}; +% What -> +% corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_MAYBE}) +% end +% end; +% _ -> +% corba:raise(?tr_inactive) +% end. + +%%-----------------------------------------------------------% +%% function : rollback_only +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : - +%% Effect : The transaction associated with the target object +%% is modified so that rollback IS the result. +%%------------------------------------------------------------ + +rollback_only(Self, {Env, Local}) -> + case ?etr_get_status(Local) of + 'StatusActive' -> + NewL = ?etr_set_status(Local, 'StatusRolledBack'), + NewEnv = ?tr_set_rollback(Env, true), + ?etr_log(?tr_get_etrap(Env),{rollback, NewL}), + send_info(?etr_get_members(NewL), 'CosTransactions_Resource', rollback), + notify_subtrAware(rollback, ?etr_get_subAw(NewL), Self), + {stop, normal, ok, {NewEnv, NewL}}; +%% Replace the reply above if allow synchronization +% case ?etr_get_sync(Local) of +% [] -> +% {stop, normal, ok, {NewEnv, NewL}}; +% _ -> +% {reply, ok, {NewEnv, NewL}} +% end; + _ -> + corba:raise(?tr_inactive) + end. + +%%-----------------------------------------------------------% +%% function : get_transaction_name +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : string - which describes the transaction associated +%% with the target object. +%% Effect : Intended for debugging. +%%------------------------------------------------------------ + +get_transaction_name(_Self, {Env, Local}) -> + {reply, ?tr_get_etrap(Env), {Env, Local}}. + +%%-----------------------------------------------------------% +%% function : create_subtransaction +%% Arguments: Self - its own object reference. +%% State - Gen-Server State +%% Returns : A control object if subtransactions are allowed, +%% otherwise an exception is raised. +%% Effect : A new subtransaction is created whos parent is +%% the transaction associated with the target object. +%% Exception: SubtransactionUnavailabe - no support for nested +%% transactions. +%% Inactive - already been prepared. +%%------------------------------------------------------------ + +create_subtransaction(Self, {Env, Local}) -> + case ?etr_get_status(Local) of + 'StatusActive' -> + case ?tr_get_subTraOK(Env) of + true -> + ETraPName = 'ETraP_Common':create_name("subc"), + Tname = 'ETraP_Common':create_name("subt"), + + %% Create context for the new object. + State = ?tr_create_context(ETraPName, Tname, + ?tr_get_typeCheck(Env), + ?tr_get_hashMax(Env), + ?tr_get_subTraOK(Env), + ?tr_get_maxR(Env), + ?tr_get_maxW(Env)), + + + State2 = ?tr_add_parent(State, Self), + + State3 = ?tr_set_alarm(State2, ?tr_get_alarm(Env)), + + State4 = ?tr_set_timeout(State3, ?tr_get_timeout(Env)), + + Control = ?tr_start_child(?SUP_ETRAP(State4)), + %% Set the SubCoordinator object reference and register it as participant. + SubCoord = 'CosTransactions_Control':get_coordinator(Control), + NewLocal = ?etr_add_member(Local, SubCoord), + {reply, Control, {Env, NewLocal}, ?tr_get_timeout(Env)}; + _ -> + %% subtransactions not allowed, raise exception. + corba:raise(?tr_subunavailable) + end; + _-> + corba:raise(?tr_inactive) + end. + +%%-----------------------------------------------------------% +%% function : get_txcontext +%% Arguments: +%% Returns : PropagationContext +%% Effect : +%%------------------------------------------------------------ + +get_txcontext(_Self, {_Env, _Local}) -> + corba:raise(#'CosTransactions_Unavailable'{}). + +%get_txcontext(Self, {Env, Local}) -> +% Otid = #'CosTransactions_otid_t'{formatID=0, +% bqual_length=0, +% tid=[corba_object:hash(Self, +% ?tr_get_hashMax(Env))]}, +% TrIDs = create_TransIdentities(?tr_get_parents(Env), Env, [], Otid), +% C=case ?tr_get_parents(Env) of +% [] -> +% #'CosTransactions_TransIdentity'{coord=Self, +% term=?tr_get_terminator(Env), +% otid=Otid}; +% _-> +% #'CosTransactions_TransIdentity'{coord=Self, +% term=?tr_NIL_OBJ_REF, +% otid=Otid} +% end, +% case ?tr_get_timeout(Env) of +% infinity -> +% #'CosTransactions_PropagationContext'{timeout=0, +% current= C, +% parents=TrIDs}; +% T -> +% #'CosTransactions_PropagationContext'{timeout=T/1000, +% current= C, +% parents=TrIDs} +% end. + +%create_TransIdentities([], _, Parents, _) -> Parents; +%create_TransIdentities([Phead|Ptail], Env, Parents, Otid) -> +% NO=Otid#'CosTransactions_TransIdentity'{otid= +% corba_object:hash(Phead, +% ?tr_get_hashMax(Env))}, +% create_TransIdentities([Phead|Ptail], Env, Parents++ +% [#'CosTransactions_TransIdentity'{coord=Phead, +% term=?tr_NIL_OBJ_REF, +% otid=NO}], +% Otid). + + +%%--------- Inherit from CosTransactions::Synchronization --- + +%%-----------------------------------------------------------% +%% function : before_completion +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%before_completion(Self, {Env, Local}) -> +% send_info(?etr_get_sync(Local), +% 'CosTransactions_Synchronization', before_completion), +% {reply, ok, {Env, Local}}. + +%%-----------------------------------------------------------% +%% function : after_completion +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%after_completion(Self, {Env, Local}, Status) -> +% send_info(?etr_get_sync(Local), Status, +% 'CosTransactions_Synchronization', after_completion), +% {stop, normal, ok, {Env, Local}}. + +%%--------------- IMPLEMENTATION SPECIFIC ------------------- +%%-----------------------------------------------------------% +%% function : start_object +%% Arguments: +%% Returns : EXIT, EXCEPTION, or {ok, State} +%% Effect : used by init/1 only. +%%------------------------------------------------------------ + +start_object(Env)-> + ?put_debug_data(self, Env), + Local = ?etr_get_init(Env), + LogName = ?tr_get_etrap(Env), + case catch file:read_file_info(LogName) of + {error, enoent} -> + %% File does not exist. It's the first time. No restart. + ?debug_print("ETraP_Server:init(~p)~n",[?tr_get_etrap(Env)]), + etrap_logmgr:start(LogName), + {ok, + {Env, ?etr_set_status(Local, 'StatusActive')}, + ?tr_get_timeout(Env)}; + {error, Reason} -> + %% File exist but error occurred. + ?tr_error_msg("Control (~p) Cannot open log file: ~p~n", + [LogName, Reason]), + {stop, "unable_to_open_log"}; + _ -> + %% File exists, perform restart. + etrap_logmgr:start(LogName), + ?debug_print("RESTART ~p~n", [?tr_get_etrap(Env)]), + prepare_restart({Env, ?etr_set_status(Local, 'StatusUnknown')}, + ?etr_read(?tr_get_etrap(Env), start)) + end. + + +%%-----------------------------------------------------------% +%% function : send_prepare +%% Arguments: List of registred resources. +%% Returns : ok - equal to void +%% Effect : calls send_prepare/3, which sends a prepare call +%% to resources participating in the transaction and then collect +%% their votes. send_prepare will block until +%% it recieves a reply from the resource. +%%------------------------------------------------------------ + +send_prepare(RegResources, Alarm) -> + send_prepare(RegResources, [], Alarm). + +% All voted ReadOnly. We are done. +send_prepare([], [], _) -> + readOnly; + +% All voted commit (VC) or ReadOnly. +send_prepare([], VC, Alarm) -> + case catch try_timeout(Alarm) of + false -> + {commit, VC}; + _-> + {rollback, VC} + end; + +send_prepare([Rhead|Rtail], VC, Alarm) -> + ?debug_print("send_prepare()~n",[]), + case catch 'CosTransactions_Resource':prepare(Rhead) of + 'VoteCommit' -> + case catch try_timeout(Alarm) of + false -> + _Env = ?get_debug_data(self), + ?eval_debug_fun({?tr_get_etrap(_Env), send_prepare}, _Env), + send_prepare(Rtail, VC++[Rhead], Alarm); + _-> + %% Timeout, rollback. However, the resource did vote + %% commit. Add it to the list. + send_info(Rtail, 'CosTransactions_Resource', rollback), + {rollback, VC++[Rhead]} + end; + 'VoteRollback' -> + %% Don't care about timeout since we voted rollback. + %% A rollback received. No need for more prepare-calls. + %% See OMG 10-51, Transaction Service:v1.0 + send_info(Rtail, 'CosTransactions_Resource', rollback), + {rollback, VC}; + 'VoteReadOnly' -> + case catch try_timeout(Alarm) of + false -> + send_prepare(Rtail, VC, Alarm); + _-> + %% timeout, reply rollback. + send_info(Rtail, 'CosTransactions_Resource', rollback), + {rollback, VC} + end; + {'EXCEPTION',E} when is_record(E, 'TIMEOUT') -> + ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", + [Rhead]), + %% Since we use presumed abort we will rollback the transaction. + send_info(Rtail, 'CosTransactions_Resource', rollback), + {rollback, VC}; + {'EXCEPTION',E} when is_record(E, 'TRANSIENT') -> + ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", + [Rhead]), + %% Since we use presumed abort we will rollback the transaction. + send_info(Rtail, 'CosTransactions_Resource', rollback), + {rollback, VC}; + {'EXCEPTION',E} when is_record(E, 'COMM_FAILURE') -> + ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", + [Rhead]), + %% Since we use presumed abort we will rollback the transaction. + send_info(Rtail, 'CosTransactions_Resource', rollback), + {rollback, VC}; + {'EXCEPTION', E} when is_record(E, 'OBJECT_NOT_EXIST') -> + ?tr_error_msg("Coordinator:prepare( ~p )~nObject unreachable.~n", + [Rhead]), + send_info(Rtail, 'CosTransactions_Resource', rollback), + {rollback, VC}; + {'EXCEPTION', Exc} -> + ?tr_error_msg("Coordinator:prepare( ~p )~nThe Object raised exception: ~p~n", + [Rhead, Exc]), + send_info(Rtail, 'CosTransactions_Resource', rollback), + %% This can occur if a subtransaction get one or more + %% "VoteCommit" followed by a "VoteRollback". + %% The subtransaction then do a send_decision(rollback), + %% which can generate Heuristic decisions. Must rollback + %% since at least one participant voted rollback. + {'EXCEPTION', Exc, VC, Rhead}; + Other -> + ?tr_error_msg("Coordinator:prepare( ~p ) failed. REASON ~p~n", + [Rhead, Other]), + send_info(Rtail, 'CosTransactions_Resource', rollback), + {failed, VC} + end. + +%%-----------------------------------------------------------% +%% function : type_check +%% Arguments: Bool - perform typecheck? +%% ID - Type it should be. +%% Func - Name of the function (for error_msg) +%% Obj - objectrefernce to test. +%% Returns : 'ok' or raises exception. +%% Effect : +%%------------------------------------------------------------ +type_check(false, _, _, _) -> + ok; +type_check(_, ID, Func, Obj) -> + case catch corba_object:is_a(Obj,ID) of + true -> + ok; + _ -> + ?tr_error_msg("~p( ~p ) Bad argument!!~n", [Func, Obj]), + corba:raise(?tr_badparam) + end. + +%%-----------------------------------------------------------% +%% function : is_heuristic +%% Arguments: Exception +%% Returns : boolean +%% Effect : Returns true if the exception is a heuristic exc. +%%------------------------------------------------------------ + +is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicMixed') -> true; +is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicHazard') -> true; +is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicCommit') -> true; +is_heuristic(E) when is_record(E, 'CosTransactions_HeuristicRollback') -> true; +is_heuristic(_) -> false. + +%%-----------------------------------------------------------% +%% function : exception_set +%% Arguments: Genserver state +%% Returns : +%% Effect : Used when restarting. +%%------------------------------------------------------------ + +exception_set({Env,Local}) -> + case ?etr_get_exc(Local) of + void -> + self() ! {suicide, self()}, + {ok, {Env, Local}}; + _ -> + {ok, {Env, Local}} + end. + +%%-----------------------------------------------------------% +%% function : set_exception +%% Arguments: Locally defined #exc{} +%% Heuristic mixed or hazard Exeption +%% Returns : Altered locally defined #exc{} +%% Effect : Set the correct tuple member to true. +%%------------------------------------------------------------ + +set_exception(Exc, E) when is_record(E, 'CosTransactions_HeuristicMixed') -> + Exc#exc{mixed = true}; +set_exception(Exc, E) when is_record(E, 'CosTransactions_HeuristicHazard') -> + Exc#exc{hazard = true}; +set_exception(Exc, _) -> Exc. + +%%-----------------------------------------------------------% +%% function : send_forget +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +send_forget([], _) -> ok; +send_forget([Rhead|Rtail], LogName) -> + ?debug_print("send_forget()~n",[]), + _Env = ?get_debug_data(self), + case catch 'CosTransactions_Resource':forget(Rhead) of + ok -> + ?eval_debug_fun({?tr_get_etrap(_Env), send_forget1}, _Env), + ?etr_log(LogName, {forgotten, Rhead}), + ?eval_debug_fun({?tr_get_etrap(_Env), send_forget2}, _Env), + send_forget(Rtail, LogName); + Other -> + ?tr_error_msg("CosTransactions_Coordinator failed sending forget to ~p~nREASON: ~p~n", + [Rhead, Other]), + ?eval_debug_fun({?tr_get_etrap(_Env), send_forget3}, _Env), + ?etr_log(LogName, {not_forgotten, Rhead}), + ?eval_debug_fun({?tr_get_etrap(_Env), send_forget4}, _Env), + send_forget(Rtail, LogName) + end. + +%%-----------------------------------------------------------% +%% function : send_decision +%% Arguments: List of registred resources which vote commit. +%% Vote - the outcome of the transaction. +%% Returns : ok - equal to void +%% Effect : Inform those who voted commit of the outcome. +%% They who voted rollback already knows the outcome. +%% They who voted ReadOnly are not affected. +%%------------------------------------------------------------ + +%%-- Adding extra parameters +send_decision({Env, Local}, Reply, Vote) -> + send_decision({Env, Local}, Reply, ?etr_get_vc(Local), Vote, #exc{}, [], 0). +send_decision({Env, Local}, Reply, Vote, VC) -> + send_decision({Env, Local}, Reply, VC, Vote, #exc{}, [], 0). +send_decision(State, no_reply, VC, Vote, Exc) -> + send_decision(State, no_reply, VC, Vote, Exc, [], 0). + +%%-- Decision sent to all members. Do not reply (used when restarting). +send_decision({Env, Local}, no_reply, [], _, #exc{mixed = true}, [], _) -> + {Env, ?etr_set_exc(Local, ?tr_mixed)}; +send_decision({Env, Local}, no_reply, [], _, #exc{hazard = true}, [], _) -> + {Env, ?etr_set_exc(Local, ?tr_hazard)}; +send_decision({Env, Local}, no_reply, [], _, _, [], _) -> + {Env, Local}; +send_decision({Env, Local}, no_reply, [], Vote, Exc, Failed, Times) -> + case ?tr_get_maxR(Env) of + Times -> + ?tr_error_msg("MAJOR ERROR, failed sending commit decision to: ~p. Tried ~p times.", [Failed,Times]), + {Env, ?etr_set_exc(Local, ?tr_hazard)}; + _-> + timer:sleep(?tr_get_maxW(Env)), + NewTimes = Times+1, + send_decision({Env, Local}, no_reply, Failed, Vote, Exc, [], NewTimes) + end; +%%-- end special cases. + +%% Decision sent to all members. Test exceptions. +send_decision({Env, Local}, Reply, [], Vote, Exc, [], _) -> + notify_subtrAware(Vote, ?etr_get_subAw(Local), ?etr_get_self(Local)), + test_exc(Exc, Vote, Reply, {Env, Local}); +%% Decision not sent to all members (one or more failed). Retry. +send_decision({Env, Local}, Reply, [], Vote, Exc, Failed, Times) -> + case ?tr_get_maxR(Env) of + Times -> + ?tr_error_msg("MAJOR ERROR, failed sending commit decision to: ~p. Tried ~p times.", [Failed,Times]), + notify_subtrAware(Vote, ?etr_get_subAw(Local), ?etr_get_self(Local)), + test_exc(Exc#exc{hazard = true}, Vote, Reply, {Env, Local}); + _-> + NewTimes = Times+1, + timer:sleep(?tr_get_maxW(Env)), + send_decision({Env, Local}, Reply, Failed, Vote, Exc, [], NewTimes) + end; + +send_decision({Env, Local}, Reply, [Rhead|Rtail], Vote, Exc, Failed, Times) -> + ?debug_print("Coordinator:send_decision(~p) Try: ~p~n",[Vote, Times]), + case catch 'CosTransactions_Resource':Vote(Rhead) of + ok -> + ?etr_log(?tr_get_etrap(Env),{sent, Rhead}), + send_decision({Env, Local}, Reply, Rtail, Vote, Exc, Failed, Times); + {'EXCEPTION', E} when Vote == commit andalso + is_record(E, 'CosTransactions_NotPrepared') -> + ?debug_print("send_decision resource unprepared~n",[]), + case catch 'CosTransactions_Resource':prepare(Rhead) of + 'VoteCommit' -> + send_decision({Env, Local}, Reply, [Rhead|Rtail], Vote, Exc, Failed, Times); + 'VoteRollback' -> + send_decision({Env, Local}, Reply, Rtail, Vote, Exc#exc{mixed = true}, Failed, Times); + {'EXCEPTION', E} -> + {SetExc, NewL, DidFail} = + evaluate_answer(E, Rhead, Vote, Exc, + ?tr_get_etrap(Env), Local), + send_decision({Env, NewL}, Reply, Rtail, Vote, SetExc, DidFail++Failed, Times) + end; + {'EXCEPTION', E} -> + {SetExc, NewL, DidFail} = + evaluate_answer(E, Rhead, Vote, Exc, ?tr_get_etrap(Env), Local), + ?tr_error_msg("Resource:~p( ~p )~nRaised Exception: ~p~n", + [Vote, Rhead, E]), + send_decision({Env, NewL}, Reply, Rtail, Vote, SetExc, DidFail++Failed, Times); + {'EXIT', _} -> + send_decision({Env, Local}, Reply, Rtail, + Vote, Exc, [Rhead|Failed], Times); + Other -> + ?tr_error_msg("Resource:~p( ~p ) failed.~nREASON: ~p~n", + [Vote, Rhead, Other]), + case catch corba_object:non_existent(Rhead) of + true when Vote == commit -> + %% Presumed rollback + send_decision({Env, Local}, Reply, Rtail, Vote, + Exc#exc{mixed = true}, Failed, Times); + true -> + %% Presumed rollback + send_decision({Env, Local}, Reply, Rtail, Vote, + Exc#exc{hazard = true}, Failed, Times); + _ -> + send_decision({Env, Local}, Reply, Rtail, + Vote, Exc, [Rhead|Failed], Times) + end + end. + +%%-----------------------------------------------------------% +%% function : notify_subtrAware, +%% Arguments: +%% Returns : +%% Effect : Invoke an operation on a list of objects. We don't +%% care about return values or exceptions. +%%------------------------------------------------------------ + +notify_subtrAware(commit, Resources, Self) -> + send_info(Resources, Self, + 'CosTransactions_SubtransactionAwareResource', + commit_subtransaction); +notify_subtrAware(_, Resources, _) -> + send_info(Resources, 'CosTransactions_SubtransactionAwareResource', + rollback_subtransaction). + +%%-----------------------------------------------------------% +%% function : send_info +%% Arguments: ObjectList - List of object refernces to call. +%% M - Module +%% F - Function +%% (Arg - required arguments) +%% Returns : ok +%% Effect : A lightweight function to be used when we don't +%% "care" about the return value. +%%------------------------------------------------------------ + +send_info([], _, _, _) -> + ok; +send_info([Rhead|Rtail], Arg, M, F) -> + ?debug_print("~p( ~p )~n",[F, Arg]), + case catch M:F(Rhead, Arg) of + {'EXIT',R} -> + ?tr_error_msg("~p:~p(~p, ~p) returned {'EXIT',~p}", [M,F,Rhead,Arg,R]); + {'EXCEPTION',E} -> + ?tr_error_msg("~p:~p(~p, ~p) returned {'EXCEPTION',~p}", [M,F,Rhead,Arg,E]); + _-> + ok + end, + send_info(Rtail, Arg, M, F). + +send_info([], _, _) -> + ok; +send_info([Rhead|Rtail], M, F) -> + ?debug_print("~p( )~n",[F]), + case catch M:F(Rhead) of + {'EXIT',R} -> + ?tr_error_msg("~p:~p(~p) returned {'EXIT',~p}", [M,F,Rhead,R]); + {'EXCEPTION',E} -> + ?tr_error_msg("~p:~p(~p) returned {'EXCEPTION',~p}", [M,F,Rhead,E]); + _-> + ok + end, + send_info(Rtail, M, F). + +%%-----------------------------------------------------------% +%% function : evaluate_answer +%% Arguments: +%% Returns : +%% Effect : Check what kind of exception we received. +%%------------------------------------------------------------ + +evaluate_answer(E, Rhead, _Vote, Exc, Log, Local) + when is_record(E, 'CosTransactions_HeuristicMixed') -> + ?etr_log(Log, {heuristic, {Rhead, E}}), + {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []}; +evaluate_answer(E, Rhead, _Vote, Exc, Log, Local) + when is_record(E, 'CosTransactions_HeuristicHazard') -> + ?etr_log(Log, {heuristic, {Rhead, E}}), + {Exc#exc{hazard = true}, ?etr_add_raisedH(Local, Rhead), []}; +evaluate_answer(E, Rhead, Vote, Exc, Log, Local) + when is_record(E, 'CosTransactions_HeuristicCommit') -> + case Vote of + commit -> + ?etr_log(Log, {heuristic, {Rhead, E}}), + {Exc, ?etr_add_raisedH(Local, Rhead), []}; + _-> + ?etr_log(Log, {heuristic, {Rhead, ?tr_mixed}}), + {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []} + end; +evaluate_answer(E, Rhead, Vote, Exc, Log, Local) + when is_record(E, 'CosTransactions_HeuristicRollback')-> + case Vote of + rollback -> + ?etr_log(Log, {heuristic, {Rhead, ?tr_rollback}}), + {Exc, ?etr_add_raisedH(Local, Rhead), []}; + _-> + ?etr_log(Log, {heuristic, {Rhead, ?tr_mixed}}), + {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []} + end; +evaluate_answer(E, Rhead, Vote, Exc, Log, Local) + when Vote == commit andalso is_record(E, 'TRANSACTION_ROLLEDBACK') -> + ?etr_log(Log, {heuristic, {Rhead, ?tr_mixed}}), + {Exc#exc{mixed = true}, ?etr_add_raisedH(Local, Rhead), []}; +evaluate_answer(E, Rhead, Vote, Exc, Log, Local) when is_record(E, 'TIMEOUT') -> + ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n", + [Vote, Rhead, E]), + case catch corba_object:non_existent(Rhead) of + true -> + %% Since we have presumed abort, the child will + %% assume rollback if this server do not exist any more. + ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}), + {Exc#exc{hazard = true}, Local, []}; + _ -> + {Exc, Local, [Rhead]} + end; +evaluate_answer(E, Rhead, Vote, Exc, Log, Local) when is_record(E, 'TRANSIENT') -> + ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n", + [Vote, Rhead, E]), + case catch corba_object:non_existent(Rhead) of + true -> + %% Since we have presumed abort, the child will + %% assume rollback if this server do not exist any more. + ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}), + {Exc#exc{hazard = true}, Local, []}; + _ -> + {Exc, Local, [Rhead]} + end; +evaluate_answer(E, Rhead, Vote, Exc, Log, Local) when is_record(E, 'COMM_FAILURE') -> + ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n", + [Vote, Rhead, E]), + case catch corba_object:non_existent(Rhead) of + true -> + %% Since we have presumed abort, the child will + %% assume rollback if this server do not exist any more. + ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}), + {Exc#exc{hazard = true}, Local, []}; + _ -> + {Exc, Local, [Rhead]} + end; +evaluate_answer(E, Rhead, Vote, Exc, Log, Local)when is_record(E, 'OBJECT_NOT_EXIST') -> + ?tr_error_msg("Coordinator:~p( ~p ) Object unreachable.~nReason: ~p~n", + [Vote, Rhead, E]), + %% Since we have presumed abort, the child will + %% assume rollback if this server do not exist any more. + ?etr_log(Log, {heuristic, {Rhead, ?tr_hazard}}), + {Exc#exc{hazard = true}, Local, []}; +evaluate_answer(Unknown, Rhead, Vote, Exc, _Log, Local)-> + ?tr_error_msg("Coordinator:~p( ~p ). Unknown reply: ~p.~n", + [Vote, Rhead, Unknown]), + {Exc, Local, []}. + + +%%-----------------------------------------------------------% +%% function : test_exc +%% Arguments: Exc - instance of #exc{} locally declared. +%% Vote - 'rollback' or 'commit' +%% Reply - If no exceptions this is the default reply. +%% State - genserver state +%% Returns : +%% Effect : Raise the correct exception or simply reply to +%% the genserver. NOTE that the testing for exceptions +%% differs if we are performing a rollback or commit. +%% Check if Mixed first; takes priority over Hazard. +%% HeuristicRollback and VoteCommit together give +%% HeuristicMixed +%% HeuristicCommit and VoteRollback together give +%% HeuristicMixed +%%------------------------------------------------------------ + +test_exc(#exc{mixed = true}, _, _, {Env, Local}) -> + {reply, {'EXCEPTION', ?tr_mixed}, {Env, ?etr_set_exc(Local, ?tr_mixed)}}; +% Left out for now to avoid dialyzer warning. +%test_exc(#exc{rollback = true}, commit, _, {Env, Local}) -> +% {reply, {'EXCEPTION', ?tr_mixed}, {Env, ?etr_set_exc(Local, ?tr_mixed)}}; +% Left out for now to avoid dialyzer warning. +%test_exc(#exc{commit = true}, rollback, _, {Env, Local}) -> +% {reply, {'EXCEPTION', ?tr_mixed}, {Env, ?etr_set_exc(Local, ?tr_mixed)}}; +test_exc(#exc{hazard = true}, _, _, {Env, Local}) -> + {reply, {'EXCEPTION', ?tr_hazard}, {Env, ?etr_set_exc(Local, ?tr_hazard)}}; +test_exc(_, _, {'EXCEPTION', E}, {Env, Local}) + when is_record(E, 'TRANSACTION_ROLLEDBACK')-> + {stop, normal, {'EXCEPTION', E}, {Env, Local}}; +%% Replace the case above if allow synchronization +%test_exc(_, _, {'EXCEPTION', E}, {Env, Local}) +% when record(E, 'TRANSACTION_ROLLEDBACK')-> +% case ?etr_get_sync(Local) of +% [] -> +% {stop, normal, {'EXCEPTION', E}, {Env, Local}}; +% _-> +% {reply, {'EXCEPTION', E}, {Env, Local}} +% end; +test_exc(_, _, {'EXCEPTION', E}, State) -> + {reply, {'EXCEPTION', E}, State}; +test_exc(_, _, Reply, {Env, Local}) -> + {stop, normal, Reply, {Env, Local}}. +%% Replace the case above if allow synchronization +%test_exc(_, _, Reply, {Env, Local}) -> +% case ?etr_get_sync(Local) of +% [] -> +% {stop, normal, Reply, {Env, Local}}; +% _ -> +% {reply, Reply, {Env, Local}} +% end. + +%%-----------------------------------------------------------% +%% function : evaluate_status +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +evaluate_status(Status) -> + case Status of + 'StatusCommitted' -> commit; + 'StatusCommitting' -> commit; + 'StatusMarkedRollback' -> rollback; + 'StatusRollingBack' -> rollback; + 'StatusRolledBack' -> rollback; + 'StatusActive' -> rollback; + 'StatusPrepared' -> rollback; + 'StatusUnknown' -> rollback; + 'StatusNoTransaction' -> rollback; + 'StatusPreparing' -> rollback; + _-> rollback + end. + + +%%-----------------------------------------------------------% +%% function : prepare_restart +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%% The file contains no data. The coordinator crashed before +%% a prepare-call was made. Presumed rollback. +prepare_restart(State, eof) -> + ?debug_print("prepare_restart: eof, init~n",[]), + self() ! {suicide, self()}, + {ok, State}; +%% Collected all necessary votes. Do commit_restart. +prepare_restart({Env, _}, {{pre_vote, _Vote, Data}, Cursor}) -> + ?debug_print("prepare_restart: pre_vote( ~p )~n",[_Vote]), + if + ?tr_is_root(Env) -> + commit_restart({Env, Data}, + ?etr_read(?tr_get_etrap(Env), Cursor), root); + true -> + commit_restart({Env, Data}, + ?etr_read(?tr_get_etrap(Env), Cursor), subCoord) + end; +%% 'rollback' called without 'prepare'. This case occurs if the Coordinator +%% crashes when send_info or notify_subtrAware. +prepare_restart({Env, _}, {{rollback, NewL}, _Cursor}) -> + ?debug_print("prepare_restart: pre_vote( rollback )~n",[]), + send_info(?etr_get_members(NewL), 'CosTransactions_Resource', rollback), + notify_subtrAware(rollback, ?etr_get_subAw(NewL), ?etr_get_self(NewL)), + self() ! {suicide, self()}, + {ok, {Env, NewL}}; +%% Something is wrong in the log. +prepare_restart(_, _) -> + ?tr_error_msg("Internal log read failed:~n", []), + {stop, {error, "restart failed"}}. + +%%-----------------------------------------------------------% +%% function : commit_restart +%% Arguments: Env - server context +%% Returns : +%% Effect : +%%------------------------------------------------------------ +commit_restart({Env, Local}, Data, Phase) -> + Exc = set_exception(#exc{}, ?etr_get_exc(Local)), + commit_restart({Env, Local}, Data, Phase, Exc). + +%% Normal case. No errors no exceptions. +commit_restart({Env, Local}, {{sent, Obj}, Cursor}, Vote, Exc) -> + ?debug_print("commit_restart: sent~n",[]), + commit_restart({Env, ?etr_remove_vc(Local, Obj)}, + ?etr_read(?tr_get_etrap(Env), Cursor), Vote, Exc); +commit_restart({Env, Local}, {{heuristic, {Obj,E}}, Cursor}, Vote, Exc) -> + ?debug_print("commit_restart: heuristic ~p~n",[E]), + NewExc = set_exception(Exc, E), + commit_restart({Env, ?etr_add_raisedH(Local, Obj)}, + ?etr_read(?tr_get_etrap(Env), Cursor), Vote, NewExc); + + +%% --- cases which only can occure once in the log ------------ + +%% The file contains no data. The coordinator crashed before +%% a decision was made. Causes rollback. +commit_restart({E, L}, eof, root, Exc) -> + ?debug_print("commit_restart: eof init (root only)~n",[]), + {Env, Local} = send_decision({E, L}, no_reply, ?etr_get_vc(L), + rollback, Exc), + exception_set({Env, Local}); +%% Replace the reply above if allow synchronization +% case ?etr_get_sync(Local) of +% [] -> +% exception_set({Env, Local}); +% SynchObjs -> +% {ok, {Env, Local}} +% end; + + +%% Passed the prepare_restart. Not received a commit decision from the +%% parent. +commit_restart({E, L}, eof, subCoord, Exc) -> + ?debug_print("commit_restart: eof init (subcoord only)~n",[]), + case catch corba_object:non_existent(?tr_get_parent(E)) of + true -> + %% Presumed rollback. + {Env, Local} = send_decision({E, L}, no_reply, ?etr_get_vc(L), + rollback, Exc), + self() ! {suicide, self()}, + {ok, {Env, Local}}; +%% Replace the reply above if allow synchronization +% case ?etr_get_sync(Local) of +% [] -> +% self() ! {suicide, self()}, +% {ok, {Env, Local}}; +% SynchObjs -> +% case ?tr_get_parents(Env) of +% [] -> +% send_info(SynchObjs, ?etr_get_status(Local), +% 'CosTransactions_Synchronization', after_completion); +% _-> +% ok +% end, +% self() ! {suicide, self()}, +% {ok, {Env, Local}} +% end; + _-> + {ok, {E, L}} + end; + +commit_restart({Env, Local}, eof, Vote, Exc) -> + ?debug_print("commit_restart: eof VOTE: ~p~n",[Vote]), + case ?etr_get_vc(Local) of + [] -> + ?debug_print("commit_restart: all sent, test exc~n",[]), + exception_set({Env, Local}); + VC -> + ?debug_print("commit_restart: note done. send more~n",[]), + State = send_decision({Env, Local}, no_reply, VC, Vote, Exc), + exception_set(State) + end; + +%% Decision made, i.e. rollback or commit. +commit_restart({Env, Local}, {rollback, Cursor}, _Phase, Exc) -> + ?debug_print("commit_restart: decided rollback~n",[]), + commit_restart({Env, ?etr_set_status(Local, 'StatusRolledBack')}, + ?etr_read(?tr_get_etrap(Env), Cursor), rollback, Exc); +commit_restart({Env, Local}, {commit, Cursor}, _Phase, Exc) -> + ?debug_print("commit_restart: decided commit~n",[]), + commit_restart({Env, ?etr_set_status(Local, 'StatusCommitted')}, + ?etr_read(?tr_get_etrap(Env), Cursor), commit, Exc); +commit_restart({Env, Local}, {forget_phase, Cursor}, _, _) -> + ?debug_print("commit_restart: start sending forget~n",[]), + forget_restart({Env, Local}, ?etr_read(?tr_get_etrap(Env), Cursor)); + +commit_restart({_Env, _Local}, _R, _, _) -> + ?debug_print("RESTART FAIL: ~p~n",[_R]), + ?tr_error_msg("Internal log read failed:~n", []), + exit("restart failed"). + +%%-----------------------------------------------------------% +%% function : forget_restart +%% Arguments: {Env, Local} - server context +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%% Exception logged. Test if we issued a 'forget()' to the Resource. +forget_restart({Env, Local}, eof) -> + case ?etr_get_raisedH(Local) of + [] -> + ?debug_print("forget_restart: all done~n",[]); + Left -> + ?debug_print("forget_restart: not done. send more~n",[]), + send_forget(Left, ?tr_get_etrap(Env)) + end, + self() ! {suicide, self()}, + {ok, {Env, Local}}; +%% Replace the reply above if allow synchronization +% case ?etr_get_sync(Local) of +% [] -> +% self() ! {suicide, self()}, +% {ok, {Env, Local}}; +% SynchObjs -> +% case ?tr_get_parents(Env) of +% [] -> +% send_info(SynchObjs, ?etr_get_status(Local), +% 'CosTransactions_Synchronization', after_completion), +% self() ! {suicide, self()}, +% {ok, {Env, Local}}; +% _-> +% {ok, {Env, Local}} +% end +% end; +forget_restart({Env, Local}, {{forgotten, Obj}, Cursor}) -> + ?debug_print("forget_restart: forgotten heuristic~n",[]), + NewL = ?etr_remove_raisedH(Local, Obj), + forget_restart({Env, NewL}, ?etr_read(?tr_get_etrap(Env), Cursor)); +forget_restart({Env, Local}, {{not_forgotten, Obj}, Cursor}) -> + ?debug_print("forget_restart: not_forgotten~n",[]), + NewL = ?etr_remove_raisedH(Local, Obj), + send_forget([Obj], dummy), + forget_restart({Env, NewL}, ?etr_read(?tr_get_etrap(Env), Cursor)). + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosTransactions/src/Makefile b/lib/cosTransactions/src/Makefile new file mode 100644 index 0000000..7e10ec1 --- /dev/null +++ b/lib/cosTransactions/src/Makefile @@ -0,0 +1,175 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +EBIN=../ebin + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug -W +endif + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(COSTRANSACTIONS_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/cosTransactions-$(VSN) +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + ETraP_Common \ + etrap_logmgr \ + ETraP_Server_impl \ + CosTransactions_Terminator_impl \ + CosTransactions_TransactionFactory_impl \ + cosTransactions + +ERL_FILES = $(MODULES:%=%.erl) +HRL_FILES = \ + ETraP_Common.hrl + +GEN_ERL_FILES = \ + oe_CosTransactions.erl \ + CosTransactions_Control.erl \ + CosTransactions_Coordinator.erl \ + CosTransactions_HeuristicCommit.erl \ + CosTransactions_HeuristicHazard.erl \ + CosTransactions_HeuristicMixed.erl \ + CosTransactions_HeuristicRollback.erl \ + CosTransactions_Inactive.erl \ + CosTransactions_InvalidControl.erl \ + CosTransactions_NoTransaction.erl \ + CosTransactions_NotPrepared.erl \ + CosTransactions_NotSubtransaction.erl \ + CosTransactions_RecoveryCoordinator.erl \ + CosTransactions_Resource.erl \ + CosTransactions_SubtransactionAwareResource.erl \ + CosTransactions_SubtransactionsUnavailable.erl \ + CosTransactions_Terminator.erl \ + CosTransactions_TransactionFactory.erl \ + CosTransactions_Unavailable.erl \ + CosTransactions_SynchronizationUnavailable.erl \ + CosTransactions_TransIdentity.erl \ + CosTransactions_PropagationContext.erl \ + CosTransactions_otid_t.erl \ + CosTransactions_WrongTransaction.erl \ + ETraP_Server.erl +# CosTransactions_Synchronization.erl \ + +EXTERNAL_INC_PATH = ../include + +GEN_HRL_FILES = \ + oe_CosTransactions.hrl \ + CosTransactions.hrl \ + CosTransactions_Control.hrl \ + CosTransactions_Coordinator.hrl \ + CosTransactions_RecoveryCoordinator.hrl \ + CosTransactions_Resource.hrl \ + CosTransactions_SubtransactionAwareResource.hrl \ + CosTransactions_Terminator.hrl \ + CosTransactions_TransactionFactory.hrl \ + ETraP.hrl \ + ETraP_Server.hrl +# CosTransactions_Synchronization.hrl \ + +EXTERNAL_GEN_HRL_FILES = $(GEN_HRL_FILES:%=$(EXTERNAL_INC_PATH)/%) + +GEN_FILES = $(GEN_ERL_FILES) $(EXTERNAL_GEN_HRL_FILES) + +TARGET_FILES = \ + $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +IDL_FILE = \ + CosTransactions.idl + +APPUP_FILE = cosTransactions.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + +APP_FILE = cosTransactions.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/cosTransactions/ebin \ + -pa $(ERL_TOP)/lib/ic/ebin\ + -pa $(ERL_TOP)/lib/orber/ebin + +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -I$(ERL_TOP)/lib/cosTransactions/include \ + -I$(ERL_TOP)/lib/orber/include \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,"cosTransactions_$(COSTRANSACTIONS_VSN)"}' + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) + +debug: + @${MAKE} TYPE=debug + +clean: + rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) + sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET) + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +$(GEN_ERL_FILES) $(EXTERNAL_GEN_HRL_FILES): CosTransactions.idl + erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTransactions.cfg"}' CosTransactions.idl + mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH) + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(GEN_ERL_FILES) $(IDL_FILE) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DATA) $(EXTERNAL_GEN_HRL_FILES) $(RELSYSDIR)/include + +release_docs_spec: diff --git a/lib/cosTransactions/src/cosTransactions.app.src b/lib/cosTransactions/src/cosTransactions.app.src new file mode 100644 index 0000000..52769b1 --- /dev/null +++ b/lib/cosTransactions/src/cosTransactions.app.src @@ -0,0 +1,43 @@ +{application, cosTransactions, + [{description, "The Erlang CosTransactions application"}, + {vsn, "%VSN%"}, + {modules, + [ + etrap_logmgr, + 'ETraP_Server_impl', + 'CosTransactions_Terminator_impl', + 'CosTransactions_TransactionFactory_impl', + 'ETraP_Common', + oe_CosTransactions, + 'CosTransactions_Control', + 'CosTransactions_Coordinator', + 'CosTransactions_HeuristicCommit', + 'CosTransactions_HeuristicHazard', + 'CosTransactions_HeuristicMixed', + 'CosTransactions_HeuristicRollback', + 'CosTransactions_Inactive', + 'CosTransactions_InvalidControl', + 'CosTransactions_NoTransaction', + 'CosTransactions_NotPrepared', + 'CosTransactions_NotSubtransaction', + 'CosTransactions_RecoveryCoordinator', + 'CosTransactions_Resource', + 'CosTransactions_SubtransactionAwareResource', + 'CosTransactions_SubtransactionsUnavailable', + 'CosTransactions_Terminator', + 'CosTransactions_TransactionFactory', + 'CosTransactions_Unavailable', + 'CosTransactions_SynchronizationUnavailable', + 'CosTransactions_TransIdentity', + 'CosTransactions_PropagationContext', + 'CosTransactions_otid_t', + 'CosTransactions_WrongTransaction', + 'ETraP_Server', + cosTransactions + ] + }, + {registered, [cosTransactions_sup, oe_cosTransactionsFactory]}, + {applications, [orber, stdlib, kernel]}, + {env, []}, + {mod, {cosTransactions, []}} +]}. diff --git a/lib/cosTransactions/src/cosTransactions.appup.src b/lib/cosTransactions/src/cosTransactions.appup.src new file mode 100644 index 0000000..f3eead4 --- /dev/null +++ b/lib/cosTransactions/src/cosTransactions.appup.src @@ -0,0 +1,6 @@ +{"%VSN%", + [ + ], + [ + ] +}. diff --git a/lib/cosTransactions/src/cosTransactions.erl b/lib/cosTransactions/src/cosTransactions.erl new file mode 100644 index 0000000..ffc01f5 --- /dev/null +++ b/lib/cosTransactions/src/cosTransactions.erl @@ -0,0 +1,115 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : cosTransactions.erl +%% Purpose : Initialize the 'cosTransactions' application +%%---------------------------------------------------------------------- + +-module(cosTransactions). + +%%--------------- INCLUDES ----------------------------------- +%% Local +-include_lib("ETraP_Common.hrl"). +-include_lib("CosTransactions.hrl"). +%%--------------- EXPORTS------------------------------------- +%% cosTransactions API external +-export([start/0, stop/0, start_factory/1, start_factory/0, stop_factory/1]). + +%% Application callbacks +-export([start/2, init/1, stop/1]). + +%%------------------------------------------------------------ +%% function : start/stop +%% Arguments: +%% Returns : +%% Effect : Starts or stops the cosTRansaction application. +%%------------------------------------------------------------ + +start() -> + application:start(cosTransactions). +stop() -> + application:stop(cosTransactions). + +%%------------------------------------------------------------ +%% function : start_factory +%% Arguments: none or an argumentlist which by default is defined +%% in ETraP_Common.hrl, i.e., '?tr_FAC_DEF' +%% Returns : ObjectRef | {'EXCEPTION', _} | {'EXIT', Reason} +%% Effect : Starts a CosTransactions_TransactionFactory +%%------------------------------------------------------------ + +start_factory() -> + ?tr_start_child(?SUP_FAC(?tr_FAC_DEF)). + +start_factory(Args) when is_list(Args) -> + ?tr_start_child(?SUP_FAC(Args)); +start_factory(Args) -> + ?tr_error_msg("applications:start( ~p ) failed. Bad parameters~n", [Args]), + exit("applications:start failed. Bad parameters"). + +%%------------------------------------------------------------ +%% function : stop_factory +%% Arguments: Factory Object Reference +%% Returns : ok | {'EXCEPTION', _} +%% Effect : +%%------------------------------------------------------------ + +stop_factory(Fac)-> + corba:dispose(Fac). + +%%------------------------------------------------------------ +%% function : start +%% Arguments: Type - see module application +%% Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +start(_, _) -> + supervisor:start_link({local, ?SUPERVISOR_NAME}, cosTransactions, app_init). + + +%%------------------------------------------------------------ +%% function : stop +%% Arguments: Arg - see module application +%% Returns : +%% Effect : Module callback for application +%%------------------------------------------------------------ + +stop(_) -> + ok. + +%%------------------------------------------------------------ +%% function : init +%% Arguments: +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +%% Starting using create_factory/X +init(own_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}; +%% When starting as an application. +init(app_init) -> + {ok,{?SUP_FLAG, [?SUP_CHILD]}}. + + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosTransactions/src/etrap_logmgr.erl b/lib/cosTransactions/src/etrap_logmgr.erl new file mode 100644 index 0000000..a418d78 --- /dev/null +++ b/lib/cosTransactions/src/etrap_logmgr.erl @@ -0,0 +1,200 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : etrap_logmgr.erl +%% Purpose : Make it easier to use disk_log. +%%---------------------------------------------------------------------- + +-module(etrap_logmgr). + +%%--------------- INCLUDES ----------------------------------- +%% Local +-include_lib("ETraP_Common.hrl"). +%%--------------- IMPORTS------------------------------------- +%%--------------- EXPORTS------------------------------------- +-export([start/1, stop/1, log_safe/2, log_lazy/2, get_next/2]). + + +%%------------------------------------------------------------ +%% function : start +%% Arguments: LogName - name of the disk_log. +%% Returns : +%% Effect : creating linked log +%%------------------------------------------------------------ + +start(LogName) -> + case catch disk_log:open([{name, LogName}, + {file, LogName}, + {type, halt}, + {size, infinity}]) of + {ok, LogName} -> + ok; + {error, Reason} -> + ?tr_error_msg("Initiating internal log failed: ~p", [Reason]), + exit({error, Reason}); + {repaired, LogName, {recovered, _Rec}, {badbytes, _Bad}} -> + ok; + Other -> + ?tr_error_msg("Initiating internal log failed: ~p", [Other]), + exit({error, Other}) + end. + +%%------------------------------------------------------------ +%% function : stop +%% Arguments: LogName - name of the disk_log. +%% Returns : +%% Effect : +%%------------------------------------------------------------ + +stop(LogName) -> + case catch disk_log:close(LogName) of + ok -> + ok; + {error, Reason} -> + ?tr_error_msg("Stopping internal log failed: ~p", [Reason]), + {error, Reason}; + Other -> + ?tr_error_msg("Stopping internal log failed: ~p", [Other]), + {error, Other} + end. + + +%%------------------------------------------------------------ +%% function : log_safe +%% Arguments: LogName - name of the disk_log. If 'dummy' is +%% used nothing should be logged. Reason, reuse code. +%% LogRecord - record to store in the log. +%% Returns : +%% Effect : Writes a logrecord and synchronizes to make sure +%% that the record is stored. +%%------------------------------------------------------------ + +log_safe(dummy, _) -> + ok; +log_safe(LogName, LogRecord) -> + case write_safe(LogName, LogRecord) of + ok -> + ok; + _ -> + %% We have to catch the exit because in some cases + %% it's not possible to abort action in the 2PC-protocol. + case catch start(LogName) of + ok -> + write_safe(LogName, LogRecord); + {'EXIT', Reason} -> + {error, Reason} + end + end. + + +write_safe(LogName, LogRecord) -> + case catch disk_log:log(LogName, LogRecord) of + ok -> % wrote to kernel successfully + case catch disk_log:sync(LogName) of + ok -> % Written to disk successfully + ok; + {error, Reason} -> + ?tr_error_msg("Internal log write failed: ~p ~p", + [Reason, LogName]), + {error, Reason}; + Other -> + ?tr_error_msg("Internal log write failed: ~p ~p", + [Other, LogName]), + {error, Other} + end; + {error, Reason} -> + ?tr_error_msg("Internal log write failed: ~p ~p", [Reason, LogName]), + {error, Reason}; + Other -> + ?tr_error_msg("Internal log write failed: ~p ~p", [Other, LogName]), + {error, Other} + end. + + +%%------------------------------------------------------------ +%% function : log_lazy +%% Arguments: LogName - name of the disk_log. If 'dummy' is +%% used nothing should be logged. Reason, reuse code. +%% LogRecord - record to store in the log. +%% Returns : +%% Effect : Writes a logrecord. The record may be lost. +%%------------------------------------------------------------ + +log_lazy(dummy, _LogRecord) -> + ok; +log_lazy(LogName, LogRecord) -> + case write_lazy(LogName, LogRecord) of + ok -> + ok; + _ -> + %% We have to catch the exit because in some cases + %% it's not possible to abort action in the 2PC-protocol. + case catch start(LogName) of + ok -> + write_lazy(LogName, LogRecord); + {'EXIT', Reason} -> + {error, Reason} + end + end. + +write_lazy(LogName, LogRecord) -> + case catch disk_log:log(LogName, LogRecord) of + ok -> + %% wrote to kernel successfully + ok; + {error, Reason} -> + %% Write to kernel failed with Reason + ?tr_error_msg("Internal log write failed: ~p", [Reason]), + {error, Reason}; + Other -> + %% unknown message received. + ?tr_error_msg("Internal log write failed: ~p", [Other]), + {error, Other} + end. + + +%%------------------------------------------------------------ +%% function : get_next +%% Arguments: LogName - name of the disk_log. +%% Cursor - place to read from. +%% Returns : {Cursor, LogRecs} - A cursor and up to N logrecords. +%% eof - the atom 'eof', indicating logfile empty. +%% {error, Reason} - error. +%% Effect : +%% Purpose : Used when performing a REDO scan +%%------------------------------------------------------------ + +get_next(LogName, Cursor) -> + case catch disk_log:chunk(LogName, Cursor, 1) of + {NewCursor, [Data]} -> + {Data, NewCursor}; + eof -> + eof; + {error, Reason} -> + ?tr_error_msg("Internal log '~p' read failed: ~p", + [LogName, Reason]), + exit({error, Reason}); + _Other -> + ?tr_error_msg("Internal log '~p' read failed: 'log_corrupt'", [LogName]), + exit({error, "log_corrupt"}) + end. + +%%--------------- END OF MODULE ------------------------------ diff --git a/lib/cosTransactions/vsn.mk b/lib/cosTransactions/vsn.mk new file mode 100644 index 0000000..404a9ed --- /dev/null +++ b/lib/cosTransactions/vsn.mk @@ -0,0 +1,9 @@ +COSTRANSACTIONS_VSN = 1.2.8 + +TICKETS = OTP-8201 + +TICKETS_1.2.7 = OTP-7987 + +TICKETS_1.2.6 = OTP-7837 + +TICKETS_1.2.5 = OTP-7595 diff --git a/lib/ic/AUTHORS b/lib/ic/AUTHORS new file mode 100644 index 0000000..f3791aa --- /dev/null +++ b/lib/ic/AUTHORS @@ -0,0 +1,8 @@ +Original Authors: + +Peter Lundel +Lars Thorsen +Babbis Xagorarakis + + +Contributors: diff --git a/lib/ic/Makefile b/lib/ic/Makefile new file mode 100644 index 0000000..07db8b7 --- /dev/null +++ b/lib/ic/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(ORBER_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +SUB_DIRECTORIES = src c_src java_src doc/src examples/pre_post_condition + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk + diff --git a/lib/ic/c_src/Makefile b/lib/ic/c_src/Makefile new file mode 100644 index 0000000..8256edd --- /dev/null +++ b/lib/ic/c_src/Makefile @@ -0,0 +1,24 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# +# Invoke with GNU make or clearmake -C gnu. +# + +include $(ERL_TOP)/make/run_make.mk diff --git a/lib/ic/c_src/Makefile.in b/lib/ic/c_src/Makefile.in new file mode 100644 index 0000000..6eef782 --- /dev/null +++ b/lib/ic/c_src/Makefile.in @@ -0,0 +1,160 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +CC = @CC@ +LIBS = @LIBS@ + +LIBDIR = ../priv/lib/$(TARGET) +OBJDIR = ../priv/obj/$(TARGET) +INCDIR = ../include +ERL_INTERFACE_FLAGS = \ + -I$(ERL_TOP)/lib/erl_interface/include \ + -I$(ERL_TOP)/lib/erl_interface/src + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(IC_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/ic-$(VSN) + +# ---------------------------------------------------- +# File Specs +# ---------------------------------------------------- + +IDL_FILES = \ + $(INCDIR)/erlang.idl + +ifeq ($(findstring win32,$(TARGET)),win32) +USING_MINGW=@MIXED_CYGWIN_MINGW@ +ifeq ($(USING_MINGW),yes) +AR_OUT = rcv +CC_FLAGS = +LIBRARY = $(LIBDIR)/libic.a +SKIP_BUILDING_BINARIES := false +else +LIBRARY = $(LIBDIR)/ic.lib +AR_OUT = -out: +CC_FLAGS = -MT +endif +ifeq ($(HOST_OS),) +HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess) +endif +ifeq ($(findstring solaris,$(HOST_OS)),solaris) +SKIP_BUILDING_BINARIES := true +endif +else +AR_OUT = rcv +CC_FLAGS = @DED_CFLAGS@ +LIBRARY = $(LIBDIR)/libic.a +SKIP_BUILDING_BINARIES := false +endif + +C_FILES = \ + ic.c \ + ic_tmo.c \ + oe_ei_encode_version.c \ + oe_ei_encode_long.c \ + oe_ei_encode_ulong.c \ + oe_ei_encode_double.c \ + oe_ei_encode_char.c \ + oe_ei_encode_string.c \ + oe_ei_encode_atom.c \ + oe_ei_encode_pid.c \ + oe_ei_encode_port.c \ + oe_ei_encode_ref.c \ + oe_ei_encode_term.c \ + oe_ei_encode_tuple_header.c \ + oe_ei_encode_list_header.c \ + oe_ei_encode_longlong.c \ + oe_ei_encode_ulonglong.c \ + oe_ei_encode_wchar.c \ + oe_ei_encode_wstring.c \ + oe_ei_decode_longlong.c \ + oe_ei_decode_ulonglong.c \ + oe_ei_decode_wchar.c \ + oe_ei_decode_wstring.c \ + oe_ei_code_erlang_binary.c + +H_FILES = $(INCDIR)/ic.h + +OBJ_FILES= $(C_FILES:%.c=$(OBJDIR)/%.o) + +ALL_CFLAGS = @CFLAGS@ @DEFS@ -I$(INCDIR) $(ERL_INTERFACE_FLAGS) $(CFLAGS) + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +ifeq ($(SKIP_BUILDING_BINARIES), true) +debug opt: +else +debug opt: $(LIBRARY) +endif + +clean: + rm -f $(LIBRARY) $(OBJ_FILES) + rm -f core *~ + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +$(OBJDIR): + -mkdir -p $(OBJDIR) + +$(LIBDIR): + -mkdir -p $(LIBDIR) + +$(LIBRARY): $(OBJDIR) $(LIBDIR) $(OBJ_FILES) + -$(AR) $(AR_OUT) $@ $(OBJ_FILES) + -$(RANLIB) $@ + +$(OBJDIR)/%.o: %.c + $(CC) $(CC_FLAGS) -c -o $@ $(ALL_CFLAGS) $< + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/c_src + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DIR) $(RELSYSDIR)/priv/lib + $(INSTALL_DATA) ic.c ic_tmo.c $(RELSYSDIR)/c_src + $(INSTALL_DATA) $(IDL_FILES) $(H_FILES) $(RELSYSDIR)/include + $(INSTALL_DATA) $(LIBRARY) $(RELSYSDIR)/priv/lib + +release_docs_spec: + + + + + + diff --git a/lib/ic/c_src/Makefile.win32 b/lib/ic/c_src/Makefile.win32 new file mode 100644 index 0000000..d782555 --- /dev/null +++ b/lib/ic/c_src/Makefile.win32 @@ -0,0 +1,108 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# + +CC = cl.exe +LIBRARIAN = lib.exe /nologo + +IC_INCLUDE = ..\include +EI_INCLUDE = \erts\lib\erl_interface\src + +CFLAGS = /MT /nologo /Ox /I$(IC_INCLUDE) /I$(EI_INCLUDE) +TARGET = win32 +OBJDIR = ..\priv\obj\$(TARGET) +LIBDIR = ..\priv\lib\$(TARGET) + + +C_FILES = \ + ic.c \ + oe_ei_encode_version.c \ + oe_ei_encode_long.c \ + oe_ei_encode_ulong.c \ + oe_ei_encode_double.c \ + oe_ei_encode_char.c \ + oe_ei_encode_string.c \ + oe_ei_encode_atom.c \ + oe_ei_encode_pid.c \ + oe_ei_encode_port.c \ + oe_ei_encode_ref.c \ + oe_ei_encode_term.c \ + oe_ei_encode_tuple_header.c \ + oe_ei_encode_list_header.c \ + oe_ei_encode_longlong.c \ + oe_ei_encode_ulonglong.c \ + oe_ei_encode_wchar.c \ + oe_ei_encode_wstring.c \ + oe_ei_decode_longlong.c \ + oe_ei_decode_ulonglong.c \ + oe_ei_decode_wchar.c \ + oe_ei_decode_wstring.c + +OBJ_FILES = \ + $(OBJDIR)\ic.obj \ + $(OBJDIR)\oe_ei_encode_version.obj \ + $(OBJDIR)\oe_ei_encode_long.obj \ + $(OBJDIR)\oe_ei_encode_ulong.obj \ + $(OBJDIR)\oe_ei_encode_double.obj \ + $(OBJDIR)\oe_ei_encode_char.obj \ + $(OBJDIR)\oe_ei_encode_string.obj \ + $(OBJDIR)\oe_ei_encode_atom.obj \ + $(OBJDIR)\oe_ei_encode_pid.obj \ + $(OBJDIR)\oe_ei_encode_port.obj \ + $(OBJDIR)\oe_ei_encode_ref.obj \ + $(OBJDIR)\oe_ei_encode_term.obj \ + $(OBJDIR)\oe_ei_encode_tuple_header.obj \ + $(OBJDIR)\oe_ei_encode_list_header.obj \ + $(OBJDIR)\oe_ei_encode_longlong.obj \ + $(OBJDIR)\oe_ei_encode_ulonglong.obj \ + $(OBJDIR)\oe_ei_encode_wchar.obj \ + $(OBJDIR)\oe_ei_encode_wstring.obj \ + $(OBJDIR)\oe_ei_decode_longlong.obj \ + $(OBJDIR)\oe_ei_decode_ulonglong.obj \ + $(OBJDIR)\oe_ei_decode_wchar.obj \ + $(OBJDIR)\oe_ei_decode_wstring.obj + + +LIBRARY = $(LIBDIR)\ic.lib + + +all: $(OBJDIR) $(LIBDIR) $(LIBRARY) + +release: + echo "Nothing to do" + +clean: + -del $(OBJ_FILES) $(LIBRARY) + +$(LIBRARY): $(OBJ_FILES) + $(LIBRARIAN) /OUT:$@ $** + +{}.c{$(OBJDIR)}.obj: + $(CC) $(CFLAGS) /c /Fo$@ $< + +$(OBJDIR): + -mkdir $(OBJDIR) + +$(LIBDIR): + -mkdir $(LIBDIR) + +$(LIBRARY): + + +{}.c: $(EI_INCLUDE)\ei.h $(IC_INCLUDE)\ic. diff --git a/lib/ic/c_src/ic.c b/lib/ic/c_src/ic.c new file mode 100644 index 0000000..1ace9ea --- /dev/null +++ b/lib/ic/c_src/ic.c @@ -0,0 +1,612 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + +static int oe_send(CORBA_Environment *env); + +void CORBA_free(void *p) +{ + if (p != NULL) + free(p); +} + + +CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len) +{ + return (CORBA_char *) malloc(len+1); +} + + +CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len) +{ + return (CORBA_wchar *) malloc(len*(__OE_WCHAR_SIZE_OF__+1)); +} + + +CORBA_Environment *CORBA_Environment_alloc(int inbufsz, int outbufsz) +{ + CORBA_Environment *env; + + env = malloc(sizeof(CORBA_Environment)); + + if (env != NULL) { + + /* CORBA */ + env->_major = CORBA_NO_EXCEPTION; + + /* Set by user */ + env->_fd= -1; + env->_inbufsz = inbufsz; + env->_inbuf = malloc(inbufsz); + env->_outbufsz = outbufsz; + env->_outbuf = malloc(outbufsz); + env->_memchunk = __OE_MEMCHUNK__; + env->_regname[0] = '\0'; + env->_to_pid = NULL; + env->_from_pid = NULL; + + /* Set by client or server */ + env->_iin = 0; + env->_iout = 0; + env->_operation[0] = '\0'; + env->_received = 0; + /* env->_caller */ + /* env->_unique */ + env->_exc_id = NULL; + env->_exc_value = NULL; + env->_ref_counter_1 = 0; + env->_ref_counter_2 = 0; + env->_ref_counter_3 = 0; + } + + return env; +} + +#if 0 +/* NOT EXPORTED SO FAR */ +void CORBA_Environment_free(CORBA_Environment *env) +{ + + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_exception_free(env); + CORBA_free(env); +} +#endif + + +CORBA_char *CORBA_exception_id(CORBA_Environment *env) +{ + + return env->_exc_id; +} + +void *CORBA_exception_value(CORBA_Environment *env) +{ + + return env->_exc_value; +} + +void CORBA_exception_free(CORBA_Environment *env) +{ + + /* Setting major value */ + env->_major=CORBA_NO_EXCEPTION; + + /* Freeing storage */ + CORBA_free(env->_exc_id); + CORBA_free(env->_exc_value); + env->_exc_id = env->_exc_value = NULL; +} + +void CORBA_exc_set(CORBA_Environment *env, + CORBA_exception_type Major, + CORBA_char *Id, + CORBA_char *Value) +{ + int ilen,vlen; + + /* Create exception only if exception not already set */ + if (env->_major == CORBA_NO_EXCEPTION) { + + /* Counting lengths */ + ilen = strlen(Id)+1; + vlen = strlen(Value)+1; + + /* Allocating storage */ + env->_exc_id = (CORBA_char *) malloc(ilen); + env->_exc_value = (CORBA_char *) malloc(vlen); + + /* Initiating */ + env->_major = Major; + strcpy(env->_exc_id,Id); + strcpy(env->_exc_value,Value); + } +} + +#define ERLANG_REF_NUM_SIZE 18 +#define ERLANG_REF_MASK (~(~((unsigned int)0) << ERLANG_REF_NUM_SIZE)) + +/* Initiating message reference */ +void ic_init_ref(CORBA_Environment *env, erlang_ref *ref) +{ + + strcpy(ref->node, erl_thisnodename()); + + ref->len = 3; + + ++env->_ref_counter_1; + env->_ref_counter_1 &= ERLANG_REF_MASK; + if (env->_ref_counter_1 == 0) + if (++env->_ref_counter_2 == 0) + ++env->_ref_counter_3; + ref->n[0] = env->_ref_counter_1; + ref->n[1] = env->_ref_counter_2; + ref->n[2] = env->_ref_counter_3; + + ref->creation = erl_thiscreation(); +} + +/* Comparing message references */ +int ic_compare_refs(erlang_ref *ref1, erlang_ref *ref2) +{ + int i; + + if(strcmp(ref1->node, ref2->node) != 0) + return -1; + + if (ref1->len != ref2->len) + return -1; + + for (i = 0; i < ref1->len; i++) + if (ref1->n[i] != ref2->n[i]) + return -1; + + return 0; +} + +/* Length counter for wide strings */ +int ic_wstrlen(CORBA_wchar * p) +{ + int len = 0; + + while(1) { + if (p[len] == 0) + return len; + + len+=1; + } +} + + +/* Wide string compare function */ +int ic_wstrcmp(CORBA_wchar * ws1, CORBA_wchar * ws2) +{ + int index = 0; + + while(1) { + if (ws1[index] == ws2[index]) { + + if (ws1[index] == 0) + return 0; + + index += 1; + + } else + return -1; + } +} + +/* For backward compatibility -- replaced by prepare_request_decoding() */ +int ___call_info___(CORBA_Object obj, CORBA_Environment *env) +{ + return oe_prepare_request_decoding(env); +} + +/* #define DEBUG_MAP */ + +#if defined(DEBUG_MAP) + +#define PRINT_MAPS(P, M, S) print_maps(P, M, S) +#define PRINT_MAP(T, M) print_map(T, "", M) + +static void print_map(char *title, char *prefix, oe_map_t *map) +{ + if (map == NULL) { + fprintf(stdout, "%s => NULL\n", title); + return; + } + + fprintf(stdout, "%s%s\n", prefix, title); + + { + int j, len = map->length; + + fprintf(stdout, "%s length: %d\n", prefix, len); + fprintf(stdout, "%s operations: 0x%X%d\n", prefix, map->operations); + + for (j = 0 ; j < len ; j++) { + fprintf(stdout, "%s operation[%d]:\n", prefix, j); + + if (map->operations[j].interface != NULL) { + fprintf(stdout, "%s intf: %s\n", prefix, + map->operations[j].interface); + } else { + fprintf(stdout, "%s intf: NULL\n", prefix); + } + fprintf(stdout, "%s name: %s\n", prefix, + map->operations[j].name); + fprintf(stdout, "%s func: 0x%X\n", prefix, + map->operations[j].function); + } + } + fflush(stdout); +} + +static void print_maps(char* title, oe_map_t * maps, int size) +{ + int i; + char p[64]; + + fprintf(stdout, "%s\n", title); + + for (i = 0 ; i < size ; i++) { + sprintf(p, "map[%d]:", i); + print_map(p, " ", &maps[i]); + } + fprintf(stdout, "\n"); + fflush(stdout); +} + +#else + +#define PRINT_MAPS(P, M, S) +#define PRINT_MAP(T, M) + +#endif /* if defined(DEBUG_MAP) */ + + +/* Generic server switch */ +int oe_exec_switch(CORBA_Object obj, CORBA_Environment *env, oe_map_t *map) +{ + /* Setting local variables */ + int res = 0; + int index = 0; + + /* XXX map may be NULL !! */ + int length = map->length; + char* op = env->_operation; + + PRINT_MAP("switching on map", map); + + /* Initiating exception indicator */ + env->_major = CORBA_NO_EXCEPTION; + + if ((res = oe_prepare_request_decoding(env) < 0)) + return res; +#if defined(DEBUG_MAP) + fprintf(stdout, "looking for operation: %s\n", op); fflush(stdout); +#endif + for (index = 0; index < length; index++) { +#if defined(DEBUG_MAP) + fprintf(stdout, "map->operations[%d].name: %s\n", + index, map->operations[index].name); + fflush(stdout); +#endif + if(strcmp(map->operations[index].name, op) == 0) { +#if defined(DEBUG_MAP) + fprintf(stdout, "calling map->operations[%d].function: 0x%X\n", + index, map->operations[index].function); + fflush(stdout); +#endif + return map->operations[index].function(obj, env); + } + } + /* Bad call */ + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, BAD_OPERATION, + "Invalid operation"); + return -1; +} + +/* For backward compatibility */ +int ___switch___(CORBA_Object obj, CORBA_Environment *env, oe_map_t *map) +{ + return oe_exec_switch(obj, env, map); +} + + +oe_map_t* oe_merge_maps(oe_map_t *maps, int size) +{ + int i, j, length, len, maplen, malloc_size; + void *memp; + oe_map_t *merged; + + if ((maps == NULL) || (size <= 0)) + return NULL; + + PRINT_MAPS("merging maps", maps, size); + + length = 0; + for (i = 0; i < size; i++) + length += (maps[i].length); + + maplen = OE_ALIGN(sizeof(oe_map_t)); + malloc_size = maplen + OE_ALIGN(length*sizeof(oe_operation_t)); + if ((memp = malloc(malloc_size)) == NULL) + return NULL; + + merged = memp; + merged->length = length; + merged->operations = (oe_operation_t *)((char*)memp + maplen); + + for (i = 0, len = 0; i < size; i++) { + for(j = 0 ; j < maps[i].length; j++) + merged->operations[len+j] = maps[i].operations[j]; + len += maps[i].length; + } + PRINT_MAP("merged map", merged); + return merged; +} + +/* For backward compatibility */ +oe_map_t* ___merge___(oe_map_t *maps, int size) +{ + return oe_merge_maps(maps, size); +} + +/* Client send message (Erlang distribution protocol) */ +static int oe_send(CORBA_Environment *env) +{ + if (strlen(env->_regname) == 0) { + if (ei_send_encoded(env->_fd, env->_to_pid, env->_outbuf, + env->_iout) < 0) { + /* XXX Cannot send to peer? */ + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE, + "Cannot connect to server"); + return -1; + } + } else { + if (ei_send_reg_encoded(env->_fd, env->_from_pid, + env->_regname, env->_outbuf, + env->_iout) < 0) { + /* XXX Cannot send to peer? */ + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE, + "Cannot connect to server"); + return -1; + } + } + return 0; +} + +/* Send notification (gen_server client) */ +int oe_send_notification(CORBA_Environment *env) +{ + return oe_send(env); +} + +/* Send request and receive reply (gen_server client) */ +int oe_send_request_and_receive_reply(CORBA_Environment *env) +{ + int msgType = 0; + erlang_msg msg; + + if (oe_send(env) < 0) + return -1; + + do { + if ((msgType = ei_receive_encoded(env->_fd, + &env->_inbuf, + &env->_inbufsz, + &msg, &env->_iin)) < 0) { + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, + "Cannot decode message"); + return -1; + } + } while (msgType != ERL_SEND && msgType != ERL_REG_SEND); + + /* Extracting return message header */ + if (oe_prepare_reply_decoding(env) < 0) { + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, "Bad message"); + return -1; + } + return 0; +} + +/* Prepare notification encoding (gen_server client) */ +int oe_prepare_notification_encoding(CORBA_Environment *env) +{ + env->_iout = 0; + oe_ei_encode_version(env); + oe_ei_encode_tuple_header(env, 2); + oe_ei_encode_atom(env, "$gen_cast"); + return 0; +} + +/* Prepare request encoding (gen_server client) */ +int oe_prepare_request_encoding(CORBA_Environment *env) +{ + int error = 0; + + env->_iout = 0; + oe_ei_encode_version(env); + oe_ei_encode_tuple_header(env, 3); + oe_ei_encode_atom(env, "$gen_call"); + oe_ei_encode_tuple_header(env, 2); + if ((error = oe_ei_encode_pid(env, env->_from_pid)) < 0) + return error; + if ((error = oe_ei_encode_ref(env, &env->_unique)) < 0) + return error; + return 0; +} + +/* Prepare reply decoding (gen_server client) */ +int oe_prepare_reply_decoding(CORBA_Environment *env) +{ + int error = 0; + int version = 0; + erlang_ref unique; + + env->_iin = 0; + env->_received = 0; + + if ((error = ei_decode_version(env->_inbuf, + &env->_iin, + &version)) < 0) + return error; + if ((error = ei_decode_tuple_header(env->_inbuf, + &env->_iin, + &env->_received)) < 0) + return error; + if ((error = ei_decode_ref(env->_inbuf, + &env->_iin, + &unique)) < 0) + return error; + return ic_compare_refs(&env->_unique, &unique); +} + + +/* Prepare request decoding (gen_server server) */ +int oe_prepare_request_decoding(CORBA_Environment *env) +{ + char gencall_atom[10]; + int error = 0; + int version = 0; + + env->_iin = 0; + env->_received = 0; + memset(gencall_atom, 0, 10); + ei_decode_version(env->_inbuf, &env->_iin, &version); + ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received); + ei_decode_atom(env->_inbuf, &env->_iin, gencall_atom); + + if (strcmp(gencall_atom, "$gen_cast") == 0) { + if ((error = ei_decode_atom(env->_inbuf, &env->_iin, + env->_operation)) < 0) { + ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received); + if ((error = ei_decode_atom(env->_inbuf, &env->_iin, + env->_operation)) < 0) { + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, BAD_OPERATION, + "Bad Message, cannot extract operation"); + return error; + } + env->_received -= 1; + } else + env->_received -= 2; + return 0; + } + if (strcmp(gencall_atom, "$gen_call") == 0) { + ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received); + if ((error = ei_decode_pid(env->_inbuf, &env->_iin, + &env->_caller)) < 0) { + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, + "Bad Message, bad caller identity"); + return error; + } + if ((error = ei_decode_ref(env->_inbuf, &env->_iin, + &env->_unique)) < 0) { + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, + "Bad Message, bad message reference"); + return error; + } + if ((error = ei_decode_atom(env->_inbuf, &env->_iin, + env->_operation)) < 0) { + + ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received); + + if ((error = ei_decode_atom(env->_inbuf, &env->_iin, + env->_operation)) < 0) { + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, BAD_OPERATION, + "Bad Message, cannot extract operation"); + return error; + } + env->_received -= 1; + return 0; + } + else { + env->_received -= 2; + return 0; + } + } + + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, + "Bad message, neither cast nor call"); + return -1; +} + +/* Prepare reply encoding (gen_server server) */ +int oe_prepare_reply_encoding(CORBA_Environment *env) +{ + env->_iout = 0; + oe_ei_encode_version(env); + oe_ei_encode_tuple_header(env, 2); + oe_ei_encode_ref(env, &env->_unique); + return 0; +} + +/* ---- Function for making it more easy to implement a server */ +/* Server receive (possibly) send reply (gen_server server) */ + +int oe_server_receive(CORBA_Environment *env, oe_map_t *map) +{ + int res = 0, loop = 1; + erlang_msg msg; + + while (res >= 0 && loop > 0) { + res = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz, + &msg, &env->_iin); + switch(res) { + case ERL_SEND: + case ERL_REG_SEND: + oe_exec_switch(NULL, env, map); + switch(env->_major) { + case CORBA_NO_EXCEPTION: + break; + case CORBA_SYSTEM_EXCEPTION: + /* XXX stderr */ + fprintf(stderr, "Request failure, reason : %s\n", + (char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + break; + default: /* Should not happen */ + CORBA_exception_free(env); + break; + } + /* send reply */ + /* XXX We are required to set env->_iout = 0 if oneway?? */ + if (env->_iout > 0) + ei_send_encoded(env->_fd, &env->_caller, env->_outbuf, + env->_iout); + loop = 0; + break; + case ERL_TICK: + break; + default: + /* XXX */ + if (res < 0) { + fprintf(stderr, "Result negative: %d\n", res); + loop = 0; + } + break; + } + } + + return 0; +} + diff --git a/lib/ic/c_src/ic_tmo.c b/lib/ic/c_src/ic_tmo.c new file mode 100644 index 0000000..78698a6 --- /dev/null +++ b/lib/ic/c_src/ic_tmo.c @@ -0,0 +1,135 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + +static int oe_send_tmo(CORBA_Environment *env, unsigned int ms); + +/* Client send message (Erlang distribution protocol) */ +static int oe_send_tmo(CORBA_Environment *env, unsigned int ms) +{ + if (strlen(env->_regname) == 0) { + if (ei_send_encoded_tmo(env->_fd, env->_to_pid, env->_outbuf, + env->_iout, ms) < 0) { + /* XXX Cannot send to peer? */ + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE, + "Cannot connect to server"); + return -1; + } + } else { + if (ei_send_reg_encoded_tmo(env->_fd, env->_from_pid, + env->_regname, env->_outbuf, + env->_iout, ms) < 0) { + /* XXX Cannot send to peer? */ + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE, + "Cannot connect to server"); + return -1; + } + } + return 0; +} + +/* Send notification (gen_server client) */ +int oe_send_notification_tmo(CORBA_Environment *env, unsigned int send_ms) +{ + return oe_send_tmo(env, send_ms); +} + +/* Send request and receive reply (gen_server client) */ +int oe_send_request_and_receive_reply_tmo(CORBA_Environment *env, + unsigned int send_ms, + unsigned int recv_ms) +{ + int msgType = 0; + erlang_msg msg; + + if (oe_send_tmo(env, send_ms) < 0) + return -1; + + do { + if ((msgType = ei_receive_encoded_tmo(env->_fd, + &env->_inbuf, + &env->_inbufsz, + &msg, &env->_iin, + recv_ms)) < 0) { + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, + "Cannot decode message"); + return -1; + } + } while (msgType != ERL_SEND && msgType != ERL_REG_SEND); + + /* Extracting return message header */ + if (oe_prepare_reply_decoding(env) < 0) { + CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, "Bad message"); + return -1; + } + return 0; +} + +/* Server receive (possibly) send reply (gen_server server) */ + +int oe_server_receive_tmo(CORBA_Environment *env, oe_map_t *map, + unsigned int send_ms, + unsigned int recv_ms) +{ + int res = 0, loop = 1; + erlang_msg msg; + + while (res >= 0 && loop > 0) { + res = ei_receive_encoded_tmo(env->_fd, &env->_inbuf, &env->_inbufsz, + &msg, &env->_iin, recv_ms); + switch(res) { + case ERL_SEND: + case ERL_REG_SEND: + oe_exec_switch(NULL, env, map); + switch(env->_major) { + case CORBA_NO_EXCEPTION: + break; + case CORBA_SYSTEM_EXCEPTION: + /* XXX stderr */ + fprintf(stderr, "Request failure, reason : %s\n", + (char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + break; + default: /* Should not happen */ + CORBA_exception_free(env); + break; + } + /* send reply */ + /* XXX We are required to set env->_iout = 0 if oneway?? */ + if (env->_iout > 0) + ei_send_encoded_tmo(env->_fd, &env->_caller, env->_outbuf, + env->_iout, send_ms); + loop = 0; + break; + case ERL_TICK: + break; + default: + /* XXX */ + if (res < 0) { + fprintf(stderr, "Result negative: %d\n", res); + loop = 0; + } + break; + } + } + + return 0; +} + diff --git a/lib/ic/c_src/oe_ei_code_erlang_binary.c b/lib/ic/c_src/oe_ei_code_erlang_binary.c new file mode 100644 index 0000000..f790f8b --- /dev/null +++ b/lib/ic/c_src/oe_ei_code_erlang_binary.c @@ -0,0 +1,105 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_encode_erlang_binary(CORBA_Environment *ev, erlang_binary *binary) { + + int size = ev->_iout; + + (int) ei_encode_binary(0, &size, binary->_buffer, binary->_length); + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + while (size >= bufsz) + bufsz += ev->_memchunk; + + if ((buf = realloc(buf, bufsz)) == NULL) { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + + ev->_outbuf = buf; + ev->_outbufsz = bufsz; + } + + return ei_encode_binary(ev->_outbuf, &ev->_iout, binary->_buffer, binary->_length); +} + + + +int oe_sizecalc_erlang_binary(CORBA_Environment *ev, int* _index, int* _size) { + + long _malloc_size = 0; + int _error = 0; + + if(*_size == 0) + *_size = ((*_size + sizeof(erlang_binary))+sizeof(double)-1)&~(sizeof(double)-1); + + if ((_error = ei_decode_binary(ev->_inbuf, _index, 0, &_malloc_size)) < 0) + return _error; + + *_size = ((*_size + (int)_malloc_size)+sizeof(double)-1)&~(sizeof(double)-1); + + return 0; +} + + +int oe_decode_erlang_binary(CORBA_Environment *ev, char *_first, int* _index, erlang_binary *binary) { + + long _length = 0; + int _error = 0; + + if((char*) binary == _first) + *_index = ((*_index + sizeof(erlang_binary))+sizeof(double)-1)&~(sizeof(double)-1); + + binary->_buffer = (CORBA_octet *)(_first+*_index); + + if ((_error = ei_decode_binary(ev->_inbuf, &ev->_iin, binary->_buffer, &_length)) < 0) + return _error; + + binary->_length = (CORBA_unsigned_long)_length; + + *_index = ((*_index)+_length+sizeof(double)-1)&~(sizeof(double)-1); + + return 0; +} + + + +int print_erlang_binary(erlang_binary *binary) { + + int i=0; + + if (binary == NULL) + return -1; + + fprintf(stdout,"binary->_length : %ld\n",binary->_length); + fprintf(stdout,"binary->_buffer : "); + if(binary->_buffer != NULL) { + for (i=0; i_length; i++) + fprintf(stdout,"%c",binary->_buffer[i]); + fprintf(stdout,"\n"); + } else + fprintf(stdout,"NULL\n"); + return 0; +} diff --git a/lib/ic/c_src/oe_ei_decode_longlong.c b/lib/ic/c_src/oe_ei_decode_longlong.c new file mode 100644 index 0000000..1fd5c84 --- /dev/null +++ b/lib/ic/c_src/oe_ei_decode_longlong.c @@ -0,0 +1,25 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_decode_longlong(const char *buf, int *index, CORBA_long_long *p) { + return ei_decode_long(buf, index, p); +} diff --git a/lib/ic/c_src/oe_ei_decode_ulonglong.c b/lib/ic/c_src/oe_ei_decode_ulonglong.c new file mode 100644 index 0000000..26e4294 --- /dev/null +++ b/lib/ic/c_src/oe_ei_decode_ulonglong.c @@ -0,0 +1,25 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_decode_ulonglong(const char *buf, int *index, CORBA_unsigned_long_long *p) { + return ei_decode_ulong(buf, index, p); +} diff --git a/lib/ic/c_src/oe_ei_decode_wchar.c b/lib/ic/c_src/oe_ei_decode_wchar.c new file mode 100644 index 0000000..b68cdb8 --- /dev/null +++ b/lib/ic/c_src/oe_ei_decode_wchar.c @@ -0,0 +1,25 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_decode_wchar(const char *buf, int *index, CORBA_wchar *p) { + return ei_decode_ulong(buf, index, p); +} diff --git a/lib/ic/c_src/oe_ei_decode_wstring.c b/lib/ic/c_src/oe_ei_decode_wstring.c new file mode 100644 index 0000000..b89922f --- /dev/null +++ b/lib/ic/c_src/oe_ei_decode_wstring.c @@ -0,0 +1,107 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +/* Scratch function */ +int oe_ei_decode_wstring(const char *buf, int *index, CORBA_wchar *p) { + + int length,error_code,type,tmp=0; + char * tmp_space = NULL; + + + if ((error_code = ei_get_type(buf, index, &type, &length)) < 0) + return error_code; + + switch(type) { + + case ERL_LIST_EXT: /* A list */ + case ERL_NIL_EXT: /* An empty list */ + + if (p) { /* Decoding part */ + + if ((error_code = ei_decode_list_header(buf, index, &length)) < 0) + return error_code; + + if (length != 0) { + for(tmp = 0; tmp < length; tmp++) + if ((error_code = oe_ei_decode_wchar(buf, index, &(p[tmp]))) < 0) + return error_code; + + /* Read list tail also */ + if ((error_code = ei_decode_list_header(buf, index, &length)) < 0) + return error_code; + } + + p[tmp] = 0; /* Wide NULL */ + + } else { /* Allocation counting part */ + + if ((error_code = ei_decode_list_header(buf, index, &length)) < 0) + return error_code; + + if (length != 0) { + for(tmp = 0; tmp < length; tmp++) + if ((error_code = oe_ei_decode_wchar(buf, index, 0)) < 0) + return error_code; + + /* Read list tail also */ + if ((error_code = ei_decode_list_header(buf, index, &length)) < 0) + return error_code; + } + } + + break; + + case ERL_STRING_EXT: /* A string */ + + if (p) { /* Decoding part */ + + /* Allocate temporary string */ + tmp_space = (char*) malloc(length*(__OE_WCHARSZ__+1)); + + if ((error_code = ei_decode_string(buf, index, tmp_space)) < 0) + return error_code; + + /* Assign characters to wide characters */ + for(tmp = 0; tmp < length; tmp++) + p[tmp] = tmp_space[tmp]; + + p[tmp] = 0; /* Wide NULL */ + + /* Free temporary string */ + CORBA_free(tmp_space); + + } else { /* Allocation counting part */ + + if ((error_code = ei_decode_string(buf, index, 0)) < 0) + return error_code; + + } + break; + + default: /* Bad header */ + return -1; + } + + return 0; +} + + diff --git a/lib/ic/c_src/oe_ei_encode_atom.c b/lib/ic/c_src/oe_ei_encode_atom.c new file mode 100644 index 0000000..d16df25 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_atom.c @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_atom(CORBA_Environment *ev, const char *p) { + int size = ev->_iout; + + (int) ei_encode_atom(0,&size,p); + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + while (size >= bufsz) + bufsz += ev->_memchunk; + + if ((buf = realloc(buf, bufsz)) == NULL) { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + + ev->_outbuf = buf; + ev->_outbufsz = bufsz; + } + + return ei_encode_atom(ev->_outbuf,&ev->_iout,p); +} + diff --git a/lib/ic/c_src/oe_ei_encode_char.c b/lib/ic/c_src/oe_ei_encode_char.c new file mode 100644 index 0000000..a180b90 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_char.c @@ -0,0 +1,44 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_char(CORBA_Environment *ev, char p) { + int size = ev->_iout + __OE_CHARSZ__; + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + if ((buf = realloc(buf,bufsz)) != NULL) { + ev->_outbuf = buf; + ev->_outbufsz += ev->_memchunk; + } + else { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + } + + return ei_encode_char(ev->_outbuf, &ev->_iout, p); +} + + + diff --git a/lib/ic/c_src/oe_ei_encode_double.c b/lib/ic/c_src/oe_ei_encode_double.c new file mode 100644 index 0000000..931b91a --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_double.c @@ -0,0 +1,43 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_double(CORBA_Environment *ev, double p) { + int size = ev->_iout + __OE_DOUBLESZ__; + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + if ((buf = realloc(buf,bufsz)) != NULL) { + ev->_outbuf = buf; + ev->_outbufsz += ev->_memchunk; + } + else { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + } + + return ei_encode_double(ev->_outbuf, &ev->_iout, p); +} + + diff --git a/lib/ic/c_src/oe_ei_encode_list_header.c b/lib/ic/c_src/oe_ei_encode_list_header.c new file mode 100644 index 0000000..b93ad9c --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_list_header.c @@ -0,0 +1,41 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_list_header(CORBA_Environment *ev, int arity) { + int size = ev->_iout + __OE_LISTHDRSZ__; + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + if ((buf = realloc(buf,bufsz)) != NULL) { + ev->_outbuf = buf; + ev->_outbufsz += ev->_memchunk; + } + else { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + } + + return ei_encode_list_header(ev->_outbuf, &ev->_iout, arity); +} diff --git a/lib/ic/c_src/oe_ei_encode_long.c b/lib/ic/c_src/oe_ei_encode_long.c new file mode 100644 index 0000000..1f2e62a --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_long.c @@ -0,0 +1,44 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_long(CORBA_Environment *ev, long p) { + int size = ev->_iout + __OE_LONGSZ__; + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + if ((buf = realloc(buf,bufsz)) != NULL) { + ev->_outbuf = buf; + ev->_outbufsz += ev->_memchunk; + } + else { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + } + + return ei_encode_long(ev->_outbuf, &ev->_iout, p); +} + + + diff --git a/lib/ic/c_src/oe_ei_encode_longlong.c b/lib/ic/c_src/oe_ei_encode_longlong.c new file mode 100644 index 0000000..79b4eef --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_longlong.c @@ -0,0 +1,44 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_longlong(CORBA_Environment *ev, CORBA_long_long p) { + int size = ev->_iout + __OE_LONGLONGSZ__; + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + if ((buf = realloc(buf,bufsz)) != NULL) { + ev->_outbuf = buf; + ev->_outbufsz += ev->_memchunk; + } + else { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + } + + /* CORBA_long_long = long because of erl_interface limitation */ + return ei_encode_long(ev->_outbuf, &ev->_iout, p); +} + + diff --git a/lib/ic/c_src/oe_ei_encode_pid.c b/lib/ic/c_src/oe_ei_encode_pid.c new file mode 100644 index 0000000..b7083f8 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_pid.c @@ -0,0 +1,45 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_pid(CORBA_Environment *ev, const erlang_pid *p) { + int size = ev->_iout; + + (int) ei_encode_pid(NULL, &size, p); + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + while (size >= bufsz) + bufsz += ev->_memchunk; + + if ((buf = realloc(buf, bufsz)) == NULL) { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + + ev->_outbuf = buf; + ev->_outbufsz = bufsz; + } + + return ei_encode_pid(ev->_outbuf, &ev->_iout, p); +} diff --git a/lib/ic/c_src/oe_ei_encode_port.c b/lib/ic/c_src/oe_ei_encode_port.c new file mode 100644 index 0000000..981f82c --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_port.c @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_port(CORBA_Environment *ev, const erlang_port *p) { + int size = ev->_iout; + + (int) ei_encode_port(NULL, &size, p); + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + while (size >= bufsz) + bufsz += ev->_memchunk; + + if ((buf = realloc(buf, bufsz)) == NULL) { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + + ev->_outbuf = buf; + ev->_outbufsz = bufsz; + } + + return ei_encode_port(ev->_outbuf, &ev->_iout, p); +} + diff --git a/lib/ic/c_src/oe_ei_encode_ref.c b/lib/ic/c_src/oe_ei_encode_ref.c new file mode 100644 index 0000000..d321469 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_ref.c @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_ref(CORBA_Environment *ev, const erlang_ref *p) { + int size = ev->_iout; + + (int) ei_encode_ref(NULL, &size, p); + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + while (size >= bufsz) + bufsz += ev->_memchunk; + + if ((buf = realloc(buf, bufsz)) == NULL) { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + + ev->_outbuf = buf; + ev->_outbufsz = bufsz; + } + + return ei_encode_ref(ev->_outbuf, &ev->_iout, p); +} + diff --git a/lib/ic/c_src/oe_ei_encode_string.c b/lib/ic/c_src/oe_ei_encode_string.c new file mode 100644 index 0000000..48de73b --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_string.c @@ -0,0 +1,47 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_string(CORBA_Environment *ev, const char *p) { + int size = ev->_iout; + + (int) ei_encode_string(0,&size,p); + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + while (size >= bufsz) + bufsz += ev->_memchunk; + + if ((buf = realloc(buf, bufsz)) == NULL) { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + + ev->_outbuf = buf; + ev->_outbufsz = bufsz; + } + + return ei_encode_string(ev->_outbuf,&ev->_iout,p); +} + + diff --git a/lib/ic/c_src/oe_ei_encode_term.c b/lib/ic/c_src/oe_ei_encode_term.c new file mode 100644 index 0000000..48de152 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_term.c @@ -0,0 +1,48 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_term(CORBA_Environment *ev, void *t) { + int size = ev->_iout; + + (int) ei_encode_term(NULL, &size, t); + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + while (size >= bufsz) + bufsz += ev->_memchunk; + + if ((buf = realloc(buf, bufsz)) == NULL) { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + + ev->_outbuf = buf; + ev->_outbufsz = bufsz; + } + + return ei_encode_term(ev->_outbuf, &ev->_iout, t); +} + + + diff --git a/lib/ic/c_src/oe_ei_encode_tuple_header.c b/lib/ic/c_src/oe_ei_encode_tuple_header.c new file mode 100644 index 0000000..c2d92a7 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_tuple_header.c @@ -0,0 +1,44 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_tuple_header(CORBA_Environment *ev, int arity) { + int size = ev->_iout + __OE_TUPLEHDRSZ__; + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + if ((buf = realloc(buf,bufsz)) != NULL) { + ev->_outbuf = buf; + ev->_outbufsz += ev->_memchunk; + } + else { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + } + + return ei_encode_tuple_header(ev->_outbuf, &ev->_iout, arity); +} + + + diff --git a/lib/ic/c_src/oe_ei_encode_ulong.c b/lib/ic/c_src/oe_ei_encode_ulong.c new file mode 100644 index 0000000..d1a9cf1 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_ulong.c @@ -0,0 +1,43 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_ulong(CORBA_Environment *ev, unsigned long p) { + int size = ev->_iout + __OE_ULONGSZ__; + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + if ((buf = realloc(buf,bufsz)) != NULL) { + ev->_outbuf = buf; + ev->_outbufsz += ev->_memchunk; + } + else { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + } + + return ei_encode_ulong(ev->_outbuf, &ev->_iout, p); +} + + diff --git a/lib/ic/c_src/oe_ei_encode_ulonglong.c b/lib/ic/c_src/oe_ei_encode_ulonglong.c new file mode 100644 index 0000000..1260053 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_ulonglong.c @@ -0,0 +1,44 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_ulonglong(CORBA_Environment *ev, CORBA_unsigned_long_long p) { + int size = ev->_iout + __OE_ULONGLONGSZ__; + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + if ((buf = realloc(buf,bufsz)) != NULL) { + ev->_outbuf = buf; + ev->_outbufsz += ev->_memchunk; + } + else { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + } + + /* CORBA_long_long = long because of erl_interface limitation */ + return ei_encode_ulong(ev->_outbuf, &ev->_iout, p); +} + + diff --git a/lib/ic/c_src/oe_ei_encode_version.c b/lib/ic/c_src/oe_ei_encode_version.c new file mode 100644 index 0000000..2448b32 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_version.c @@ -0,0 +1,42 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_version(CORBA_Environment *ev) { + int size = ev->_iout + __OE_VSNSZ__; + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + if ((buf = realloc(buf,bufsz)) != NULL) { + ev->_outbuf = buf; + ev->_outbufsz += ev->_memchunk; + } + else { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + } + + return ei_encode_version(ev->_outbuf, &ev->_iout); +} + diff --git a/lib/ic/c_src/oe_ei_encode_wchar.c b/lib/ic/c_src/oe_ei_encode_wchar.c new file mode 100644 index 0000000..6b9505a --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_wchar.c @@ -0,0 +1,27 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_wchar(CORBA_Environment *ev, CORBA_wchar p) { + return oe_ei_encode_ulong(ev, p); +} + + diff --git a/lib/ic/c_src/oe_ei_encode_wstring.c b/lib/ic/c_src/oe_ei_encode_wstring.c new file mode 100644 index 0000000..6f26c53 --- /dev/null +++ b/lib/ic/c_src/oe_ei_encode_wstring.c @@ -0,0 +1,62 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include + + +int oe_ei_encode_wstring(CORBA_Environment *ev, CORBA_wchar *p) { + + int len,wchar,size,tmp,error_code; + + len = ic_wstrlen(p); + size = ev->_iout + __OE_LISTHDRSZ__ +(len * __OE_WCHARSZ__); + + if (size >= ev->_outbufsz) { + char *buf = ev->_outbuf; + int bufsz = ev->_outbufsz + ev->_memchunk; + + while (size >= bufsz) + bufsz += ev->_memchunk; + + if ((buf = realloc(buf, bufsz)) == NULL) { + CORBA_exc_set(ev, CORBA_SYSTEM_EXCEPTION, NO_MEMORY, "End of heap memory while encoding"); + return -1; /* OUT OF MEMORY */ + } + + ev->_outbuf = buf; + ev->_outbufsz = bufsz; + } + + /* Encode the wide string */ + error_code = 0; + + if ((error_code = oe_ei_encode_list_header(ev, len)) < 0) + return error_code; + + for(tmp = 0; tmp < len; tmp++) + if ((error_code = oe_ei_encode_wchar(ev, p[tmp])) < 0) + return error_code; + + if ((error_code = oe_ei_encode_empty_list(ev)) < 0) + return error_code; + + return 0; +} + + diff --git a/lib/ic/doc/html/.gitignore b/lib/ic/doc/html/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/ic/doc/man1/.gitignore b/lib/ic/doc/man1/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/ic/doc/man3/.gitignore b/lib/ic/doc/man3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/ic/doc/pdf/.gitignore b/lib/ic/doc/pdf/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/ic/doc/src/CORBA_Environment_alloc.xml b/lib/ic/doc/src/CORBA_Environment_alloc.xml new file mode 100644 index 0000000..909379d --- /dev/null +++ b/lib/ic/doc/src/CORBA_Environment_alloc.xml @@ -0,0 +1,142 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CORBA_Environment_alloc + + + + 1998-12-01 + A +
+ CORBA_Environment_alloc + Allocation function for the CORBA_Environement struct + +

The CORBA_Environment_alloc() function is the + function used to allocate and initiate the CORBA_Environment + structure.

+
+ + + CORBA_Environment *CORBA_Environment_alloc(inbufsz, outbufsz) + Initialize communication + + int inbufsz; + int outbufsz; + + +

This function is used to create and initiate the CORBA_Environment + structure. In particular, it is used to dynamically allocate a CORBA_Environment + structure and set the default values for the structure's fields.

+

inbufsize is the wished size of input buffer.

+

outbufsize is the wished size of output buffer.

+

CORBA_Environment is the CORBA 2.0 state structure used by the + generated stub.

+

This function will set all needed default values and allocate buffers equal + to the values passed, but will not allocate space for the _to_pid and _from_pid fields.

+

To free the space allocated by CORBA_Environment_alloc/2 :

+ + +

First call CORBA_free for the input and output buffers.

+
+ +

After freeing the buffer space, call CORBA_free for the CORBA_Environment space.

+
+
+
+
+
+ +
+ The CORBA_Environment structure +

Here is the complete definition of the CORBA_Environment structure, + defined in file ic.h :

+ +/* Environment definition */ +typedef struct { + + /*----- CORBA compatibility part ------------------------*/ + /* Exception tag, initially set to CORBA_NO_EXCEPTION ---*/ + CORBA_exception_type _major; + + /*----- External Implementation part - initiated by the user ---*/ + /* File descriptor */ + int _fd; + /* Size of input buffer */ + int _inbufsz; + /* Pointer to always dynamically allocated buffer for input */ + char *_inbuf; + /* Size of output buffer */ + int _outbufsz; + /* Pointer to always dynamically allocated buffer for output */ + char *_outbuf; + /* Size of memory chunks in bytes, used for increasing the output + buffer, set to >= 32, should be around >= 1024 for performance + reasons */ + int _memchunk; + /* Pointer for registered name */ + char _regname[256]; + /* Process identity for caller */ + erlang_pid *_to_pid; + /* Process identity for callee */ + erlang_pid *_from_pid; + + /*- Internal Implementation part - used by the server/client ---*/ + /* Index for input buffer */ + int _iin; + /* Index for output buffer */ + int _iout; + /* Pointer for operation name */ + char _operation[256]; + /* Used to count parameters */ + int _received; + /* Used to identify the caller */ + erlang_pid _caller; + /* Used to identify the call */ + erlang_ref _unique; + /* Exception id field */ + CORBA_char *_exc_id; + /* Exception value field */ + void *_exc_value; + + +} CORBA_Environment; + + +

Remember to set the field values _fd , _regname , *_to_pid and/or + *_from_pid to the appropriate application values. These are not automatically + set by the stubs.

+
+ +

Never assign static buffers to the buffer pointers, never set the _memchunk field to + a value less than 32.

+
+
+ +
+ SEE ALSO +

ic(3)

+
+ +
+ + diff --git a/lib/ic/doc/src/Makefile b/lib/ic/doc/src/Makefile new file mode 100644 index 0000000..fff930d --- /dev/null +++ b/lib/ic/doc/src/Makefile @@ -0,0 +1,320 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(IC_VSN) +APPLICATION=ic +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Java specific +# ---------------------------------------------------- +JAVADOC=javadoc +JAVA_INCL_ROOT = $(ERL_TOP)/lib/jinterface/priv/ +JAVA_SRC_ROOT = $(ERL_TOP)/lib/ic/java_src/ +JAVA_CLASS_SUBDIR = com/ericsson/otp/ic/ + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = ic.xml \ + ic_clib.xml \ + ic_c_protocol.xml + +XML_PART_FILES = part.xml \ + part_notes.xml + +XML_CHAPTER_FILES = \ + ch_introduction.xml \ + ch_basic_idl.xml \ + ch_ic_protocol.xml \ + ch_erl_plain.xml \ + ch_erl_genserv.xml \ + ch_c_mapping.xml \ + ch_c_client.xml \ + ch_c_server.xml \ + ch_c_corba_env.xml \ + ch_java.xml \ + notes.xml + +BOOK_FILES = book.xml + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif + +# ---------------------------------------------------- + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +JAVA_SOURCE_FILES = \ + Holder.java \ + BooleanHolder.java \ + ByteHolder.java \ + CharHolder.java \ + DoubleHolder.java \ + FloatHolder.java \ + IntHolder.java \ + LongHolder.java \ + ShortHolder.java \ + StringHolder.java \ + Environment.java \ + Any.java \ + AnyHelper.java \ + AnyHolder.java \ + TypeCode.java \ + TCKind.java \ + Pid.java \ + PidHolder.java \ + PidHelper.java \ + Ref.java \ + RefHolder.java \ + RefHelper.java \ + Port.java \ + PortHolder.java \ + PortHelper.java \ + Term.java \ + TermHolder.java \ + TermHelper.java + + +JD_INDEX_HTML_FILES = \ + allclasses-frame.html \ + allclasses-noframe.html \ + deprecated-list.html \ + index-all.html \ + overview-tree.html \ + stylesheet.css \ + help-doc.html \ + index.html \ + package-list \ + serialized-form.html \ + constant-values.html + +JD_GIF_FILES = \ + ../html/java/resources/inherit.gif + + +PACK_DIR = com/ericsson/otp/ic +JAVA_SOURCE_DIR = ../../java_src/$(PACK_DIR) + +JD_PACK_HTML_FILES = \ + package-frame.html \ + package-summary.html \ + package-tree.html + +JAVADOC_PACK_HTML_FILES = \ + $(JAVA_SOURCE_FILES:%.java=../html/java/$(PACK_DIR)/%.html) \ + $(JD_PACK_HTML_FILES:%=../html/java/$(PACK_DIR)/%) + +JAVADOC_INDEX_HTML_FILES = $(JD_INDEX_HTML_FILES:%=../html/java/%) + +JAVADOC_GENERATED_FILES = $(JAVADOC_PACK_HTML_FILES) $(JAVADOC_INDEX_HTML_FILES) + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +CLASSPATH = $(JAVA_SRC_ROOT):$(JAVA_INCL_ROOT) + +XML_FLAGS += +DVIPS_FLAGS += +JAVADOCFLAGS = \ + -classpath $(CLASSPATH) \ + -d ../doc/html/java \ + -windowtitle "Package com.ericsson.otp.ic version $(IC_VSN)" \ + -public \ + -footer "
Copyright © 1991-2007 Ericsson AB
" + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +ifdef DOCSUPPORT + +docs: pdf html man $(JAVADOC_GENERATED_FILES) + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html $(JAVADOC_GENERATED_FILES) gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTML_FILES) $(MAN3_FILES) + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) + rm -rf ../html/java/* + +endif + +$(JAVADOC_GENERATED_FILES): + @(cd ../../java_src; $(JAVADOC) $(JAVADOCFLAGS) com.ericsson.otp.ic) + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +$(INDEX_TARGET): $(INDEX_SRC) ../../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +debug opt: + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + (/bin/cp -rf $(HTMLDIR) $(RELSYSDIR)/doc) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java + $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/resources + $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com + $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com/ericsson + $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com/ericsson/otp + $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com/ericsson/otp/ic + $(INSTALL_DATA) $(JAVADOC_INDEX_HTML_FILES) \ + $(RELSYSDIR)/doc/html/java + $(INSTALL_DATA) $(JD_GIF_FILES) \ + $(RELSYSDIR)/doc/html/java/resources + $(INSTALL_DATA) $(JAVADOC_PACK_HTML_FILES) \ + $(RELSYSDIR)/doc/html/java/com/ericsson/otp/ic + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + + +release_spec: + + diff --git a/lib/ic/doc/src/book.gif b/lib/ic/doc/src/book.gif new file mode 100644 index 0000000000000000000000000000000000000000..94b38687920c5386f0d90df2cfc962d66f52fbce GIT binary patch literal 1081 zcmV-91jhSENk%v~VJrYQ0K@U3Z&d%1>*52OU z=jZ3|@9+2b_W%F@EC2ui04xAE000I5ARvxpX`Uh%Eez$Ma2!{|XMe{g?|T;9x5JA^ zG%bL@N^vRj5RkV9bLkO4ZPIBmas5oR#mf&V1Q#(0YhcjmXe*9~d=7a)?vMy(=-KE* z8yQRzT~`AL3l4P-3kL!Lf=d(yg_TGJLq#4K5D7Jwg%4&P850c&1Y@8d0)H_S5pFPj z7ZR$K4m$^o4iXXx39coCpaZff8wUU$784g63O)Mnh1d zM*Ony;LwB#3?8W4Fn~dfDxggNp6C!kf(B*{AQb3^!o#OZ2{2Ij__0FI3O->S0!o2G zg@f-96evKTsnY>a2Pj~$%K;+++!`!k(;yCksSK!^1M@%uPY44fe1t$i?MDI+c2ZbC za|F=4KrQICaN${m0^A%h5YV8o0a~3adU`fEQr`1qssBIw;^v!UF;k;yW-v@4+eo>JYd}fHVVU z5gLf*p9x%mVi^DlSTI8WPNw|_zy%J@^^O%t7;wu6|1F@62n+%+n+O+(7C~JYKp}tz zPXIAiOdhnDfD0a6fWQkLNGO6;!$2WQfj6jx)&W2YPymny2!Ox=N)36z-FBgSXr4c6dN%+LI-06;0gjrH4CDHEr=iiO;mnh?Fk3i5Wq1C#9AnbqG>3C zxFaCoE>b2iV1odev}UfA7}V< + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + ic + + + 1998-09-29 + 4.0.4 + book.sgml +
+ + + ic + + + + + + + + + + + + + + +
+ diff --git a/lib/ic/doc/src/c-part.xml b/lib/ic/doc/src/c-part.xml new file mode 100644 index 0000000..91c81c8 --- /dev/null +++ b/lib/ic/doc/src/c-part.xml @@ -0,0 +1,40 @@ + + + + +
+ + 2002 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + IDL to C language Mapping + + + 2002-06-25 + A +
+ +

IDL to C

+
+ + + + +
+ diff --git a/lib/ic/doc/src/ch_basic_idl.xml b/lib/ic/doc/src/ch_basic_idl.xml new file mode 100644 index 0000000..d993fa3 --- /dev/null +++ b/lib/ic/doc/src/ch_basic_idl.xml @@ -0,0 +1,163 @@ + + + + +
+ + 20022009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + OMG IDL + + + 2002-07-15 + + ch_basic_idl.xml +
+ +
+ OMG IDL - Overview +

The purpose of OMG IDL, Interface Definition Language, mapping + is to act as translator between platforms and languages. An IDL + specification is supposed to describe data types, object types etc.

+

Since the C and Java IC backends only supports a subset of the + IDL types supported by the other backends, the mapping is divided into + different parts. For more information about IDL to Erlang mapping, + i.e., CORBA, plain Erlang and generic Erlang Server, see the Orber + User's Guide. How to use the plain Erlang and generic Erlang Server is + found in this User's Guide.

+ +
+ Reserved Compiler Names and Keywords +

The use of some names is strongly discouraged due to + ambiguities. However, the use of some names is prohibited + when using the Erlang mapping , as they are strictly reserved for IC.

+

IC reserves all identifiers starting with OE_ and oe_ + for internal use.

+

Note also, that an identifier in IDL can contain alphabetic, + digits and underscore characters, but the first character + must be alphabetic. +

+

Using underscores in IDL names can lead to ambiguities + due to the name mapping described above. It is advisable to + avoid the use of underscores in identifiers.

+

The OMG defines a set of reserved words, shown below, for use as keywords. + These may not be used as, for example, identifiers.

+ + + abstract + double + local + raises + typedef + + + any + exception + long + readonly + unsigned + + + attribute + enum + module + sequence + union + + + boolean + factory + native + short + ValueBase + + + case + FALSE + Object + string + valuetype + + + char + fixed + octet + struct + void + + + const + float + oneway + supports + wchar + + + context + in + out + switch + wstring + + + custom + inout + private + TRUE + + + + default + interface + public + truncatable + + + OMG IDL keywords +
+

The keywords listed above must be written exactly as shown. Any usage + of identifiers that collide with a keyword is illegal. For example, + long is a valid keyword; Long and LONG are + illegal as keywords and identifiers. But, since the OMG must be able + to expand the IDL grammar, it is possible to use Escaped Identifiers. For example, it is not unlikely that native + have been used in IDL-specifications as identifiers. One option is to + change all occurrences to myNative. Usually, it is necessary + to change programming language code that depends upon that IDL as well. + Since Escaped Identifiers just disable type checking (i.e. if it is a reserved + word or not) and leaves everything else unchanged, it is only necessary to + update the IDL-specification. To escape an identifier, simply prefix it + with _. The following IDL-code is illegal:

+ +typedef string native; +interface i { + void foo(in native Arg); + }; +}; + +

With Escaped Identifiers the code will look like:

+ +typedef string _native; +interface i { + void foo(in _native Arg); + }; +}; + +
+
+
+ diff --git a/lib/ic/doc/src/ch_c_client.xml b/lib/ic/doc/src/ch_c_client.xml new file mode 100644 index 0000000..7d4f8ec --- /dev/null +++ b/lib/ic/doc/src/ch_c_client.xml @@ -0,0 +1,149 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The C Client Back-end + + + 2004-01-14 + C + ch_c_client.xml +
+ +
+ Introduction +

With the option {be, c_client} the IDL Compiler generates + C client stubs according to the IDL to C mapping, on top of the + Erlang distribution and gen_server protocols.

+

The developer has to write additional code, that together with + the generated C client stubs, form a hidden Erlang node. That + additional code uses erl_interface functions for defining + the hidden node, and for establishing connections to other + Erlang nodes.

+
+ +
+ Generated Stub Files +

The generated stub files are:

+ + +

For each IDL interface, a C source file, the name of which + is .c]]>. Each operation of the + IDL interface is mapped to a C function (with scoped name) + in that file;

+
+ +

C source files that contain functions for type conversion, + memory allocation, and data encoding/decoding;

+
+ +

C header files that contain function prototypes and type + definitions.

+
+
+

All C functions are exported (i.e. not declared static).

+
+ +
+ C Interface Functions +

For each IDL operation a C interface function is + generated, the prototype of which is:

+

( oe_obj, , CORBA_Environment *oe_env);]]>

+

where

+ + +

]]> is the value to be returned as defined + by the IDL specification;

+
+ +

oe_obj]]> is the client interface + object;

+
+ +

]]> is a list of parameters of the + operation, defined in the same order as defined by the IDL + specification;

+
+ +

CORBA_Environment *oe_env is a pointer to the current + client environment. It contains the current file descriptor, + the current input and output buffers, etc. For details see + CORBA_Environment C Structure.

+
+
+
+ +
+ Generating, Compiling and Linking +

To generate the C client stubs type the following in an + appropriate shell:

+

,

+

where ICROOT is the root of the IC application. The + -I ICROOT/include is only needed if File.idl + refers to erlang.idl.

+

When compiling a generated C stub file, the directories + ICROOT/include and EICROOT/include, have to be + specified as include directories, where EIROOT is the + root directory of the Erl_interface application.

+

When linking object files the EIROOT/lib and + ICROOT/priv/lib directories have to be specified.

+
+ +
+ An Example +

In this example the IDL specification file "random.idl" is used + for generating C client stubs (the file is contained in the IC + /examples/c-client directory):

+ +

Generate the C client stubs:

+ + + +

Six files are generated.

+

Compile the C client stubs:

+

Please read the ReadMe file att the + examples/c-client directory

+

In the same + directory you can find all the code for this example.

+

In particular you will find the client.c file that contains + all the additional code that must be written to obtain a complete + client.

+

In the examples/c-client directory you will also find + source code for an Erlang server, which can be used for testing + the C client.

+
+
+ + diff --git a/lib/ic/doc/src/ch_c_corba_env.xml b/lib/ic/doc/src/ch_c_corba_env.xml new file mode 100644 index 0000000..557eeff --- /dev/null +++ b/lib/ic/doc/src/ch_c_corba_env.xml @@ -0,0 +1,385 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CORBA_Environment C Structure + + + 2003-12-15 + PC1 + ch_c_corba_env.xml +
+ +

This chapter describes the CORBA_Environment C structure.

+ +
+ C Structure +

Here is the complete definition of the CORBA_Environment + C structure, defined in file "ic.h" :

+ +/* Environment definition */ +typedef struct { + + /*----- CORBA compatibility part ------------------------*/ + /* Exception tag, initially set to CORBA_NO_EXCEPTION ---*/ + CORBA_exception_type _major; + + /*----- External Implementation part - initiated by the user ---*/ + /* File descriptor */ + int _fd; + /* Size of input buffer */ + int _inbufsz; + /* Pointer to always dynamically allocated buffer for input */ + char *_inbuf; + /* Size of output buffer */ + int _outbufsz; + /* Pointer to always dynamically allocated buffer for output */ + char *_outbuf; + /* Size of memory chunks in bytes, used for increasing the output + buffer, set to >= 32, should be around >= 1024 for performance + reasons */ + int _memchunk; + /* Pointer for registered name */ + char _regname[256]; + /* Process identity for caller */ + erlang_pid *_to_pid; + /* Process identity for callee */ + erlang_pid *_from_pid; + + /*- Internal Implementation part - used by the server/client ---*/ + /* Index for input buffer */ + int _iin; + /* Index for output buffer */ + int _iout; + /* Pointer for operation name */ + char _operation[256]; + /* Used to count parameters */ + int _received; + /* Used to identify the caller */ + erlang_pid _caller; + /* Used to identify the call */ + erlang_ref _unique; + /* Exception id field */ + CORBA_char *_exc_id; + /* Exception value field */ + void *_exc_value; + + +} CORBA_Environment; + +

The structure is divided into three parts:

+ + +

The CORBA Compatibility part, demanded by the standard OMG + IDL mapping v2.0.

+
+ +

The external implementation part used for generated + client/server code.

+
+ +

The internal part useful for those who wish to define their + own functions.

+
+
+
+ +
+ The CORBA Compatibility Part +

Contains only one field _major defined as a + CORBA_Exception_type. The CORBA_Exception type is an integer + which can be one of:

+ + +

CORBA_NO_EXCEPTION, by default equal to 0, can be + set by the application programmer to another value.

+
+ +

CORBA_SYSTEM_EXCEPTION, by default equal to -1, can + be set by the application programmer to another value.

+
+
+

The current definition of these values are:

+ + #define CORBA_NO_EXCEPTION 0 + #define CORBA_SYSTEM_EXCEPTION -1 + +
+ +
+ The External Part +

This part contains the following fields:

+ + +

int _fd - a file descriptor returned from + erl_connect. Used for connection setting.

+
+ +

char* _inbuf - pointer to a buffer used for + input. Buffer size checks are done under runtime that + prevent buffer overflows. This is done by expanding the + buffer to fit the input message. In order to allow buffer + reallocation, the output buffer must always be dynamically + allocated. The pointer value can change under runtime in + case of buffer reallocation.

+
+ +

int _inbufsz - start size of input buffer. Used + for setting the input buffer size under initialization of + the Erl_Interface function ei_receive_encoded/5. The value + of this field can change under runtime in case of input + buffer expansion to fit larger messages

+
+ +

int _outbufsz - start size of output buffer. The + value of this field can change under runtime in case of + input buffer expansion to fit larger messages

+
+ +

char* _outbuf - pointer to a buffer used for + output. Buffer size checks prevent buffer overflows under + runtime, by expanding the buffer to fit the output message + in cases of lack of space in buffer. In order to allow + buffer reallocation, the output buffer must always be + dynamically allocated. The pointer value can change under + runtime in case of buffer reallocation.

+
+ +

int _memchunk - expansion unit size for the output + buffer. This is the size of memory chunks in bytes used for + increasing the output in case of buffer expansion. The value + of this field must be always set to >= 32, should be at + least 1024 for performance reasons.

+
+ +

char regname[256] - a registered name for a process.

+
+ +

erlang_pid* _to_pid - an Erlang process identifier, + is only used if the registered_name parameter is the empty + string.

+
+ +

erlang_pid* _from_pid - your own process id so the + answer can be returned.

+
+
+
+ +
+ The Internal Part +

This part contains the following fields:

+ + +

int _iin - Index for input buffer. Initially set + to zero. Updated to agree with the length of the received + encoded message.

+
+ +

int _iout - Index for output buffer Initially set + to zero. Updated to agree with the length of the message + encoded to the communication counterpart.

+
+ +

char _operation[256] - Pointer for operation name. + Set to the operation to be called.

+
+ +

int _received - Used to count parameters. + Initially set to zero.

+
+ +

erlang_pid _caller - Used to identify the caller. + Initiated to a value that identifies the caller.

+
+ +

erlang_ref _unique - Used to identify the call. + Set to a default value in the case of generated functions.

+
+ +

CORBA_char* _exc_id - Exception id field. + Initially set to NULL to agree with the initial value of + _major (CORBA_NO_EXCEPTION).

+
+ +

void* _exc_value - Exception value field Initially + set to NULL to agree with the initial value of + _major (CORBA_NO_EXCEPTION).

+
+
+

The advanced user who defines his own functions has to + update/support these values in a way similar to how they are + updated in the generated code.

+
+ +
+ Creating and Initiating the CORBA_Environment Structure +

There are two ways to set the CORBA_Environment structure:

+ + +

Manually

+

The following default values must be set to the + CORBA_Environment *ev fields, when buffers for + input/output should have the size inbufsz/ + outbufsz:

+ + +

ev->_inbufsz = inbufsz;

+

The value for this field can be between 0 and maximum + size of a signed integer.

+
+ +

ev->_inbuf = malloc(inbufsz);

+

The size of the allocated buffer must be equal to the + value of its corresponding index, _inbufsz.

+
+ +

ev->_outbufsz = outbufsz;

+

The value for this field can be between 0 and maximum + size of a signed integer.

+
+ +

ev->_outbuf = malloc(outbufsz);

+

The size of the allocated buffer must be equal to the + value of its corresponding index, _outbufsz.

+
+ +

ev->_memchunk = __OE_MEMCHUNK__;

+

Please note that __OE_MEMCHUNK__ is equal to + 1024, you can set this value to a value bigger + than 32 yourself.

+
+ +

ev->_to_pid = NULL;

+
+ +

ev->_from_pid = NULL;

+
+
+

+
+ +

By using the CORBA_Environment_alloc/2 function.

+

The CORBA_Environment_alloc function is defined as:

+ +\\011 CORBA_Environment *CORBA_Environment_alloc(int inbufsz, + int outbufsz); + +

where:

+ + +

inbufsz is the desired size of input buffer

+
+ +

outbufsz is the desired size of output + buffer

+
+ +

return value is a pointer to an allocated and + initialized CORBA_Environment structure.

+

+
+
+

This function will set all needed default values and + allocate buffers equal to the values passed, but will not + allocate space for the _to_pid and _from_pid fields.

+

To free the space allocated by CORBA_Environment_alloc/2:

+ + +

First call CORBA_free for the input and output buffers.

+
+ +

After freeing the buffer space, call CORBA_free for + the CORBA_Environment space.

+
+
+
+
+ +

Remember to set the fields _fd, _regname, + *_to_pid and/or *_from_pid to the + appropriate application values. These are not automatically + set by the stubs.

+
+ +

Never assign static buffers to the buffer pointers. Never set + the _memchunk field to a value less than + 32.

+
+
+ +
+ Setting System Exceptions +

If the user wishes to set own system exceptions at critical + positions on the code, it is strongly recommended to use one of + the current values:

+ + +

CORBA_NO_EXCEPTION upon success. The value of the _exc_id + field should be then set to NULL. The value of the + _exc_value field should be then set to NULL.

+
+ +

CORBA_SYSTEM_EXCEPTION upon system failure. The value of + the _exc_id field should be then set to one of the values + defined in "ic.h" :

+ + #define UNKNOWN "UNKNOWN" + #define BAD_PARAM "BAD_PARAM" + #define NO_MEMORY "NO_MEMORY" + #define IMPL_LIMIT "IMP_LIMIT" + #define COMM_FAILURE "COMM_FAILURE" + #define INV_OBJREF "INV_OBJREF" + #define NO_PERMISSION "NO_PERMISSION" + #define INTERNAL "INTERNAL" + #define MARSHAL "MARSHAL" + #define INITIALIZE "INITIALIZE" + #define NO_IMPLEMENT "NO_IMPLEMENT" + #define BAD_TYPECODE "BAD_TYPECODE" + #define BAD_OPERATION "BAD_OPERATION" + #define NO_RESOURCES "NO_RESOURCES" + #define NO_RESPONSE "NO_RESPONSE" + #define PERSIST_STORE "PERSIST_STORE" + #define BAD_INV_ORDER "BAD_INV_ORDER" + #define TRANSIENT "TRANSIENT" + #define FREE_MEM "FREE_MEM" + #define INV_IDENT "INV_IDENT" + #define INV_FLAG "INV_FLAG" + #define INTF_REPOS "INTF_REPOS" + #define BAD_CONTEXT "BAD_CONTEXT" + #define OBJ_ADAPTER "OBJ_ADAPTER" + #define DATA_CONVERSION "DATA_CONVERSION" + #define OBJ_NOT_EXIST "OBJECT_NOT_EXIST" + +
+
+

The value of the _exc_value field should be then set to a string + that explains the problem in an informative way. The user + should use the functions CORBA_exc_set/4 and + CORBA_exception_free/1 to free the exception. + The user has to use CORBA_exception_id/1 and + CORBA_exception_value/1 to access exception information. + Prototypes for these functions are declared in "ic.h"

+
+
+ + diff --git a/lib/ic/doc/src/ch_c_mapping.xml b/lib/ic/doc/src/ch_c_mapping.xml new file mode 100644 index 0000000..58b026e --- /dev/null +++ b/lib/ic/doc/src/ch_c_mapping.xml @@ -0,0 +1,892 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + IDL to C mapping + + + 2002-08-06 + PB1 + ch_c_mapping.xml +
+ +
+ Introduction +

The IC C mapping (used by the C client and C server back-ends) follows + the OMG C Language Mapping Specification.

+

The C mapping supports the following:

+ + +

All OMG IDL basic types except long double and any.

+
+ +

All OMG IDL constructed types.

+
+ +

OMG IDL constants.

+
+ +

Operations with passing of parameters and receiving of + results. inout parameters are not supported.

+
+
+

The following is not supported: +

+ + +

Access to attributes.

+
+ +

User defined exceptions.

+

+
+ +

User defined objects.

+

+
+
+
+ +
+ C Mapping Characteristics + +
+ Reserved Names +

The IDL compiler reserves all identifiers starting with + OE_ and oe_ for internal use.

+
+ +
+ Scoped Names +

The C programmer must always use the global name for a type, + constant or operation. The C global name corresponding to an + OMG IDL global name is derived by converting occurrences of + "::" to underscore, and eliminating the leading "::". So, for + example, an operation op1 defined in interface + I1 which is defined in module M1 would be + written as M1::I1::op1 in IDL and as M1_I1_op1 + in C.

+ +

If underscores are used in IDL names it can lead to + ambiguities due to the name mapping described above, + therefore it is advisable to avoid underscores in + identifiers.

+
+
+ +
+ Generated Files +

Two files will be generated for each scope. One set of files + will be generated for each module and each interface scope. + An extra set is generated for those definitions at top + level scope. One of the files is a header file(.h), and the + other file is a C source code file (.c). In addition to these + files a number of C source files will be generated for type encodings, + they are named according to the following template: + .c]]>.

+

For example:

+ lseq; + + interface i1 { + ... + }; + ... +}; + ]]> +

XXX This is C client specific. + Will produce the files oe_spec.h and + oe_spec.c for the top scope level. Then the files + m1.h and m1.c for the module m1 and + files m1_i1.h and m1_i1.c for the interface + i1. The typedef will produce oe_code_m1_lseq.c.

+

The header file contains type definitions for all + struct types and sequences and constants in the IDL file. The + c file contains all operation stubs if the the scope is an interface.

+

In addition to the scope-related files a C source file will + be generated for encoding operations of all struct and + sequence types.

+
+
+ +
+ Basic OMG IDL Types +

The mapping of basic types is as follows.

+ + + OMG IDL type + C type + Mapped to C type + + + float + CORBA_float + float + + + double + CORBA_double + double + + + short + CORBA_short + short + + + unsigned short + CORBA_unsigned_short + unsigned short + + + long + CORBA_long + long + + + long long + CORBA_long_long + long + + + unsigned long + CORBA_unsigned_long + unsigned long + + + unsigned long long + CORBA_unsigned_long_long + unsigned long + + + char + CORBA_char + char + + + wchar + CORBA_wchar + unsigned long + + + boolean + CORBA_boolean + unsigned char + + + octet + CORBA_octet + char + + + any + Not supported + + + + long double + Not supported + + + + Object + Not supported + + + + void + void + void + + OMG IDL Basic Types +
+

XXX Note that several mappings are not according to OMG C Language + mapping.

+
+ +
+ Constructed OMG IDL Types +

Constructed types have mappings as shown in the following table.

+ + + OMG IDL type + Mapped to C type + + + string + CORBA_char* + + + wstring + CORBA_wchar* + + + struct + struct + + + union + union + + + enum + enum + + + sequence + struct (see below) + + + array + array + + OMG IDL Constructed Types +
+

An OMG IDL sequence (an array of variable length),

+ NAME; + ]]> +

is mapped to a C struct as follows:

+ +/* C */ +typedef struct { + CORBA_unsigned_long _maximum; + CORBA_unsigned_long _length; + C_TYPE* _buffer; +} C_NAME; + +

where C_TYPE is the mapping of IDL_TYPE, and where + C_NAME is the scoped name of NAME.

+
+ +
+ OMG IDL Constants +

An IDL constant is mapped to a C constant through a C + #define macro, where the name of the macro is scoped. + Example:

+ +// IDL +module M1 { + const long c1 = 99; +}; + +

results in the following:

+ +/* C */ +#define M1_c1 99 + +
+ +
+ OMG IDL Operations +

An OMG IDL operation is mapped to C function. Each C operation + function has two mandatory parameters: a first parameter of + interface object type, and a last parameter of + environment type.

+

+

In a C operation function the the in and out + parameters are located between the first and last parameters + described above, and they appear in the same order as in the IDL + operation declaration.

+

Notice that inout parameters are not supported.

+

+

The return value of an OMG IDL operation is mapped to a + corresponding return value of the C operation function.

+

Mandatory C operation function parameters:

+ + CORBA_Object oe_obj - the first parameter of a C + operation function. This parameter is required by the OMG C Language Mapping Specification, but in the current + implementation there is no particular use for it. + +

CORBA_Environment* oe_env - the last parameter of a C + operation function. The parameter is defined in the C header + file ic.h and has the following public fields:

+ + +

CORBA_Exception_type _major - indicates if an + operation invocation was successful which will be one of + the following:

+ + CORBA_NO_EXCEPTION + CORBA_SYSTEM_EXCEPTION + +
+ int _fd - a file descriptor returned from + erl_connect function. + int _inbufsz - size of input buffer. + char* _inbuf - pointer to a buffer used for + input. + int _outbufsz - size of output buffer. + char* _outbuf - pointer to a buffer used for + output. + +

int _memchunk - expansion unit size for the + output buffer. This is the size of memory chunks in + bytes used for increasing the output in case of buffer + expansion. The value of this field must be always set + to >= 32, should be at least 1024 for performance + reasons.

+
+ char regname[256] - a registered name for a + process. + erlang_pid* _to_pid - an Erlang process + identifier, is only used if the registered_name parameter + is the empty string. + erlang_pid* _from_pid - your own process id so + the answer can be returned +
+

Beside the public fields, other private fields + are internally used but are not mentioned here.

+
+
+

Example:

+ +// IDL +interface i1 { + long op1(in long a); + long op2(in string s, out long count); +}; + +

Is mapped to the following C functions

+ +/* C */ +CORBA_long i1_op1(i1 oe_obj, CORBA_long a, CORBA_Environment* oe_env) +{ + ... +} +CORBA_long i1_op2(i1 oe_obj, CORBA_char* s, CORBA_long *count, +CORBA_Environment* oe_env) +{ + ... +} + + + +
+ Operation Implementation +

There is no standard CORBA mapping for the C-server side, + as it is implementation-dependent but built in a similar way. + The current server side mapping is different from the client + side mapping in several ways:

+ + Argument mappings + Result values + Structure + Usage + Exception handling + +
+
+ +
+ Exceptions +

Although exception mapping is not implemented, the stubs will + generate CORBA system exceptions in case of operation failure. + Thus, the only exceptions propagated by the system are built in + system exceptions.

+
+ +
+ Access to Attributes +

Not Supported

+
+ +
+ Summary of Argument/Result Passing for the C-client +

The user-defined parameters can only be in or out + parameters, as + inout parameters are not supported.

+

This table summarize the types a client passes as arguments to + a stub, and receives as a result.

+ + + OMG IDL type + In + Out + Return + + + short + CORBA_short + CORBA_short* + CORBA_short + + + long + CORBA_long + CORBA_long* + CORBA_long + + + long long + CORBA_long_long + CORBA_long_long* + CORBA_long_long + + + unsigned short + CORBA_unsigned_short + CORBA_unsigned_short* + CORBA_unsigned_short + + + unsigned long + CORBA_unsigned_long + CORBA_unsigned_long* + CORBA_unsigned_long + + + unsigned long long + CORBA_unsigned_long_long + CORBA_unsigned_long_long* + CORBA_unsigned_long_long + + + float + CORBA_float + CORBA_float* + CORBA_float + + + double + CORBA_double + CORBA_double* + CORBA_double + + + boolean + CORBA_boolean + CORBA_boolean* + CORBA_boolean + + + char + CORBA_char + CORBA_char* + CORBA_char + + + wchar + CORBA_wchar + CORBA_wchar* + CORBA_wchar + + + octet + CORBA_octet + CORBA_octet* + CORBA_octet + + + enum + CORBA_enum + CORBA_enum* + CORBA_enum + + + struct, fixed + struct* + struct* + struct + + + struct, variable + struct* + struct** + struct* + + + union, fixed + union* + union* + union + + + union, variable + union* + union** + union* + + + string + CORBA_char* + CORBA_char** + CORBA_char* + + + wstring + CORBA_wchar* + CORBA_wchar** + CORBA_wchar* + + + sequence + sequence* + sequence** + sequence* + + + array, fixed + array + array + array_slice* + + + array, variable + array + array_slice** + array_slice* + + Basic Argument and Result passing +
+

A client is responsible for providing storage of all arguments passed + as in arguments.

+ + + OMG IDL type + Out + Return + + + short + 1 + 1 + + + long + 1 + 1 + + + long long + 1 + 1 + + + unsigned short + 1 + 1 + + + unsigned long + 1 + 1 + + + unsigned long long + 1 + 1 + + + float + 1 + 1 + + + double + 1 + 1 + + + boolean + 1 + 1 + + + char + 1 + 1 + + + wchar + 1 + 1 + + + octet + 1 + 1 + + + enum + 1 + 1 + + + struct, fixed + 1 + 1 + + + struct, variable + 2 + 2 + + + string + 2 + 2 + + + wstring + 2 + 2 + + + sequence + 2 + 2 + + + array, fixed + 1 + 3 + + + array, variable + 3 + 3 + + Client argument storage responsibility +
+ + + Case + Description + + + 1 + Caller allocates all necessary storage, except that which may be encapsulated and managed within the parameter itself. + + + 2 + The caller allocates a pointer and passes it by reference to the callee. The callee sets the pointer to point to a valid instance of the parameter's type. The caller is responsible for releasing the returned storage. Following completion of a request, the caller is not allowed to modify any values in the returned storage. To do so the caller must first copy the returned instance into a new instance, then modify the new instance. + + + 3 + The caller allocates a pointer to an array slice which has all the same dimensions of the original array except the first, and passes it by reference to the callee. The callee sets the pointer to point to a valid instance of the array. The caller is responsible for releasing the returned storage. Following completion of a request, the caller is not allowed to modify any values in the returned storage. To do so the caller must first copy the returned instance into a new instance, then modify the new instance. + + Argument passing cases +
+

The returned storage in case 2 and 3 is allocated as one block of memory + so it is possible to deallocate it with one call of CORBA_free.

+
+ +
+ Supported Memory Allocation Functions + + +

CORBA_Environment can be allocated from the user by calling + CORBA_Environment_alloc().

+

The interface for this function is

+

CORBA_Environment *CORBA_Environment_alloc(int inbufsz, int outbufsz);

+

where :

+ + +

inbufsz is the desired size of input buffer

+
+ +

outbufsz is the desired size of output buffer

+
+ +

return value is a pointer to an allocated and initialized + CORBA_Environment structure

+

+
+
+
+ +

Strings can be allocated from the user by calling CORBA_string_alloc().

+

The interface for this function is

+

CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len);

+

where :

+ + +

len is the length of the string to be allocated.

+
+
+
+
+

Thus far, no other type allocation function is supported.

+
+ +
+ Special Memory Deallocation Functions + + +

void CORBA_free(void *storage)

+

This function will free storage allocated by the stub.

+
+ +

void CORBA_exception_free(CORBA_environment *ev)

+

This function will free storage allocated under exception propagation.

+
+
+
+ +
+ Exception Access Functions + + +

CORBA_char *CORBA_exception_id(CORBA_Environment *ev)

+

This function will return raised exception identity.

+
+ +

void *CORBA_exception_value(CORBA_Environment *ev)

+

This function will return the value of a raised exception.

+
+
+
+ +
+ Special Types + + +

The erlang binary type has some special features.

+

+

While the erlang::binary idl type has the same C-definition as + a generated sequence of octets :

+ binary; +\011 +\011 }; + ]]> +

it provides a way on sending trasparent data between C and Erlang.

+

The C-definition (ic.h) for an erlang binary is :

+ +\011 typedef struct { +\011 CORBA_unsigned_long _maximum; +\011 CORBA_unsigned_long _length; +\011 CORBA_octet* _buffer; +\011 } erlang_binary; /* ERLANG BINARY */ + +

The differences (between erlang::binary and ]]>) are :

+ + +

on the erlang side the user is sending/receiving typical + built in erlang binaries, using term_to_binary() / binary_to_term() + to create / extract binary structures.

+
+ +

no encoding/decoding functions are generated

+
+ +

the underlying protocol is more efficient than usual sequences of + octets

+
+
+

The erlang binary IDL type is defined in erlang.idl, while it's + C definition is located in the ic.h header file, both in the + /include]]> directory. + The user will have to include the file erlang.idl in order to use the + erlang::binary type.

+
+
+
+ +
+ A Mapping Example +

+ + This is a small example of a simple stack. There are two + operations on the stack, push and pop. The example shows all + generated files as well as conceptual usage of the stack.

+ +// The source IDL file: stack.idl + +struct s { + long l; + string s; +}; + +interface stack { + void push(in s val); + s pop(); +}; + +

When this file is compiled it produces four files, two for the + top scope and two for the stack interface scope. The important parts + of the generated C code for the stack API is shown below. +

+

stack.c

+ + +void push(stack oe_obj, s val, CORBA_Environment* oe_env) { + ... +} + + +s* pop(stack oe_obj, CORBA_Environment* oe_env) { + ... +} + +

oe_stack.h

+ +#ifndef OE_STACK_H +#define OE_STACK_H + + +/*------------------------------------------------------------ + * Struct definition: s + */ +typedef struct { + long l; + char *s; +} s; + + + +#endif + +

stack.h just contains an include statement of oe_stack.h.

+

oe_code_s.c

+ + +int oe_sizecalc_s(CORBA_Environment + *oe_env, int* oe_size_count_index, int* oe_size) { + ... +} + +int oe_encode_s(CORBA_Environment *oe_env, s* oe_rec) { + ... +} + +int oe_decode_s(CORBA_Environment *oe_env, char *oe_first, + int* oe_outindex, s *oe_out) { + ... +} + +

The only files that are really important are the .h + files and the stack.c file.

+
+
+ diff --git a/lib/ic/doc/src/ch_c_server.xml b/lib/ic/doc/src/ch_c_server.xml new file mode 100644 index 0000000..c66ae85 --- /dev/null +++ b/lib/ic/doc/src/ch_c_server.xml @@ -0,0 +1,148 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The C Server Back-end + + + 2004-01-14 + C + ch_c_server.xml +
+ +
+ Introduction +

With the option {be, c_server} the IDL Compiler generates + C server skeletons according to the IDL to C mapping, on top of + the Erlang distribution and gen_server protocols.

+

The developer has to write additional code, that together with + the generated C server skeletons, form a hidden Erlang + node. That additional code contains implementations of call-back + functions that implement the true server functionality, and also + code uses erl_interface functions for defining the hidden + node and for establishing connections to other Erlang nodes.

+
+ +
+ Generated Stub Files +

The generated stub files are:

+ + +

For each IDL interface, a C source file, the name of which + is __s.c]]>. Each operation of the + IDL interface is mapped to a C function (with scoped name) + in that file;

+
+ +

C source files that contain functions for type conversion, + memory allocation, and data encoding/decoding;

+
+ +

C header files that contain function prototypes and type + definitions.

+
+
+

All C functions are exported (i.e. not declared static).

+
+ +
+ C Skeleton Functions +

For each IDL operation a C skeleton function is generated, the + prototype of which is __exec( oe_obj, CORBA_Environment *oe_env)]]>, where ]]>, and + CORBA_Environment are of the same type as for the + generated C client stubs code.

+

Each __exec()]]> function calls the + call-back function

+

_rs* __cb( oe_obj, , CORBA_Environment *oe_env)]]>

+

where the arguments are of the same type as those generated for + C client stubs.

+

The return value _rs* ]]> is a pointer + to a function with the same signature as the call-back function + _cb]]>, and is called after the call-back + function has been evaluated (provided that the pointer is not equal + to NULL).

+
+ +
+ The Server Loop +

The developer has to implement code for establishing connections + with other Erlang nodes, code for call-back functions and restore + functions.

+

+

In addition, the developer also has to implement code for a + server loop, that receives messages and calls the relevant + __exec function. For that purpose the IC library function + oe_server_receive() function can be used.

+
+ +
+ Generating, Compiling and Linking +

To generate the C server skeletons type the following in an + appropriate shell:

+

erlc -I ICROOT/include "+{be, c_server}" File.idl,

+

where ICROOT is the root of the IC application. The + -I ICROOT/include is only needed if File.idl + refers to erlang.idl.

+

When compiling a generated C skeleton file, the directories + ICROOT/include and EICROOT/include, have to be + specified as include directories, where EIROOT is the + root directory of the Erl_interface application.

+

When linking object files the EIROOT/lib and + ICROOT/priv/lib directories have to be specified.

+
+ +
+ An Example +

In this example the IDL specification file "random.idl" is used + for generating C server skeletons (the file is contained in the IC + /examples/c-server directory):

+ +module rmod { + + interface random { + + double produce(); + + oneway void init(in long seed1, in long seed2, in long seed3); + + }; + +}; +

Generate the C server skeletons:

+ +erlc '+{be, c_server}' random.idl +Erlang IDL compiler version X.Y.Z +

Six files are generated.

+

Compile the C server skeletons:

+

Please read the ReadMe file in the + examples/c-server directory.

+

In the same directory you can find all the code for this + example. In particular you will find the server.c file + that contains all the additional code that must be written to + obtain a complete server.

+

In the examples/c-server directory you will also find + source code for an Erlang client, which can be used for testing + the C server.

+
+
+ + diff --git a/lib/ic/doc/src/ch_erl_genserv.xml b/lib/ic/doc/src/ch_erl_genserv.xml new file mode 100644 index 0000000..972eff7 --- /dev/null +++ b/lib/ic/doc/src/ch_erl_genserv.xml @@ -0,0 +1,205 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Using the Erlang Generic Server Back-end + + + 98-08-06 + B + ch_erl_genserver.xml +
+ +
+ Introduction +

The mapping of OMG IDL to the Erlang programming language when Erlang + generic server is the back-end of choice is similar to the one used in + the chapter 'OMG IDL Mapping'. + The only difference is in the generated code, a client stub and + server skeleton to an Erlang gen_server. Orber's User's Guide + contain a more detailed description of IDL to Erlang mapping.

+
+ +
+ Compiling the Code +

The ic:gen/2 function can be called from the command + line as follows:

+

+ +shell> erlc "+{be, erl_genserv}" MyFile.idl + +
+ +
+ Writing the Implementation File +

For each IDL interface ]]> defined in the IDL file :

+ + Create the corresponding Erlang file that will hold the + Erlang implementation of the IDL definitions. + Call the implementation file after the scope of the IDL interface, + followed by the suffix _impl. + Export the implementation functions. + +

For each function defined in the IDL interface :

+ + Implement an Erlang function that uses as arguments in the same + order, as the input arguments described in the IDL file, and returns + the value described in the interface. + When using the function, follow the mapping described in chapter 2. + +
+ +
+ An Example +

In this example, a file random.idl generates code for the Erlang + gen_server back-end:

+ +// Filename random.idl +module rmod { + + interface random { + // Generate a new random number + double produce(); + // Initialize random generator + oneway void init(in long seed1, in long seed2, in long seed3); + + }; +}; + +

When the file "random.idl" is compiled (e.g., shell> erlc "+{be, erl_genserv}" random.idl) + five files are produced; two for the top scope, two for the interface scope, + and one for the module scope. The header files for top scope and interface + are empty and not shown here. In this case, the stub/skeleton file + rmod_random.erl is the most important. This module exports two kinds of + operations:

+ + Administrative - used when, for example, creating and + terminating the server. + IDL dependent - operations defined in the IDL + specification. In this case, produce and init. + + +
+ Administrative Operations +

To create a new server instance, one of the following functions should + be used:

+ + oe_create/0/1/2 - create a new instance of the object. + Accepts Env and RegName, in that order, as parameters. + The former is passed uninterpreted to the initialization operation + of the call-back module, while the latter must be as the + gen_server parameter ServerName. If Env is + left out, an empty list will be passed. + oe_create_link/0/1/2 - similar to oe_create/0/1/2, + but create a linked server. + typeID/0 - returns the scooped id compliant with the + OMG standard. In this case the string + "IDL:rmod/random:1.0". + stop/1 - asynchronously terminate the server. The required + argument is the return value from any of the start functions. + +
+ +
+ IDL Dependent Operations +

Operations can either be synchronous or asynchronous + (i.e., oneway). These are, respectively, mapped to + gen_server:call/2/3 and gen_server:cast/2. + Consult the gen_server documentation for valid return values.

+

The IDL dependent operations in this example are listed below. + The first argument must be the whatever the create operation returned.

+ + init(ServerReference, Seed1, Seed2, Seed3) - initialize + the random number generator. + produce(ServerReference) - generate a new random number. + +
+

If the compile option timeout is used a timeout must be added + (e.g., produce(ServerReference, 5000)). For more information, see + the gen_server documentation.

+ +
+ Implementation Module +

The implementation module shall, unless the compile option + impl is used, be named rmod_random_impl.erl. + and could look like this:

+ +-module('rmod_random_impl'). +%% Mandatory gen_server operations +-export([init/1, terminate/2, code_change/3]). +%% Add if 'handle_info' compile option used +-export([handle_info/2]). +%% API defined in IDL specification +-export([produce/1,init/4]). + +%% Mandatory operations +init(Env) -> + {ok, []}. + +terminate(From, Reason) -> + ok. + +code_change(OldVsn, State, Extra) -> + {ok, State}. + +%% Optional +handle_info(Info, State) -> + {noreply, NewState}. + +%% IDL specification +produce(State) -> + case catch random:uniform() of +\\011{'EXIT',_} -> +\\011 {stop, normal, "random:uniform/0 - EXIT", State}; +\\011RUnif -> + {reply, RUnif, State} + end. + + +init(State, S1, S2, S3) -> + case catch random:seed(S1, S2, S3) of +\\011{'EXIT',_} -> +\\011 {stop, normal, State}; +\\011_ -> + {noreply, State} + end. + +

Compile the code and run the example:

+ make:all(). +Recompile: rmod_random +Recompile: oe_random +Recompile: rmod_random_impl +up_to_date +2> {ok,R} = rmod_random:oe_create(). +{ok,<0.30.0>} +3> rmod_random:init(R, 1, 2, 3). +ok +4> rmod_random:produce(R). +1.97963e-4 +5> + ]]> +
+
+
+ + diff --git a/lib/ic/doc/src/ch_erl_plain.xml b/lib/ic/doc/src/ch_erl_plain.xml new file mode 100644 index 0000000..36de46f --- /dev/null +++ b/lib/ic/doc/src/ch_erl_plain.xml @@ -0,0 +1,175 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Using the Plain Erlang Back-end + + + 98-05-06 + B + ch_erl_plain.xml +
+ +
+ Introduction +

The mapping of OMG IDL to the Erlang programming language when + Plain Erlang + is the back-end of choice is similar to the one used in pure Erlang IDL + mapping. The only difference is on the generated code and the extended + use of pragmas for code generation: IDL functions are translated + to Erlang + module function calls.

+
+ +
+ Compiling the Code +

In the Erlang shell type :

+

ic:gen(, [{be, erl_plain}])]]>.

+
+ +
+ Writing the Implementation File +

For each IDL interface ]]> defined in the IDL file:

+ + Create the corresponding Erlang file that will hold the + Erlang implementation of the IDL definitions. + Call the implementation file after the scope of the IDL interface, + followed by the suffix _impl. + Export the implementation functions. + +

For each function defined in the IDL interface :

+ + Implement an Erlang function that uses as arguments in the same + order, as the input arguments described in the IDL file, and returns + the value described in the interface. + When using the function, follow the mapping described in chapter 2. + +
+ +
+ An Example +

+ + In this example, a file "random.idl" is generates code for the plain Erlang + back-end :

+ + +

Main file : "plain.idl"

+ +\011 +module rmod { + + interface random { + + double produce(); + + oneway void init(in long seed1, in long seed2, in long seed3); + + }; + +}; + +
+
+

Compile the file :

+ + Erlang (BEAM) emulator version 4.9 + + Eshell V4.9 (abort with ^G) + 1> ic:gen(random,[{be, erl_plain}]). + Erlang IDL compiler version 2.5.1 + ok + 2> + +

+

When the file "random.idl" is compiled it produces five files: two for + the top scope, two for the interface scope, and one for the module + scope. The header files for top scope and interface + are empty and not shown here. In this case only the file for the interface + rmod_random.erl is important :. + +

+ + +

Erlang file for interface : "rmod_random.erl"

+ + +-module(rmod_random). + + + +%% Interface functions +-export([produce/0, init/3]). + +%%------------------------------------------------------------ +%% Operation: produce +%% +%% Returns: RetVal +%% +produce() -> + rmod_random_impl:produce(). + +%%------------------------------------------------------------ +%% Operation: init +%% +%% Returns: RetVal +%% +init(Seed1, Seed2, Seed3) -> + rmod_random_impl:init(Seed1, Seed2, Seed3). + +
+
+

The implementation file should be called rmod_random_impl.erl + and could look like this:

+ + -module('rmod_random_impl'). + + -export([produce/0,init/3]). + + + produce() -> + random:uniform(). + + + init(S1,S2,S3) -> + random:seed(S1,S2,S3). + +

Compiling the code :

+ +2> make:all(). +Recompile: rmod_random +Recompile: oe_random +Recompile: rmod_random_impl +up_to_date + +

+

Running the example :

+ +3> rmod_random:init(1,2,3). +ok +4> rmod_random:produce(). +1.97963e-4 +5> + +
+
+ diff --git a/lib/ic/doc/src/ch_ic_protocol.xml b/lib/ic/doc/src/ch_ic_protocol.xml new file mode 100644 index 0000000..678fdc7 --- /dev/null +++ b/lib/ic/doc/src/ch_ic_protocol.xml @@ -0,0 +1,233 @@ + + + + +
+ + 20032009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + IC Protocol + + + 2003-12-11 + PA1 + ch_ic_protocol.xml +
+

The purpose of this chapter is to explain the bits and bytes of the + IC protocol, which is a composition of the Erlang distribution protocol + and the Erlang/OTP gen_server protocol. If you do not intend to replace + the Erlang distribution protocol, or replace the gen_server protocol, + skip over this chapter. +

+ +
+ Introduction +

The IDL Compiler (IC) transforms Interface Definition Language + (IDL) specifications files to interface code for Erlang, C, and + Java. The Erlang language mapping is described in the Orber + documentation, while the other mappings are described in the IC + documentation (they are of course in accordance with the CORBA C + and Java language mapping specifications, with some restrictions). +

+

The most important parts of an IDL specification are the operation + declarations. An operation defines what information a client + provides to a server, and what information (if any) the client + gets back from the server. We consider IDL operations and language + mappings in section 2. +

+

What we here call the IC protocol, is the description of messages + exchanged between IC end-points (client and servers). It is valid + for all IC back-ends, except the 'erl_plain' and 'erl_corba' + back-ends. + The IC protocol is in turn embedded into the Erlang gen_server + protocol, which is described below. + Finally, the gen_server protocol is embedded in the Erlang + distribution protocol. Pertinent parts of that protocol is + described further below. +

+
+ +
+ Language mappings and IDL operations + +
+ IDL Operations +

An IDL operation is declared as follows:

+ +\011[oneway] RetType Op(in IType1 I1, in IType2 I2, ..., in ITypeN IN, +\011out OType1 O1, out OType2 O2, ..., out OTypeM OM) +\011N, M = 0, 1, 2, ...\011\011(2.1.1) + +

`Op' is the operation name, RetType is the return type, and ITypei, + i = 1, 2, ..., N, and OTypej, j = 1, 2, ..., M, are the `in' types + and `out' types, respectively. The values I1, I2, ..., IN are + provided by the caller, and the value of RetType, and the values + O1, O2, ..., OM, are provided as results to the caller. +

+

The types can be any basic types or derived types declared in the + IDL specification of which the operation declaration is a part. +

+

If the RetType has the special name `void' there is no return + value (but there might still be result values O1, 02, ..., OM). +

+

The `in' and `out' parameters can be declared in any order, but + for clarity we have listed all `in' parameters before the `out' + parameters in the declaration above. +

+

If the keyword `oneway' is present, the operation is a cast, i.e. + there is no confirmation of the operation, and consequently there + must be no result values: RetType must be equal to `void', and M = + 0 must hold. +

+

Otherwise the operation is a call, i.e. it is confirmed (or else + an exception is raised). +

+

Note carefully that an operation declared without `oneway' is + always a call, even if RetType is `void' and M = 0. +

+
+ +
+ Language Mappings +

There are several CORBA Language Mapping specifications. These are + about mapping interfaces to various programming languages. IC + supports the CORBA C and Java mapping specifications, and the + Erlang language mapping specified in the Orber documentation. +

+

Excerpt from "6.4 Basic OMG IDL Types" in the Orber User's Guide: +

+ + +

Functions with return type void will return the atom ok.

+
+
+

Excerpt from "6.13 Invocations of Operations" in the Orber User's + Guide: +

+ + +

A function call will invoke an operation. The first parameter + of the function should be the object reference and then all in + and inout parameters follow in the same order as specified in + the IDL specification. The result will be a return value + unless the function has inout or out parameters specified; in + which case, a tuple of the return value, followed by the + parameters will be returned.

+
+
+

Hence the function that is mapped from an IDL operation to Erlang + always have a return value (an Erlang function always has). That + fact has influenced the IC protocol, in that there is always a + return value (which is 'ok' if the return type was declared 'void').

+
+
+ +
+ IC Protocol +

Given the operation declaration (2.1.1) the IC protocol maps to + messages as follows, defined in terms of Erlang terms. +

+ +
+ Call (Request/Reply, i.e. not oneway) + + request:\011\011 Op\011\011\011atom()\011\011N = 0\011 +\011\011\011 {Op, I1, I2, ..., IN}\011tuple()\011\011N > 0 +\011\011\011\011\011\011\011\011(3.1.1) + + reply:\011\011 Ret\011\011\011\011\011M = 0 +\011\011\011 {Ret, O1, O2, ..., OM}\011\011\011M > 0 +\011\011\011\011\011\011\011\011(3.1.2) +

Notice: Even if the RetType of the operation Op is + declared to be 'void', a return value 'ok' is returned in + the reply message. That + return value is of no significance, and is therefore ignored (note + however that a C server back-end returns the atom 'void' instead + of 'ok'). +

+
+ +
+ Cast (oneway) + + + notification:\011Op\011\011\011atom()\011\011N = 0 +\011\011\011{Op, I1, I2, ..., IN}\011tuple()\011\011N > 0 +\011\011\011\011\011\011\011\011(3.2.1) +

(There is of course no return message). +

+
+
+ +
+ Gen_server Protocol +

Most of the IC generated code deals with encoding and decoding the + gen_server protocol. +

+ +
+ Call + + + request:\011{'$gen_call', {self(), Ref}, Request}\011\011(4.1.1) + + reply:\011{Ref, Reply}\011\011\011\011\011(4.1.2) +

where Request and Reply are the messages defined in the previous + chapter. +

+
+ +
+ Cast + + notification: {'$gen_cast', Notification}\011\011(4.2.1) +

where Notification is the message defined in the previous chapter. +

+
+
+ +
+ Erlang Distribution Protocol +

Messages (of interest here) between Erlang nodes are of the form:

+ + Len(4), Type(1), CtrlBin(N), MsgBin(M)\011\011\011(5.1) +

Type is equal to 112 = PASS_THROUGH. +

+

CtrlBin and MsgBin are Erlang terms in binary form (as if created + by term_to_binary/1), whence for each of them the first byte is + equal to 131 = VERSION_MAGIC. +

+

CtrlBin (of interest here) contains the SEND and REG_SEND control + messages, which are binary forms of the Erlang terms

+ +\011{2, Cookie, ToPid} ,\011\011\011\011\011(5.2) +

and

+ +\011{6, FromPid, Cookie, ToName} ,\011\011\011\011(5.3) +

respectively. +

+

The CtrlBin(N) message is read and written by erl_interface code + (C), j_interface code (Java), or the Erlang distribution + implementation, which are invoked from IC generated code. +

+

The MsgBin(N) is the "real" message, i.e. of the form described + in the previous section. +

+
+
+ diff --git a/lib/ic/doc/src/ch_introduction.xml b/lib/ic/doc/src/ch_introduction.xml new file mode 100644 index 0000000..898d2a7 --- /dev/null +++ b/lib/ic/doc/src/ch_introduction.xml @@ -0,0 +1,148 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Using the IC Compiler + + + 2002-08-02 + PB1 + ch_introduction.xml +
+ +
+ Introduction +

The IC application is an IDL compiler implemented in Erlang. + The IDL compiler generates client stubs and server skeletons. + Several back-ends are supported, and they fall into three main + groups.

+

The first group consists of a CORBA back-end:

+ + IDL to Erlang CORBA + +

This back-end is for CORBA communication and implementation, + and the generated code uses the CORBA specific protocol for + communication between clients and servers. See the + Orber application User's Guide and manuals for + further details.

+
+
+

The second group consists of a simple Erlang back-end:

+ + IDL to plain Erlang + +

This back-end provides a very simple Erlang client + interface. It can only be used within an Erlang node, + and the communication between client and "server" is + therefore in terms of ordinary function calls.

+

This back-end can be considered a short-circuit version of + the IDL to Erlang gen_server back-end (see further below).

+
+
+

The third group consists of backends for Erlang, C, and + Java. The communication between clients and servers is by the + Erlang distribution protocol, facilitated by + erl_interface and jinterface for C and Java, + respectively.

+

All back-ends of the third group generate code compatible with + the Erlang gen_server behavior protocol. Thus generated client + code corresponds to call() or cast() of an Erlang + gen_server. Similarly, generated server code corresponds + to handle_call() or handle_cast() of an Erlang + gen_server.

+

The back-ends of the third group are: +

+ + IDL to Erlang gen_server + +

Client stubs and server skeletons are generated. Data types + are mapped according to the IDL to Erlang mapping described + in the Orber User's Guide.

+

+
+ IDL to C client + +

Client stubs are generated. The mapping of data types is + described further on in the C client part of this guide.

+
+ IDL to C server + +

Server skeletons are generated. The mapping of data types is + described further on in the C server part of this guide.

+
+ IDL to Java + +

Client stubs and server skeletons are generated. The mapping + of data types is described further on in the Java part of + this guide.

+
+
+
+ +
+ Compilation of IDL Files +

The IC compiler is invoked by executing the generic erlc + compiler from a shell:

+ +%> erlc +'{be,BackEnd}' File.idl + +

where BackEnd is according to the table below, and + File.idl is the IDL file to be compiled.

+ + + Back-end + BackEndoption + + + IDL to CORBA + erl_corba + + + IDL to CORBA template + erl_template + + + IDL to plain Erlang + erl_plain + + + IDL to Erlang gen_server + erl_genserv + + + IDL to C client + c_client + + + IDL to C server + c_server + + + IDL to Java + java + + Compiler back-ends and options +
+

For more details on IC compiler options consult the ic(3) manual page.

+
+
+ diff --git a/lib/ic/doc/src/ch_java.xml b/lib/ic/doc/src/ch_java.xml new file mode 100644 index 0000000..831850f --- /dev/null +++ b/lib/ic/doc/src/ch_java.xml @@ -0,0 +1,737 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + IDL to Java language Mapping + + + 98-09-24 + A + ch_java.xml +
+ +
+ Introduction +

This chapter describes the mapping of OMG IDL constructs to the Java + programming language for the generation of native Java - Erlang + communication.

+

This language mapping defines the following:

+ + +

All OMG IDL basic types

+
+ +

All OMG IDL constructed types

+
+ +

References to constants defined in OMG IDL

+
+ +

Invocations of operations, including passing of + parameters and receiving of result

+
+ +

Access to attributes

+
+
+
+ +
+ Specialties in the Mapping + +
+ Names Reserved by the Compiler +

The IDL compiler reserves all identifiers starting with + OE_ and oe_ for internal use.

+
+
+ +
+ Basic OMG IDL Types +

The mapping of basic types are according to the standard. All basic types have + a special Holder class.

+ + + OMG IDL type + Java type + + + float + float + + + double + double + + + short + short + + + unsigned short + short + + + long + int + + + long long + long + + + unsigned long + long + + + unsigned long long + long + + + char + char + + + wchar + char + + + boolean + boolean + + + octet + octet + + + string + java.lang.String + + + wstring + java.lang.String + + + any + Any + + + long double + Not supported + + + Object + Not supported + + + void + void + + OMG IDL basic types +
+
+ +
+ Constructed OMG IDL Types +

All constructed types are according to the standard with three (3) major exceptions.

+

+ + +

The IDL Exceptions are not implemented in this Java mapping.

+

+
+ +

The functions used for read/write to streams, defined in Helper functions + are named unmarshal (instead for read) and marshal (instead for write).

+

+
+ +

The streams used in Helper functions are OtpInputStream for + input and OtpOutputStream for output.

+

+
+
+
+ +
+ Mapping for Constants +

Constants are mapped according to the standard.

+
+ +
+ Invocations of Operations +

Operation invocation is implemented according to the standard. + The implementation is in the class Stub.java]]> which implements + the interface in .java]]>.

+ +test._iStub client; + +client.op(10); + + +
+ Operation Implementation +

The server is implemented through extension of the class + ImplBase.java]]> and implementation of all the methods in the + interface.

+ +public class server extends test._iImplBase { + + public void op(int i) throws java.lang.Exception { + System.out.println("Received call op()"); + o.value = i; + return i; + } + +} + +
+
+ +
+ Exceptions +

While exception mapping is not implemented, the stubs will + generate some Java exceptions in case of operation failure. + No exceptions are propagated through the communication.

+
+ +
+ Access to Attributes +

Attributes are supported according to the standard.

+
+ +
+ Summary of Argument/Result Passing for Java +

All types (in, out or inout) of user defined parameters are supported + in the Java mapping. This is also the case in the Erlang mappings but not in the C + mapping. inout parameters are not supported in the C mapping so if you are going to + do calls to or from a C program inout cannot be used in the IDL specifications.

+

out and inout parameters must be of Holder types. There is a jar file ( ic.jar) + with Holder classes for the basic types in the ic application. This library is in the directory + /priv]]>.

+
+ +
+ Communication Toolbox +

The generated client and server stubs use the classes + defined in the jinterface package to communicate + with other nodes. + The most important classes are :

+ + +

OtpInputStream which is the stream class used for incoming message storage

+

+
+ +

OtpOutputStream which is the stream class used for outgoing message storage

+

+
+ +

OtpErlangPid which is the process identification class used to identify processes inside + a java node.

+

The recommended constructor function for the OtpErlangPid is + OtpErlangPid(String node, int id, int serial, int creation) where :

+

+ + +

String node, is the name of the node where this process runs.

+

+
+ +

int id, is the identification number for this identity.

+

+
+ +

int serial, internal information, must be an 18-bit integer.

+

+
+ +

int creation, internal information, must have value in range 0..3.

+

+
+
+
+ +

OtpConnection which is used to define a connection between nodes.

+

While the connection object is stub side constructed in client stubs, it is + returned after calling the accept function from an OtpErlangServer object + in server stubs. + The following methods used for node connection :

+

+ + +

OtpInputStream receiveBuf(), which returns the incoming streams that + contain the message arrived.

+

+
+ +

void sendBuf(OtpErlangPid client, OtpOutputStream reply), which sends + a reply message (in an OtpOutputStream form) to the client node.

+

+
+ +

void close(), which closes a connection.

+

+
+
+
+ +

OtpServer which is used to define a server node.

+

The recommended constructor function for the OtpServer is :

+

+ + +

OtpServer(String node, String cookie). where :

+

+ + +

node is the requested name for the new java node, + represented as a String object.

+

+
+ +

cookie is the requested cookie name for the new java node, + represented as a String object.

+

+
+
+
+
+

The following methods used for node registration and connection acceptance :

+

+ + +

boolean publishPort(), which registers the server node to epmd daemon.

+

+
+ +

OtpConnection accept(), which waits for a connection and returns the + OtpConnection object which is unique for each client node.

+

+
+
+
+
+
+ +
+ The Package com.ericsson.otp.ic +

The package com.ericsson.otp.ic + contains a number of java classes specially designed for the IC generated java-back-ends :

+ + +

Standard java classes defined through OMG-IDL java mapping :

+ + +

BooleanHolder

+
+ +

ByteHolder

+
+ +

CharHolder

+
+ +

ShortHolder

+
+ +

IntHolder

+
+ +

LongHolder

+
+ +

FloatHolder

+
+ +

DoubleHolder

+
+ +

StringHolder

+
+ +

Any, + AnyHelper, + AnyHolder

+
+ +

TypeCode

+
+ +

TCKind

+

+
+
+
+ +

Implementation-dependant classes :

+ + +

Environment

+
+ +

Holder

+

+
+
+
+ +

Erlang compatibility classes :

+ + +

Pid, + PidHelper, + PidHolder

+

The Pid class originates from OtpErlangPid and is used to + represent the Erlang built-in pid type, a process's identity. + PidHelper and PidHolder are helper respectively holder classes for Pid.

+

+
+ +

Ref, + RefHelper, + RefHolder

+

The Ref class originates from OtpErlangRef and is used to + represent the Erlang built-in ref type, an Erlang reference. + RefHelper and RefHolder are helper respectively holder classes for Ref.

+

+
+ +

Port, + PortHelper, + PortHolder

+

The Port class originates from OtpErlangPort and is used to + represent the Erlang built-in port type, an Erlang port. + PortHelper and PortHolder are helper respectively holder classes for Port.

+

+
+ +

Term, + TermHelper, + TermHolder

+

The Term class originates from Any and is used to + represent the Erlang built-in term type, an Erlang term. + TermHelper and TermHolder are helper respectively holder classes for Term.

+

+
+
+

To use the Erlang build-in classes, you will have to include the file erlang.idl + located under $OTPROOT/lib/ic/include.

+
+
+
+ +
+ The Term Class +

The Term class is intended to represent the Erlang term generic type. + It extends the Any class and it is basically used in the same way as + in the Any type.

+

The big difference between Term and Any is the use of guard methods + instead of TypeCode to determine the data included in the Term. + This is especially true when the Term's value class cannot be + determined at compilation time. The guard methods found in Term :

+ + +

boolean isAtom() returns true if the Term is an OtpErlangAtom, false otherwise

+

+
+ +

boolean isConstant() returns true if the Term is neither an OtpErlangList nor an OtpErlangTuple, false otherwise

+

+
+ +

boolean isFloat() returns true if the Term is an OtpErlangFloat, false otherwise

+

+
+ +

boolean isInteger() returns true if the Term is an OtpErlangInt, false otherwise

+

+
+ +

boolean isList() returns true if the Term is an OtpErlangList, false otherwise

+

+
+ +

boolean isString() returns true if the Term is an OtpErlangString, false otherwise

+

+
+ +

boolean isNumber() returns true if the Term is an OtpErlangInteger or an OtpErlangFloat, false otherwise

+

+
+ +

boolean isPid() returns true if the Term is an OtpErlangPid or Pid, false otherwise

+

+
+ +

boolean isPort() returns true if the Term is an OtpErlangPort or Port, false otherwise

+

+
+ +

boolean isReference() returns true if the Term is an OtpErlangRef, false otherwise

+

+
+ +

boolean isTuple() returns true if the Term is an OtpErlangTuple, false otherwise

+

+
+ +

boolean isBinary() returns true if the Term is an OtpErlangBinary, false otherwise

+

+
+
+
+ +
+ Stub File Types +

For each interface, three (3) stub/skeleton files are generated :

+ + +

A java interface file, named after the idl interface.

+

+
+ +

A client stub file, named after the convention Stub]]> + which implements the java interface. Example : _stackStub.java

+

+
+ +

A server stub file, named after the convention ImplBase]]> + which implements the java interface. Example : _stackImplBase.java

+

+
+
+
+ +
+ Client Stub Initialization, Methods Exported +

The recommended constructor function for client stubs accepts four (4) parameters :

+

+ + +

String selfNode, the node identification name to be used in the new + client node.

+

+
+ +

String peerNode, the node identification name where the client process is running.

+

+
+ +

String cookie, the cookie to be used.

+

+
+ +

Object server, where the java Object can be one of:

+

+ + +

OtpErlangPid, the server's process identity under the node where the server + process is running.

+

+
+ +

String, the server's registered name under the node where the server + process is running.

+

+
+
+
+
+

The methods exported from the generated client stub are :

+

+ + +

void __disconnect(), which disconnects the server connection.

+

+
+ +

void __reconnect(), which disconnects the server connection if open, + and then connects to the same peer.

+

+
+ +

void __stop(), which sends the standard stop termination call. + When connected to an Erlang server, the server will be terminated. + When connected to a java server, this will set a stop flag that + denotes that the server must be terminated.

+

+
+ +

com.ericsson.otp.erlang.OtpErlangRef __getRef(), will return the message reference + received from a server that denotes which call it is referring to. + This is useful when building asynchronous clients.

+

+
+ +

java.lang.Object __server(), which returns the server for the current connection.

+

+
+
+
+ +
+ Server Skeleton Initialization, Server Stub Implementation, Methods Exported +

The constructor function for server skeleton accepts no parameters.

+

The server skeleton file contains a server switch which + decodes messages from the input stream and calls implementation + (callback) functions. + As the server skeleton is declared abstract, the application + programmer will have to create a stub class that extends the + skeleton file. In this class, all operations defined in the interface + class, generated under compiling the idl file, are implemented.

+

The server skeleton file exports the following methods:

+

+ + +

OtpOutputStrem invoke(OtpInputStream request), where the input + stream request is unmarshalled, the implementation function is called + and a reply stream is marshalled.

+

+
+ +

boolean __isStopped(), which returns true if a stop message is received. + The implementation of the stub should always check if such a message is received + and terminate if so.

+

+
+ +

boolean __isStopped(com.ericsson.otp.ic.Environment), which returns true if + a stop message is received for a certain Environment and Connection. + The implementation of the stub should always check if such a message is received + and terminate if so.

+

+
+ +

OtpErlangPid __getCallerPid(), which returns the caller identity for the latest call.

+

+
+ +

OtpErlangPid __getCallerPid(com.ericsson.otp.ic.Environment), which returns the caller + identity for the latest call on a certain Environment.

+

+
+ +

java.util.Dictionary __operations(), which returns the operation dictionary which + holds all operations supported by the server skeleton.

+

+
+
+
+ +
+ A Mapping Example +

+ + This is a small example of a simple stack. There are two + operations on the stack, push and pop. The example shows some of the + generated files.

+ +// The source IDL file: stack.idl + +struct s { + long l; + string s; +}; + +interface stack { + void push(in s val); + s pop(); +}; + +

When this file is compiled it produces eight files. Three important files + are shown below. +

+

The public interface is in stack.java.

+ + +public interface stack { + +/**** + * Operation "stack::push" interface functions + * + */ + + void push(s val) throws java.lang.Exception; + +/**** + * Operation "stack::pop" interface functions + * + */ + + s pop() throws java.lang.Exception; + +} + +

For the IDL struct s three files are generated, a public class in s.java.

+ + +final public class s { + // instance variables + public int l; + public java.lang.String s; + + // constructors + public s() {}; + public s(int _l, java.lang.String _s) { + l = _l; + s = _s; + }; + +}; + +

A holder class in sHolder.java and a helper class in sHelper.java. + The helper class is used for marshalling.

+ + +public class sHelper { + + // constructors + private sHelper() {}; + + // methods + public static s unmarshal(OtpInputStream in) + throws java.lang.Exception { +\011: +\011: + }; + + public static void marshal(OtpOutputStream out, s value) + throws java.lang.Exception { +\011: +\011: + }; + +}; + +
+ +
+ Running the Compiled Code +

When using the generated java code you must have added + /priv]]> and + /priv]]> to your + CLASSPATH variable to get + basic Holder types and the communication classes.

+
+
+ diff --git a/lib/ic/doc/src/erl-part.xml b/lib/ic/doc/src/erl-part.xml new file mode 100644 index 0000000..b5041dc --- /dev/null +++ b/lib/ic/doc/src/erl-part.xml @@ -0,0 +1,38 @@ + + + + +
+ + 2002 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + IDL to Erlang language Mapping + + + 2002-06-25 + A +
+ +

Tjosan Erlang

+
+ + +
+ diff --git a/lib/ic/doc/src/fascicules.xml b/lib/ic/doc/src/fascicules.xml new file mode 100644 index 0000000..0678195 --- /dev/null +++ b/lib/ic/doc/src/fascicules.xml @@ -0,0 +1,18 @@ + + + + + + User's Guide + + + Reference Manual + + + Release Notes + + + Off-Print + + + diff --git a/lib/ic/doc/src/ic.gif b/lib/ic/doc/src/ic.gif new file mode 100644 index 0000000000000000000000000000000000000000..d78cf7d8ed4221716bdf833bf56d7435d1eb68b6 GIT binary patch literal 17015 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 + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + ic + + + + 2004-01-08 + B +
+ ic + The Erlang IDL Compiler + +

The ic module is an Erlang implementation of an OMG IDL + compiler. Depending on the choice of back-end the code will map + to Erlang, C, or Java. The compiler generates client stubs and + server skeletons.

+

Two kinds of files are generated for each scope: Ordinary code + files and header files. The latter are used for defining record + definitions, while the ordinary files contain the object + interface functions.

+
+ + + ic:gen(FileName) -> Result + ic:gen(FileName, [Option]) -> Result + Generate stub and server code according to the OMG CORBA standard. + + Result = ok | error | {ok, [Warning]} | {error, [Warning], [Error]} + + Option = [ GeneralOption | CodeOption | WarningOption | BackendOption] + + GeneralOption = + {outdir, String()} | {cfgfile, String()} | {use_preproc, bool()} | + {preproc_cmd, String()} | {preproc_flags, String()} + + CodeOption = + {gen_hrl, bool()} | {serv_last_call, exception | exit} | {{impl, String()}, String()} | {light_ifr, bool()} + this | {this, String()} | {{this, String()}, bool()} | + from | {from, String()} | {{from, String()}, bool()} | + handle_info | {handle_info, String()} | {{handle_info, String()}, bool()} | + timeout | {timeout, String()} | {{timeout, String()}, bool()} | + {scoped_op_calls, bool()} | {scl, bool()} | + {user_protocol, Prefix} | + {c_timeout, SendTimeout, RecvTimeout} | + {c_report, bool()} | + {precond, {atom(), atom()}} | {{precond, String()} {atom(), atom()}} | + {postcond, {atom(), atom()}} | {{postcond, String()} {atom(), atom()}} + + WarningOption = + {'Wall', bool()} | {maxerrs, int() | infinity} | + {maxwarns, int() | infinity} | {nowarn, bool()} | + {warn_name_shadow, bool()} | {pedantic, bool()} | + {silent, bool()} + + BackendOption = {be, Backend} + + Backend = erl_corba | erl_template | erl_plain | erl_genserv | c_client | c_server | java + + DirNAme = string() | atom() + FileName = string() | atom() + + +

The tuple {Option, true} can be replaced by + Option for boolean values.

+

The ic:gen/2 function can be called from the command + line as follows:

+

erlc "+Option" ... File.idl

+

Example:

+

erlc "+{be,c_client}" '+{outdir, "../out"}' File.idl

+
+
+
+ +
+ General options + + outdir + +

Places all output files in the directory given by the option. + The directory will be created if it does not already exist.

+

Example option: {outdir, "output/generated"}.

+
+ cfgfile + +

Uses FileName as configuration file. Options will + override compiler defaults but can be overridden by command line + options. Default value is ".ic_config".

+

Example option: {cfgfile, "special.cfg"}.

+
+ use_preproc + +

Uses a preprocessor. Default value is true.

+
+ preproc_cmd + +

Command string to invoke the preprocessor. The actual + command will be built as + preproc_cmd++preproc_flags++FileName

+

Example option: {preproc_cmd, "erl"}).

+

Example option: {preproc_cmd, "gcc -x c++ -E"}.

+
+ preproc_flags + +

Flags given to the preprocessor.

+

Example option: {preproc_flags, "-I../include"}.

+
+
+
+ +
+ Code options + + light_ifr + +

Currently, the default setting is false. To be able to + use this option Orber must be configured to use Light IFR (see + Orber's User's Guide). When this options is used, the size of the + generated files used to register the API in the IFR DB are minimized.

+

Example option: {light_ifr, true}.

+
+ gen_hrl + +

Generate header files. Default is true.

+
+ serv_last_call + +

Makes the last gen_server handle_call either raise a + CORBA exception or just exit plainly. Default is the exception. +

+
+ {{impl, IntfName}, ModName} + +

Assumes that the interface with name IntfName is + implemented by the module with name ModName and + will generate calls to the ModName module in the + server behavior. Note that the IntfName must be a + fully scoped name as in "M1::I1".

+

+
+ this + +

Adds the object reference as the first parameter to the + object implementation functions. This makes the + implementation aware of its own object reference. +

+The option + comes in three varieties: this which activates the + parameter for all interfaces in the source file, {this, IntfName} which activates the parameter for a specified + interface and {{this, IntfName}, false} which + deactivates the parameter for a specified + interface.

+

Example option: this) activates the parameter for + all interfaces.

+

Example option: {this, "M1::I1"} activates the + parameter for all functions of M1::I1.

+

Example options: [this, {{this, "M1::I2"}, false}] + activates the parameter for all interfaces except + M1::I2.

+
+ from + +

Adds the invokers reference as the first parameter to the + object implementation two-way functions. If both + from and this options are used the invokers + reference parameter will be passed as the second + parameter. This makes it possible for the implementation to + respond to a request and continue executing + afterwards. Consult the gen_server and Orber + documentation how this option may be used.

+The option + comes in three varieties: from which activates the + parameter for all interfaces in the source file, {from, IntfName} which activates the parameter for a specified + interface and {{from, IntfName}, false} which + deactivates the parameter for a specified interface.

+

Example option: from) activates the parameter for + all interfaces.

+

Example options: [{from, "M1::I1"}] activates the + parameter for all functions of M1::I1.

+

Example options: [from, {{from, "M1::I2"}, false}] + activates the parameter for all interfaces except + M1::I2.

+
+ handle_info + +

Makes the object server call a function handle_info + in the object implementation module on all unexpected + messages. Useful if the object implementation need to trap + exits.

+

Example option: handle_info will activates module + implementation handle_info for all interfaces in the + source file.

+

Example option: {{handle_info, "M1::I1"}, true} + will activates module implementation handle_info for + the specified interface.

+

Example options: [handle_info, {{handle_info, "M1::I1"}, false}] will generate the handle_info + call for all interfaces except M1::I1.

+
+ timeout + +

Used to allow a server response time limit to be set by the user. + This should be a string that represents the scope for the interface + which should have an extra variable for wait time initialization.

+

Example option: {timeout,"M::I"}) produces server + stub which will has an extra timeout parameter in the initialization + function for that interface.

+

Example option: timeout produces server + stub which will has an extra timeout parameter in the initialization + function for all interfaces in the source file.

+

Example options: [timeout, {{timeout,"M::I"}, false}] + produces server stub which will has an extra timeout + parameter in the initialization function for all interfaces + except M1::I1.

+
+ scoped_op_calls + +

Used to produce more refined request calls to server. When + this option is set to true, the operation name which was + mentioned in the call is scoped. This is essential to avoid + name clashes when communicating with c-servers. This option + is available for the c-client, c-server and the Erlang + gen_server back ends. All of the parts generated by ic + have to agree in the use of this option. Default is + false.

+

Example options: + [{be,c_genserv},{scoped_op_calls,true}]) produces + client stubs which sends "scoped" requests to a gen_server + or a c-server.

+
+ user_protocol + +

Used to define a own protocol different from the default + Erlang distribution + gen_server protocol. Currently only + valid for C back-ends. For further details see IC C protocol.

+

Example options: + [{be,c_client},{user_protocol, "my_special"}]) produces + client stubs which use C protocol functions with the prefix + "my_special".

+
+ c_timeout + +

Makes sends and receives to have timeouts (C back-ends only). These + timeouts are specified in milliseconds.

+

Example options: + [{be,c_client},{c_timeout, 10000, 20000}]) produces + client stubs which use a 10 seconds send timeout, and a + 20 seconds receive timeout.

+
+ c_report + +

Generates code for writing encode/decode errors to stderr (C back-ends only). + timeouts are specified in milliseconds.

+

Example options: + [{be,c_client}, c_report]).

+
+ scl + +

Used for compatibility with previous compiler versions up + to 3.3. Due to better semantic checks on enumerants, + the compiler discovers name clashes between user defined + types and enumerant values in the same name space. By + enabling this option the compiler turns off the extended + semantic check on enumerant values. Default is + false.

+

Example option: {scl,true}

+
+ precond + +

Adds a precondition call before the call to the operation + implementation on the server side.

+

The option comes in three varieties: {precond, {M, F}} which activates the call for operations in all + interfaces in the source file, {{precond, IntfName}, {M, F}} which activates the call for all operations in a + specific interface and {{precond, OpName}, {M, F}} + which activates the call for a specific operation.

+

The precondition function has the following signature + m:f(Module, Function, Args).

+

Example option: {precond, {mod, fun}} adds the call + of m:f for all operations in the idl file.

+

Example options: [{{precond, "M1::I"}, {mod, fun}}] + adds the call of m:f for all operations in the + interface M1::I1.

+

Example options: [{{precond, "M1::I::Op"}, {mod, fun}}] adds the call of m:f for the operation + M1::I::Op.

+
+ postcond + +

Adds a postcondition call after the call to the operation + implementation on the server side.

+

The option comes in three varieties: {postcond, {M, F}} which activates the call for operations in all + interfaces in the source file, {{postcond, IntfName}, {M, F}} which activates the call for all operations in a + specific interface and {{postcond, OpName}, {M, F}} + which activates the call for a specific operation.

+

The postcondition function has the following signature + m:f(Module, Function, Args, Result).

+

Example option: {postcond, {mod, fun}} adds the call + of m:f for all operations in the idl file.

+

Example options: [{{postcond, "M1::I"}, {mod, fun}}] + adds the call of m:f for all operations in the + interface M1::I1.

+

Example options: [{{postcond, "M1::I::Op"}, {mod, fun}}] adds the call of m:f for the operation + M1::I::Op.

+
+
+
+ +
+ Warning options + + 'Wall' + +

The option activates all reasonable warning messages in + analogy with the gcc -Wall option. Default value is true.

+
+ maxerrs + +

The maximum numbers of errors that can be detected before + the compiler gives up. The option can either have an integer + value or the atom infinity. Default number is 10.

+
+ maxwarns + +

The maximum numbers of warnings that can be detected before + the compiler gives up. The option can either have an integer + value or the atom infinity. Default value is + infinity.

+
+ nowarn + +

Suppresses all warnings. Default value is false.

+
+ warn_name_shadow + +

Warning appears whenever names are shadowed due to + inheritance; for example, if a type name is redefined from a + base interface. Note that it is illegal to overload + operation and attribute names as this causes an error to be + produced. Default value is true.

+
+ pedantic + +

Activates all warning options. Default value is false.

+
+ silent + +

Suppresses compiler printed output. Default value is false.

+
+
+
+ +
+ Back-End options +

Which back-end IC will generate code for is determined by the supplied + {be,atom()} option. If left out, erl_corba is used. + Currently, IC support the following back-ends:

+ + erl_corba + +

This option switches to the IDL generation for CORBA.

+
+ erl_template + +

Generate CORBA call-back module templates for each interface in the target + IDL file. Note, will overwrite existing files.

+
+ erl_plain + +

Will produce plain Erlang modules which contain functions that + map to the corresponding interface functions on the input file.

+
+ erl_genserv + +

This is an IDL to Erlang generic server generation option.

+
+ c_client + +

Will produce a C client to the generic Erlang server.

+
+ c_server + +

Will produce a C server switch with functionality of a + generic Erlang server.

+
+ java + +

Will produce Java client stubs and server skeletons with + functionality of a generic Erlang server.

+
+ c_genserv + +

Deprecated. Use c_client instead.

+
+
+
+ +
+ Preprocessor +

The IDL compiler allows several preprocessors to be used, the + Erlang IDL preprocessor or other standard C preprocessors. + Options can be used to provide extra flags such as include + directories to the preprocessor. The build in the Erlang IDL + preprocessor is used by default, but any standard C preprocessor + such as gcc is adequate.

+

The preprocessor command is formed by appending the prepoc_cmd + to the preproc_flags option and then appending the input IDL + file name.

+
+ +
+ Configuration +

The compiler can be configured in two ways:

+ + +

Configuration file

+
+ +

Command line options

+
+
+

The configuration file is optional and overrides the compiler + defaults and is in turn overridden by the command line options. + The configuration file shall contain options in the form of + Erlang terms. The configuration file is read using + file:consult.

+

An example of a configuration file, note the "." after each + line.

+ +{outdir, gen_dir}. +{{impl, "M1::M2::object"}, "obj"}. + +
+ +
+ Output files +

The compiler will produce output in several files depending on + scope declarations found in the IDL file. At most + three file types will be generated for each scope (including the top scope), + depending on the compiler back-end and the compiled interface. + Generally, the output per interface will be a header file (.hrl/ + .h) and one or more Erlang/C files (.erl/.c). + Please look at the language mapping for each back-end for details.

+

There will be at least one set of files for an IDL file, for the + file level scope. Modules and interfaces also have their own set + of generated files.

+
+ +
+ diff --git a/lib/ic/doc/src/ic_c_protocol.xml b/lib/ic/doc/src/ic_c_protocol.xml new file mode 100644 index 0000000..f895fe0 --- /dev/null +++ b/lib/ic/doc/src/ic_c_protocol.xml @@ -0,0 +1,158 @@ + + + + +
+ + 2004 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + IC C Protocol Functions + + + 2004-04-06 + A +
+ ic_c_protocol + IC C Protocol Functions + +

This manual page lists some of the functions of the IC C runtime + library that are used internally for the IC protocol. +

+

The listed functions are used internally by generated C client + and server code. They are documented here for the advanced user that want to replace the default protocol (Erlang + distribution + gen_server) by his own protocol, For each set of + client or sever functions below with prefix oe, the user + has to implement his own set of functions, the names of which + are obtained by replacing the oe prefix by Prefix. + The Prefix has to be set with the option + {user_protocol, Prefix} at compile time.

+

The following terminology is used (reflected in names of + functions): a notification is a message send from + client to server, without any reply back (i.e. a + oneway operation); a request is a message sent + from client to server, and where a reply message is + sent back from the server to the client.

+

In order to understand how the functions work and what they do + the user must study their implementation in the IC C + library (source file is ic.c), and also consider how they + are used in the C code of ordinary generated client stubs or + server skeletons.

+

+
+ +
+ Client Protocol Functions +

The following functions are used internally by generated C + client code.

+
+ + + intoe_prepare_notification_encoding(CORBA_Environment *env) + Prepare client notification encoding. + +

The result of this function is the beginning of a binary of + in external format of the tuple {'$gen_cast', X} where + X is not yet filled in.

+

In generated client code this function is the first to be called + in the encoding function for each oneway operation.

+
+
+ + intoe_send_notification(CORBA_Environment *env) + intoe_send_notification_tmo(CORBA_Environment *env, unsigned int send_ms) + Send client notification. + +

Sends a client notification to a server according to the + Erlang distribution + gen_server protocol.

+

The send_ms parameter specified a timeout in milliseconds.

+
+
+ + intoe_prepare_request_encoding(CORBA_Environment *env) + Prepare client request encoding. + +

The result of this function is the beginning of a binary in + the external format of the tuple {'$gen_call', {Pid, Ref}, X} where X is not yet filled in.

+

In generated client code this function is the first to be called + in the encoding function for each twoway operation.

+
+
+ + intoe_send_request_and_receive_reply(CORBA_Environment *env) + intoe_send_request_and_receive_reply_tmo(CORBA_Environment *env, unsigned int send_ms, unsigned int recv_ms) + Send client request and receive reply. + +

Sends a client request and receives the reply according to + the Erlang distribution + gen_server protocol. This function + calls the oe_prepare_reply_decoding function in order + to obtain the gen_server reply. +

+

send_ms and recv_ms specify timeouts for send + and receive, respectively, in milliseconds.

+
+
+ + intoe_prepare_reply_decoding(CORBA_Environment *env) + Prepare client decoding of reply. + +

Decodes the binary version of the tuple {Ref, X}, + where X is to be decoded later by the specific client + decoding function.

+
+
+
+ +
+ Server Protocol Functions +

The following functions are used internally by generated C + server code.

+
+ + + intoe_prepare_request_decoding(CORBA_Environment *env) + Prepare server decoding of request. + +

Decodes the binary version of the tuple {'$gen_cast', Op} (Op an atom), or the tuple {'$gen_cast', {Op, X}}, where Op is the operation name, and + where X is to be decoded later by the specific + operation decoding function; or

+

decodes the binary version of the tuple {'$gen_call', {Pid, Ref}, Op} (Op an atom), or the tuple + {'$gen_call', {Pid, Ref}, {Op, X}}, where Op> + is the operation name, and X is to be decode later by + the specific operation decoding function.

+
+
+ + intoe_prepare_reply_encoding(CORBA_Environment *env) + Prepare server encoding of reply. + +

Encodes the beginning of the binary version of the tuple + {{Ref,X}, where X is to be filled in by the + specific server encoding function.

+
+
+
+ +
+ SEE ALSO +

ic(3), ic_clib(3), IC Protocol

+
+ +
+ diff --git a/lib/ic/doc/src/ic_clib.xml b/lib/ic/doc/src/ic_clib.xml new file mode 100644 index 0000000..b557c4b --- /dev/null +++ b/lib/ic/doc/src/ic_clib.xml @@ -0,0 +1,246 @@ + + + + +
+ + 20032009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + IC C Library Functions + + + 2003-12-16 + PB1 +
+ ic_clib + IC C Library Functions + +

This manual page lists some of the functions in the IC C runtime + library.

+
+ +
+ Allocation and Deallocation Functions +

The following functions are used for allocating and + deallocating a CORBA_Environment structure.

+
+ + + CORBA_Environment*CORBA_Environment_alloc(int inbufsz, int outbufsz) + Allocate environment data. + +

This function is used to allocate and initiate the + CORBA_Environment structure. In particular, it is used + to dynamically allocate a CORBA_Environment structure and set + the default values for the structure's fields.

+

inbufsize is the initial size of the input + buffer.

+

outbufsize is the initial size of the output + buffer.

+

CORBA_Environment is the CORBA 2.0 state structure + used by the generated stub.

+

This function will set all needed default values and + allocate buffers the lengths of which are equal to the + values passed, but will not allocate space for the _to_pid + and _from_pid fields.

+

To free the space allocated by CORBA_Environment_alloc() do + as follows.

+ + +

First call CORBA_free for the input and output buffers.

+
+ +

After freeing the buffer space, call CORBA_free for the + CORBA_Environment space.

+
+
+
+
+ + voidCORBA_free(void *p) + Free any allocated data. + +

Frees allocated space pointed to by p.

+
+
+ + CORBA_char*CORBA_string_alloc(CORBA_unsigned_long len) + Allocate a string. + +

Allocates a (simple) CORBA character string of length len + 1.

+
+
+ + CORBA_wchar*CORBA_wstring_alloc(CORBA_unsigned_long len) + Allocate a wide string. + +

Allocates a CORBA wide string of length len + 1.

+
+
+
+ +
+ Exception Functions +

Functions for retrieving exception ids and values, and for setting + exceptions.

+
+ + + CORBA_char*CORBA_exception_id(CORBA_Environment *env) + Get exception identity. + +

Returns the exception identity if an exception is set, otherwise + it returns NULL.

+
+
+ + void*CORBA_exception_value(CORBA_Environment *env) + Get exception value. + +

Returns the exception value, if an exception is set, otherwise + it returns NULL.

+
+
+ + voidCORBA_exc_set(CORBA_Environment *env, CORBA_exception_type Major, CORBA_char *Id, CORBA_char *Value) + Set exception. + +

Sets the exception type, exception identity, and exception value + in the environment pointed to by env.

+
+
+
+ +
+ Server Reception +

The following function is provided for convenience.

+
+ + + intoe_server_receive(CORBA_Environment *env, oe_map_t *map) + intoe_server_receive_tmo(CORBA_Environment *env, oe_map_t *map, unsigned int send_ms, unsigned int recv_ms) + Server receive of notification or request, and sending of reply (in case of request). + +

Provides a loop that receives one message, executes the + operation in question, and in case of a two-way operation + sends a reply.

+

send_ms and recv_ms specify timeout values + in milliseconds for send and receive, respectively.

+
+
+
+ +
+ Generic Execution Switch and Map Merging +

Function for searching for server operation function, and for + calling it if found. Function for merging maps (see the include + file ic.h for definitions).

+
+ + + intoe_exec_switch(CORBA_Object obj, CORBA_Environment *env, oe_map_t *map) + Search for server operation and execute it. + +

Search for server operation and execute it.

+
+
+ + oe_map_t*oe_merge_maps(oe_map_t *maps, int size) + Merge an array of server maps to one single map. + +

Merge an array of server maps to one single map.

+
+
+
+ +
+ The CORBA_Environment structure +

Here is the complete definition of the CORBA_Environment structure, + defined in file ic.h:

+ + /* Environment definition */ + typedef struct { + + /*----- CORBA compatibility part ------------------------*/ + /* Exception tag, initially set to CORBA_NO_EXCEPTION ---*/ + CORBA_exception_type _major; + + /*----- External Implementation part - initiated by the user ---*/ + /* File descriptor */ + int _fd; + /* Size of input buffer */ + int _inbufsz; + /* Pointer to always dynamically allocated buffer for input */ + char *_inbuf; + /* Size of output buffer */ + int _outbufsz; + /* Pointer to always dynamically allocated buffer for output */ + char *_outbuf; + /* Size of memory chunks in bytes, used for increasing the output + buffer, set to >= 32, should be around >= 1024 for performance + reasons */ + int _memchunk; + /* Pointer for registered name */ + char _regname[256]; + /* Process identity for caller */ + erlang_pid *_to_pid; + /* Process identity for callee */ + erlang_pid *_from_pid; + + /*- Internal Implementation part - used by the server/client ---*/ + /* Index for input buffer */ + int _iin; + /* Index for output buffer */ + int _iout; + /* Pointer for operation name */ + char _operation[256]; + /* Used to count parameters */ + int _received; + /* Used to identify the caller */ + erlang_pid _caller; + /* Used to identify the call */ + erlang_ref _unique; + /* Exception id field */ + CORBA_char *_exc_id; + /* Exception value field */ + void *_exc_value; + + + } CORBA_Environment; + + +

Always set the field values _fd, _regname, + _to_pid and/or *_from_pid to appropriate + application values. These are not automatically set by the + stubs.

+
+ +

Never assign static buffers to the buffer pointers, and never + set the _memchunk field to a value less than + 32.

+
+
+ +
+ SEE ALSO +

ic(3), ic_c_protocol(3) +

+
+ +
+ diff --git a/lib/ic/doc/src/java-part.xml b/lib/ic/doc/src/java-part.xml new file mode 100644 index 0000000..69cc0f0 --- /dev/null +++ b/lib/ic/doc/src/java-part.xml @@ -0,0 +1,37 @@ + + + + +
+ + 2002 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + IDL to Java language Mapping + + + 2002-06-25 + A +
+ +

+
+ +
+ diff --git a/lib/ic/doc/src/make.dep b/lib/ic/doc/src/make.dep new file mode 100644 index 0000000..64694ee --- /dev/null +++ b/lib/ic/doc/src/make.dep @@ -0,0 +1,24 @@ +# ---------------------------------------------------- +# >>>> Do not edit this file <<<< +# This file was automaticly generated by +# /home/otp/bin/docdepend +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# TeX files that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: book.tex c-part.tex ch_basic_idl.tex ch_c_client.tex \ + ch_c_corba_env.tex ch_c_mapping.tex ch_c_server.tex \ + ch_erl_genserv.tex ch_erl_plain.tex ch_ic_protocol.tex \ + ch_introduction.tex ch_java.tex erl-part.tex \ + ic.tex ic_c_protocol.tex ic_clib.tex java-part.tex \ + ref_man.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + diff --git a/lib/ic/doc/src/notes.gif b/lib/ic/doc/src/notes.gif new file mode 100644 index 0000000000000000000000000000000000000000..e000cca26a383722eca87f4d87a5841292b0b8ea GIT binary patch literal 2005 zcmc(e`(I0c1HeD$>})&L($>wE%9*B;E}M!dPv>-9341YwWX&zf>scU1zfBrl=I{N9;r;i^$ ze)#ZVWMt(1`}gnOy?gui?eOsMn>TM>zkWS5H1z7#tHHs+fq?;|(fIP^%NH+RJb(WD z*|TR)pFVx^ogEz=?d|P)y}qrjt+lnarKLru(`mKZ=H_ONMx$1%@7%d_`}XZyw{G3MdGp4N z8%<43jg5^B4Gq_?U%z(k+SRL9>+9>UT)9$LS65qGTT@eW`SRsUmo8nrc=5u83+KckWzORn^(EXDcf!&zw1P`t<2jr%qK=RFs#Ot5m9!Cr_R@apL&#<7H)K$BrF4 zdi1DLsXTJzNNH(lNl8g@aq;29hl`4e3JVJr3dNyAhYlV*SWr-qpP!$XmzSHHo0F3x zm&-FUGSbu2Wir|R{rmUr+qZY`-n6u|)YR0Jl$1St_9Q1K@7}$8*REYVckbM=V@Fa_ zl0+iezI}UQV&b-K+Y%BIwr<_JdGqE?n>KCSxN*aV4Pvo4E-p?a60KjqJ~lRX-MV!# zF)?e`u3fWc&Fa;wSFKvLa^=buD^>`F!ez^r2?T=0ix)>lMMXwNMnpvL`TX$k@UXD3 zkdTnz;NYO3Ac7zQ0|OT>TD_t~>&yScf|nl;PS)z!tt#o5`J!{InNIkDMn48x{RpYG`B=-}XBZ*Mm zJ0_E9VPQd|(M(NEQ52<8sT2wYK@bv&1j8@{LE!(5`#%Ezya3Qi0HOB$8kHskwQ`Hm z*OY4y(48X7__Y-+c}(wwXZqSxZHKVn+_d2V9bX<;)o5v8$jlB{tz6vnwfvQAiMw6t z0IXVSedvhT17nJCGJ_XCYT%)5*?chw5R9s25QXlX!e_sd7hr)!eyKroJ4zhgi|iRe z9BRcDRXkmj&PH5Z1EswZP1Yik}bX?KQfDMotrhur?Z`l6 z9SHWUks6^bPWsX|jEswdY)vps%VI@IAvY7W9?a_N?~xI!M!5pm(Ry5JJ;$6wSb!Kw z1Ofz-ES$>6ni1O}ScWTvR$Wsm*pF-~}^QqIoOkG6>BJ?$;+XE5N4m%cOVTgl$q1H6Cj2CRZ#Cwk*Z+A1}6-ZGIOnZ zriKR6JwuHEr#89IP&lU0d>}f|iQ2(xTebl}Km=JKc>w~{On}kI=M0e4E*aE>B!t(` zz!7B(z}xLdevm2fNGl*)VFk@hhEN1isQ4%eVdfhlo64C^B-c26^Z?T#Tc$&!YL-EE zsr_sc%})?_z}$saj#x(bLnO=CUH5f1>6}R!!dMZ|W9GTgpb9n@*5fiBqnDrne~DCT zx&%mdn3ma=CO4$ZCjP+)Zks2RB*+Tt`QEtb2g6+n+RKF1oJqVMUCo0mdGDTz#3Q^?T4648gGi%gvvJ#j{AlN2b z`m?E;VM>mcPQBC_Y6=8kn9B=CL=o-QgXt_x2k`|YJusL&`b=Pj%+?u4tr>8h24sDX + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + IDL Compiler Release Notes + + + + 2004-04-06 + AC + notes.xml +
+ +
+ IC 4.2.23 + +
+ Improvements and New Features + + +

+ The documentation is now built with open source tools (xsltproc and fop) + that exists on most platforms. One visible change is that the frames are removed.

+

+ Own Id: OTP-8201 Aux Id:

+
+
+
+
+ +
+ IC 4.2.22 + +
+ Fixed Bugs and Malfunctions + + +

The 64-bit version of libic was not compiled with the -fPIC flag.

+

Own id: OTP-8088

+
+
+
+
+ +
+ IC 4.2.21 + +
+ Fixed Bugs and Malfunctions + + +

The function print_erlang_binary (oe_ei_code_erlang_binary.c) + updated to avoid compiler warning.

+

Own id: OTP-7982

+
+
+
+
+ +
+ IC 4.2.20 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7837

+
+
+
+
+ +
+ IC 4.2.19 + +
+ Improvements and New Features + + +

Documentation source included in open source releases.

+

Own id: OTP-7595

+
+
+
+
+ +
+ IC 4.2.18 + +
+ Fixed Bugs and Malfunctions + + +

Insufficient buffer allocated when passing wide strings + using the C backend on a 64-bit architecture.

+

Own Id: OTP-7313 Aux Id:

+
+
+
+
+ +
+ IC 4.2.17 + +
+ Improvements and New Features + + +

Updated file headers.

+

Own id: OTP-7011

+
+ +

IC no longer use the obsolete function file:rawopen/2.

+

Own id: OTP-7182

+
+
+
+
+ +
+ IC 4.2.16 + +
+ Improvements and New Features + + +

Added links to classes inherited from Jinterface in the + User's Guide.

+

Own Id: OTP-6965 Aux Id:

+
+
+
+
+ +
+ IC 4.2.15 + +
+ Fixed Bugs and Malfunctions + + +

If an inherited function name begun with a capital letter + the generated stub/skeleton oe_tc/1 function was incorrect.

+

Own Id: OTP-6855 Aux Id:

+
+
+
+
+ +
+ IC 4.2.14 + +
+ Improvements and New Features + + +

The documentation source has been converted from SGML to XML.

+

Own Id: OTP-6754 Aux Id:

+
+
+
+
+ +
+ IC 4.2.13 + +
+ Improvements and New Features + + +

Minor Makefile changes.

+

Own Id: OTP-6701 Aux Id:

+
+
+
+
+ +
+ IC 4.2.12 + +
+ Improvements and New Features + + +

Dead code was deleted from the following modules: + ic_cclient, ic_code, ic_cserver, ic_erlbe, ic_java_type, + ic_noc, ic_plainbe, ic_pp, ic_pragma, icscan, icstruct, + ictype, icunion.

+
+
+
+
+ +
+ IC 4.2.11 + +
+ Improvements and New Features + + +

Changed code generation to avoid warnings such as unused + variables.

+

Own Id: OTP-5930 Aux Id:

+
+
+
+
+ +
+ IC 4.2.10 + +
+ Fixed Bugs and Malfunctions + + +

The FD_SETSIZE limit has been increased to 2048 for + VxWorks/PPC603.

+

Own Id: OTP-5395 Aux Id: seq9751

+
+
+
+
+ +
+ IC 4.2.9 + +
+ Fixed Bugs and Malfunctions + + +

In C back-ends, the compiler crashed when generating C code + for error reports when a scoped name was used as a type + in a union.

+

Own Id: OTP-5375 Aux Id: seq9740

+
+
+
+
+ +
+ IC 4.2.8 + +
+ Fixed Bugs and Malfunctions + + +

In C back-ends, when decoding a sequence of "small" + integers, which from Erlang is sent as a string (i.e. + each element between 0 and 255), each string element was + considered to be of signed character type. Each such + element is now correctly treated as an unsigned character + type.

+

Own Id: OTP-5205 Aux Id: seq9241

+
+
+
+
+ +
+ IC 4.2.7 + +
+ Improvements and New Features + + +

A new compiler option c_report has been introduced + for C back-ends (client and server). If that option is + set, encoding/decoding errors will be reported to + stderr.

+

Own Id: OTP-4977

+
+
+
+
+ +
+ IC 4.2.6 + +
+ Improvements and New Features + + +

The size of modules, used then registering data in the + IFR DB (e.g., oe_MyModule:oe_register()), can be minimized + if the compile option light_ifr is used and Orber is + configured to use Light IFR. Requires that orber-3.5.1, or + later, is used.

+

Own Id: OTP-5036

+
+
+
+ +
+ Incompatibilities + + +

The compile option multiple_be is no longer supported.

+

Own Id: OTP-5049

+
+
+
+
+ +
+ IC 4.2.5 + +
+ Improvements and New Features + + +

Send and receive functions with timeouts have been added + to the C back-ends for the standard protocol (i.e. Erlang + distribution + gen_server protocol).

+

Accordingly a new compiler option {c_timeout, {SendTimeout, RecvTimeout}} has been added. Timeouts + are specified in milliseconds.

+

A user that want to implement its own protocols with + function timeouts has to implement the following functions.

+

For C clients the functions int PFX_send_notification(CORBA_Environment *env, unsigned int send_ms), and int PFX_send_request_and_receive_reply(CORBA_Environment *env, unsigned int send_ms, unsigned int recv_ms) + have to be additionally implemented, where PFX is the + user defined prefix.

+

For C servers no additional functions have to be + implemented, but a clone of the int oe_server_receive_tmo(CORBA_Environment *env, oe_map_t *map, unsigned int send_ms, unsigned int recv_ms) + might be handy.

+

Own Id: OTP-4972

+
+
+
+
+ +
+ IC 4.2.4 + +
+ Improvements and new features + + +

The C back-ends has been opened up, so that a user can + define his own protocol, differing from the Erlang + distribution + gen_server protocol.

+ + For C clients it means to replace the library functions + int oe_prepare_notification_encoding(CORBA_Environment *env), int oe_send_notification(CORBA_Environment *env), int oe_prepare_request_encoding(CORBA_Environment *env), + int oe_send_request_and_receive_reply(CORBA_Environment *env), and int oe_prepare_reply_decoding(CORBA_Environment *env), + with functions of the same signature, but with the prefix + "oe" replaced by a user defined prefix. + For C servers the functions int oe_prepare_request_decoding(CORBA_Environment *env), + and int oe_prepare_reply_encoding(CORBA_Environment *env), are similarly replaced.

+ + The new compiler option {user_protocol, Prefix} has + been added.

+

Own Id: OTP-4834

+
+
+
+
+ +
+ IC 4.2.3 + +
+ Fixed Bugs and Malfunctions + + +

In generated code for the C server back-end, the naming scope + was in error for prototypes in C header files for interfaces + inheriting base interfaces.

+

Own Id: OTP-4881

+
+
+
+
+ +
+ IC 4.2.2 + +
+ Fixed Bugs and Malfunctions + + +

IDL long long and unsigned long long could not + be used in a struct for the Java backend.

+

All unsigned integer types for the Java backend + had broken marshalling for large values.

+

Own Id: OTP-4763

+
+
+
+
+ +
+ IC 4.2.1 + +
+ Fixed Bugs and Malfunctions + + +

A scoping problem (IC could not find typedefs contained + inherited interfaces) in the C-backend solved.

+

Own Id: OTP-4758

+
+
+
+
+ +
+ IC 4.2 + +
+ Improvements and New Features + + +

The CORBA stub/skeleton-files generated by IC have been improved, + i.e., depending on the IDL-files, reduced the size of the + erl- and beam-files and decreased dependencies off Orber's + Interface Repository. It is necessary to re-compile all IDL-files + and use COS-applications, including Orber, compiled with + IC-4.2.

+

Own Id: OTP-4576

+
+
+
+
+
+ diff --git a/lib/ic/doc/src/old_notes.xml b/lib/ic/doc/src/old_notes.xml new file mode 100644 index 0000000..9ba0262 --- /dev/null +++ b/lib/ic/doc/src/old_notes.xml @@ -0,0 +1,1565 @@ + + + + +
+ + 20032009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + IDL Compiler Release Notes + + + + 2003-11-19 + AB +
+ +
+ IC 4.1.8 + +
+ Fixed Bugs and Malfunctions + + +

IDL-files containing result or Result as, + for example, parameter name, caused an exit with reason + bad_match.

+

Own Id: OTP-4532

+
+ +

Uninitialized variables were used in ic_init_ref for + C backends.

+

Own Id: OTP-4537

+ + Aux Id: seq7666, ETOtr17107

+
+ +

CORBA_Environment_alloc() left some fields + uninitialized in the returned pointer to an + CORBA_Environment for C backends.

+

Own Id: OTP-4538

+
+ +

The function ic_compare_refs() for C backends + could find two unequal references to be equal.

+

Own Id: OTP-4539

+
+
+
+
+ +
+ IC 4.1.7 + +
+ Fixed Bugs and Malfunctions + + +

Operation names were always scoped in C server backend, + irrespective of the setting of the option + scoped_op_calls.

+

Own Id: OTP-4521

+ + Aux Id: seq7643, ETOtr16925

+
+
+
+
+ +
+ IC 4.1.6 + +
+ Improvements and New Features + + +

For C backends generated code checks that the + _length field of bounded sequences (i.e. specified + as ]]>) does not exceed the + specified maximum length. If so, an exception is raised.

+

Own Id: OTP-4471

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

The _maximum field was not set for sequence structs + generated by the C backends.

+

Own Id: OTP-4471

+ + Aux Id: seq7600, ETOtr16308

+
+ +

There was a memory leak in C backends in case there was a + decoding error in a sequence with elements of basic type.

+

Own Id: OTP-4475

+
+ +

For for C backends, IDL structs defined within an + interface were not mapped into C structs in appropriate + include files.

+

Own Id: OTP-4481

+ + Aux Id: seq7617

+
+ +

If the user, incorrectly, trap exit's but did not use the + 'handle_info' compile option it would cause the server to + terminate. The same problem occurred if someone, + illegally, sent a message to the server. It could also + happen for illegal oneway operations.

+

Own Id: OTP-4488

+
+
+
+
+ +
+ IC 4.1.5 + +
+ Fixed Bugs and Malfunctions + + +

Invalid C code was generated for type short.

+

Own Id: OTP-4450

+ + Aux Id: seq7582

+
+
+
+
+ +
+ IC 4.1.4 +
+ Fixed Bugs and Malfunctions + + +

Operation functions inherited by an interface were not + placed in the map table in generated code for the C server + backend. As a result such functions were not found by the + switch function of the interface.

+

Own Id: OTP-4448

+ + Aux Id: seq7582

+
+
+
+
+ +
+ IC 4.1.3.1 + +
+ Fixed Bugs and Malfunctions + + +

A non-ANSI compliant construct in libic.a was changed.

+

Own Id: -

+
+
+
+
+ +
+ IC 4.1.3 + +
+ Improvements and New Features + + +

For Erlang and C back-ends an IC version stamp has been + added to generated source code. This stamp i preserved in + compiled target code.

+
+ +

For C backends an assert() expression has been + added to generated code. That expression asserts that the + result of a memory allocation size calculation is strictly + positive. An error will result in a printout and an + abort(). The assertion can be inhibited by defining + the macro NDEBUG (according to ANSI C).

+

If the assertion is inhibited, and a size calculation error + is detected, an INTERNAL CORBA exception is set.

+
+ +

An internal reorganization of C backend generator code has + been done (addition of module ic_cclient). Several + changes has been done in generated C code:

+ + +

The typedef ___generic___ has been replaced by + the typedef ___exec_function___, which has been + made more strict; for backward compatibility the + ___generic___ typedef is now an alias for + ___exec_function___.

+
+ +

Function parameters that are arrays, has been changed + to be pointers to array slices, which are equivalent + according to ANSI C.

+
+ +

The storage class specifier extern has been + removed from function prototypes in header files.

+
+ +

Redundant type casts have been removed from generated code. + Also some local "generic" variables have been renamed.

+
+
+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

Module info vsn replaced by app_vsn.

+

Own Id: OTP-4341

+
+ +

IC-4.1.2 disabled the definition of float constants + beginning with a zero (e.g. 0.14).

+

Own Id: OTP-4367

+
+ +

IC did not handle constant definitions correctly for + char, string, wchar and wstring.

+

Own Id: OTP-4067, OTP-3222

+
+ +

IC did not recognize all reserved words defined in the + OMG specification (2.3.1). The new keywords are fixed, abstract, custom, factory, local, native, private, public, supports, truncatable, 'ValueBase' and + valuetype. But for now this is only active for the + erl_corba backend and only incorrect usage of + fixed, since this datatype is now supported, + triggers an error for this backend.

+

Own Id: OTP-4368

+
+ +

It was not possible to use wchar or wstring inside a + union body when using the Java backend.

+

Own Id: + OTP-4365

+
+ +

The compile options this and handle_info + did not behave as described in the documentation. The + timeout now behaves as, for example, + handle_info.

+

Own Id: OTP-4386, OTP-3231

+
+ +

If we typedef a sequence, which contains a struct or a union, + the access function id/0 returned an incorrect IFR Id + if a prefix pragma was used.

+

Own Id: OTP-4387

+
+ +

If an IDL file contained a prefix pragma, incorrect + IFR-id's was generated in the IFR-registration operation + oe_register for aliases (typedef) and + attributes.

+

Own Id: OTP-4388, OTP-4392

+
+ +

For C back-ends, when encodings/decodings failed, memory + allocated for variable size parameter types was not freed.

+

Own Id: OTP-4391 +

+Aux Id: seq7438, ETOtr14009

+
+ +

If an IDL file contained a multiple typedef + (e.g. typedef string str1, str2;), the oe_unregister + operation failed to remove all data, in this case str2, + from the IFR.

+

Own Id: OTP-4393

+
+ +

IC did not recognize octet-constants + (e.g. const octet octetmax = 255;).

+

Own Id: OTP-4400

+
+ +

Negative 'long long' constants was not accepted + (e.g. const long long MyConstant = -1;).

+

Own Id: OTP-4401

+
+
+
+
+ +
+ IC 4.1.2 + +
+ Fixed Bugs and Malfunctions + + +

Merging of map's (___map___) using the + ___merge___ function does not work.

+

Own Id: OTP-4323

+
+ +

Error in generated C decode/encode functions for union's with + discriminator where the union has no value for all discriminator + values. E.g. a union with discriminator boolean where only the + discriminator value TRUE has a corresponding union value. + Here is how such a thing would look in IDL:

+
+\011    union OptXList switch(boolean) {
+\011       case TRUE: integer  val;
+            };
+          
+

Own Id: OTP-4322

+
+ +

Scoped op calls ('{scoped_op_calls, true}') does not handle + module/function names beginning with capital letter (e.g. + Megaco should be 'Megaco') for oneway operations (handle_cast).

+

Own Id: OTP-4310

+
+ +

A bug is fixed on C-IDL erlang binaries that caused + pointer error when residing inside sequences.

+

Own Id: OTP-4303

+
+
+
+
+ +
+ IC 4.1.1 + +
+ Improvements and New Features + + +

A new option 'multiple_be' is added that allows multiple backend + generation for the same IDL file.

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

A bug is fixed on IDL types that contain underscore '_'.

+

Own Id: OTP-3710

+
+ +

A bug is fixed on IDL structs that caused scope confusion + when types and fields of a struct had the same name.

+

Own Id: OTP-2893

+
+
+
+
+ +
+ IC 4.0.7 + +
+ Improvements and New Features + + +

The Erlang binary special type is introduced, that + allows efficient transfer of binaries between Erlang and C.

+

Own Id:OTP-4107

+
+
+
+
+ +
+ IC 4.0.6 + +
+ Fixed Bugs and Malfunctions + + +

A bug is fixed on noc backend which caused generation of erroneous code.

+

Own Id: OTP-3812

+
+
+
+
+ +
+ IC 4.0.5 + +
+ Improvements and New Features + + +

The pragma code option is extended to point + specific functions on NOC backend, not only + interfaces.

+

+
+
+
+
+ +
+ IC 4.0.4 + +
+ Fixed Bugs and Malfunctions + + +

A bug in pragma prefix when including IDL files is fixed. + This caused problems for Erlang-corba IFR registrations.

+

Own Id: OTP-3620

+
+
+
+
+ +
+ IC 4.0.3 + +
+ Improvements and New Features + + +

Limited support on multiple file module definitions.

+

The current version supports multiple file module definitions all + backends except the c oriented backends.

+

Own Id: OTP-3550

+
+
+
+
+ +
+ IC 4.0.2 +
+ Fixed Bugs and Malfunctions + + +

A bug is fixed on Erlang backends.

+

The (recently) introduced generation of files + describing sequence and array files were even + true for included interfaces. In the case of + some Erlang backends this were unnecessary.

+

Own Id: OTP-3485

+
+
+
+
+ +
+ IC 4.0.1 + +
+ Improvements and New Features + + +

New functionality added on Java and Erl_genserv backends.

+

+ + +

On the Java client stub :

+

+ + +

The Java client have now one more constructor function, + that allows to continue with an already started connection.

+
+ +

void __stop() which sends a stop cast call to the server. + While this causes the Erlang server to terminate, it + sets a stop flag to the Java server environment, requesting the + server to terminate.

+
+ +

void __reconnect() which closes the current client connection + if open and then connects to the same server.

+
+
+

The Environment variable is now declared as public.

+
+ +

On the Java server skeleton :

+

+ + +

boolean __isStopped() which returns true if a stop + message where received, false otherwise. The user must check if + this function returns true, and in this case exit the implemented + server loop.

+
+
+

The Environment variable is now declared as protected which + allows the implementation that extends the stub to access it.

+
+ +

On the Erlang gen_server stub :

+

+ + +

stop(Server) which yields to a cast call to the standard + gen_server stop function. This will always terminate the + Erlang gen_server, while it will set the stop flag for the + Java server stub.

+
+
+
+
+

Own Id: OTP-3433

+
+
+
+
+ +
+ IC 4.0 + +
+ Improvements and New Features + + +

New types handled by IC.

+

The following OMG-IDL types are added in this compiler version :

+ + +

long long

+

unsigned long long

+

wchar

+

wstring

+
+
+

Own Id: OTP-3331

+

+
+ +

TypeCode as built in type and access code files for array and sequence types.

+ + +

As TypeCode is a pseudo-interface, it is now is a built-in type on IC.

+
+ +

Access code files which contain information about TypeCode, ID and Name are + now generated for user defined arrays and sequences.

+
+
+

Own Id: OTP-3392

+
+
+
+
+ +
+ IC 3.8.2 +
+ Fixed Bugs and Malfunctions +

A bug is fixed on preprocessor directive expansion.

+

When nested #ifdef - #ifndef directives, a bug caused + improper included file expansion. This is fixed by + repairing the preprocessor expansion function.

+

Own Id: OTP-3472

+
+
+ +
+ IC 3.8.1 + +
+ Improvements and New Features + + +

Build in Erlang types support for java-backends

+

The built-in Erlang types term, port, ref and pid + are needed in Java backends in order to support an + efficient mapping between the two languages. + The new types are also supported by additional + helpers and holders to match with OMGs Java mapping + As a result of this, the following classes are added to + the com.ericsson.otp.ic interface :

+ + +

Term,TermHelper,TermHolder which represents the + built-in Erlang type term

+
+ +

Ref,RefHelper,RefHolder which represents the + built-in Erlang type ref

+
+ +

Port,PortHelper, PortHolder which represents the + built-in Erlang type port

+
+ Pid, PidHelper and PidHolder which represents the + built-in Erlang type pid +
+

+

Own Id: OTP-3348

+

+
+ +

Compile time preprocessor macro variable definitions

+

The preprocessor lacked possibility to accept user + defined variables other than the one defined in IDL files. + This limited the use of command-ruled IDL specifications. + Now the build-in preprocessor allows the user to set variables + by using the "preproc_flags" option the same way + as using the "gcc" preprocessor.

+

Supported flags :

+ + +

"]]> which defines a variable

+
+ +

"]]> which undefines a variable

+
+
+

+

Own Id: OTP-3349

+
+
+
+ +
+ Fixed Bugs and Malfunctions +

A bug on comment type expansion is fixed.

+

The comment type expansion were erroneous when + inherited types (NOC backend). + This is now fixed and the type naming agree with + the scope of the inheritor interface.

+

Own Id: OTP-3346

+
+
+ +
+ IC 3.8 + +
+ Improvements and New Features + + +

The code generated for java backend is optimized + due to use of streams instead for tuple classes + when (un)marshalling message calls. + Support for building clients using asynchronous + client calls and effective multi-threaded servers.

+

Own Id: OTP-3310

+

+
+ +

The any type is now supported for java backend.

+

Own Id: OTP-3311

+
+
+
+ +
+ A bug on C generated constants is fixed +

While the constants are evaluated and behave well when used + inside an IDL specification their C-export were not working properly. + The constant export definitions were not generated well :

+ + +

the declared C definition were erroneous ( the name did not always agree + with the scope the constant were declared in ).

+
+ +

there were no C- definition generated for the c-server backend when + the constants were declared inside an interface.

+
+
+

Own Id: OTP-3219

+
+ +
+ Incompatibilities +

Due to optimizations in java backend, the stub initialization and usage + differs than the previous version.

+

Client stub interface changes:

+ + +

Client disconnects by calling the __disconnect() function instead + for the old _closeConnection()

+

+
+ +

All marshal operation functions have now the interface :

+

_marshal(Environment<, Param |, Params >)]]>

+

instead for

+

_marshal(< Param, | Params, >OtpErlangPid, OtpErlangRef)]]>

+

+
+ +

All unmarshal operation functions have now the interface :

+

_< OpName >_unmarshal(Environment<, Param |, Params >)]]>

+

instead for

+

_< OpName >_unmarshal(< Param, | Params, >OtpErlangTuple, OtpErlangRef)]]>

+

+
+ +

Call reference extraction is available by the client function :

+

OtpErlangRef __getRef()

+

instead for previous function :

+

OtpErlangRef _getReference(OtpErlangTuple)

+

+
+
+

Server skeleton interface changes:

+ + +

The implementation function no longer have to contain the + two (2) contractor functions (with super()). This is due + to the fact that there is only one contractor function for each + skeleton file :

+

ImplBase()]]>

+

+
+ +

The parameter for the caller identity extraction function _getCallerPid + is now an Environment variable instead for an OtpErlangTuple.

+

+
+ +

There is a new invoke function :

+

OtpOutputStream invoke(OtpInputStream)

+

instead for the old one :

+

OtpErlangTuple invoke(OtpErlangTuple)

+

+
+ +

The OtpConnection class function used for receiving messages is now :

+

OtpInputStream receiveBuf()

+

instead for the old one :

+

OtpErlangTuple receive()

+

+
+ +

The OtpConnection class function used for sending messages is now :

+

void sendBuf(OtpErlangPid, OtpOutputStream)

+

instead for the old one :

+

void send(OtpErlangPid, OtpErlangTuple)

+

+
+
+
+
+ +
+ IC 3.7.1 + +
+ Improvements and New Features +

Some memory usage optimizations for the compiler were done.

+
+ +
+ Fixed bugs and malfunctions + + +

A bug is fixed when C backend is used.

+

When C-union with enumerant discriminator, the size + calculation of the discriminator value were erroneous. + This lead to the side effect that only the first case of the + union were allowed. + The error were fixed by fixing the size calculation of + the discriminator.

+

Own Id: OTP-3215

+
+
+
+
+ +
+ IC 3.7 +
+ Fixed Bugs and Malfunctions + + +

A bug is fixed when C backend is used.

+

When unions with enumerant discriminator + were decoded, an error encountered in the + union size calculation.

+

Own Id: OTP-3209

+
+
+
+
+ +
+ IC 3.6 +
+ Fixed Bugs and Malfunctions + + +

A bug is fixed when NOC backend is used.

+

When several functions with the same name + were found in the included file tree, + a compile time failure occurred.

+

Own Id: OTP-3203

+
+
+
+
+ +
+ IC 3.5 + +
+ Improvements and New Features + + +

Noc backend optimization

+

When NOC backend is choosen, the type code + information on the stub functions is reduced + to a single atom "no_tk". + This is the default behavior. The typecode + generation is enabled by the "use_tk" switch.

+

Own Id: OTP-3196

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

General java backend bug fixes

+

Protocol errors on user defined structures and + union types are corrected.

+
+
+
+
+ +
+ IC 3.4 + +
+ Improvements and New Features + + +

Semantic test enhancements.

+

The compiler detects now semantic errors when enumerant + values collide with user defined types on the same name scope.

+

Own Id: OTP-3157

+

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

General java backend bug-fixes

+

Several bugs were fixed on user defined types.

+ + +

Union discriminators work better when + all possible case values are defined.

+
+ +

A bug on Interface inherited operations is + fixed that cause errors on generated server switch.

+
+ +

Type definitions on included files are better generated.

+
+
+

Own Id: OTP-3156

+

+
+
+
+
+ +
+ IC 3.3 + +
+ Improvements and New Features + + +

A new back-end which generates Java code according to the CORBA IDL to Java mapping for + communication with the Erlang distribution protocol has been added to IC. + For the moment there is no support for the Erlang types Pid, Ref, Port and Term + but this will be added later.

+

Own Id: OTP-2779

+

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

Fixed the bug that the c code backends sometimes generated incorrect code for + struct arguments. They shall always be pointers.

+

Own Id: OTP-2732

+

+
+ +

The code generation is fixed so the array parameters now follow the + CORBA V2.0 C mapping.

+

Own Id: OTP-2873

+

+
+ +

Fixed the problem that the checking of the numbers of out-parameters always was true.

+

Own Id: OTP-2944

+

+
+ +

Fixed the bug that some temporary variables was not declared when c code.

+

Own Id: OTP-2950

+

+
+
+
+
+ +
+ IC 3.2.2 + +
+ Improvements and New Features + + +

Unions are now supported to agree with OMG's C mapping.

+

Own Id: OTP-2868

+

+
+ +

There is now a possibility to use pre- and postcondition methods on the server side + for IC generated Corba Objects. The compiler option is documented in the ic reference manual + and an example of how the pre- and postcondition methods should be designed and used is + added to ic example directory (an ReadMe.txt file exists with some instructions for + running the example code).

+

Own Id: OTP-3068

+

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

The compiler ignores unknown/non supported pragma directives. A warning is raised + while the generated code will then be the same as if the corresponding + (unknown) pragma directive were missing.

+

Own Id: OTP-3052

+

+
+
+
+
+ +
+ IC 3.2.1 +
+ Fixed Bugs and Malfunctions + + +

Wrong C code was generated for limited strings when they where included + from another IDL specification.

+

Own Id: OTP-3033

+

+
+
+
+
+ +
+ IC 3.2 +
+ Fixed Bugs and Malfunctions + + +

The buffers for in/output used by C-stubs are now expandable. + This fixes buffer overflow problems when messages received/sent + do not fit in buffers.

+

Own Id: OTP-3001

+

+
+
+
+ +
+ Incompatibilities +

The CORBA_Environment structure has now two new fields, the buffers for in/output + must now be dynamically allocated.

+
+
+ +
+ IC 3.1.2 +
+ Fixed Bugs and Malfunctions + + +

The generated IFR registration function for constants has been fixed + so the parameters are correct.

+

Own Id: OTP-2856

+

+
+ +

Error in the C code generation of ONEWAY operations without parameters + The bug was an decoding error in the operation header. The generated code expected one + parameter instead of zero. This is now fixed.

+

Own Id: OTP-2909

+

+
+ +

Type problems on floats and booleans fixed.

+

Erroneous code for runtime checks on float was removed and + the internal format of the data representing the boolean value + is upgraded.

+

Own Id: OTP-2925

+

+
+ +

The generated code for arrays of typedefined strings were + erroneous in the C-backends due to a failure in the compiler internal type + checking.

+

Own Id: OTP-2936

+

+
+ +

The generated code for typedefined nested sequences were erroneous + in the C-backends. Pointer mismatches caused compilation failure.

+

Own Id: OTP-2937

+

+
+
+
+ +
+ Incompatibilities +

The IDL specifications must be regenerated for C due to changes in the code generation.

+

One must regenerate IDL specifications for Erlang CORBA if there are constants in the + specification due to previous errors in the IFR registration functions (OTP-2856).

+
+
+ +
+ IC 3.1.1 + +
+ Improvements and New Features + + +

Improvements on error report on unsupported types by

+

propagating warning when declaring unions in C -backends

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

A bug is fixed when arrays that contained variable size data + on C-backends

+

The compiler generated erroneous code when IDL + defined arrays that contained variable size data such + as strings, variable size structs or sequences.

+

Own Id: OTP-2900

+

+
+ +

A bug is fixed when sequences that contained variable size data + on C_backends

+

The compiler generated erroneous code when IDL + defined arrays that contained variable size data such + as strings, variable size structs or other sequences.

+

Own Id: OTP-2901

+

+
+ +

A bug concerning bounded strings on C-backends is fixed.

+

The compiler generated erroneous code for IDL + defined bounded strings. Syntax errors were generated + in special cases of typdedefined strings.

+

Own Id: OTP-2898

+

+
+ +

A runtime error when sequences that contained integer types is fixed.

+

When C-clients/server that communicated with Erlang clients/servers, + and the data send by Erlang part were a list of small numbers, + the Erlang runtime compacts the list to a string. This caused a + runtime error when sending sequences of integer types and all had + value less than 256.

+

Own Id: OTP-2899

+

+
+ +

An OMG IDL - C mapping problem on enumerant values is fixed.

+

The enumerant values names is now prefixed by the current scope, + as defined in the specification.

+

Own Id: OTP-2902

+

+
+ +

A problem when using constants in array declarations is fixed.

+

Array dimensions declared with constants generated erroneous code.

+

Own Id: OTP-2864

+

+
+
+
+ +
+ Incompatibilities + + +

Changes in C-generation on enumerant values.

+
+
+
+
+ +
+ IC 3.1 +
+ Fixed Bugs and Malfunctions + + +

A bug is fixed on the generated structures.

+

The generated C code for the structures corresponds now + to direct mapping of C-structs.

+

Own Id: OTP-2843

+

+
+
+
+ +
+ Incompatibilities + + +

Included structures inside a struct are no longer pointers.

+
+
+
+
+ +
+ IC 3.0 + +
+ Improvements and New Features + + +

Interface change for C-backends

+

Major interface change. The new interface is CORBA 2.0 + compliant.

+

Own Id: OTP-2845

+

+
+ +

The C-backends functionality is improved

+ + +

Due to interface change and some unneeded error + checks,the C-generated code is fairly optimized.

+
+
+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

Several serious bugs on decoding and memory allocation are fixed.

+
+
+
+ +
+ Incompatibilities + + +

Interface change on the C-backends

+

In order to be CORBA 2.0 compatible, the new version + generates fully incompatible C code.

+
+
+
+
+ +
+ IC 2.5.1 + +
+ Improvements and New Features + + +

A new backend is added : C-server

+

This back-ends can be used to create servers, + compatible to c-clients, and Erlang genserver clients. + The code produced is a collection of functions for + encoding and decoding messages and a switch that coordinates + them. These parts can be used to create other servers as well. + All functions are exported to header files.

+

Own Id: OTP-2713

+

+
+ +

The C-client functionality is improved

+ + +

The static buffer used for input/output is removed along + with the memset function that initiated it. + The new client is at least 20-30 percent faster.

+
+ +

The internal structure of the client is changed. + The client functions are now a collection of encoding + and decoding message functions ruled by a specific + call function. While the basic client generated is + a synchronous client, the exported functions + support the implementation of threaded asynchronous + clients.

+
+ +

The static buffer used for input/output is remove along + with the memset function that initiated it. + The new client is at least 20-30 percent faster.

+
+ +

The code generated is generally improved, warnings are + (almost) eliminated, while no unidentified variable + errors occur.

+
+ +

The IDL types unsigned shorts, shorts, floats are supported now.

+
+ +

All generated functions are exported in client header files..

+
+
+

Own Id: OTP-2712

+

+
+
+
+ +
+ Changes in compiler usage and code generation. + + +

A new option is added for the C-server back-end : c_server.

+
+ +

A new option is added : scoped_op_calls.

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

A bug oneway operations on erl_corba and erl_genserv that caused + en exit due to internal interface error is fixed.

+
+ +

A bug on oneway operations on c_genserv back-end that caused several + variables to be unidentified is fixed.

+
+
+
+ +
+ Incompatibilities + + +

Interface change on the C-client

+

The client functions are called with two extra variables, a pointer to + an array of char - used for storage and an integer - the array size

+
+ +

The IDL type attribute is disabled, due to some implementation problems.

+
+
+
+
+ +
+ IC 2.1 + +
+ Improvements and New Features + + +

The compiler now provides more in depth information (printouts) when errors occur.

+

In some cases the compiler stops compiling + due to an abnormal exit or incompatible input. + In this situation, a "fatal error" may occur but the compiler will + generate information explaining the problem.

+

Own Id: OTP-2565

+

+
+
+
+
+ +
+ IC 2.0 + +
+ Improvements and New Features + + +

The IDL compiler is now a separate application and is longer a part of Orber.

+
+ +

Pragma handling implementation.

+

Pragma ID, prefix + and version are implemented to agree with CORBA revision + 2.0. The compiler accepts and applies these on the + behavior of the compiled code.

+ In this implementation, + pragmas are accepted by the parser and applied by the use + of ic_pragma functions.

+ All IFR-identity handling now + passes through pragma table. As pragma handling in OMG-IDL + is affecting the identity of an ifr-object, all identity + handling and registration is now controlled by pragma + functions. A hash table called "pragmatab" contains vital + identity information used under compilation.

+

+

There two major pragma categories :

+ + +

Normal pragmas, are used in the code where + basic definitions and statements appear.

+
+ +

Under certain circumstances, ugly pragmas can now + appear inside code, parameter lists, structure + definitions ... etc.

+ It is quite challenging to + allow ugly pragmas, but the effects of unlimited ugly + pragma implementation on the parser can be enormous. + Ugly pragmas can cause the parser source code to + become time consuming and user unreadable.

+ In order + to allow ugly pragmas but not destroy the current + structure of the parser, the use of ugly pragmas is + limited. Multiple pragma directives are allowed + inside parameter lists, unions, exceptions, + enumerated type, structures... as long as they are do not + appear between two keywords or between keywords and + identifiers.

+
+
+

The pragma effect is the same for both scope and basic + pragma rules.

+

When compiling, an IFR-identity + must be looked up several times but by storing identity aliases inside + the pragma table there this an increase in both speed and + flexibility.

+

Own Id: OTP-2128

+

+
+ +

Code for interface inheritance registration for the IFR + registration code .

+

Inherited interfaces can now + be registered as a list of interface descriptions by + entering code for inherited interface registration under + new interface creation. This is achieved by correcting the + function reg2/6 and adding two more functions, + get_base_interfaces/2 and call_fun_str/2

+

Own Id: + OTP-2134

+

+
+ +

IFR registration checks for included IDL files.

+

All top level definitions (with respect to the scope) - + modules, interfaces, constants, types or exceptions - found + in an IDL file are either defined inside the compiled IDL + file or inside included files. + By having an extended registration of all top level + definitions it becomes possible to simply produce checks + for those included by the current IDL file. + A function call include_reg_test/1 is added in all + OE_* files that checks for IFR-registration on all included + IDL files. The code for that function is added inside the + OE_* file, while the function is called under OE_*:OE_register/0 + operation.

+

Own Id: OTP-2138

+

+
+ +

Exception registration under IFR-operation creation.

+

By entering code for exception registration under operation + creation, the exceptions of an operation can be checked now. + This is done by correcting the function get_exceptions/4 + and adding two more functions, excdef/5 and get_EXC_ID/5 + ( the last two are cooperating with the first one and + all three are defined in the module "ictk" ).

+

Own Id: OTP-2102

+

+
+ +

New back-end to IDL compiler : Plain Erlang.

+

The new back-end just translates IDL specifications + to Erlang module calls. No pragmas are allowed.

+

Own Id: OTP-2471

+

+
+ +

New back-end to IDL compiler : generic server.

+

A new back-end that translates IDL specifications + to a standard OTP generic server.

+

Own Id: OTP-2482

+

+
+ +

New back-end to IDL compiler : c client generation

+

A new back-end that translates IDL specifications + to a C API for accessing servers in Erlang.

+

Own Id: OTP-1511

+

+
+ +

All records in generated files reveal own Erlang modules.

+

In Erlang related back-ends, every structure + which generates definition form is a record, + (such as union, struct, exception.... ). These records are + held in a generated Erlang files which + contain functions that reveal record information.

+ + The Erlang file which contain these functions is + named after the scope of the record (similar + to the generated module and interface files).

+ + Three functions are available :

+ + +

tc/0 - returns the record type code,

+
+ +

id/0 - returns the record id,

+
+ +

name - returns the record name.

+
+
+

Own Id: OTP-2473

+

+
+ +

Changes in compiler usage and code generation.

+ + +

New compilation flags. + New flag be ( = back-end ) which is + used by the compiler to choose back-end. + Default back-end is set to erl_corba.

+
+ +

Stub files have an extra function oe_dependency/0 + indicating file dependency. This + helps the user to determine which IDL files should to + be compiled beside the compiled file.

+
+
+

Own Id: OTP-2474

+

+
+ +

The IDL generation for CORBA is changed so standard gen_server return values can be used + from the implementation module. The change is compatible so that old values remain valid.

+

Own Id: OTP-2485

+

+
+ +

It's now possible to generate an API to a CORBA object that accepts + timeout values in the calls in the same manner as gen_server. + The option to the compiler is "timeout".

+

Own Id: OTP-2487

+

+
+
+
+ +
+ Fixed Bugs and Malfunctions + + +

Empty file generation problem is fixed. + When the IDL module definition did not contain + constant definitions, the generated stub file for that module + definition was empty. After checking the module body, + these files will not be generated anymore.

+
+
+
+ +
+ Incompatibilities + + +

Changes in generated files.

+

Stub-files generated by the compiler had + prefix "OE_" and those used by Orber + had also a register/unregister function + called "OE_register"/"OE_unregister" and + a directive "OE_get_interface" passed + to the gen_server. + This made it difficult/irritating to use, + for example call to the register function + in Orber would appear as shown below:

+ + +

'OE_filename':'OE_register'().

+
+
+

This is changed by using the prefix "oe_" + instead for "OE_" for the above. + A registration call in Orber is now written:

+ + +

oe_filename:oe_register().

+
+
+

Own Id: OTP-2440

+

+
+
+
+
+
+ diff --git a/lib/ic/doc/src/part.xml b/lib/ic/doc/src/part.xml new file mode 100644 index 0000000..376a0b3 --- /dev/null +++ b/lib/ic/doc/src/part.xml @@ -0,0 +1,45 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + IC User's Guide + + + 1998-08-07 + 2.1 +
+ +

The IC application is an Erlang implementation of an IDL + compiler.

+
+ + + + + + + + + + +
+ diff --git a/lib/ic/doc/src/part_notes.xml b/lib/ic/doc/src/part_notes.xml new file mode 100644 index 0000000..0aac643 --- /dev/null +++ b/lib/ic/doc/src/part_notes.xml @@ -0,0 +1,37 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Idl Compiler Release Notes + + + 1998-05-06 + 2.1 +
+ +

The IDL + Compiler Application is an Erlang implementation of a compiler for the IDL language. +

+
+ +
+ diff --git a/lib/ic/doc/src/ref_man.gif b/lib/ic/doc/src/ref_man.gif new file mode 100644 index 0000000000000000000000000000000000000000..b13c4efd53ff30209e94a832b9b141aefa01373e GIT binary patch literal 1530 zcmdVZdppw$0KoB|UD(ZKjLpudxl|bD5*~BdW(#wPxjQR!4XwvDQJz|2?rd%yODG+} zTS?d`8$ziw@9efjcbb8~ZJV`F`NeQj-Rb#--RW#!YS zPs_{8OG`^1KYmEb&dp9*T_4@VeSFc{Z zeEIUlix(;Hhy1Lrh+M1f0n>TM(S67S0;;O2u%F4=$ii+~`^0Klrkw{chQc_%8TvSw4P*9Mc zpP!ePmz$fLlanJ52(q)YuU)&AnVEUz%9YEPFK1+AT)K4W;>C;U>FH@{X%{YBNKH*W zfBt+*N=kBaa#B)KVq#)KLPC6e{JC@Ics$E-3+>FMd= z;o5R+g5Q78Vv{ zGTGeR+|10()YOzjBAJ+&7#kZK85t3YL|t879UUD4fq=*3wY9ZzI2;y>)zZ?^)YQaa zFd7;fYHDh#s;Vj~D$2^rC=?2bL?RFfI2;ax!IYGg6crVrP$&cf0fWIH5J*8m0r;Os z`p^I03jpi@P=FC!+v{kk6S6LO_!Iu)95sCwBtcqW%*9y*G+T7kk6cw&i6X!~u9ub^ z(;p_fv9U$vWTl#^q0-1BITpV6n#M{a{we|K$qn8tF1dhi2#U)iChGwf%c>!EMdamI z$h@1HHE$AU0uQ06DJaKq=RDnzU^TZiOigaDbX?9sbbG2Mo zru2uhl#`IQgUVf0v!Xj-d%-$1xRm>;TQmHNwcAfcM=qjwu=nh zQh;0;RMT@!2!f)5xXw7CWD^X8atslf08f~GlvPC&!u3CIvJ6wy=4qhoBAlk74dDIc za5tv{OoL_(_?n6N^K=DFVPbx|J4#5`n`9n$heG9OfAim6K_sx=yuqZzUrzW~%(8B5(t!Xl{Hb0?L6-vF=+wDe8$ zTT`s`Dq0fpfEZM3+{q@m}*YWuf-$-b$k$LLWEZK;Ee|dK!!GAvHA;V z*1da#TyGWrnurc+>Z42^g}P$+dV8CLlZ-G3$5&lvmrHi*;me*Y^_v!=AL*c_d4sqi z`SWVr{)P|6KptK|>YQR5CUyjEppnvPJ-9YQBBMdn(+)quWG#%To7OvoyB^9=`#bkY st1M+qtZTt#!ZD6_9%~hW^bvUb7(Sl{bx5FV=!1r@;+Z6>KNX<-3tg&0LjV8( literal 0 HcmV?d00001 diff --git a/lib/ic/doc/src/ref_man.xml b/lib/ic/doc/src/ref_man.xml new file mode 100644 index 0000000..153b25c --- /dev/null +++ b/lib/ic/doc/src/ref_man.xml @@ -0,0 +1,38 @@ + + + + +
+ + 19982009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + IC Reference Manual + + + 2003-12-16 + PB1 +
+ +

The IC application is an Erlang implementation of an IDL + compiler.

+
+ + + +
+ diff --git a/lib/ic/doc/src/summary.html.src b/lib/ic/doc/src/summary.html.src new file mode 100644 index 0000000..cb92e51 --- /dev/null +++ b/lib/ic/doc/src/summary.html.src @@ -0,0 +1 @@ +IDL compiler diff --git a/lib/ic/doc/src/user_guide.gif b/lib/ic/doc/src/user_guide.gif new file mode 100644 index 0000000000000000000000000000000000000000..e6275a803db46bc56df2b31240f80e68a4eb28b5 GIT binary patch literal 1581 zcmd6mi9gc|0Kk8njctY*W^QwCJ{HX#%4V)-y(i>aMOY|Iy@!%dZA6YGb49u7IpPyu zxpLn_avvd{2!$L^&hlRW#rysR-_Q5+`C8dn8X8V>k`j;wKQ1gR%+Jry&CSiu&d$utOixe0fB$}JYHD(Fa$;g)e0+Rt zY;1INbYx^?czAedXlQV7@ZGz20|Nv7{r!D?eZ9TCJRYy7r>DESyQ{0Kv$M0KqocjO zy{)aSwY9aSrKP#Kxv8nCv9YnCq2bM&H}&=Pb#-;MwY4=hHPzMCuV25es;a82tgNW0 zc=_^WSy|bO7cWXnOG`>hii?Yjii!#g3kwPg^7Hfa^73+Xb8~WXva_?Zva&KWGoL+s z_Vnq~jEs!*^z{(M&Qxg*t zV`JkpXU-TI85tTH>g((4>FMd}>gwp|kVqtLZEYmX?x|!eX(Kl9CtEE3!%>OGRc>9)Rn&SYM zj~Y~*8(l`PO4G;6R;FqaD@X#~VMifcR)pt=DvF{Q3(>@Ud>(7)(V4{v)PmxVK~kPo zjj~AEyr<1v8vx#~Tk98U5_J`0L}~fU>RjhaAKM=MUf{g5m?T z)+IHOf7l%`QALwKCeyDj6SLD45WBagBU?Fw4{df%%9E4Y2u)Wk*W$nyCUXV^5gf*w zJcTmdm_5ACzSYODr)n2;x_FnPc`B(M`LXIbz9g71J`3n))Gq$bQK+sRivkPkZkj>F zXejb80{#?f()6mQl&jOcTB0m7HQ)B0eJ!3!3LG1z5Dy4!8UDX&qmZHiEZH4hCN$qe z4*)g+{|y}64a+3k1Ar7VS%DkXnyczs>8pr>ch^qPgriJZarAD;X*)P0t_Uea!m)bj zekgBBW+6d2l7{g|`zZIq7r_Y&symb`GN>UKUQ)c!TxUa0r_Gumy9Jeti%E)uL##a# zMGizq*jB%VA7Ip@(A3hq9YH69qL7NjkWRA2q5;hU`xYmEN)bB>aqrz!?T?Ynv*X-7 zk5PfTmt$8kTF6UOKy_o?XHYzxtkg%ZbG*StHxDNDsyD5c2a>x5vWvVCApVgu@XNF$})`XD-pCH3`9zE-Lj6@!*TS9lwVaP}h|-H2`m~ItYQE$0z|a zt4=D`BBR~(5MZ;L{+LQk#4$5Kz`eloKZBK-7eFm?OlZCy;GH~%L;($J;|e#tww(~b et1Zl|+ha7@T8X2%4FJEoWS?mjDfbqXtih~yb literal 0 HcmV?d00001 diff --git a/lib/ic/ebin/.gitignore b/lib/ic/ebin/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/ic/examples/all-against-all/Makefile b/lib/ic/examples/all-against-all/Makefile new file mode 100644 index 0000000..a71099e --- /dev/null +++ b/lib/ic/examples/all-against-all/Makefile @@ -0,0 +1,117 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Point this at your version of OTP +OTPROOT=/usr/local/otp/releases/otp_beam_sunos5_r7a + +# Type actual IC Version +ICVSN=4.0.4 + +# Type actual Erl Interface Vesrion +EIVSN=3.2.2 + +# Type actual Erl Interface Vesrion +JIVSN=1.2 + +# IDL file(s) +IDLS=random.idl + +# Own C-server files +CSRV=server callbacks + +# Own C-client files +CCL=client + +# Generated C-server files +GCSRVS=rmod_random__s + +# Generated C-server files +GCCLS=rmod_random + +# Includes +IFLAGS=-I$(OTPROOT)/lib/ic-$(ICVSN)/include \ + -I$(OTPROOT)/lib/erl_interface-$(EIVSN)/include + +LDFLAGS=-L$(OTPROOT)/lib/ic-$(ICVSN)/priv/lib \ + -L$(OTPROOT)/lib/erl_interface-$(EIVSN)/lib + +LDLIBS=-lic -lerl_interface -lei -lnsl -lsocket + + +# Erlang compiler +ERLC=$(OTPROOT)/bin/erlc + +# Erlang compiler flags. +EFLAGS='+{scoped_op_calls,true}' + +# C compiler +CC=gcc + +# C compiler flags +CFLAGS=-ggdb -O2 -Wall $(IFLAGS) + +# Java compiler +JAVAC=javac + +CLASSPATH= "./:$(OTPROOT)/lib/ic-$(ICVSN)/priv/ic.jar:$(OTPROOT)/lib/jinterface-$(JIVSN)/priv/OtpErlang.jar" +JFLAGS=-classpath $(CLASSPATH) -O + +JGENJFILES = \ + ./rmod/_randomImplBase.java \ + ./rmod/random.java \ + ./rmod/randomHolder.java \ + ./rmod/_randomStub.java \ + ./rmod/randomHelper.java + + +all: server client eall jall + + +server: + $(ERLC) $(EFLAGS) '+{be,c_server}' $(IDLS) + $(CC) $(IFLAGS) -c $(CSRV:=.c) $(GCSRVS:=.c) + $(CC) $(CSRV:=.o) $(GCSRVS:=.o) -o $@ $(LDFLAGS) $(LDLIBS) + +client: + $(ERLC) $(EFLAGS) '+{be,c_client}' $(IDLS) + $(CC) $(IFLAGS) -c $(CCL:=.c) $(GCCLS:=.c) + $(CC) $(CCL:=.o) $(GCCLS:=.o) -o $@ $(LDFLAGS) $(LDLIBS) + +eall: + $(ERLC) $(EFLAGS) '+{be,erl_genserv}' $(IDLS) + $(ERLC) *.erl + +jall: + $(ERLC) $(EFLAGS) '+{be,java}' $(IDLS) + $(JAVAC) $(JFLAGS) */*.java *.java + + +clean: + /bin/rm -rf $(GCCLS:=.o) $(GCCLS:=.c) $(GCSRVS:=.o) $(GCSRVS:=.c) $(CCL:=.o) $(CSRV:=.o) rmod.erl rmod_random.erl *.jam *.beam oe* *.h *.hrl *~ core server client *.class + + + + + + + + + + + diff --git a/lib/ic/examples/all-against-all/Makefile.win32 b/lib/ic/examples/all-against-all/Makefile.win32 new file mode 100644 index 0000000..0085a85 --- /dev/null +++ b/lib/ic/examples/all-against-all/Makefile.win32 @@ -0,0 +1,138 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Point this at your version of OTP +OTPROOT=c:\Progra~1\erl5.0.1\ + +# Type actual IC Version +ICVSN=4.0.4 + +# Type actual Erl Interface Vesrion +EIVSN=3.2.2 + +# Type actual Erl Interface Vesrion +JIVSN=1.2 + +# IDL file(s) +IDLS=random.idl + +# Own C-server files +CSRV=server.c callbacks.c +CSRVO=server.obj callbacks.obj + +# Own C-client files +CCL=client.c +CCLO=client.obj + +# Generated C-server files +GCSRVS=rmod_random__s.c +GCSRVSO=rmod_random__s.obj + +# Generated C-client files +GCCLS=rmod_random.c +GCCLSO=rmod_random.obj + +# Includes +IFLAGS=-I"$(OTPROOT)\lib\ic-$(ICVSN)\include" \ + -I"$(OTPROOT)\lib\erl_interface-$(EIVSN)\include" + +LDFLAGS=/LIBPATH:"$(OTPROOT)\lib\ic-$(ICVSN)\priv\lib" \ + /LIBPATH:"$(OTPROOT)\lib\erl_interface-$(EIVSN)\lib" + +LDLIBS=ic.lib erl_interface.lib ei.lib ws2_32.lib + + +# Erlang compiler +ERLC=$(OTPROOT)\bin\erlc + +# Erlang compiler flags. +EFLAGS="+{scoped_op_calls,true}" + + +# C compiler +CC=cl + +# C compiler flags +CFLAGS=-MT -D__WIN32__ $(IFLAGS) + + +# Java compiler +JAVAC=c:\Progra~1\jdk1.3\bin\javac + +# Java +JAVA=c:\Progra~1\jdk1.3\bin\java + + +# Java compiler flags +CLASSPATH= ".;$(OTPROOT)\lib\ic-$(ICVSN)\priv\ic.jar;$(OTPROOT)\lib\jinterface-$(JIVSN)\priv\OtpErlang.jar" +JFLAGS=-classpath $(CLASSPATH) -O + + +all: server.exe client.exe client.beam client.class + + +server.exe: + $(ERLC) $(EFLAGS) "+{be,c_server}" $(IDLS) + $(CC) -c $(CFLAGS) $(CSRV) $(GCSRVS) + $(CC) -o server.exe $(CSRVO) $(GCSRVSO) -link $(LDFLAGS) $(LDLIBS) + + +client.exe: + $(ERLC) $(EFLAGS) "+{be,c_client}" $(IDLS) + $(CC) -c $(CFLAGS) $(CCL) $(GCCLS) + $(CC) -o client.exe $(CCLO) $(GCCLSO) -link $(LDFLAGS) $(LDLIBS) + +client.beam: + $(ERLC) $(EFLAGS) "+{be,erl_genserv}" $(IDLS) + $(ERLC) *.erl + +client.class: + $(ERLC) $(EFLAGS) "+{be,java}" $(IDLS) + $(JAVAC) $(JFLAGS) rmod/*.java + $(JAVAC) $(JFLAGS) *.java + +jclient.run: + $(JAVA) -classpath $(CLASSPATH) client + +jserver.run: + $(JAVA) -classpath $(CLASSPATH) server + + +clean: + -@del /f /q rmod + -@rmdir rmod + -@del *.jam + -@del *.beam + -@del oe* + -@del *.h + -@del *.hrl + -@del server.exe + -@del client.exe + -@del *.obj + -@del rmod_random*.c + -@del *~ + -@del *class + -@del rmod.erl + -@del rmod_random.erl + + + + + + diff --git a/lib/ic/examples/all-against-all/ReadMe b/lib/ic/examples/all-against-all/ReadMe new file mode 100644 index 0000000..7503291 --- /dev/null +++ b/lib/ic/examples/all-against-all/ReadMe @@ -0,0 +1,122 @@ +This is a short description on the use of Erlang,C or Java +client and servers against each other. +The base is a client that initiates and uses a random number +generator that lies on an server. + +There are two make files, one for Unix and one for Windows, +the Unix make file is just named "Makefile", while the Windows +is named "Makefile.win32". + +Instructions. + +1) On Makefile : + * Modify the OTPROOT variable on the Makefile to point + to the root for your erlang instalation. + * Modify IC and Erl_Interface versions to agree your + OTP version. + +2) Type "make" to build the example. + + +3) Start the empd deamon by using the command : + + epmd -daemon + + +4) Do this when you want to run : + + * an Erlang server. + + Start erlang with the options + + -setcookie -sname + + In this example you should use : + + erl -setcookie flash -sname babbis + + * a C server. + + Just type : + + server + + * a Java server. + + Set and export the CLASSPATH variable to + point to the java classes located in java development kit, + the Otp's classes and the current directory. + Your classpath should look like this : + + .:/lib/ic-3.8.1/priv/ic.jar:/lib/jinterface_0.9.2/priv/OtpErlang.jar + + where : + + is the location there OTP is installed + + Then type : + + java server + + +5) Do this when you want to run : + + * an Erlang client. + + ** If you have no valid named erlang node, + start erlang with the options + + -setcookie -sname + + In this example you should use : + + erl -setcookie flash -sname client + + On the erlang shell, type + + client:start(). + + ** If you have a valid named erlang node, started + whith the same "cookie", on the erlang shell, type + + client:start(). + + + * a C client, just type + + client + + + * a Java client. + + + Set and export the CLASSPATH variable to + point to the java classes located in java development kit, + the Otp's classes and the current directory. + Your classpath should look like this : + + .:/lib/ic-4.0/priv/ic.jar:/lib/jinterface_1.1/priv/OtpErlang.jar + + where : + + is the location there OTP is installed + + Then type : + + java client + + + +6) Please note that : + + * you must always have the same cookie in order to eastablish connection + between clients and servers. + + * you cannot start two servers with the same name. + In this example all servers share the same name in order to test + several constallations. Kill a server before starting another one. + + + + + diff --git a/lib/ic/examples/all-against-all/callbacks.c b/lib/ic/examples/all-against-all/callbacks.c new file mode 100644 index 0000000..f8642f4 --- /dev/null +++ b/lib/ic/examples/all-against-all/callbacks.c @@ -0,0 +1,45 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ + +#include +#include "rmod_random__s.h" + + +rmod_random_produce__rs* +rmod_random_produce__cb(rmod_random oe_obj, double *rs, CORBA_Environment *oe_env) + +{ + *rs = (double) rand(); + + return (rmod_random_produce__rs*) NULL; +} + + +rmod_random_init__rs* +rmod_random_init__cb(rmod_random oe_obj, long* seed1, long* seed2, long* seed3, CORBA_Environment *oe_env) + +{ + srand(*seed1 * *seed2 * *seed3); + + return (rmod_random_init__rs*) NULL; +} + + + diff --git a/lib/ic/examples/all-against-all/client.c b/lib/ic/examples/all-against-all/client.c new file mode 100644 index 0000000..e0a52b1 --- /dev/null +++ b/lib/ic/examples/all-against-all/client.c @@ -0,0 +1,153 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ + +/* Just include the interface function */ +#include "rmod_random.h" + + +/* Assign your own node name here */ +#define CLNODENAME "c50" +#define SNODENAME "babbis" +#define SREGNAME "rmod_random_impl" +#define COOKIE "flash" +#define INBUFSZ 1024 +#define OUTBUFSZ 1024 +#define HOSTNAMESZ 256 + + + +/* Stopping node */ +void client_exit(CORBA_Environment *env) { + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + + erl_close_connection(env->_fd); + exit(1); +} + + +int main(){ + + double result=0; + int i=0; + int error = 0; + erlang_pid pid; + char host[HOSTNAMESZ]; + char server_node[HOSTNAMESZ]; + char client_node[HOSTNAMESZ]; + CORBA_Environment *env; + + /* Initiate names */ +#ifdef __WIN32__ + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(1, 1); + if ((error = WSAStartup(wVersionRequested, &wsaData))) { + fprintf(stderr,"Can't initialize windows sockets: %d",error); + return 0; + } +#endif + error = gethostname(host,HOSTNAMESZ); + if (error) { +#ifdef __WIN32__ + fprintf(stderr,"can't find own hostname (error = %ld) !\n",WSAGetLastError()); +#else /* not __WIN32__ */ + fprintf(stderr,"can't find own hostname !\n"); +#endif + } + sprintf(client_node,"%s@%s",CLNODENAME,host); + sprintf(server_node,"%s@%s",SNODENAME,host); + + /* Create and init CORBA_Environment */ + env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ); + + /* Initiating the connection */ + erl_init(NULL,0); + erl_connect_init(50,COOKIE,0); + + /* Initiating pid*/ + strcpy(pid.node,client_node); + pid.num = 99; + pid.serial = 0; + pid.creation = 0; + + /* Fixing environment variable */ + env->_fd=erl_connect(server_node); + strcpy(env->_regname,SREGNAME); + env->_to_pid = NULL; + env->_from_pid = &pid; + + if (env->_fd < 0) { + fprintf(stderr,"Error : Cannot connect to Server\n"); + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + exit(1); + } + + /* Calling the init function */ + rmod_random_init(NULL, 1, 2, 3, env); + + switch(env->_major) { + case CORBA_NO_EXCEPTION: /* Success */ + printf("Init complete !\n"); + break; + case CORBA_SYSTEM_EXCEPTION: /* System exception */ + printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + client_exit(env); + default: /* Should not come here */ + client_exit(env); + } + + /* Calling the produce function */ + for(i=1; i<=10; i++) { + result = rmod_random_produce(NULL, env); + + switch(env->_major) { + case CORBA_NO_EXCEPTION: /* Success */ + break; + case CORBA_SYSTEM_EXCEPTION: /* System exception */ + printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + client_exit(env); + default: /* Should not come here */ + client_exit(env); + } + + printf("the random number nr%d is %f\n",i,result); + } + + /* Closing the connection */ + erl_close_connection(env->_fd); + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + + return 0; +} diff --git a/lib/ic/examples/all-against-all/client.erl b/lib/ic/examples/all-against-all/client.erl new file mode 100644 index 0000000..921c2c9 --- /dev/null +++ b/lib/ic/examples/all-against-all/client.erl @@ -0,0 +1,53 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : client.erl +%% Purpose : +%%---------------------------------------------------------------------- + +-module(client). + +-export([produce/0,init/3,call/0]). + +-define(SERVER,{rmod_random_impl, + list_to_atom("babbis@"++hd(tl(string:tokens(atom_to_list(node()),"@"))))}). +-define(CLIENTMOD,'rmod_random'). + +produce() -> + ?CLIENTMOD:produce(?SERVER). + + +init(Seed1, Seed2, Seed3) -> + io:format("Init..."), + ?CLIENTMOD:init(?SERVER,Seed1, Seed2, Seed3), + io:format("ok\n"). + + +call() -> + init(1,2,3), + produce(0). + + +produce(10) -> + ok; +produce(Ctr) -> + N = produce(), + io:format("Random~p = ~p\n",[Ctr,N]), + produce(Ctr+1). diff --git a/lib/ic/examples/all-against-all/client.java b/lib/ic/examples/all-against-all/client.java new file mode 100644 index 0000000..4dc88cf --- /dev/null +++ b/lib/ic/examples/all-against-all/client.java @@ -0,0 +1,60 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +public class client { + + private static java.lang.String SNode = "client"; + private static java.lang.String PNode = "babbis"; + private static java.lang.String Cookie = "flash"; + private static java.lang.String Server = "rmod_random_impl"; + + private static rmod._randomStub stub; + + public static void main(String[] args) { + + try { + + stub = new rmod._randomStub(SNode,PNode,Cookie,Server); + int seed1 = 1; + int seed2 = 2; + int seed3 = 3; + double random = 0; + + System.out.print("\nClient initialization...."); + stub.init(seed1,seed2,seed3); + System.out.println("ok\n"); + + + for (int i = 0; i < 10; i++) { + random = stub.produce(); + System.out.println("Random" + i + " = " + random); + } + System.out.println("\nClient terminated.\n"); + + stub.__disconnect(); + + } catch( Exception e) { + System.out.println("Exception :"); + e.printStackTrace(); + } + + } + +} + diff --git a/lib/ic/examples/all-against-all/random.idl b/lib/ic/examples/all-against-all/random.idl new file mode 100644 index 0000000..b44f737 --- /dev/null +++ b/lib/ic/examples/all-against-all/random.idl @@ -0,0 +1,50 @@ +// ``The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved via the world wide web at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// The Initial Developer of the Original Code is Ericsson Utvecklings AB. +// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +// AB. All Rights Reserved.'' +// +// $Id$ +// + +#ifndef _RANDOM_IDL +#define _RANDOM_IDL + +module rmod { + + interface random { + + double produce(); + + oneway void init(in long seed1, in long seed2, in long seed3); + + }; + +}; + + +#endif + + + + + + + + + + + + + + + diff --git a/lib/ic/examples/all-against-all/rmod_random_impl.erl b/lib/ic/examples/all-against-all/rmod_random_impl.erl new file mode 100644 index 0000000..8113cfb --- /dev/null +++ b/lib/ic/examples/all-against-all/rmod_random_impl.erl @@ -0,0 +1,48 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(rmod_random_impl). +-export([init/1, terminate/2]). +-export([produce/1,init/4]). + + +init(Env) -> + {ok, []}. + +terminate(From, Reason) -> + ok. + + +produce(_Random) -> + case catch random:uniform() of + {'EXIT',_} -> + true; + RUnif -> + {reply,RUnif,[]} + end. + + +init(_Random,S1,S2,S3) -> + case catch random:seed(S1,S2,S3) of + {'EXIT',_} -> + true; + _ -> + {noreply,[]} + end. + diff --git a/lib/ic/examples/all-against-all/server.c b/lib/ic/examples/all-against-all/server.c new file mode 100644 index 0000000..be4953e --- /dev/null +++ b/lib/ic/examples/all-against-all/server.c @@ -0,0 +1,261 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ + +#include +#include +#include +#include +#ifdef __WIN32__ +#include +#include +#include +#include +#else /* not __WIN32__ */ +#include +#include +#include +#include +#include +#include +#endif +#include "rmod_random__s.h" + +/* Used functions */ +static int getport(int sockd); +static int getlisten(int port); +static int init(int *sd, int *portnr, int *epmd_fd); +void terminate(int *fd, int *sd, int *epmd_fd); +static void server_loop(int fd, int sd); + +/* change these, or even better, make command-line args to program... */ +#define COOKIE "flash" +#define SERVER "babbis" +#define NODENAMESZ 512 +#define HOSTNAMESZ 256 +#define INBUFSZ 1024 +#define OUTBUFSZ 1024 + + +int main(int argc, char **argv) +{ + int sd; + int portnr; + int epmd_fd; + + /* crate file descriptors */ + if (init(&sd, &portnr, &epmd_fd) < 0) + return -1; + + /* start server loop */ + server_loop(sd,epmd_fd); + + return 0; +} + + + +static void server_loop(int sd, int epmd_fd) +{ + ErlConnect conn; + erlang_msg msg; + int status=1; + CORBA_Environment *env; + + /* Create and init CORBA_Environment */ + env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ); + + while (status >= 0) { + + status = 1; + + if ((env->_fd = erl_accept(sd,&conn)) < 0) { + /* error */ + fprintf(stderr,"Accept failed: %s\n",strerror(errno)); + } + else { + /* connection */ + fprintf(stderr,"Accepted connection from %s\n",conn.nodename); + + while (status >= 0) { + + /* write message to buffer */ + status = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz, &msg, &env->_iin); + switch(status) { + case ERL_SEND: + case ERL_REG_SEND : + /* do transaction with fd */ + rmod_random__switch(NULL,env); + + switch(env->_major) { + case CORBA_NO_EXCEPTION: /* Success */ + break; + case CORBA_SYSTEM_EXCEPTION: /* System exception */ + printf("Request failure, reason : %s\n",(char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + break; + default: /* Should not come here */ + CORBA_exception_free(env); + break; + } + + /* send outdata */ + if (env->_iout > 0) + ei_send_encoded(env->_fd,&env->_caller,env->_outbuf,env->_iout); + break; + + case ERL_TICK : + break; + default : /* < 0 */ + printf("Connection terminated\n"); + break; + } + } + } + status=0; /* restart */ + } + + /* close file descriptors */ + terminate(&env->_fd, &sd, &epmd_fd); + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); +} + + + +static int init(int *sd, int *portnr, int *epmd_fd) +{ + char host[HOSTNAMESZ]; + char servernode[NODENAMESZ]; + struct hostent *h; + int error = 0; + +#ifdef __WIN32__ + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(1, 1); + if ((error = WSAStartup(wVersionRequested, &wsaData))) { + fprintf(stderr,"Can't initialize windows sockets: %d",error); + } +#endif + /* get the host name */ + error = gethostname(host,HOSTNAMESZ); + if (error) { +#ifdef __WIN32__ + fprintf(stderr,"can't find own hostname (error = %ld) !\n",WSAGetLastError()); +#else /* not __WIN32__ */ + fprintf(stderr,"can't find own hostname !\n"); +#endif + } + else { + /* identify host */ + if (!(h = erl_gethostbyname(host))) + fprintf(stdout,"can't find own ip address\n"); + else { + + /* get a listen port. 0 means let system choose port number */ + *sd = getlisten(0); + + /* what port did we get? */ + /* this call not necessary if we specified port in call to getlisten() */ + *portnr = getport(*sd); + + /* make the nodename server@host */ + sprintf(servernode,"%s@%s",SERVER,host); + + /* initiate */ + erl_init(NULL,0); + + /* host, alive, alive@host, addr, cookie, creation */ + erl_connect_xinit(host,SERVER,servernode,(Erl_IpAddr)(h->h_addr_list[0]),COOKIE,0); + + /* let epmd know we are here */ + *epmd_fd = erl_publish(*portnr); + + return 0; + } + } + return -1; +} + + +void terminate(int *fd, int *sd, int *epmd_fd) { + + close(*fd); + + /* remove info from epnd */ + close(*epmd_fd); + + /* return socket */ + close(*sd); + +} + + + +/* tells you what port you are using on given socket */ +static int getport(int sockd) +{ + struct sockaddr_in addr; + int namelen = sizeof(addr); + int i; + + memset(&addr,0,sizeof(addr)); + + if ((i = getsockname(sockd,(struct sockaddr *)&addr,&namelen))<0) + return i; + + return ntohs(addr.sin_port); +} + + + +/* return a listen socket, bound to given port */ +/* specify port = 0 to let system assign port */ +static int getlisten(int port) +{ + int sockd; + struct sockaddr_in inaddr; + int opt = 1; + int i; + + /* get listen socket */ + if ((sockd = socket(AF_INET,SOCK_STREAM,0)) < 0) return sockd; + + if ((i=setsockopt(sockd,SOL_SOCKET,SO_REUSEADDR,(void *)&opt,sizeof(opt)))<0) + return i; + + /* bind to requested port */ + memset(&inaddr,0,sizeof(inaddr)); + inaddr.sin_family = AF_INET; + inaddr.sin_addr.s_addr = htonl(INADDR_ANY); + inaddr.sin_port = htons(port); + + if ((i = bind(sockd,(struct sockaddr*) &inaddr, sizeof(inaddr))) < 0) + return i; + + listen(sockd,5); + + return sockd; +} + diff --git a/lib/ic/examples/all-against-all/server.erl b/lib/ic/examples/all-against-all/server.erl new file mode 100644 index 0000000..24ace2e --- /dev/null +++ b/lib/ic/examples/all-against-all/server.erl @@ -0,0 +1,40 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(server). +-export([start/0]). + + + +%% This starts up the random number server +start() -> + %% Start the gen server + {ok,Pid} = rmod_random:oe_create([],{local,'rmod_random_impl'}), + true. + + + + + + + + + + + diff --git a/lib/ic/examples/all-against-all/server.java b/lib/ic/examples/all-against-all/server.java new file mode 100644 index 0000000..6b5fe8f --- /dev/null +++ b/lib/ic/examples/all-against-all/server.java @@ -0,0 +1,82 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +public class server { + + private static java.lang.String SNode = "babbis"; + private static java.lang.String Cookie = "flash"; + private static java.lang.String RegName = "rmod_random_impl"; + + public static void main(String[] args) { + + + System.out.println("\nServer running.\n"); + boolean serverState = true; + boolean recState = true; + + try { + + com.ericsson.otp.erlang.OtpServer self = new com.ericsson.otp.erlang.OtpServer(SNode, Cookie); + self.publishPort(); + + /* Server loop */ + while(serverState == true) { + + com.ericsson.otp.erlang.OtpConnection connection = self.accept(); + serverImpl srv = new serverImpl(); + com.ericsson.otp.erlang.OtpInputStream request; + com.ericsson.otp.erlang.OtpOutputStream reply; + com.ericsson.otp.erlang.OtpErlangPid client; + + /* Server loop */ + while(recState == true) { + + if (connection.isConnected() == true) + try { + + request = connection.receiveBuf(); + + reply = srv.invoke(request); + + if (reply != null) { + client = srv.__getCallerPid(); + + connection.sendBuf(client,reply); + } + + } catch( Exception e) { + System.out.println("Server terminated.\n\n"); + recState = false; + serverState = false; + } + } + + connection.close(); + } + + } catch( Exception e) { + System.out.println("Initialization exception :"); + e.printStackTrace(); + } + } +} + + + + diff --git a/lib/ic/examples/all-against-all/serverImpl.java b/lib/ic/examples/all-against-all/serverImpl.java new file mode 100644 index 0000000..d5fb66e --- /dev/null +++ b/lib/ic/examples/all-against-all/serverImpl.java @@ -0,0 +1,42 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +public class serverImpl extends rmod._randomImplBase { + + java.util.Random random = null; + + + public void init(int seed1, int seed2, int seed3) throws java.lang.Exception { + + random = new java.util.Random(seed1+seed2+seed3); + }; + + + public double produce() throws java.lang.Exception { + + return random.nextDouble(); + } + +} + + + + + + diff --git a/lib/ic/examples/c-client/Makefile b/lib/ic/examples/c-client/Makefile new file mode 100644 index 0000000..7c57e4f --- /dev/null +++ b/lib/ic/examples/c-client/Makefile @@ -0,0 +1,86 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Point this at your version of OTP +OTPROOT=/usr/local/otp/daily_build/otp_beam_sunos5_r8a.latest + +# Type actual IC Version +ICVSN=4.1.1 + +# Type actual Erl Interface Vesrion +EIVSN=3.3.0 + +# IDL file(s) +IDLS=random.idl + +# Own C-client files +CCL=client + +# Generated C-server files +GCCLS=oe_code_seed rmod_random + +# Includes +IFLAGS=-I$(OTPROOT)/lib/ic-$(ICVSN)/include \ + -I$(OTPROOT)/lib/erl_interface-$(EIVSN)/include + +LDFLAGS=-L$(OTPROOT)/lib/ic-$(ICVSN)/priv/lib \ + -L$(OTPROOT)/lib/erl_interface-$(EIVSN)/lib + +LDLIBS=-lic -lerl_interface -lei -lnsl -lsocket + + +# Erlang compiler +ERLC=$(OTPROOT)/bin/erlc + +# Erlang compiler flags. +EFLAGS='+{preproc_flags,"-I $(OTPROOT)/usr/include"}' '+{scoped_op_calls,true}' + + +# C compiler +CC=gcc + +# C compiler flags +CFLAGS=-ggdb -O2 -Wall $(IFLAGS) + + +all: server client + + +server: + $(ERLC) $(EFLAGS) '+{be,erl_genserv}' $(IDLS) + $(ERLC) *.erl + +client: + $(ERLC) $(EFLAGS) '+{be,c_client}' $(IDLS) + $(CC) $(IFLAGS) -c $(CCL:=.c) $(GCCLS:=.c) + $(CC) $(CCL:=.o) $(GCCLS:=.o) -o $@ $(LDFLAGS) $(LDLIBS) + + + +clean: + /bin/rm -f $(GCCLS:=.o) $(GCCLS:=.c) $(CCL:=.o) *.jam *.beam oe* rmod_random.erl *.h *.hrl *~ core client + + + + + + + + + diff --git a/lib/ic/examples/c-client/ReadMe b/lib/ic/examples/c-client/ReadMe new file mode 100644 index 0000000..28372c3 --- /dev/null +++ b/lib/ic/examples/c-client/ReadMe @@ -0,0 +1,46 @@ +This is a short description on the use of the c-client demo, +a client that initiates and uses a random number generator +that lies on an Erlang-genserver. + +Instructions. + +1) On Makefile : + * Modify the OTPROOT variable on the Makefile to point + to the root for your erlang instalation. + * Modify IC and Erl_Interface versions to agree your + OTP version. + +2) Type "make" to build the example. + + +3) Start erlang with the options + -setcookie -sname + + In this example you should use : + + erl -setcookie flash -sname babbis + + +4) On the erlang shell type : + -------------------------- + + rmod_random:oe_create([],{local,rmod_random_impl}). ( initializes the server ) + + or + + test:start(). + + + Then start a new terminal window and type : + ------------------------------------------- + + client ( calls the client ) + + + + + + + + + diff --git a/lib/ic/examples/c-client/client.c b/lib/ic/examples/c-client/client.c new file mode 100644 index 0000000..816477c --- /dev/null +++ b/lib/ic/examples/c-client/client.c @@ -0,0 +1,130 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ + +/* Include the interface function and ei_connect */ +#include "rmod_random.h" +#include "ei_connect.h" + +/* Assign your own node name here */ +#define SNODE "babbis@balin" +#define SERVER "rmod_random_impl" +#define COOKIE "flash" +#define CLNODE "c47@balin" +#define INBUFSZ 1024 +#define OUTBUFSZ 1024 + +/* Stopping node */ +void client_exit(CORBA_Environment *env) { + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + + close(env->_fd); + exit(1); +} + +int main() +{ + double result=0; + int i=0; + erlang_pid pid; + CORBA_Environment *env; + seed idata; + ei_cnode ec; + + /* Create and init CORBA_Environment */ + env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ); + + /* Initialize seed */ + idata.seed1 = 1; + idata.seed2 = 2; + idata.seed3 = 3; + + /* Initiating the connection */ + ei_connect_init(&ec, "c47", COOKIE, 0); + + /* Initiating pid*/ + strcpy(pid.node,CLNODE); + pid.num = 99; + pid.serial = 0; + pid.creation = 0; + + /* Fixing environment variable */ + env->_fd = ei_connect(&ec, SNODE); + strcpy(env->_regname, SERVER); + env->_to_pid = NULL; + env->_from_pid = &pid; + + if (env->_fd < 0) { + fprintf(stderr,"Error : Cannot connect to Server\n"); + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + exit(1); + } + + /* Calling the init function */ + rmod_random_init(NULL, &idata, env); + + switch(env->_major) { + case CORBA_NO_EXCEPTION: /* Success */ + printf("Init complete !\n"); + break; + case CORBA_SYSTEM_EXCEPTION: /* System exception */ + printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + client_exit(env); + default: /* Should not come here */ + client_exit(env); + } + + /* Calling the produce function */ + for(i=1; i<=10; i++) { + result = rmod_random_produce(NULL, env); + + switch(env->_major) { + case CORBA_NO_EXCEPTION: /* Success */ + break; + case CORBA_SYSTEM_EXCEPTION: /* System exception */ + printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + client_exit(env); + default: /* Should not come here */ + client_exit(env); + } + + printf("the random number nr%d is %f\n",i,result); + } + + /* Closing the connection */ + close(env->_fd); + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + + return 0; +} + diff --git a/lib/ic/examples/c-client/random.idl b/lib/ic/examples/c-client/random.idl new file mode 100644 index 0000000..cfe38e3 --- /dev/null +++ b/lib/ic/examples/c-client/random.idl @@ -0,0 +1,51 @@ +// ``The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved via the world wide web at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// The Initial Developer of the Original Code is Ericsson Utvecklings AB. +// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +// AB. All Rights Reserved.'' +// +// $Id$ +// +#ifndef _RANDOM_IDL +#define _RANDOM_IDL + +struct seed { + long seed1; + long seed2; + long seed3; +}; + +module rmod { + + interface random { + + double produce(); + + oneway void init(in seed idata); + + }; + +}; + +#endif + + + + + + + + + + + + diff --git a/lib/ic/examples/c-client/rmod_random_impl.erl b/lib/ic/examples/c-client/rmod_random_impl.erl new file mode 100644 index 0000000..863e3e8 --- /dev/null +++ b/lib/ic/examples/c-client/rmod_random_impl.erl @@ -0,0 +1,52 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module('rmod_random_impl'). +-include("oe_random.hrl"). +-export([init/1, terminate/2]). +-export([produce/1,init/2]). + + +init(Env) -> + {ok, []}. + +terminate(From, Reason) -> + ok. + + +produce(_Random) -> + case catch random:uniform() of + {'EXIT',_} -> + true; + RUnif -> + {reply,RUnif,[]} + end. + + +init(_Random,IData) -> + S1 = IData#seed.seed1, + S2 = IData#seed.seed2, + S3 = IData#seed.seed3, + case catch random:seed(S1,S2,S3) of + {'EXIT',_} -> + true; + _ -> + {noreply,[]} + end. + diff --git a/lib/ic/examples/c-client/test.erl b/lib/ic/examples/c-client/test.erl new file mode 100644 index 0000000..0a05ce2 --- /dev/null +++ b/lib/ic/examples/c-client/test.erl @@ -0,0 +1,43 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +% Start Erlang with : erl -sname -setcookie + +-module(test). + +-export([start/0,exec/0]). + + +start() -> + io:format("Starting server~n"), + rmod_random:oe_create([],{local,'rmod_random_impl'}). + +exec() -> + io:format("Running client~n"), + OutPut = os:cmd("client"), + io:format("~s",[OutPut]). + + + + + + + + + diff --git a/lib/ic/examples/c-server/Makefile b/lib/ic/examples/c-server/Makefile new file mode 100644 index 0000000..caf4306 --- /dev/null +++ b/lib/ic/examples/c-server/Makefile @@ -0,0 +1,89 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Point this at your version of OTP +OTPROOT=/usr/local/otp/daily_build/otp_beam_sunos5_r8a.latest + +# Type actual IC Version +ICVSN=4.1.1 + +# Type actual Erl Interface Vesrion +EIVSN=3.3.0 + +# IDL file(s) +IDLS=random.idl + +# Own C-server files +CSRV=server callbacks + +# Own C-client files +CCL=client + +# Generated C-server files +GCSRVS=rmod_random__s + +# Generated C-server files +GCCLS=rmod_random + +# Includes +IFLAGS=-I$(OTPROOT)/lib/ic-$(ICVSN)/include \ + -I$(OTPROOT)/lib/erl_interface-$(EIVSN)/include + +LDFLAGS=-L$(OTPROOT)/lib/ic-$(ICVSN)/priv/lib \ + -L$(OTPROOT)/lib/erl_interface-$(EIVSN)/lib + +LDLIBS=-lic -lerl_interface -lei -lnsl -lsocket + + +# Erlang compiler +ERLC=$(OTPROOT)/bin/erlc + +# Erlang compiler flags. +EFLAGS='+{preproc_flags,"-I $(OTPROOT)/usr/include"}' '+{scoped_op_calls,true}' + + +# C compiler +CC=gcc + +# C compiler flags +CFLAGS=-ggdb -O2 -Wall $(IFLAGS) + + +all: server client erlclient + + +server: + $(ERLC) $(EFLAGS) '+{be,c_server}' $(IDLS) + $(CC) $(IFLAGS) -c $(CSRV:=.c) $(GCSRVS:=.c) + $(CC) $(CSRV:=.o) $(GCSRVS:=.o) -o $@ $(LDFLAGS) $(LDLIBS) + +client: + $(ERLC) $(EFLAGS) '+{be,c_client}' $(IDLS) + $(CC) $(IFLAGS) -c $(CCL:=.c) $(GCCLS:=.c) + $(CC) $(CCL:=.o) $(GCCLS:=.o) -o $@ $(LDFLAGS) $(LDLIBS) + +erlclient: + $(ERLC) $(EFLAGS) '+{be,erl_genserv}' $(IDLS) + $(ERLC) *.erl + + +clean: + /bin/rm -f $(GCCLS:=.o) $(GCCLS:=.c) $(GCSRVS:=.o) $(GCSRVS:=.c) $(CCL:=.o) $(CSRV:=.o) *.jam *.beam oe* *.h *.hrl *~ core server client + + diff --git a/lib/ic/examples/c-server/ReadMe b/lib/ic/examples/c-server/ReadMe new file mode 100644 index 0000000..69fce4c --- /dev/null +++ b/lib/ic/examples/c-server/ReadMe @@ -0,0 +1,45 @@ +This is a short description on the use of the client demo, +a client that initiates and uses a random number generator +that lies on a C-server. + +Instructions. + +1) Modify the OTPROOT variable on the Makefile to point + to the root for your erlang instalation. + Modify IC and Erl_Interface versions to agree your + OTP version. + +2) + Type : + ------ + + make ( generates and compiles all code ) + + server ( starts the c-server ) + + + To test the c-client against the c-server start a new terminal window and type : + -------------------------------------------------------------------------------- + + client ( calls the server ) + + + To test the erlang-client against the c-server start a new terminal window and type : + ------------------------------------------------------------------------------------- + + + erl -sname client -setcookie flash ( start erlang ) + + client:init(1,2,3). ( initiates the random generator ) + + client:produce(). ( calls the random generator ) + + + + + + + + + + diff --git a/lib/ic/examples/c-server/callbacks.c b/lib/ic/examples/c-server/callbacks.c new file mode 100644 index 0000000..d50d26c --- /dev/null +++ b/lib/ic/examples/c-server/callbacks.c @@ -0,0 +1,45 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ + +#include +#include "rmod_random__s.h" + + +rmod_random_produce__rs* +rmod_random_produce__cb(rmod_random oe_obj, double *rs, CORBA_Environment *oe_env) + +{ + *rs = (double) rand(); + + return (rmod_random_produce__rs*) NULL; +} + + +rmod_random_init__rs* +rmod_random_init__cb(rmod_random oe_obj, long* seed1, long* seed2, long* seed3, CORBA_Environment *oe_env) + +{ + srand(*seed1 * *seed2 * *seed3); + + return (rmod_random_init__rs*) NULL; +} + + + diff --git a/lib/ic/examples/c-server/client.c b/lib/ic/examples/c-server/client.c new file mode 100644 index 0000000..fa57008 --- /dev/null +++ b/lib/ic/examples/c-server/client.c @@ -0,0 +1,124 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ + +/* Include the interface function, and ei_connect */ +#include "rmod_random.h" +#include "ei_connect.h" + +/* Assign your own node name here */ +#define SNODE "babbis@balin" +#define SERVER "rmod_random_impl" +#define COOKIE "flash" +#define CLNODE "c47@balin" +#define INBUFSZ 1024 +#define OUTBUFSZ 1024 + +/* Stopping node */ +void client_exit(CORBA_Environment *env) { + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + + close(env->_fd); + exit(1); +} + +int main() +{ + double result=0; + int i=0; + erlang_pid pid; + CORBA_Environment *env; + ei_cnode ec; + + /* Create and init CORBA_Environment */ + env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ); + + /* Initiating the connection */ + ei_connect_init(&ec, "c47", COOKIE, 0); + + /* Initiating pid*/ + strcpy(pid.node, CLNODE); + pid.num = 99; + pid.serial = 0; + pid.creation = 0; + + /* Fixing environment variable */ + env->_fd = ei_connect(&ec, SNODE); + strcpy(env->_regname,SERVER); + env->_to_pid = NULL; + env->_from_pid = &pid; + + if (env->_fd < 0) { + fprintf(stderr,"Error : Cannot connect to Server\n"); + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + exit(1); + } + + /* Calling the init function */ + rmod_random_init(NULL, 1, 2, 3, env); + + switch(env->_major) { + case CORBA_NO_EXCEPTION: /* Success */ + printf("Init complete !\n"); + break; + case CORBA_SYSTEM_EXCEPTION: /* System exception */ + printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + client_exit(env); + default: /* Should not come here */ + client_exit(env); + } + + /* Calling the produce function */ + for(i=1; i<=10; i++) { + result = rmod_random_produce(NULL, env); + + switch(env->_major) { + case CORBA_NO_EXCEPTION: /* Success */ + break; + case CORBA_SYSTEM_EXCEPTION: /* System exception */ + printf("Init call failure, reason : %s\n",(char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + client_exit(env); + default: /* Should not come here */ + client_exit(env); + } + + printf("the random number nr%d is %f\n",i,result); + } + + /* Closing the connection */ + close(env->_fd); + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + + return 0; +} + diff --git a/lib/ic/examples/c-server/client.erl b/lib/ic/examples/c-server/client.erl new file mode 100644 index 0000000..e225fc5 --- /dev/null +++ b/lib/ic/examples/c-server/client.erl @@ -0,0 +1,44 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%%---------------------------------------------------------------------- +%%% File : client.erl +%%% Author : Babbis Xagorarakis +%%% Purpose : +%%% Created : 22 Oct 1998 by Babbis Xagorarakis +%%%---------------------------------------------------------------------- + +-module(client). +-author('babbis@balin'). + +-export([produce/0,init/3]). + +-define(SERVER,{rmod_random_impl,'babbis@balin'}). +-define(CLIENTMOD,'rmod_random'). + +produce() -> + ?CLIENTMOD:produce(?SERVER). + + +init(Seed1, Seed2, Seed3) -> + ?CLIENTMOD:init(?SERVER, Seed1, Seed2, Seed3). + + + + diff --git a/lib/ic/examples/c-server/random.idl b/lib/ic/examples/c-server/random.idl new file mode 100644 index 0000000..b2c21bd --- /dev/null +++ b/lib/ic/examples/c-server/random.idl @@ -0,0 +1,49 @@ +// ``The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved via the world wide web at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// The Initial Developer of the Original Code is Ericsson Utvecklings AB. +// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +// AB. All Rights Reserved.'' +// +// $Id$ +// + +#ifndef _RANDOM_IDL +#define _RANDOM_IDL + +module rmod { + + interface random { + + double produce(); + + oneway void init(in long seed1, in long seed2, in long seed3); + + }; + +}; + +#endif + + + + + + + + + + + + + + + diff --git a/lib/ic/examples/c-server/server.c b/lib/ic/examples/c-server/server.c new file mode 100644 index 0000000..7e3c620 --- /dev/null +++ b/lib/ic/examples/c-server/server.c @@ -0,0 +1,245 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ + +#include +#include +#include +#include +#ifdef __WIN32__ +#include +#include +#include +#include +#else /* not __WIN32__ */ +#include +#include +#include +#include +#include +#include +#endif +#include "rmod_random__s.h" +#include "ei_connect.h" + +/* Used functions */ +extern int gethostname(char *buf, int buflen); +static int getport(int sockd); +static int getlisten(int port); +static int init(ei_cnode *ec, int *sd, int *portnr, int *epmd_fd); +void terminate(int *fd, int *sd, int *epmd_fd); +static void server_loop(ei_cnode *ec, int fd, int sd); + +/* change these, or even better, make command-line args to program... */ +#define COOKIE "flash" +#define SERVER "babbis" +#define NODENAMESZ 512 +#define HOSTNAMESZ 256 +#define INBUFSZ 1024 +#define OUTBUFSZ 1024 + + +int main(int argc, char **argv) +{ + int sd; + int portnr; + int epmd_fd; + ei_cnode ec; + + /* crate file descriptors */ + if (init(&ec, &sd, &portnr, &epmd_fd) < 0) + return -1; + + /* start server loop */ + server_loop(&ec, sd, epmd_fd); + + return 0; +} + + + +static void server_loop(ei_cnode *ec, int sd, int epmd_fd) +{ + ErlConnect conn; + erlang_msg msg; + int status=1; + CORBA_Environment *env; + + /* Create and init CORBA_Environment */ + env = CORBA_Environment_alloc(INBUFSZ,OUTBUFSZ); + + while (status >= 0) { + status = 1; + + if ((env->_fd = ei_accept(ec, sd, &conn)) < 0) { + /* error */ + fprintf(stderr,"Accept failed: %s\n",strerror(errno)); + } else { + /* connection */ + fprintf(stderr,"Accepted connection from %s\n",conn.nodename); + + while (status >= 0) { + + /* write message to buffer */ + status = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz, &msg, &env->_iin); + switch(status) { + case ERL_SEND: + case ERL_REG_SEND : + /* do transaction with fd */ + rmod_random__switch(NULL,env); + + switch(env->_major) { + case CORBA_NO_EXCEPTION: /* Success */ + break; + case CORBA_SYSTEM_EXCEPTION: /* System exception */ + printf("Request failure, reason : %s\n",(char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + break; + default: /* Should not come here */ + CORBA_exception_free(env); + break; + } + + /* send outdata */ + if (env->_iout > 0) + ei_send_encoded(env->_fd,&env->_caller,env->_outbuf,env->_iout); + break; + + case ERL_TICK : + break; + default : /* < 0 */ + printf("Connection terminated\n"); + break; + } + } + } + status=0; /* restart */ + } + + /* close file descriptors */ + terminate(&env->_fd, &sd, &epmd_fd); + + /* Free env & buffers */ + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); +} + + + +static int init(int *sd, int *portnr, int *epmd_fd) +{ + char host[HOSTNAMESZ]; + char servernode[NODENAMESZ]; + struct hostent *h; + + /* get the host name */ + if ((gethostname(host,HOSTNAMESZ))) + fprintf(stderr,"can't find own hostname\n"); + else { + /* identify host */ + if (!(h = erl_gethostbyname(host))) + fprintf(stdout,"can't find own ip address\n"); + else { + + /* get a listen port. 0 means let system choose port number */ + *sd = getlisten(0); + + /* what port did we get? */ + /* this call not necessary if we specified port in call to getlisten() */ + *portnr = getport(*sd); + + /* make the nodename server@host */ + sprintf(servernode,"%s@%s",SERVER,host); + + /* initiate */ + /* cnode, host, alive, alive@host, addr, cookie, creation */ + if (ei_connect_xinit(ec, host, SERVER, servernode, + (Erl_IpAddr)(h->h_addr_list[0]), + COOKIE, 0) == 0) { + /* let epmd know we are here */ + *epmd_fd = ei_publish(ec, *portnr); + if (*epmd_fd >= 0) + return 0; + } + } + } + return -1; +} + + +void terminate(int *fd, int *sd, int *epmd_fd) { + + close(*fd); + + /* remove info from epnd */ + close(*epmd_fd); + + /* return socket */ + close(*sd); + +} + + + +/* tells you what port you are using on given socket */ +static int getport(int sockd) +{ + struct sockaddr_in addr; + int namelen = sizeof(addr); + int i; + + memset(&addr,0,sizeof(addr)); + + if ((i = getsockname(sockd,(struct sockaddr *)&addr,&namelen))<0) + return i; + + return ntohs(addr.sin_port); +} + + + +/* return a listen socket, bound to given port */ +/* specify port = 0 to let system assign port */ +static int getlisten(int port) +{ + int sockd; + struct sockaddr_in inaddr; + int opt = 1; + int i; + + /* get listen socket */ + if ((sockd = socket(AF_INET,SOCK_STREAM,0)) < 0) return sockd; + + if ((i=setsockopt(sockd,SOL_SOCKET,SO_REUSEADDR,(void *)&opt,sizeof(opt)))<0) + return i; + + /* bind to requested port */ + memset(&inaddr,0,sizeof(inaddr)); + inaddr.sin_family = AF_INET; + inaddr.sin_addr.s_addr = htonl(INADDR_ANY); + inaddr.sin_port = htons(port); + + if ((i = bind(sockd,(struct sockaddr*) &inaddr, sizeof(inaddr))) < 0) + return i; + + listen(sockd,5); + + return sockd; +} diff --git a/lib/ic/examples/erl-genserv/ReadMe b/lib/ic/examples/erl-genserv/ReadMe new file mode 100644 index 0000000..cde588e --- /dev/null +++ b/lib/ic/examples/erl-genserv/ReadMe @@ -0,0 +1,30 @@ +This is a short description on the use of the c-client demo, +a client that initiates and uses a random number generator +that lies on an Erlang-genserver. + +Instructions. + + On the erlang shell type : + -------------------------- + + ic:gen(random,[{be,erl_genserv}]). ( generates the plain code ) + + make:all(). ( compiles the erlang code ) + + {ok,R} = rmod_random:oe_create(). ( initializes the server ) + + + Running the example : + --------------------- + + rmod_random:init(R,1,2,3). ( initializes the generator ) + + rmod_random:produce(R). ( generates a random number ) + + + + + + + + diff --git a/lib/ic/examples/erl-genserv/random.idl b/lib/ic/examples/erl-genserv/random.idl new file mode 100644 index 0000000..4527988 --- /dev/null +++ b/lib/ic/examples/erl-genserv/random.idl @@ -0,0 +1,50 @@ +// ``The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved via the world wide web at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// The Initial Developer of the Original Code is Ericsson Utvecklings AB. +// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +// AB. All Rights Reserved.'' +// +// $Id$ +// + +#ifndef _RANDOM_IDL +#define _RANDOM_IDL + + +module rmod { + + interface random { + + double produce(); + + oneway void init(in long seed1, in long seed2, in long seed3); + + }; + +}; + +#endif + + + + + + + + + + + + + + + diff --git a/lib/ic/examples/erl-genserv/rmod_random_impl.erl b/lib/ic/examples/erl-genserv/rmod_random_impl.erl new file mode 100644 index 0000000..70f5887 --- /dev/null +++ b/lib/ic/examples/erl-genserv/rmod_random_impl.erl @@ -0,0 +1,63 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module('rmod_random_impl'). +-export([init/1, terminate/2, start/0]). +-export([produce/1,init/4]). + + +init(Env) -> + {ok, []}. + +terminate(From, Reason) -> + ok. + + +produce(_Random) -> + case catch random:uniform() of + {'EXIT',_} -> + true; + RUnif -> + {reply,RUnif,[]} + end. + + +init(_Random,S1,S2,S3) -> + case catch random:seed(S1,S2,S3) of + {'EXIT',_} -> + true; + _ -> + {noreply,[]} + end. + + +%% This starts up the random number server +start() -> + %% Start the gen server + {ok,Pid} = rmod_random:oe_create([],{local,'rmod_random_impl'}), + true. + + + + + + + + + diff --git a/lib/ic/examples/erl-plain/ReadMe b/lib/ic/examples/erl-plain/ReadMe new file mode 100644 index 0000000..26440b4 --- /dev/null +++ b/lib/ic/examples/erl-plain/ReadMe @@ -0,0 +1,27 @@ +This is a short description on the use of the erl-plain demo, +a client that initiates and uses a random number generator +that lies on an Erlang-genserver. + +Instructions. + + On the erlang shell type : + -------------------------- + + ic:gen(random,[{be,erl_plain}]). ( generates the plain code ) + + make:all(). ( compiles the erlang code ) + + + Running the example : + --------------------- + + rmod_random:init(1,2,3). ( initializes the generator ) + + rmod_random:produce(). ( generates a random number ) + + + + + + + diff --git a/lib/ic/examples/erl-plain/random.idl b/lib/ic/examples/erl-plain/random.idl new file mode 100644 index 0000000..f776223 --- /dev/null +++ b/lib/ic/examples/erl-plain/random.idl @@ -0,0 +1,52 @@ +// ``The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved via the world wide web at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// The Initial Developer of the Original Code is Ericsson Utvecklings AB. +// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +// AB. All Rights Reserved.'' +// +// $Id$ +// +#pragma CODEOPT "[{be,c_genserv}]" + + +#ifndef _RANDOM_IDL +#define _RANDOM_IDL + + +module rmod { + + interface random { + + double produce(); + + oneway void init(in long seed1, in long seed2, in long seed3); + + }; + +}; + +#endif + + + + + + + + + + + + + + + diff --git a/lib/ic/examples/erl-plain/rmod_random_impl.erl b/lib/ic/examples/erl-plain/rmod_random_impl.erl new file mode 100644 index 0000000..7e7b2f0 --- /dev/null +++ b/lib/ic/examples/erl-plain/rmod_random_impl.erl @@ -0,0 +1,32 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module('rmod_random_impl'). + +-export([produce/0,init/3]). + + +produce() -> + random:uniform(). + + +init(S1,S2,S3) -> + random:seed(S1,S2,S3), + ok. + diff --git a/lib/ic/examples/java-client-server/ReadMe b/lib/ic/examples/java-client-server/ReadMe new file mode 100644 index 0000000..9fde464 --- /dev/null +++ b/lib/ic/examples/java-client-server/ReadMe @@ -0,0 +1,69 @@ +This is a short description on the use of the java demo, +a client that initiates and uses a random number generator +that lies on a java-server. You will be able to shift the +existing client/server with the ones refered to the other +examples. + +Instructions. + +1) Start erlang + + On the erlang shell type : + -------------------------- + + ic:gen(random,[{be,java}]). ( generates the java code ) + + +2) Modify the "SNode" string on file "server.java" to the server + node name thet suites for your machine. + + +3) Modify the "SNode" string on file "client.java" to the client + node for your machine and the "PNode" string for the server + node ( = the same as the SNode for the "server.java" file ). + + +4) Set and export the CLASSPATH variable to point to the + java classes located in java development kit, the + Otp's classes and the current directory. + Your classpath should look like this : + + .:/lib/ic-4.0/priv/ic.jar:/lib/jinterface_1.1/priv/OtpErlang.jar + + where : + + is the location there OTP is installed + + +5) Start the empd deamon by using the command : + + epmd -daemon + + +6) Compile the generated java code : + + javac rmod/*.java ( compiles all generated java code ) + + javac *.java ( compiles all manually writen java code ) + + +7) Start the java on an terminal window : + + java server ( starts the java-server ) + + +8) Start the client on an terminal window : + + java client ( calls the server ) + + + + + + + + + + + + diff --git a/lib/ic/examples/java-client-server/client.java b/lib/ic/examples/java-client-server/client.java new file mode 100644 index 0000000..4dc88cf --- /dev/null +++ b/lib/ic/examples/java-client-server/client.java @@ -0,0 +1,60 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +public class client { + + private static java.lang.String SNode = "client"; + private static java.lang.String PNode = "babbis"; + private static java.lang.String Cookie = "flash"; + private static java.lang.String Server = "rmod_random_impl"; + + private static rmod._randomStub stub; + + public static void main(String[] args) { + + try { + + stub = new rmod._randomStub(SNode,PNode,Cookie,Server); + int seed1 = 1; + int seed2 = 2; + int seed3 = 3; + double random = 0; + + System.out.print("\nClient initialization...."); + stub.init(seed1,seed2,seed3); + System.out.println("ok\n"); + + + for (int i = 0; i < 10; i++) { + random = stub.produce(); + System.out.println("Random" + i + " = " + random); + } + System.out.println("\nClient terminated.\n"); + + stub.__disconnect(); + + } catch( Exception e) { + System.out.println("Exception :"); + e.printStackTrace(); + } + + } + +} + diff --git a/lib/ic/examples/java-client-server/random.idl b/lib/ic/examples/java-client-server/random.idl new file mode 100644 index 0000000..b2c21bd --- /dev/null +++ b/lib/ic/examples/java-client-server/random.idl @@ -0,0 +1,49 @@ +// ``The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved via the world wide web at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// The Initial Developer of the Original Code is Ericsson Utvecklings AB. +// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +// AB. All Rights Reserved.'' +// +// $Id$ +// + +#ifndef _RANDOM_IDL +#define _RANDOM_IDL + +module rmod { + + interface random { + + double produce(); + + oneway void init(in long seed1, in long seed2, in long seed3); + + }; + +}; + +#endif + + + + + + + + + + + + + + + diff --git a/lib/ic/examples/java-client-server/server.java b/lib/ic/examples/java-client-server/server.java new file mode 100644 index 0000000..6b5fe8f --- /dev/null +++ b/lib/ic/examples/java-client-server/server.java @@ -0,0 +1,82 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +public class server { + + private static java.lang.String SNode = "babbis"; + private static java.lang.String Cookie = "flash"; + private static java.lang.String RegName = "rmod_random_impl"; + + public static void main(String[] args) { + + + System.out.println("\nServer running.\n"); + boolean serverState = true; + boolean recState = true; + + try { + + com.ericsson.otp.erlang.OtpServer self = new com.ericsson.otp.erlang.OtpServer(SNode, Cookie); + self.publishPort(); + + /* Server loop */ + while(serverState == true) { + + com.ericsson.otp.erlang.OtpConnection connection = self.accept(); + serverImpl srv = new serverImpl(); + com.ericsson.otp.erlang.OtpInputStream request; + com.ericsson.otp.erlang.OtpOutputStream reply; + com.ericsson.otp.erlang.OtpErlangPid client; + + /* Server loop */ + while(recState == true) { + + if (connection.isConnected() == true) + try { + + request = connection.receiveBuf(); + + reply = srv.invoke(request); + + if (reply != null) { + client = srv.__getCallerPid(); + + connection.sendBuf(client,reply); + } + + } catch( Exception e) { + System.out.println("Server terminated.\n\n"); + recState = false; + serverState = false; + } + } + + connection.close(); + } + + } catch( Exception e) { + System.out.println("Initialization exception :"); + e.printStackTrace(); + } + } +} + + + + diff --git a/lib/ic/examples/java-client-server/serverImpl.java b/lib/ic/examples/java-client-server/serverImpl.java new file mode 100644 index 0000000..d5fb66e --- /dev/null +++ b/lib/ic/examples/java-client-server/serverImpl.java @@ -0,0 +1,42 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +public class serverImpl extends rmod._randomImplBase { + + java.util.Random random = null; + + + public void init(int seed1, int seed2, int seed3) throws java.lang.Exception { + + random = new java.util.Random(seed1+seed2+seed3); + }; + + + public double produce() throws java.lang.Exception { + + return random.nextDouble(); + } + +} + + + + + + diff --git a/lib/ic/examples/pre_post_condition/Makefile b/lib/ic/examples/pre_post_condition/Makefile new file mode 100644 index 0000000..68e2168 --- /dev/null +++ b/lib/ic/examples/pre_post_condition/Makefile @@ -0,0 +1,128 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# ``The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved via the world wide web at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# The Initial Developer of the Original Code is Ericsson Utvecklings AB. +# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +# AB. All Rights Reserved.'' +# +# $Id$ +# +include $(ERL_TOP)/make/target.mk + +EBIN= ./ + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(IC_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/ic-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +IDL_FILES = \ + ex.idl + +GEN_ERL_MODULES = \ + oe_ex \ + m_i \ + m_NotAnInteger + +MODULES= \ + m_i_impl \ + tracer + +GEN_HRL_FILES = \ + oe_ex.hrl \ + m.hrl \ + m_i.hrl + +HRL_FILES = +TXT_FILES = ReadMe.txt + +ERL_FILES= $(MODULES:%=%.erl) + + +TARGET_FILES = \ + $(GEN_ERL_MODULES:%=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_LOCAL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin -pa $(ERL_TOP)/lib/ic/ebin +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_LOCAL_FLAGS) \ + -pa $(ERL_TOP)/lib/orber -I$(ERL_TOP)/lib/orber +YRL_FLAGS = + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +debug opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES) $(CLASS_FILES) + rm -f errs core *~ + +docs: + +test: $(TEST_TARGET_FILES) + + +$(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES): ex.idl + erlc $(ERL_LOCAL_FLAGS) +'{precond,{tracer,pre}}' \ + +'{{postcond,"m::i::f"},{tracer,post}}' ex.idl + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/examples/pre_post_condition + $(INSTALL_DATA) $(ERL_FILES) $(IDL_FILES) $(TXT_FILES) $(RELSYSDIR)/examples/pre_post_condition + + +release_docs_spec: + + diff --git a/lib/ic/examples/pre_post_condition/ReadMe.txt b/lib/ic/examples/pre_post_condition/ReadMe.txt new file mode 100644 index 0000000..9db54f4 --- /dev/null +++ b/lib/ic/examples/pre_post_condition/ReadMe.txt @@ -0,0 +1,73 @@ + ``The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved via the world wide web at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson Utvecklings AB. + Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings + AB. All Rights Reserved.'' + + $Id$ + + +This example shows how pre and post condition can be used for a Corba server object. + + +The example consists of three files; + +ex.idl - the interface specification +m_i_impl.erl - the server implementation +tracer.erl - a module which contains a pre and a post condition + + +The IDL file can for example be compiled with the following options: + +ic:gen(ex, [{precond, {tracer, pre}},{{postcond, "m::i::f"}, {tracer, post}}]). + +The result is that the function m::i::f gets both a pre and post condition call while +the function m::i::g just get a pre condition call. + + +A pre/post condition function should always return the atom ok and if something is wrong +it should raise an exception ( ex: corba:raise(#userexception{}) ). + + + + +Compile all erlang files and test the application. + +First start an erlang node, then type the following commands in the erlang shell. + +1> mnesia:create_schema([]). +2> orber:install([]). +3> orber:start(). +3> +3> X = m_i:oe_create(). +4> catch m_i:f(X, 17). +Precond called in process <0.139.0>: m_i:f() [[],17] +f working .... +Postcond called in process <0.139.0>: m_i:f() [[],17] {reply,{17,17},[]} +17 +5> +5> catch m_i:f(X, q). +6> {'EXCEPTION',{m_NotAnInteger,"IDL:m/NotAnInteger:1.0"}} +7> +7>m_i:g(X, 17). +Precond called in process <0.139.0>: m_i:g() [[],17] +ok +g working .... +8> +8>corba_boa:dispose(X). +9> orber:stop(). +10> + + + + + diff --git a/lib/ic/examples/pre_post_condition/ex.idl b/lib/ic/examples/pre_post_condition/ex.idl new file mode 100644 index 0000000..e632448 --- /dev/null +++ b/lib/ic/examples/pre_post_condition/ex.idl @@ -0,0 +1,29 @@ +// ``The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved via the world wide web at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// The Initial Developer of the Original Code is Ericsson Utvecklings AB. +// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +// AB. All Rights Reserved.'' +// +// $Id$ +// + +module m { + + exception NotAnInteger {}; + + interface i { + short f(in short i); + oneway void g(in long i); + }; + +}; + diff --git a/lib/ic/examples/pre_post_condition/m_i_impl.erl b/lib/ic/examples/pre_post_condition/m_i_impl.erl new file mode 100644 index 0000000..d43ee0a --- /dev/null +++ b/lib/ic/examples/pre_post_condition/m_i_impl.erl @@ -0,0 +1,49 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%------------------------------------------------------------ +%% +%% Example +%% +%%------------------------------------------------------------ +-module(m_i_impl). + +%% Standard functions +-export([init/1, terminate/2]). +%% Interface functions +-export([f/2, g/2]). + +init(_Env) -> + {ok, []}. + +terminate(_From, _Reason) -> + ok. + +f(State, In) -> + io:format("f working ....\n", []), + {reply, In, State}. + +g(State, _In) -> + io:format("g working ....\n", []), + {noreply, State}. + + + + + diff --git a/lib/ic/examples/pre_post_condition/tracer.erl b/lib/ic/examples/pre_post_condition/tracer.erl new file mode 100644 index 0000000..4cba7ba --- /dev/null +++ b/lib/ic/examples/pre_post_condition/tracer.erl @@ -0,0 +1,56 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: tracer.erl +%% +%% Description: +%% This file contains an example of pre and post conditions for +%% the corba backend. +%% +%%----------------------------------------------------------------- +-module(tracer). +-include("m.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([pre/3, post/4]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- +pre(M, F, [State, I]) when is_integer(I) -> + io:format("Precond called in process ~p: ~s:~s() ~p\n", [self(), M, F, [State, I]]), + ok; +pre(_M, _F, _A) -> %% Just an silly example to get an exception case + corba:raise(#'m_NotAnInteger'{}). + +post(M, F, A, R) -> + io:format("Postcond called in process ~p: ~s:~s() ~p ~p\n", [self(), M, F, A, R]), + ok. + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- diff --git a/lib/ic/include/erlang.idl b/lib/ic/include/erlang.idl new file mode 100644 index 0000000..78acc7c --- /dev/null +++ b/lib/ic/include/erlang.idl @@ -0,0 +1,57 @@ +// ``The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved via the world wide web at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// The Initial Developer of the Original Code is Ericsson Utvecklings AB. +// Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +// AB. All Rights Reserved.'' +// +// $Id$ +// + +#ifndef _ERLANG_IDL_ +#define _ERLANG_IDL_ + +module erlang +{ + + // an erlang pid + struct pid { + string<256> node; + unsigned long num; + unsigned long serial; + unsigned long creation; + }; + + // an erlang port + struct port { + string<256> node; + unsigned long id; + unsigned long creation; + }; + + // port and ref have identical structure + struct ref { + string<256> node; + unsigned long id; + unsigned long creation; + }; + + + // an erlang term + typedef any term; + + + // an erlang binary + typedef sequence binary; + +}; + +#endif diff --git a/lib/ic/include/ic.h b/lib/ic/include/ic.h new file mode 100644 index 0000000..b3b8a2f --- /dev/null +++ b/lib/ic/include/ic.h @@ -0,0 +1,431 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include +#include +#include +#include +#include + +#ifdef __WIN32__ +/* Windows.h #defines interface to struct, get rid of it! */ +#ifdef interface +#undef interface +#endif +#endif + +#ifndef __IC_H__ +#define __IC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Standard type mapping */ + +#ifndef __CORBA_SHORT__ +#define __CORBA_SHORT__ + typedef short CORBA_short; +#endif + +#ifndef __CORBA_LONG__ +#define __CORBA_LONG__ + typedef long CORBA_long; +#endif + +/* CORBA_long_long = long because of erl_interface limitation */ +#ifndef __CORBA_LONG_LONG__ +#define __CORBA_LONG_LONG__ + typedef long CORBA_long_long; /* LONG LONG */ +#endif + +#ifndef __CORBA_UNSIGNED_SHORT__ +#define __CORBA_UNSIGNED_SHORT__ + typedef unsigned short CORBA_unsigned_short; +#endif + +#ifndef __CORBA_UNSIGNED_LONG__ +#define __CORBA_UNSIGNED_LONG__ + typedef unsigned long CORBA_unsigned_long; +#endif + +/* CORBA_unsigned long_long = unsigned long because of erl_interface + limitation */ + +#ifndef __CORBA_UNSIGNED_LONG_LONG__ +#define __CORBA_UNSIGNED_LONG_LONG__ + typedef unsigned long CORBA_unsigned_long_long; +#endif + +#ifndef __CORBA_FLOAT__ +#define __CORBA_FLOAT__ + typedef float CORBA_float; +#endif + +#ifndef __CORBA_DOUBLE__ +#define __CORBA_DOUBLE__ + typedef double CORBA_double; +#endif + + +#ifndef __CORBA_LONG_DOUBLE__ +#define __CORBA_LONG_DOUBLE__ + typedef double CORBA_long_double; +#endif + +#ifndef __CORBA_CHAR__ +#define __CORBA_CHAR__ + typedef char CORBA_char; +#endif + +#ifndef __CORBA_WCHAR__ +#define __CORBA_WCHAR__ + typedef unsigned long CORBA_wchar; +#endif + +#ifndef __CORBA_BOOLEAN__ +#define __CORBA_BOOLEAN__ + typedef unsigned char CORBA_boolean; +#endif + +#ifndef __CORBA_OCTET__ +#define __CORBA_OCTET__ + typedef char CORBA_octet; +#endif + +#ifndef CORBA_enum +#define CORBA_enum enum +#endif + +#ifndef __ERLANG_BINARY__ +#define __ERLANG_BINARY__ + typedef struct { + CORBA_unsigned_long _maximum; + CORBA_unsigned_long _length; + CORBA_octet* _buffer; + } erlang_binary; +#endif + + +/* Object definition */ + typedef void* CORBA_Object; + + +/* Exception discriminators */ +#ifndef CORBA_NO_EXCEPTION +#define CORBA_NO_EXCEPTION 0 +#endif + +#ifndef CORBA_SYSTEM_EXCEPTION +#define CORBA_SYSTEM_EXCEPTION -1 +#endif + +#ifndef CORBA_USER_EXCEPTION +#define CORBA_USER_EXCEPTION -2 +#endif + +/* System exceptions */ + +#define UNKNOWN "UNKNOWN" +#define BAD_PARAM "BAD_PARAM" +#define NO_MEMORY "NO_MEMORY" +#define IMPL_LIMIT "IMP_LIMIT" +#define COMM_FAILURE "COMM_FAILURE" +#define INV_OBJREF "INV_OBJREF" +#define NO_PERMISSION "NO_PERMISSION" +#define INTERNAL "INTERNAL" +#define MARSHAL "MARSHAL" +#define INITIALIZE "INITIALIZE" +#define NO_IMPLEMENT "NO_IMPLEMENT" +#define BAD_TYPECODE "BAD_TYPECODE" +#define BAD_OPERATION "BAD_OPERATION" +#define NO_RESOURCES "NO_RESOURCES" +#define NO_RESPONSE "NO_RESPONSE" +#define PERSIST_STORE "PERSIST_STORE" +#define BAD_INV_ORDER "BAD_INV_ORDER" +#define TRANSIENT "TRANSIENT" +#define FREE_MEM "FREE_MEM" +#define INV_IDENT "INV_IDENT" +#define INV_FLAG "INV_FLAG" +#define INTF_REPOS "INTF_REPOS" +#define BAD_CONTEXT "BAD_CONTEXT" +#define OBJ_ADAPTER "OBJ_ADAPTER" +#define DATA_CONVERSION "DATA_CONVERSION" +#define OBJ_NOT_EXIST "OBJECT_NOT_EXIST" + + + +/* Exception type */ + typedef int CORBA_exception_type; + + +#ifndef __CORBA_ENVIRONMENT__ +#define __CORBA_ENVIRONMENT__ + +/* Environment definition */ + typedef struct { + + /*----- CORBA compatibility part ------------------------------------*/ + CORBA_exception_type _major; /* Exception tag, initially set + to CORBA_NO_EXCEPTION */ + + /*----- External Implementation part - initiated by the user --------*/ + int _fd; /* File descriptor */ + int _inbufsz; /* Size of input buffer */ + char *_inbuf; /* Pointer to always + dynamically allocated + buffer for input */ + int _outbufsz; /* Size of output buffer */ + char *_outbuf; /* Pointer to always + dynamically + allocated buffer + for output */ + int _memchunk; /* Size of memory + chunks in bytes, + used for increasing + the output buffer, + set to >= 32, + should be around >= + 1024 for + performance reasons */ + char _regname[256]; /* Pointer for + registered name */ + erlang_pid *_to_pid; /* Process identity + for caller */ + erlang_pid *_from_pid; /* Process identity + for callee */ + /*----- Internal Implementation part - used by the server/client ----*/ + int _iin; /* Index for input buffer */ + int _iout; /* Index for output buffer */ + char _operation[256]; /* Pointer for operation name*/ + int _received; /* Used to count parameters */ + erlang_pid _caller; /* Used to identify + the caller*/ + erlang_ref _unique; /* Used to identify the call */ + CORBA_char *_exc_id; /* Exception id field */ + void *_exc_value; /* Exception value field */ + + unsigned int _ref_counter_1; /* Counter for reference */ + unsigned int _ref_counter_2; /* Counter for reference */ + unsigned int _ref_counter_3; /* Counter for reference */ + + } CORBA_Environment; + +#endif + + +/* Corba standard functions */ + + void CORBA_free(void *); + CORBA_char *CORBA_string_alloc(CORBA_unsigned_long); + CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long); + CORBA_char *CORBA_exception_id(CORBA_Environment *env); + void *CORBA_exception_value(CORBA_Environment *env); + void CORBA_exception_free(CORBA_Environment *env); + void CORBA_exc_set(CORBA_Environment *env, + CORBA_exception_type Major, + CORBA_char *Id, + CORBA_char *Value); + CORBA_Environment *CORBA_Environment_alloc(int inbufsz, int outbufsz); + void ic_init_ref(CORBA_Environment *env, erlang_ref *ref); + int ic_compare_refs(erlang_ref *ref1, erlang_ref *ref2); + +/* Used internally */ + +#define __OE_MEMCHUNK__ 1024 +#define __OE_VSNSZ__ 1 +#define __OE_LONGSZ__ 7 +#define __OE_LONGLONGSZ__ 7 +#define __OE_ULONGSZ__ 7 +#define __OE_ULONGLONGSZ__ 7 +#define __OE_DOUBLESZ__ 32 +#define __OE_CHARSZ__ 2 +#define __OE_WCHARSZ__ 7 +#define __OE_TUPLEHDRSZ__ 5 +#define __OE_LISTHDRSZ__ 5 + +/* The actual size of a wide char (used to be #define __OE_WCHAR_SIZE_OF__ 4) */ +#define __OE_WCHAR_SIZE_OF__ sizeof(CORBA_wchar) + +/* Size check macro */ +#define OE_MALLOC_SIZE_CHECK(env,x) { \ + assert((x) > 0); \ + if (!((x) > 0)) { \ + CORBA_exc_set((env), CORBA_SYSTEM_EXCEPTION, INTERNAL, \ + "Bad malloc size calculation"); \ + return -1; \ + } \ +} + +/* Exec function -- probably not needed */ + typedef int oe_exec_function_t(CORBA_Object, CORBA_Environment*); +/* These are for backward compatibility */ + typedef oe_exec_function_t ___exec_function___; + typedef oe_exec_function_t ___generic___; + +/* Operation declaration */ + typedef struct { + char *interface; + char *name; + oe_exec_function_t *function; + } oe_operation_t; + +/* For backward compatibility */ + typedef oe_operation_t ___operation___; + +/* Map declaration */ + typedef struct { + int length; + oe_operation_t *operations; + } oe_map_t; +/* For backward compatibility */ + typedef oe_map_t ___map___; + +/* Align macro */ +#define OE_ALIGN(x) (((x) + sizeof(double) - 1) & ~(sizeof(double) - 1)) + +/* Encoders */ + int oe_ei_encode_version(CORBA_Environment *env); + int oe_ei_encode_long(CORBA_Environment *env, long p); + int oe_ei_encode_longlong(CORBA_Environment *env, CORBA_long_long p); + int oe_ei_encode_ulong(CORBA_Environment *env, unsigned long p); + int oe_ei_encode_ulonglong(CORBA_Environment *env, + CORBA_unsigned_long_long p); + int oe_ei_encode_double(CORBA_Environment *env, double p); + int oe_ei_encode_char(CORBA_Environment *env, char p); + int oe_ei_encode_wchar(CORBA_Environment *env, CORBA_wchar p); + int oe_ei_encode_string(CORBA_Environment *env, const char *p); + int oe_ei_encode_wstring(CORBA_Environment *env, CORBA_wchar *p); + int oe_ei_encode_atom(CORBA_Environment *env, const char *p); + int oe_ei_encode_pid(CORBA_Environment *env, const erlang_pid *p); + int oe_ei_encode_port(CORBA_Environment *env, const erlang_port *p); + int oe_ei_encode_ref(CORBA_Environment *env, const erlang_ref *p); + int oe_ei_encode_term(CORBA_Environment *env, void *t); + int oe_ei_encode_tuple_header(CORBA_Environment *env, int arity); + int oe_ei_encode_list_header(CORBA_Environment *env, int arity); + int oe_encode_erlang_binary(CORBA_Environment *env, erlang_binary *binary); + +#define oe_ei_encode_empty_list(ev) oe_ei_encode_list_header(ev,0) + +/* Decoders */ + int oe_ei_decode_wchar(const char *buf, int *index, CORBA_wchar *p); + int oe_ei_decode_wstring(const char *buf, int *index, CORBA_wchar *p); + int oe_ei_decode_longlong(const char *buf, int *index, CORBA_long_long *p); + int oe_ei_decode_ulonglong(const char *buf, int *index, + CORBA_unsigned_long_long *p); + int oe_decode_erlang_binary(CORBA_Environment *env, char *buf, int *index, + erlang_binary *binary); + +/* Generic client encoders (gen_server protocol) */ + int oe_prepare_notification_encoding(CORBA_Environment *env); + int oe_prepare_request_encoding(CORBA_Environment *env); + +/* Generic client decoders (gen_server protocol) */ + int oe_prepare_reply_decoding(CORBA_Environment *env); + +/* Generic client send and receive functions (Erlang distribution protocol) */ + int oe_send_notification(CORBA_Environment *env); + int oe_send_notification_tmo(CORBA_Environment *env, unsigned int send_ms); + int oe_send_request_and_receive_reply(CORBA_Environment *env); + int oe_send_request_and_receive_reply_tmo(CORBA_Environment *env, + unsigned int send_ms, + unsigned int recv_ms); + +/* Generic server decoder */ + int oe_prepare_request_decoding(CORBA_Environment *env); + +/* Generic server encoder */ + int oe_prepare_reply_encoding(CORBA_Environment *env); + +/* -------- */ + +/* Generic server receive (possibly send reply) */ + int oe_server_receive(CORBA_Environment *env, oe_map_t *map); + int oe_server_receive_tmo(CORBA_Environment *env, oe_map_t *map, + unsigned int send_ms, + unsigned int recv_ms); + +/* -------- */ + +/* Size calculators */ + int oe_sizecalc_erlang_binary(CORBA_Environment *env, int *index, + int *size); +/* Print functions */ + int print_erlang_binary(erlang_binary*); + +/* Length counter for wide strings */ + int ic_wstrlen(CORBA_wchar * p); + +/* Wide string comparison */ + int ic_wstrcmp(CORBA_wchar * ws1, CORBA_wchar * ws2); + +/* Put for 64-bits integer type */ +#define put64le(s,n) do { \ + (s)[0] = (n) & 0xff; \ + (s)[1] = ((n) >> 8) & 0xff; \ + (s)[2] = ((n) >> 16) & 0xff; \ + (s)[3] = ((n) >> 24) & 0xff; \ + (s)[4] = ((n) >> 32) & 0xff; \ + (s)[5] = ((n) >> 40) & 0xff; \ + (s)[6] = ((n) >> 48) & 0xff; \ + (s)[7] = ((n) >> 56) & 0xff; \ + (s)[8] = ((n) >> 64) & 0xff; \ + (s) += 8; \ +} while (0) + +/* Get for 64-bits integer type */ +#define get64le(s) \ + ((s) += 8, \ + ((((unsigned char *)(s))[-1] << 56) | \ + (((unsigned char *)(s))[-2] << 48) | \ + (((unsigned char *)(s))[-3] << 40) | \ + (((unsigned char *)(s))[-4] << 32) | \ + (((unsigned char *)(s))[-5] << 24) | \ + (((unsigned char *)(s))[-6] << 16) | \ + (((unsigned char *)(s))[-7] << 8) | \ + ((unsigned char *)(s))[-8])) + + + +/* Exec function switch */ + int oe_exec_switch(CORBA_Object, CORBA_Environment*, oe_map_t*); +/* For backward compatibility */ + int ___switch___(CORBA_Object, CORBA_Environment*, oe_map_t*); + +/* For backward compatibility -- replaced by oe_prepare_request_decoding() */ + int ___call_info___(CORBA_Object, CORBA_Environment*); + +/* Map merging */ + oe_map_t* oe_merge_maps(oe_map_t*, int); +/* For backward compatibility */ + oe_map_t* ___merge___(oe_map_t*, int); + +/* Macro for error reporting */ + +#ifdef OE_C_REPORT +#define OE_RPT_ERR(x) fprintf(stderr, (x)) +#else +#define OE_RPT_ERR(x) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/ic/info b/lib/ic/info new file mode 100644 index 0000000..96cb88d --- /dev/null +++ b/lib/ic/info @@ -0,0 +1,2 @@ +group: orb Object Request Broker & IDL Applications +short: IDL compiler diff --git a/lib/ic/internal_doc/c-improvements-1.txt b/lib/ic/internal_doc/c-improvements-1.txt new file mode 100644 index 0000000..ccfdec7 --- /dev/null +++ b/lib/ic/internal_doc/c-improvements-1.txt @@ -0,0 +1,84 @@ +Peter Hogfeldt 2003-08-14 PA1 + +IC C BACK-ENDS IMPROVEMENTS + +1 C CLIENT + +1.1 Cast + + Each oneway operation roughly consists of the following code + parts: + + - encoding the cast message + - setting index of the out buffer to zero (1.1.1) + - encoding the magic (1.1.1) + - encoding a tuple header of size 2 (1.1.1) + - encoding '$gen_cast' (1.1.1) + - encoding the operation parameters (1.1.2) + - sending the cast message (1.1.3) + + Only (1.1.2) is unique for the operation in question. + +1.1.1 Todo + + Define functions: + + int oe_ei_encode_cast(CORBA_environment *) that performs (1.1.1) + + int oe_ei_cast(CORBA_environment *) that performs (1.1.3) + + This will reduce code size. + + As compiler options + + oe_ei_encode_cast(), and + oe_ei_cast() + + may be replaced by user defined functions. + +1.2 Call + + Each (non-oneway) operation roughly consists of the following code + parts: + + - encoding the call message + - setting index of the out buffer to zero (1.2.1) + - encoding the magic (1.2.1) + - encoding a tuple header of size 3 (1.2.1) + - encoding '$gen_call' (1.2.1) + - encoding a tuple header of size 2 (1.2.1) + - encoding the from pid (1.2.1) + - encoding the unique ref (1.2.1) + - encoding the operation parameters (1.2.2) + - sending the call message (1.2.3) + - receiving the reply message (1.2.3) + - decoding the reply parameters (1.2.4) + + Only (1.2.2) and (1.2.4) are unique for the operation in question. + +1.2.1 Todo + + Define functions: + + int oe_ei_encode_send(CORBA_environment *) that performs (1.2.1) + + int oe_ei_send_and_receive(CORBA_environment *) that performs (1.2.3) + + This will reduce code size. + + As compiler options + + oe_ei_encode_send(), and + oe_ei_send_and_receive() + + may be replaced by user defined function. + + +2 SERVER + + We do not provide any code for receiving operation messages, execute + operations, and send the result back. Should we not do that? + + + + \ No newline at end of file diff --git a/lib/ic/internal_doc/protocol.txt b/lib/ic/internal_doc/protocol.txt new file mode 100644 index 0000000..54e1ef5 --- /dev/null +++ b/lib/ic/internal_doc/protocol.txt @@ -0,0 +1,182 @@ +Peter Hogfeldt 2003-08-18 PA3 + +THE IC PROTOCOL + +1 INTRODUCTION + + The IDL Compiler (IC) transforms Interface Definition Language + (IDL) specifications files to interface code for Erlang, C, and + Java. The Erlang language mapping is described in the Orber + documentation, while the other mappings are described in the IC + documentation (they are of course in accordance with the CORBA C + and Java language mapping specifications, with some restrictions). + + The most important parts of an IDL specification are the operation + declarations. An operation defines what information a client + provides to a server, and what information (if any) the client + gets back from the server. We consider IDL operations and language + mappings in section 2. + + What we here call the IC protocol, is the description of messages + exchanged between IC end-points (client and servers). It is valid + for all IC back-ends, except the 'erl_plain' and 'erl_corba' + back-ends. The protocol is described in section 3. + + The IC protocol is in turn embedded into the Erlang gen_server + protocol, which is described in section 4. + + Finally, the gen_server protocol is embedded in the Erlang + distribution protocol. Pertinent parts of that protocol is + described in section 5. + + +2 LANGUAGE MAPPINGS AND IDL OPERATIONS + +2.1 IDL Operations + + An IDL operation is declared as follows: + + [oneway] RetType Op(in IType1 I1, in IType2 I2, ..., in ITypeN IN, + out OType1 O1, out OType2 O2, ..., out OTypeM OM) + N, M = 0, 1, 2, ... (2.1.1) + + `Op' is the operation name, RetType is the return type, and ITypei, + i = 1, 2, ..., N, and OTypej, j = 1, 2, ..., M, are the `in' types + and `out' types, respectively. The values I1, I2, ..., IN are + provided by the caller, and the value of RetType, and the values + O1, O2, ..., OM, are provided as results to the caller. + + The types can be any basic types or derived types declared in the + IDL specification of which the operation declaration is a part. + + If the RetType has the special name `void' there is no return + value (but there might still be result values O1, 02, ..., OM). + + The `in' and `out' parameters can be declared in any order, but + for clarity we have listed all `in' parameters before the `out' + parameters in the declaration above. + + If the keyword `oneway' is present, the operation is a cast, i.e. + there is no confirmation of the operation, and consequently there + must be no result values: RetType must be equal to `void', and M = + 0 must hold. + + Otherwise the operation is a call, i.e. it is confirmed (or else + an exception is raised). + + Note carefully that an operation declared without `oneway' is + always a call, even if RetType is `void' and M = 0. + +2.2 Language Mappings + + There are several CORBA Language Mapping specifications. These are + about mapping interfaces to various programming languages. IC + supports the CORBA C and Java mapping specifications, and the + Erlang language mapping specified in the Orber documentation. + + Excerpt from "6.4 Basic OMG IDL Types" in the Orber User's Guide: + + Functions with return type void will return the atom ok. + + Excerpt from "6.13 Invocations of Operations" in the Orber User's Guide: + + A function call will invoke an operation. The first parameter + of the function should be the object reference and then all in + and inout parameters follow in the same order as specified in + the IDL specification. The result will be a return value + unless the function has inout or out parameters specified; in + which case, a tuple of the return value, followed by the + parameters will be returned. + + Hence the function that is mapped from an IDL operation to Erlang + always have a return value (an Erlang function always has). That + fact has influenced the IC protocol, in that there is always a + return value (which is 'ok' if the return type was declared 'void'). + + +3 IC PROTOCOL + + Given the operation declaration (2.1.1) the IC protocol maps to + messages as follows, defined in terms of Erlang terms. + +3.1 Call (Request/Reply, i.e. not oneway) + + request: Op atom() N = 0 + {Op, I1, I2, ..., IN} tuple() N > 0 + (3.1.1) + + reply: Ret M = 0 + {Ret, O1, O2, ..., OM} M > 0 + (3.1.2) + + Notice; Even if the RetType of the operation Op is declared to be + 'void', a return value 'ok' is returned in the reply message. That + return value is of no significance, and is therefore ignored (note + however that a C server back-end returns the atom 'void' instead + of 'ok'). + +3.2 Cast (oneway) + + notification: Op atom() N = 0 + {Op, I1, I2, ..., IN} tuple() N > 0 + (3.2.1) + (There is of course no return message). + +3.3 Propagation of Exceptions + + Currently there is no propagation of exceptions from the server to + the client. As it is now a an exception detected by the server + will hang the client in a receive. That is unacceptable. + + Exception propagation is only meaningful for Call (request/reply). + + +4 GEN_SERVER PROTOCOL + + Most of the IC generated code deals with encoding and decoding the + gen_server protocol. + +4.1 Call + + request: {'$gen_call', {self(), Ref}, Request} (4.1.1) + + reply: {Ref, Reply} (4.1.2) + + where Request and Reply are the messages defined in 3.1 Call. + +4.2 Cast + + notification: {'$gen_cast', Notification} (4.2.1) + + where Notification is the message defined in 3.2 Cast. + + +5 ERLANG DISTRIBUTION PROTOCOL + + Messages (of interest here) between Erlang nodes are of the form: + + Len(4), Type(1), CtrlBin(N), MsgBin(M) (5.1) + + Type is equal to 112 = PASS_THROUGH. + + CtrlBin and MsgBin are Erlang terms in binary form (as if created + by term_to_binary/1), whence for each of them the first byte is + equal to 131 = VERSION_MAGIC. + + CtrlBin (of interest here) contains the SEND and REG_SEND control + messages, which are binary forms of the Erlang terms + + {2, Cookie, ToPid} , (5.2) + + and + + {6, FromPid, Cookie, ToName} , (5.3) + + respectively. + + The CtrlBin(N) message is read and written by erl_interface code + (C), j_interface code (Java), or the Erlang distribution + implementation, which are invoked from IC generated code. + + The MsgBin(N) is the "real" message, i.e. of the form described + in section 4. diff --git a/lib/ic/java_src/Makefile b/lib/ic/java_src/Makefile new file mode 100644 index 0000000..e6a4cd7 --- /dev/null +++ b/lib/ic/java_src/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(ORBER_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +SUB_DIRECTORIES = com/ericsson/otp/ic + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk + diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Any.java b/lib/ic/java_src/com/ericsson/otp/ic/Any.java new file mode 100644 index 0000000..7337241 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/Any.java @@ -0,0 +1,1023 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + + +/** + +The Any class is the java mapping of the any OMG-IDL type. + + +**/ + + +public class Any { + + // Typecode value holder + protected TypeCode tcV; + + // Primitive value holder + protected java.lang.String stringV; + protected byte byteV; + protected boolean booleanV; + protected char charV; + protected short shortV; + protected int intV; + protected long longV; + protected float floatV; + protected double doubleV; + + // Streams used for user defined types + protected com.ericsson.otp.erlang.OtpInputStream is; + protected com.ericsson.otp.erlang.OtpOutputStream os; + + + // Constructor + public Any() { + tcV = null; + } + + // Equal function + + /** + Any comparison method + @return true if the input Any is equal to the object, false otherwize + **/ + public boolean equal(com.ericsson.otp.ic.Any _any) { + + int _is1Len,_is2Len; + byte _compressed[]; + com.ericsson.otp.erlang.OtpInputStream _is1,_is2; + TypeCode _tc = _any.type(); + + if (!tcV.equal(_tc)) + return false; + + try { + + TCKind _tck = _tc.kind(); + + switch (_tck.value()) { + + case TCKind._tk_short: + return (_any.extract_short() == shortV); + + case TCKind._tk_ushort: + return (_any.extract_ushort() == shortV); + + case TCKind._tk_long: + return (_any.extract_long() == intV); + + case TCKind._tk_longlong: + return (_any.extract_longlong() == longV); + + case TCKind._tk_ulong: + return (_any.extract_ulong() == intV); + + case TCKind._tk_ulonglong: + return (_any.extract_ulonglong() == longV); + + case TCKind._tk_float: + return equal(_any.extract_float(),floatV); + + case TCKind._tk_double: + return equal(_any.extract_double(),doubleV); + + case TCKind._tk_boolean: + return (_any.extract_boolean() == booleanV); + + case TCKind._tk_char: + return (_any.extract_char() == charV); + + case TCKind._tk_wchar: + return (_any.extract_wchar() == charV); + + case TCKind._tk_octet: + return (_any.extract_octet() == byteV); + + case TCKind._tk_string: + return (_any.extract_string().compareTo(stringV) == 0); + + case TCKind._tk_wstring: + return (_any.extract_wstring().compareTo(stringV) == 0); + + case TCKind._tk_sequence: + + _is1 = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray()); + + _is2 = _any.extract_Streamable(); + + if (_is1.peek() != _is2.peek()) { + + // _is1's sequence is compressed to string + if(_is1.peek() == com.ericsson.otp.erlang.OtpExternal.stringTag) { + + _compressed = (_is1.read_string()).getBytes(); + _is1Len = _compressed.length; + + _is2.read_list_head(); + + for(int i = 0; i < _is1Len; i++) { + if ((long)(_compressed[i] & 0xff) != _is2.read_long()) + return false; + } + + _is2.read_nil(); + } + else { // _is2's sequence is compressed to string + + _compressed = (_is2.read_string()).getBytes(); + _is2Len = _compressed.length; + + _is1.read_list_head(); + + for(int i = 0; i < _is2Len; i++) + if ((long)(_compressed[i] & 0xff) != _is1.read_long()) + return false; + + _is1.read_nil(); + } + } + else { // None of them is compressed + + _is2Len = _is2.available(); + + if (_is1.available() != _is2Len) + return false; + + for(int i = 0; i < _is2Len; i++) { + if (_is1.read() != _is2.read()) + return false; + } + } + + return true; + + case TCKind._tk_struct: + case TCKind._tk_union: + case TCKind._tk_array: + case TCKind._tk_enum: + + _is1 = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray()); + + _is2 = _any.extract_Streamable(); + + _is2Len = _is2.available(); + + if (_is1.available() != _is2Len) + return false; + + for(int i = 0; i < _is2Len; i++) { + if (_is1.read() != _is2.read()) + return false; + } + + return true; + + // Not used in real + case TCKind._tk_any: + case TCKind._tk_void: + case TCKind._tk_atom: + case TCKind._tk_null: + case TCKind._tk_TypeCode: + case TCKind._tk_Principal: + case TCKind._tk_objref: + case TCKind._tk_alias: + case TCKind._tk_except: + case TCKind._tk_longdouble: + case TCKind._tk_fixed: + return true; + + default : + return false; + + } + } catch (Exception e) { + //e.printStackTrace(); + return false; + } + + } + + + /* Equal function for floats ( relative diff ) */ + boolean equal(float x, float y) { + + if (x != 0) + return (java.lang.Math.abs((x-y)/x) < 1.0E-15); + + if (y != 0) + return (java.lang.Math.abs((y-x)/y) < 1.0E-15); + + return (x==y); + } + + /* Equal function for doubles ( relative diff ) */ + boolean equal(double x, double y) { + + if (x != 0) + return (java.lang.Math.abs((x-y)/x) < 1.0E-15); + + if (y != 0) + return (java.lang.Math.abs((y-x)/y) < 1.0E-15); + + return (x==y); + } + + + + /** + TypeCode accessor method + @return the Any's TypeCode + **/ + public TypeCode type() { + return tcV; + } + + + /** + TypeCode insertion method + **/ + public void type(TypeCode _tc) { + tcV = _tc; + } + + + /* Value accessors */ + + /** + Reads a value from the stream, according to the inserted TypeCode + **/ + public void read_value(com.ericsson.otp.erlang.OtpInputStream _is, + TypeCode _tc) + throws java.lang.Exception { + + tcV = _tc; + + switch(tcV.kind().value()) { + + case TCKind._tk_short : + shortV = _is.read_short(); + break; + case TCKind._tk_ushort : + shortV = _is.read_ushort(); + break; + case TCKind._tk_long : + intV = _is.read_int(); + break; + case TCKind._tk_ulong : + intV = _is.read_uint(); + break; + case TCKind._tk_longlong : + longV = _is.read_long(); + break; + case TCKind._tk_ulonglong : + longV = _is.read_ulong(); + break; + case TCKind._tk_float : + floatV = _is.read_float(); + break; + case TCKind._tk_double : + doubleV = _is.read_double(); + break; + case TCKind._tk_boolean : + booleanV = _is.read_boolean(); + break; + case TCKind._tk_char : + case TCKind._tk_wchar : + charV = _is.read_char(); + break; + case TCKind._tk_octet : + byteV = _is.read_byte(); + break; + case TCKind._tk_string : + case TCKind._tk_wstring : + stringV = _is.read_string(); + break; + case TCKind._tk_atom : + stringV = _is.read_atom(); + break; + case TCKind._tk_void : + _is.read_atom(); + break; + + /* + * Not supported types + */ + case TCKind._tk_any : + case TCKind._tk_null : + case TCKind._tk_TypeCode : + case TCKind._tk_Principal : + case TCKind._tk_objref : + case TCKind._tk_alias : + case TCKind._tk_except : + case TCKind._tk_longdouble : + case TCKind._tk_fixed : + throw new java.lang.Exception("Unsupported type"); + + default: // User defined type + + if (os == null) + os = new com.ericsson.otp.erlang.OtpOutputStream(); + else + os.reset(); + + try { + read_user_defined(_is, _tc); + is = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray()); + } catch (Exception e) { + throw new java.lang.Exception("BAD VALUE"); + } + } + + } + + void read_user_defined(com.ericsson.otp.erlang.OtpInputStream _is, TypeCode _tc) + throws java.lang.Exception { + + TypeCode memberTC = null; + int len = -1; + int __tag; + + switch(_tc.kind().value()) { + + case TCKind._tk_short : + os.write_short(_is.read_short()); + break; + case TCKind._tk_ushort : + os.write_ushort(_is.read_ushort()); + break; + case TCKind._tk_long : + os.write_int(_is.read_int()); + break; + case TCKind._tk_longlong : + os.write_long(_is.read_long()); + break; + case TCKind._tk_ulong : + os.write_uint(_is.read_uint()); + break; + case TCKind._tk_ulonglong : + os.write_ulong(_is.read_ulong()); + break; + case TCKind._tk_float : + os.write_float(_is.read_float()); + break; + case TCKind._tk_double : + os.write_double(_is.read_double()); + break; + case TCKind._tk_boolean : + os.write_boolean(_is.read_boolean()); + break; + case TCKind._tk_char : + case TCKind._tk_wchar : + os.write_char(_is.read_char()); + break; + case TCKind._tk_octet : + os.write_byte(_is.read_byte()); + break; + case TCKind._tk_string : + case TCKind._tk_wstring : + os.write_string(_is.read_string()); + break; + + case TCKind._tk_struct: + len = _is.read_tuple_head(); + os.write_tuple_head(len); + os.write_atom(_is.read_atom()); + // Member list + len -=1; + for(int i=0; iInstead for write,read methods, the methods marshal respective +unmarshal are used to denote the implementation difference. + +**/ + + +public class AnyHelper { + + // Constructors + private AnyHelper() {} + + // Methods + /** + Marshal method for the Any class, encodes the Any object to the output stream. + **/ + public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Any _any) + throws java.lang.Exception { + + TypeCode _tc = _any.type(); + + _out.write_tuple_head(3); + _out.write_atom("any"); + + TypeCode.marshal(_out, _tc); + _any.write_value(_out); + + } + + /** + Unmarshal method for the Any class, decodes an Any object from the stream. + @return Any, read from the input stream + **/ + public static Any unmarshal(com.ericsson.otp.erlang.OtpInputStream _in) + throws java.lang.Exception { + + Any _value; + TypeCode _tc; + + _in.read_tuple_head(); + + if ((_in.read_atom()).compareTo("any") != 0) + throw new java.lang.Exception(""); + + _tc = TypeCode.unmarshal(_in); + _value = new Any(); + _value.read_value(_in,_tc); + + return _value; + } + +} + + + diff --git a/lib/ic/java_src/com/ericsson/otp/ic/AnyHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/AnyHolder.java new file mode 100644 index 0000000..fa28bd0 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/AnyHolder.java @@ -0,0 +1,60 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + +Holder class for Any, according to OMG-IDL java mapping. +

Instead for _write,_read methods, the methods _marshal respective +_unmarshal are used to denote the implementation difference. + +**/ + +final public class AnyHolder { + + // Instance variables + public Any value; + + // Constructors + public AnyHolder() {} + + public AnyHolder(Any initial) { + value = initial; + } + + // Methods + /** + Marshal method for the Any class, encodes the Any object to the output stream. + **/ + public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out) + throws java.lang.Exception { + AnyHelper.marshal(out, value); + } + + /** + Unmarshal method for the Any class, decodes an Any object from the stream and + assigns it to the Holder value. + **/ + public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in) + throws java.lang.Exception { + value = AnyHelper.unmarshal(in); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/BooleanHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/BooleanHolder.java new file mode 100644 index 0000000..5e91ae8 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/BooleanHolder.java @@ -0,0 +1,62 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * A Holder class for IDL's out/inout argument passing modes for boolean + * + */ +package com.ericsson.otp.ic; + +/** + +Holder class for Boolean, according to OMG-IDL java mapping. + +**/ + + +final public class BooleanHolder implements Holder { + public boolean value; + + public BooleanHolder() {} + + public BooleanHolder(boolean initial) { + value = initial; + } + + /* Extra methods not in standard. */ + /** + Comparisson method for Booleans. + @return true if the input object equals the current object, false otherwize + **/ + public boolean equals( Object obj ) { + if( obj instanceof Boolean ) + return ( value == ((Boolean)obj).booleanValue()); + else + return false; + } + + /** + Comparisson method for Booleans. + @return true if the input boolean value equals the value of the current object, false otherwize + **/ + public boolean equals( boolean b ) { + return ( value == b ); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/ByteHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/ByteHolder.java new file mode 100644 index 0000000..cd70573 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/ByteHolder.java @@ -0,0 +1,61 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * A Holder class for IDL's out/inout argument passing modes for byte + * + */ +package com.ericsson.otp.ic; + +/** + +Holder class for Byte, according to OMG-IDL java mapping. + +**/ + +final public class ByteHolder implements Holder { + public byte value; + + public ByteHolder() {} + + public ByteHolder(byte initial) { + value = initial; + } + + /* Extra methods not in standard. */ + /** + Comparisson method for Bytes. + @return true if the input object equals the current object, false otherwize + **/ + public boolean equals( Object obj ) { + if( obj instanceof Byte ) + return ( value == ((Byte)obj).byteValue()); + else + return false; + } + + /** + Comparisson method for Byte. + @return true if the input boolean value equals the value of the current object, false otherwize + **/ + public boolean equals( byte b ) { + return ( value == b); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/CharHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/CharHolder.java new file mode 100644 index 0000000..6005269 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/CharHolder.java @@ -0,0 +1,63 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * A Holder class for IDL's out/inout argument passing modes for char + * + */ +package com.ericsson.otp.ic; + + +/** + +Holder class for Char, according to OMG-IDL java mapping. + +**/ + + +final public class CharHolder implements Holder { + public char value; + + public CharHolder() {} + + public CharHolder(char initial) { + value = initial; + } + + /* Extra methods not in standard. */ + /** + Comparisson method for Chars. + @return true if the input object equals the current object, false otherwize + **/ + public boolean equals( Object obj ) { + if( obj instanceof Character ) + return ( value == ((Character)obj).charValue()); + else + return false; + } + + /** + Comparisson method for Chars. + @return true if the input char value equals the value of the current object, false otherwize + **/ + public boolean equals( char c ) { + return ( value == c); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/DoubleHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/DoubleHolder.java new file mode 100644 index 0000000..d0da72c --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/DoubleHolder.java @@ -0,0 +1,61 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * A Holder class for IDL's out/inout argument passing modes for double + * + */ +package com.ericsson.otp.ic; + +/** + +Holder class for Double, according to OMG-IDL java mapping. + +**/ + +final public class DoubleHolder implements Holder { + public double value; + + public DoubleHolder() {} + + public DoubleHolder(double initial) { + value = initial; + } + + /* Extra methods not in standard. */ + /** + Comparisson method for Doubles. + @return true if the input object equals the current object, false otherwize + **/ + public boolean equals( Object obj ) { + if( obj instanceof Double ) + return ( value == ((Double)obj).doubleValue()); + else + return false; + } + + /** + Comparisson method for Doubles. + @return true if the input double value equals the value of the current object, false otherwize + **/ + public boolean equals( double d ) { + return ( value == d); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java new file mode 100644 index 0000000..f0c66f0 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java @@ -0,0 +1,475 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * The Environment class for Java IDL + * + */ +package com.ericsson.otp.ic; + +/** + + The Environment class handles communication + setup and stub state. The methods of this class + are specially designed for the generated stubs. + This class must be used when designing asynchronous + message passing. + + **/ + + +public class Environment { + + // Private variables + private com.ericsson.otp.erlang.OtpSelf self; + private com.ericsson.otp.erlang.OtpPeer peer; + private java.lang.Object server; + private java.lang.String cookie; + private com.ericsson.otp.erlang.OtpConnection connection; + private com.ericsson.otp.erlang.OtpErlangRef send_ref; /* Client side send reference */ + private com.ericsson.otp.erlang.OtpErlangRef receive_ref; /* Client side received reference */ + private com.ericsson.otp.erlang.OtpErlangPid clientP; + private com.ericsson.otp.erlang.OtpErlangPid serverP; + private com.ericsson.otp.erlang.OtpOutputStream os; /* Output stream */ + private com.ericsson.otp.erlang.OtpInputStream is; /* Input stream */ + private boolean stopped; + + // Private variables used by server only + private int tag; + private java.lang.String operation; + private java.lang.String type; + private com.ericsson.otp.erlang.OtpErlangRef ref; /* Server side client reference */ + private com.ericsson.otp.erlang.OtpErlangPid caller; /* Server side client pid */ + + // Tags to distiguish client / server environments + private boolean clientT; + private boolean serverT; + + + /** + Client stub side constructor. + **/ + public Environment(com.ericsson.otp.erlang.OtpSelf _Self, + com.ericsson.otp.erlang.OtpPeer _Peer, + java.lang.Object _Server) throws java.lang.Exception { + + init(); + clientT = true; + self = _Self; + peer = _Peer; + server = _Server; + os = new com.ericsson.otp.erlang.OtpOutputStream(); + } + + + /** + Client stub side constructor. + **/ + public Environment(java.lang.String _SelfNode, + java.lang.String _PeerNode, + java.lang.String _Cookie, + java.lang.Object _Server) throws java.lang.Exception { + + init(); + clientT = true; + self = new com.ericsson.otp.erlang.OtpSelf(_SelfNode, _Cookie); + peer = new com.ericsson.otp.erlang.OtpPeer(_PeerNode); + cookie = _Cookie; + server = _Server; + os = new com.ericsson.otp.erlang.OtpOutputStream(); + } + + + /** + Client stub side constructor. + **/ + public Environment(com.ericsson.otp.erlang.OtpConnection _connection, + java.lang.Object _Server) throws java.lang.Exception { + + init(); + clientT = true; + self = _connection.self(); + peer = _connection.peer(); + connection = _connection; + server = _Server; + os = new com.ericsson.otp.erlang.OtpOutputStream(); + } + + + /** + Server skeleton side constructor. + **/ + public Environment() throws java.lang.Exception { + + init(); + serverT = true; + stopped = false; + os = new com.ericsson.otp.erlang.OtpOutputStream(); + + } + + + /* Communication toolbox */ + + /** + Client stub side connector. + **/ + public void connect() throws java.lang.Exception { + + if (connection == null) + connection = self.connect(peer); + + clientP = new com.ericsson.otp.erlang.OtpErlangPid(self); /* This is not perfect */ + send_ref = new com.ericsson.otp.erlang.OtpErlangRef(self); + + } + + /** + Reconnects a client by closing existing connection + and connecting. + **/ + public void reconnect() throws java.lang.Exception { + + if (connection.isConnected()) + connection.close(); + + connection = self.connect(peer); + + } + + /** + Closes the established connection. + **/ + public void disconnect() { + + connection.close(); + + } + + + /** + Client side message sender. + **/ + public void send() throws java.lang.Exception { + + if (server instanceof java.lang.String) + connection.sendBuf((java.lang.String)server, os); + else + connection.sendBuf((com.ericsson.otp.erlang.OtpErlangPid)server, os); + + } + + + /** + Client message receiver. + **/ + public void receive() throws java.lang.Exception { + + is = connection.receiveBuf(); + + if (clientT) { // If client, decode message reference too + is.read_tuple_head(); + receive_ref = is.read_ref(); + } + } + + + /** + Universal message receiver. + **/ + public void receive(com.ericsson.otp.erlang.OtpConnection _connection) throws java.lang.Exception { + + is = _connection.receiveBuf(); + + if (clientT) { // If client, decode message reference too + is.read_tuple_head(); + receive_ref = is.read_ref(); + } + } + + + /* Accessors */ + + /** + Server RegName/OtpErlangPid accessor. + Used to access the server Reg/Pid, which + initiated the connection. + @return java.lang.Object, the server for the active OtpConnection. + **/ + public java.lang.Object server() { + + return server; + + } + + /** + Caller identity accessor. Used by a server stub to access the + caller identity of the received message. + @return OtpErlangPid, the caller identity. + **/ + public com.ericsson.otp.erlang.OtpErlangPid caller_pid() { + + return clientP; + + } + + + /** + Received message reference accessor. Used by a server stub to access the + reference of the received message. + @return OtpErlangRef, the reference of the received message. + **/ + public com.ericsson.otp.erlang.OtpErlangRef received_ref() { + + return receive_ref; + + } + + + /* Encoders */ + + /** + Client Pid Encoder. Used by a server stub to encode the + enclosed client process identity. + **/ + public void write_client_pid() { + + os.write_pid(clientP.node(),clientP.id(),clientP.serial(),clientP.creation()); + + } + + /** + Client Ref Encoder. Used by a server stub to encode the + enclosed client message reference. + **/ + public void write_client_ref() { + + os.write_ref(send_ref.node(),send_ref.id(),send_ref.creation()); + + } + + + + /* Field access functions */ + + /** + Output Stream accessor. + @return OtpOutputStream, the enclosed output stream. + **/ + public com.ericsson.otp.erlang.OtpOutputStream getOs() { + return os; + } + + /** + Input Stream accessor. + @return OtpInputStream, the enclosed input stream. + **/ + public com.ericsson.otp.erlang.OtpInputStream getIs() { + return is; + } + + /** + Server skeleton side client (caller) pid accessor. + @return OtpErlangPid, the caller process identity. + **/ + public com.ericsson.otp.erlang.OtpErlangPid getScaller() { + return caller; + } + + /** + Server skeleton side client call reference accessor. + @return OtpErlangRef, the latest call message reference. + **/ + public com.ericsson.otp.erlang.OtpErlangRef getSref() { + return ref; + } + + + + /* Field modifiers */ + + + + /* Decoders */ + + /** + Decodes the message head from existing stream. + Assignes message data to private variables of the Environment Object. + **/ + public void uHead() throws java.lang.Exception { + uHead(is); + } + + /** + Decodes the message head and writes over input stream. + Assignes message data to private variables of the Environment Object. + **/ + public void uHead(com.ericsson.otp.erlang.OtpInputStream _is) throws java.lang.Exception { + + is = _is; + is.read_tuple_head(); + type = is.read_atom(); + + if (type.equals("$gen_call")) { // Call type operation + is.read_tuple_head(); + caller = is.read_pid(); + ref = is.read_ref(); + tag = is.peek(); + + switch (tag) { + case com.ericsson.otp.erlang.OtpExternal.atomTag: + operation = is.read_atom(); + break; + default: + is.read_tuple_head(); + operation = is.read_atom(); + } + } else { // Cast type operation + tag = is.peek(); + switch (tag) { + case com.ericsson.otp.erlang.OtpExternal.atomTag: + operation = is.read_atom(); + break; + default: + is.read_tuple_head(); + operation = is.read_atom(); + } + } + } + + /** + Operation label accessor. + @return int, the label hash value. + **/ + public int uLabel(java.util.Dictionary _operations) { + + java.lang.Integer __label = + (java.lang.Integer) _operations.get(operation); + + if(__label == null) + return -1; + + return __label.intValue(); + } + + + + /* Controllers */ + + /** + Operation controller. + @return boolean, true if the operation variable found in Environment class + is supported in the input operation dictionary, false otherwize. + **/ + public boolean validOp(java.util.Dictionary _operations) { + + if((_operations.get(operation)) == null) + return false; + + return true; + } + + + /** + Server stop request controller. + @return boolean, true if there is a client request for the server + to be stopped, false otherwize. + **/ + public boolean isStopped() { + return stopped; + }; + + + + /* Destroy functions */ + + /* + Creates and sends a stop message. + Called by client stub to terminate the server. + */ + public void client_stop_server() + throws java.lang.Exception { + + // Message header assembly + os.reset(); + os.write_tuple_head(2); + os.write_atom("$gen_cast"); + + os.write_atom("stop"); + + send(); + + } + + /* + Sets the stop flag for the server. + Called by server skeleton when stop message is received. + */ + public void server_stop_server() { + + // Note at server is dead ! + stopped = true; + } + + + /* Private methods */ + + /** + Private variable initialization. + **/ + public void init() { + + clientT = false; + serverT = false; + stopped = false; + self = null; + peer = null; + server = null; + cookie = null; + connection = null; + clientP = null; + serverP = null; + send_ref = null; + receive_ref = null; + os = null; + is = null; + + tag = -1; + operation = null; + type = null; + + }; + +} + + + + + + + + + + + + + + + + diff --git a/lib/ic/java_src/com/ericsson/otp/ic/FloatHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/FloatHolder.java new file mode 100644 index 0000000..4904fd5 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/FloatHolder.java @@ -0,0 +1,62 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * A Holder class for IDL's out/inout argument passing modes for float + * + */ +package com.ericsson.otp.ic; + +/** + +Holder class for Float, according to OMG-IDL java mapping. + +**/ + + +final public class FloatHolder implements Holder { + public float value; + + public FloatHolder() {} + + public FloatHolder(float initial) { + value = initial; + } + + /* Extra methods not in standard. */ + /** + Comparisson method for Floats. + @return true if the input object equals the current object, false otherwize + **/ + public boolean equals( Object obj ) { + if( obj instanceof Float ) + return ( value == ((Float)obj).floatValue()); + else + return false; + } + + /** + Comparisson method for Floats. + @return true if the input float value equals the value of the current object, false otherwize + **/ + public boolean equals( float f ) { + return ( value == f); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Holder.java b/lib/ic/java_src/com/ericsson/otp/ic/Holder.java new file mode 100644 index 0000000..a00efce --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/Holder.java @@ -0,0 +1,33 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * Holder interface class. +*/ +package com.ericsson.otp.ic; +import java.io.Serializable; + +/** + Holder interface class. + **/ + +public interface Holder extends Serializable +{ + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/IntHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/IntHolder.java new file mode 100644 index 0000000..1037af4 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/IntHolder.java @@ -0,0 +1,62 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * A Holder class for IDL's out/inout argument passing modes for long + * + */ +package com.ericsson.otp.ic; + +/** + +Holder class for Int, according to OMG-IDL java mapping. + +**/ + +final public class IntHolder implements Holder { + public int value; + + public IntHolder() {} + + public IntHolder(int initial) { + value = initial; + } + + /* Extra methods not in standard. */ + + /** + Comparisson method for Ints. + @return true if the input object equals the current object, false otherwize + **/ + public boolean equals( Object obj ) { + if( obj instanceof Integer ) + return ( value == ((Integer)obj).intValue()); + else + return false; + } + + /** + Comparisson method for Ints. + @return true if the input int value equals the value of the current object, false otherwize + **/ + public boolean equals( int i ) { + return ( value == i); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/LongHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/LongHolder.java new file mode 100644 index 0000000..8fa4430 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/LongHolder.java @@ -0,0 +1,60 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * A Holder class for IDL's out/inout argument passing modes for long + * + */ +package com.ericsson.otp.ic; + +/** + +Holder class for Long, used by the Term class. + +**/ + +final public class LongHolder implements Holder { + public long value; + + public LongHolder() {} + + public LongHolder(long initial) { + value = initial; + } + + /** + Comparisson method for Longs. + @return true if the input object equals the current object, false otherwize + **/ + public boolean equals( Object obj ) { + if( obj instanceof Long ) + return ( value == ((Long)obj).longValue()); + else + return false; + } + + /** + Comparisson method for Longs. + @return true if the input long value equals the value of the current object, false otherwize + **/ + public boolean equals( long l ) { + return ( value == l); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Makefile b/lib/ic/java_src/com/ericsson/otp/ic/Makefile new file mode 100644 index 0000000..f730749 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/Makefile @@ -0,0 +1,118 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk + + +JAVA_DEST_ROOT = $(ERL_TOP)/lib/ic/priv/ +JAVA_SRC_ROOT = $(ERL_TOP)/lib/ic/java_src/ +JAVA_CLASS_SUBDIR = com/ericsson/otp/ic/ +JAVA_INCL_ROOT = $(ERL_TOP)/lib/jinterface/priv/ + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include $(ERL_TOP)/lib/ic/vsn.mk +VSN=$(IC_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/ic-$(VSN) + +# +# JAVA macros +# +JAVA_CLASSES = \ + Holder \ + BooleanHolder \ + ByteHolder \ + CharHolder \ + DoubleHolder \ + FloatHolder \ + IntHolder \ + LongHolder \ + ShortHolder \ + StringHolder \ + Environment \ + Any \ + AnyHelper \ + AnyHolder \ + TypeCode \ + TCKind \ + Pid \ + PidHolder \ + PidHelper \ + Ref \ + RefHolder \ + RefHelper \ + Port \ + PortHolder \ + PortHelper \ + Term \ + TermHolder \ + TermHelper + +TARGET_FILES= $(JAVA_CLASSES:%=$(JAVA_DEST_ROOT)$(JAVA_CLASS_SUBDIR)%.class) +JAVA_FILES= $(JAVA_CLASSES:%=%.java) + +JARFILE= ic.jar + +# ---------------------------------------------------- +# Programs and Flags +# ---------------------------------------------------- +CLASSPATH = $(JAVA_SRC_ROOT):$(JAVA_INCL_ROOT) + +JAR= jar + +JAVADOCFLAGS=-d $(DOCDIR) +JAVAFLAGS=-d $(JAVA_DEST_ROOT) +JARFLAGS= -cvf + +JAVA_OPTIONS = + +# ---------------------------------------------------- +# Make Rules +# ---------------------------------------------------- + +debug opt: $(JAVA_DEST_ROOT)$(JARFILE) + +$(JAVA_DEST_ROOT)$(JARFILE): $(TARGET_FILES) + @(cd $(JAVA_DEST_ROOT) ; $(JAR) $(JARFLAGS) $(JARFILE) $(JAVA_CLASS_SUBDIR)) + +clean: + rm -f $(TARGET_FILES) *~ + +docs: + +# ---------------------------------------------------- +# Release Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/java_src/com/ericsson/otp/ic + $(INSTALL_DATA) $(JAVA_FILES) $(RELSYSDIR)/java_src/com/ericsson/otp/ic + $(INSTALL_DIR) $(RELSYSDIR)/priv + $(INSTALL_DATA) $(JAVA_DEST_ROOT)$(JARFILE) $(RELSYSDIR)/priv + +release_docs_spec: + diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Pid.java b/lib/ic/java_src/com/ericsson/otp/ic/Pid.java new file mode 100644 index 0000000..8d0608b --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/Pid.java @@ -0,0 +1,55 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + + +/** + +Pid class mapps the built-in erlang type pid, a process identity. + +**/ + + +final public class Pid extends com.ericsson.otp.erlang.OtpErlangPid { + + public Pid(com.ericsson.otp.erlang.OtpSelf self) { + super(self); + } + + public Pid(com.ericsson.otp.erlang.OtpInputStream buf) + throws com.ericsson.otp.erlang.OtpErlangDecodeException { + super(buf); + } + + + public Pid(String node, int id, int serial, int creation) { + super(node,id,serial,creation); + } + + + /** + Comparisson method for Pid. + @return true if the input Pid value equals the value of the current object, false otherwize + **/ + public boolean equal(Pid _pid) { + return super.equals(_pid); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/PidHelper.java b/lib/ic/java_src/com/ericsson/otp/ic/PidHelper.java new file mode 100644 index 0000000..a51ff2f --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/PidHelper.java @@ -0,0 +1,144 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + Helper class for Pid. + **/ + +public class PidHelper { + + // constructors + private PidHelper() {} + + // methods + /** + Marshal method for the Pid class, encodes the Pid object to the output stream. + **/ + public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Pid _value) + throws java.lang.Exception { + + _out.write_pid(_value.node(),_value.id(),_value.serial(),_value.creation()); + } + + /** + Unmarshal method for the Pid class, decodes a Pid object from the stream. + @return Pid, read from the input stream + **/ + public static Pid unmarshal(com.ericsson.otp.erlang.OtpInputStream _in) + throws java.lang.Exception { + + // Double job is done here, there should be + // a function returning a Pid instead of an + // OtpErlangPid + com.ericsson.otp.erlang.OtpErlangPid oep = _in.read_pid(); + + return new Pid(oep.node(),oep.id(),oep.serial(),oep.creation()); + } + + /** + Standard method that returns the interface repository identity. + @return String containing the interface repository identity of Pid + **/ + public static String id() { + return "IDL:com/ericsson/otp/ic/Pid:1.0"; + } + + /** + Standard method that returns the Pid class name. + @return String containing the class name of Pid + **/ + public static String name() { + return "Pid"; + } + + /** + Holds the TypeCode + **/ + private static com.ericsson.otp.ic.TypeCode _tc; + + /** + Standard TypeCode accessor method. + @return the TypeCode for Pid + **/ + synchronized public static com.ericsson.otp.ic.TypeCode type() { + + if (_tc != null) + return _tc; + + com.ericsson.otp.ic.TypeCode _tc0 = + new com.ericsson.otp.ic.TypeCode(); + _tc0.kind(com.ericsson.otp.ic.TCKind.tk_struct); + _tc0.id("IDL:com/ericsson/otp/ic/Pid:1.0"); + _tc0.name("Pid"); + _tc0.member_count(4); + _tc0.member_name(0,"node"); + com.ericsson.otp.ic.TypeCode _tc1 = + new com.ericsson.otp.ic.TypeCode(); + _tc1.kind(com.ericsson.otp.ic.TCKind.tk_string); + _tc1.length(256); + _tc0.member_type(0,_tc1); + _tc0.member_name(1,"num"); + com.ericsson.otp.ic.TypeCode _tc2 = + new com.ericsson.otp.ic.TypeCode(); + _tc2.kind(com.ericsson.otp.ic.TCKind.tk_ulong); + _tc0.member_type(1,_tc2); + _tc0.member_name(2,"serial"); + com.ericsson.otp.ic.TypeCode _tc3 = + new com.ericsson.otp.ic.TypeCode(); + _tc3.kind(com.ericsson.otp.ic.TCKind.tk_ulong); + _tc0.member_type(2,_tc3); + _tc0.member_name(3,"creation"); + com.ericsson.otp.ic.TypeCode _tc4 = + new com.ericsson.otp.ic.TypeCode(); + _tc4.kind(com.ericsson.otp.ic.TCKind.tk_ulong); + _tc0.member_type(3,_tc4); + + _tc = _tc0; + + return _tc0; + } + + + /** + Standard method for inserting a Pid to an Any. + **/ + public static void insert(com.ericsson.otp.ic.Any _any, Pid _this) + throws java.lang.Exception { + + com.ericsson.otp.erlang.OtpOutputStream _os = + new com.ericsson.otp.erlang.OtpOutputStream(); + + _any.type(type()); + marshal(_os, _this); + _any.insert_Streamable(_os); + } + + /** + Standard method for extracting a Pid from an Any. + @return Pid, the value found in an Any contained stream. + **/ + public static Pid extract(com.ericsson.otp.ic.Any _any) + throws java.lang.Exception { + + return unmarshal(_any.extract_Streamable()); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/PidHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/PidHolder.java new file mode 100644 index 0000000..9e42385 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/PidHolder.java @@ -0,0 +1,54 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + Holder class for Pid. + **/ + +final public class PidHolder { + + /** + Pid instance variable. + **/ + public Pid value; + + // constructors + public PidHolder() {} + public PidHolder(Pid initial) { + value = initial; + } + + // methods + /** + Marshal method for the PidHolder class, encodes the Pid object value to the output stream. + **/ + public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out) throws java.lang.Exception { + PidHelper.marshal(out, value); + } + + /** + Unmarshal method for the PidHolder class, decodes a Pid object from the output stream + and assigns it to the Holder value field. + **/ + public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in) throws java.lang.Exception { + value = PidHelper.unmarshal(in); + } +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Port.java b/lib/ic/java_src/com/ericsson/otp/ic/Port.java new file mode 100644 index 0000000..e830365 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/Port.java @@ -0,0 +1,48 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + +Port class mapps the built-in erlang type port, a process port. + +**/ + +final public class Port extends com.ericsson.otp.erlang.OtpErlangPort { + + public Port(com.ericsson.otp.erlang.OtpInputStream buf) + throws com.ericsson.otp.erlang.OtpErlangDecodeException { + super(buf); + } + + public Port(String node, int id, int creation) { + super(node,id,creation); + } + + /** + Comparisson method for Port. + @return true if the input Port value equals the value of the current object, false otherwize + **/ + public boolean equal(Port _port) { + return super.equals(_port); + } + + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/PortHelper.java b/lib/ic/java_src/com/ericsson/otp/ic/PortHelper.java new file mode 100644 index 0000000..26c7971 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/PortHelper.java @@ -0,0 +1,140 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + Helper class for Port. + **/ + +public class PortHelper { + + // constructors + private PortHelper() {} + + // methods + + /** + Marshal method for the Port class, encodes the Port object to the output stream. + **/ + public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Port _value) + throws java.lang.Exception { + + _out.write_port(_value.node(),_value.id(),_value.creation()); + } + + /** + Unmarshal method for the Port class, decodes a Port object from the stream. + @return Port, read from the input stream + **/ + public static Port unmarshal(com.ericsson.otp.erlang.OtpInputStream _in) + throws java.lang.Exception { + + // Double job is done here, there should be + // a function returning a Port instead of an + // OtpErlangPort + com.ericsson.otp.erlang.OtpErlangPort oep = _in.read_port(); + + return new Port(oep.node(),oep.id(),oep.creation()); + } + + /** + Standard method that returns the interface repository identity. + @return String containing the interface repository identity of Port + **/ + public static String id() { + return "IDL:com/ericsson/otp/ic/Port:1.0"; + } + + /** + Standard method that returns the Port class name. + @return String containing the class name of Port + **/ + public static String name() { + return "Port"; + } + + /** + Holds the TypeCode + **/ + private static com.ericsson.otp.ic.TypeCode _tc; + + /** + Standard TypeCode accessor method. + @return the TypeCode for Port + **/ + synchronized public static com.ericsson.otp.ic.TypeCode type() { + + if (_tc != null) + return _tc; + + com.ericsson.otp.ic.TypeCode _tc0 = + new com.ericsson.otp.ic.TypeCode(); + _tc0.kind(com.ericsson.otp.ic.TCKind.tk_struct); + _tc0.id("IDL:com/ericsson/otp/ic/Port:1.0"); + _tc0.name("Port"); + _tc0.member_count(3); + _tc0.member_name(0,"node"); + com.ericsson.otp.ic.TypeCode _tc1 = + new com.ericsson.otp.ic.TypeCode(); + _tc1.kind(com.ericsson.otp.ic.TCKind.tk_string); + _tc1.length(256); + _tc0.member_type(0,_tc1); + _tc0.member_name(1,"id"); + com.ericsson.otp.ic.TypeCode _tc2 = + new com.ericsson.otp.ic.TypeCode(); + _tc2.kind(com.ericsson.otp.ic.TCKind.tk_ulong); + _tc0.member_type(1,_tc2); + _tc0.member_name(2,"creation"); + com.ericsson.otp.ic.TypeCode _tc3 = + new com.ericsson.otp.ic.TypeCode(); + _tc3.kind(com.ericsson.otp.ic.TCKind.tk_ulong); + _tc0.member_type(2,_tc3); + + _tc = _tc0; + + return _tc0; + } + + + /** + Standard method for inserting a Port to an Any. + **/ + public static void insert(com.ericsson.otp.ic.Any _any, Port _this) + throws java.lang.Exception { + + com.ericsson.otp.erlang.OtpOutputStream _os = + new com.ericsson.otp.erlang.OtpOutputStream(); + + _any.type(type()); + marshal(_os, _this); + _any.insert_Streamable(_os); + } + + /** + Standard method for extracting a Port from an Any. + @return Port, the value found in an Any contained stream. + **/ + public static Port extract(com.ericsson.otp.ic.Any _any) + throws java.lang.Exception { + + return unmarshal(_any.extract_Streamable()); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/PortHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/PortHolder.java new file mode 100644 index 0000000..80744f2 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/PortHolder.java @@ -0,0 +1,56 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + Holder class for Port. + **/ + +final public class PortHolder { + + /** + Port instance variable. + **/ + public Port value; + + // constructors + public PortHolder() {} + public PortHolder(Port initial) { + value = initial; + } + + // methods + /** + Marshal method for the PortHolder class, encodes the Port object value to the output stream. + **/ + public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out) + throws java.lang.Exception { + PortHelper.marshal(out, value); + } + + /** + Unmarshal method for the PortHolder class, decodes a Port object from the output stream + and assigns it to the Holder value field. + **/ + public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in) + throws java.lang.Exception { + value = PortHelper.unmarshal(in); + } +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Ref.java b/lib/ic/java_src/com/ericsson/otp/ic/Ref.java new file mode 100644 index 0000000..0a38769 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/Ref.java @@ -0,0 +1,60 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + +Ref class mapps the built-in erlang type Ref, a message reference. + +**/ + +final public class Ref extends com.ericsson.otp.erlang.OtpErlangRef { + + public Ref(com.ericsson.otp.erlang.OtpSelf self) { + super(self); + } + + + public Ref(com.ericsson.otp.erlang.OtpInputStream buf) + throws com.ericsson.otp.erlang.OtpErlangDecodeException { + super(buf); + } + + /** + Old style Ref costructor. Costructs an Ref that coresponds to the + old erlang Ref type. + **/ + public Ref(String node, int id, int creation) { + super(node,id,creation); + } + + public Ref(String node, int[] ids, int creation) { + super(node,ids,creation); + } + + /** + Comparisson method for Ref. + @return true if the input Ref value equals the value of the current object, false otherwize + **/ + public boolean equal(Ref _ref) { + return super.equals(_ref); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/RefHelper.java b/lib/ic/java_src/com/ericsson/otp/ic/RefHelper.java new file mode 100644 index 0000000..a58dec7 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/RefHelper.java @@ -0,0 +1,141 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + Helper class for Ref. + **/ + +public class RefHelper { + + // constructors + private RefHelper() {} + + // methods + /** + Marshal method for the Ref class, encodes the Ref object to the output stream. + **/ + public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Ref _value) + throws java.lang.Exception { + + _out.write_ref(_value.node(),_value.id(),_value.creation()); + } + + /** + Unmarshal method for the Ref class, decodes a Ref object from the stream. + @return Ref, read from the input stream + **/ + public static Ref unmarshal(com.ericsson.otp.erlang.OtpInputStream _in) + throws java.lang.Exception { + + // Double job is done here, there should be + // a function returning a Ref instead of an + // OtpErlangRef + com.ericsson.otp.erlang.OtpErlangRef oer = _in.read_ref(); + + if (oer.isNewRef()) + return new Ref(oer.node(),oer.ids(),oer.creation()); + else + return new Ref(oer.node(),oer.id(),oer.creation()); + } + + /** + Standard method that returns the interface repository identity. + @return String containing the interface repository identity of Ref + **/ + public static String id() { + return "IDL:com/ericsson/otp/ic/Ref:1.0"; + } + + /** + Standard method that returns the Ref class name. + @return String containing the class name of Ref + **/ + public static String name() { + return "Ref"; + } + + /** + Holds the TypeCode + **/ + private static com.ericsson.otp.ic.TypeCode _tc; + + /** + Standard TypeCode accessor method. + @return the TypeCode for Ref + **/ + synchronized public static com.ericsson.otp.ic.TypeCode type() { + + if (_tc != null) + return _tc; + + com.ericsson.otp.ic.TypeCode _tc0 = + new com.ericsson.otp.ic.TypeCode(); + _tc0.kind(com.ericsson.otp.ic.TCKind.tk_struct); + _tc0.id("IDL:com/ericsson/otp/ic/Ref:1.0"); + _tc0.name("Ref"); + _tc0.member_count(3); + _tc0.member_name(0,"node"); + com.ericsson.otp.ic.TypeCode _tc1 = + new com.ericsson.otp.ic.TypeCode(); + _tc1.kind(com.ericsson.otp.ic.TCKind.tk_string); + _tc1.length(256); + _tc0.member_type(0,_tc1); + _tc0.member_name(1,"id"); + com.ericsson.otp.ic.TypeCode _tc2 = + new com.ericsson.otp.ic.TypeCode(); + _tc2.kind(com.ericsson.otp.ic.TCKind.tk_ulong); + _tc0.member_type(1,_tc2); + _tc0.member_name(2,"creation"); + com.ericsson.otp.ic.TypeCode _tc3 = + new com.ericsson.otp.ic.TypeCode(); + _tc3.kind(com.ericsson.otp.ic.TCKind.tk_ulong); + _tc0.member_type(2,_tc3); + + _tc = _tc0; + + return _tc0; + } + + /** + Standard method for inserting a Ref to an Any. + **/ + public static void insert(com.ericsson.otp.ic.Any _any, Ref _this) + throws java.lang.Exception { + + com.ericsson.otp.erlang.OtpOutputStream _os = + new com.ericsson.otp.erlang.OtpOutputStream(); + + _any.type(type()); + marshal(_os, _this); + _any.insert_Streamable(_os); + } + + /** + Standard method for extracting a Ref from an Any. + @return Ref, the value found in an Any contained stream. + **/ + public static Ref extract(com.ericsson.otp.ic.Any _any) + throws java.lang.Exception { + + return unmarshal(_any.extract_Streamable()); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/RefHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/RefHolder.java new file mode 100644 index 0000000..2dc3f4b --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/RefHolder.java @@ -0,0 +1,54 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + Holder class for Ref. + **/ + +final public class RefHolder { + + /** + Ref instance variable. + **/ + public Ref value; + + // constructors + public RefHolder() {} + public RefHolder(Ref initial) { + value = initial; + } + + // methods + /** + Marshal method for the RefHolder class, encodes the Ref object value to the output stream. + **/ + public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out) throws java.lang.Exception { + RefHelper.marshal(out, value); + } + + /** + Unmarshal method for the RefHolder class, decodes a Ref object from the output stream + and assigns it to the Holder value field. + **/ + public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in) throws java.lang.Exception { + value = RefHelper.unmarshal(in); + } +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/ShortHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/ShortHolder.java new file mode 100644 index 0000000..81fd765 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/ShortHolder.java @@ -0,0 +1,61 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * A Holder class for IDL's out/inout argument passing modes for long + * + */ +package com.ericsson.otp.ic; + +/** + +Holder class for Short, according to OMG-IDL java mapping. + +**/ + +final public class ShortHolder implements Holder { + public short value; + + public ShortHolder() {} + + public ShortHolder(short initial) { + value = initial; + } + + /* Extra methods not in standard. */ + /** + Comparisson method for Shorts. + @return true if the input object equals the current object, false otherwize + **/ + public boolean equals( Object obj ) { + if( obj instanceof Short ) + return ( value == ((Short)obj).shortValue()); + else + return false; + } + + /** + Comparisson method for Shorts. + @return true if the input short value equals the value of the current object, false otherwize + **/ + public boolean equals( short s ) { + return ( value == s); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/StringHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/StringHolder.java new file mode 100644 index 0000000..09b42dc --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/StringHolder.java @@ -0,0 +1,62 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * A Holder class for IDL's out/inout argument passing modes for string + * + */ +package com.ericsson.otp.ic; + + +/** + +Holder class for String, according to OMG-IDL java mapping. + +**/ + +final public class StringHolder implements Holder { + public String value; + + public StringHolder() {} + + public StringHolder(String initial) { + value = initial; + } + + /* Extra methods not in standard. */ + /** + Comparisson method for Strings. + @return true if the input object equals the current object, false otherwize + **/ + public boolean equals( Object obj ) { + if( obj instanceof String ) + return ( value == obj); + else + return false; + } + + /** + Comparisson method for Strings. + @return true if the input String value equals the value of the current object, false otherwize + **/ + public boolean equals( String s ) { + return ( value == s); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/TCKind.java b/lib/ic/java_src/com/ericsson/otp/ic/TCKind.java new file mode 100644 index 0000000..210f7f6 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/TCKind.java @@ -0,0 +1,199 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * The TCKind class for Java IDL + * + */ +package com.ericsson.otp.ic; + +/** + The TCKind class is the implementation of the OMG-IDL enumerant type TCKind. + **/ + +final public class TCKind { + + // instance variables + public static final int _tk_null = 0, + _tk_void = 1, + _tk_short = 2, + _tk_long = 3, + _tk_ushort = 4, + _tk_ulong = 5, + _tk_float = 6, + _tk_double = 7, + _tk_boolean = 8, + _tk_char = 9, + _tk_octet = 10, + _tk_any = 11, + _tk_TypeCode = 12, + _tk_Principal = 13, + _tk_objref = 14, + _tk_struct = 15, + _tk_union = 16, + _tk_enum = 17, + _tk_string = 18, + _tk_sequence = 19, + _tk_array = 20, + _tk_alias = 21, + _tk_except = 22, + _tk_longlong = 23, + _tk_ulonglong = 24, + _tk_longdouble = 25, + _tk_wchar = 26, + _tk_wstring = 27, + _tk_fixed = 28, + _tk_atom = 20000, /* Used for union label default value only */ + _tk_pid = 20001, /* Used for special pid struct */ + _tk_port = 20002, /* Used for special port struct */ + _tk_ref = 20003, /* Used for special ref struct */ + _tk_term = 20004; /* Used for special term struct */ + + public static final TCKind tk_null = new TCKind(_tk_null); + public static final TCKind tk_void = new TCKind(_tk_void); + public static final TCKind tk_short = new TCKind(_tk_short); + public static final TCKind tk_long = new TCKind(_tk_long); + public static final TCKind tk_ushort = new TCKind(_tk_ushort); + public static final TCKind tk_ulong = new TCKind(_tk_ulong); + public static final TCKind tk_float = new TCKind(_tk_float); + public static final TCKind tk_double = new TCKind(_tk_double); + public static final TCKind tk_boolean = new TCKind(_tk_boolean); + public static final TCKind tk_char = new TCKind(_tk_char); + public static final TCKind tk_octet = new TCKind(_tk_octet); + public static final TCKind tk_any = new TCKind(_tk_any); + public static final TCKind tk_TypeCode = new TCKind(_tk_TypeCode); + public static final TCKind tk_Principal = new TCKind(_tk_Principal); + public static final TCKind tk_objref = new TCKind(_tk_objref); + public static final TCKind tk_struct = new TCKind(_tk_struct); + public static final TCKind tk_union = new TCKind(_tk_union); + public static final TCKind tk_enum = new TCKind(_tk_enum); + public static final TCKind tk_string = new TCKind(_tk_string); + public static final TCKind tk_sequence = new TCKind(_tk_sequence); + public static final TCKind tk_array = new TCKind(_tk_array); + public static final TCKind tk_alias = new TCKind(_tk_alias); + public static final TCKind tk_except = new TCKind(_tk_except); + public static final TCKind tk_longlong = new TCKind(_tk_longlong); + public static final TCKind tk_ulonglong = new TCKind(_tk_ulonglong); + public static final TCKind tk_longdouble = new TCKind(_tk_longdouble); + public static final TCKind tk_wchar = new TCKind(_tk_wchar); + public static final TCKind tk_wstring = new TCKind(_tk_wstring); + public static final TCKind tk_fixed = new TCKind(_tk_fixed); + protected static final TCKind tk_atom = new TCKind(_tk_atom); + protected static final TCKind tk_pid = new TCKind(_tk_pid); + protected static final TCKind tk_port = new TCKind(_tk_port); + protected static final TCKind tk_ref = new TCKind(_tk_ref); + protected static final TCKind tk_term = new TCKind(_tk_term); + private int _value; + + // constructors + private TCKind(int __value) { + _value = __value; + } + + // methods + + /** + Accessor method for the value of TCKind. + @return int, the value of TCKind object + **/ + public int value() { + return _value; + } + + /** + Translator method for TCKind. + Traslates the input integer value to a TCKind enumerant object. + @return TCKind, a TCKind object + **/ + public static final TCKind from_int(int __value) throws java.lang.Exception { + switch (__value) { + case _tk_null: + return tk_null; + case _tk_void: + return tk_void; + case _tk_short: + return tk_short; + case _tk_long: + return tk_long; + case _tk_ushort: + return tk_ushort; + case _tk_ulong: + return tk_ulong; + case _tk_float: + return tk_float; + case _tk_double: + return tk_double; + case _tk_boolean: + return tk_boolean; + case _tk_char: + return tk_char; + case _tk_octet: + return tk_octet; + case _tk_any: + return tk_any; + case _tk_TypeCode: + return tk_TypeCode; + case _tk_Principal: + return tk_Principal; + case _tk_objref: + return tk_objref; + case _tk_struct: + return tk_struct; + case _tk_union: + return tk_union; + case _tk_enum: + return tk_enum; + case _tk_string: + return tk_string; + case _tk_sequence: + return tk_sequence; + case _tk_array: + return tk_array; + case _tk_alias: + return tk_alias; + case _tk_except: + return tk_except; + case _tk_longlong: + return tk_longlong; + case _tk_ulonglong: + return tk_ulonglong; + case _tk_longdouble: + return tk_longdouble; + case _tk_wchar: + return tk_wchar; + case _tk_wstring: + return tk_wstring; + case _tk_fixed: + return tk_fixed; + case _tk_atom: + return tk_atom; + case _tk_pid: + return tk_pid; + case _tk_port: + return tk_port; + case _tk_ref: + return tk_ref; + case _tk_term: + return tk_term; + default: + throw new java.lang.Exception(""); + } + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Term.java b/lib/ic/java_src/com/ericsson/otp/ic/Term.java new file mode 100644 index 0000000..9219cb7 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/Term.java @@ -0,0 +1,1109 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + +The Term class is intended to represent the erlang term generic type. +It extends the Any class and is basically used the same way as the Any class. +

The main difference between Term and Any is the use of guard methods +instead for TypeCode to determine the data included in the Term. +This actual when cannot determine a Term's value class returned at compile time. + +**/ + +final public class Term extends Any { + + // Primitive value holder + protected java.lang.String atomV; + protected long longV; + protected Pid PidV; + protected Ref RefV; + protected Port PortV; + protected com.ericsson.otp.erlang.OtpErlangObject ObjV; + protected int tag; + + /** + Tag accessor method + @return int, the tag of the Object that denotes the erlang external format tag + **/ + public int tag() { + return tag; + } + + /* Guards */ + + /** + Guard method + @return true if the Term is an OtpErlangAtom, false otherwize + **/ + public boolean isAtom() { + + if (ObjV == null) { + if (tag == com.ericsson.otp.erlang.OtpExternal.atomTag) + return true; + + return false; + } + + return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangAtom) ; + } + + /** + Guard method + @return true if the Term is not an OtpErlangList nor an OtpErlangTuple, false otherwize + **/ + public boolean isConstant() { + if (isList()) + return false; + + if (isTuple()) + return false; + + return true; + } + + /** + Guard method + @return true if the Term is an OtpErlangFloat, false otherwize + **/ + public boolean isFloat() { + if (tag == com.ericsson.otp.erlang.OtpExternal.floatTag) + return true; + + return false; + } + + /** + Guard method + @return true if the Term is an OtpErlangInt, false otherwize + **/ + public boolean isInteger() { + switch(tag) { + case com.ericsson.otp.erlang.OtpExternal.smallIntTag: + case com.ericsson.otp.erlang.OtpExternal.intTag: + case com.ericsson.otp.erlang.OtpExternal.smallBigTag: + return true; + default: + return false; + } + } + + /** + Guard method + @return true if the Term is an OtpErlangList, false otherwize + **/ + public boolean isList() { + + if (ObjV == null) { + switch(tag) { + case com.ericsson.otp.erlang.OtpExternal.listTag: + case com.ericsson.otp.erlang.OtpExternal.stringTag: + case com.ericsson.otp.erlang.OtpExternal.nilTag: + return true; + default: + return false; + } + } + + if (ObjV instanceof com.ericsson.otp.erlang.OtpErlangList) + return true; + + if (ObjV instanceof com.ericsson.otp.erlang.OtpErlangString) + return true; + + return false; + } + + + /** + Guard method + @return true if the Term is an OtpErlangString, false otherwize + **/ + public boolean isString() { + + if (ObjV == null) { + switch(tag) { + case com.ericsson.otp.erlang.OtpExternal.stringTag: + case com.ericsson.otp.erlang.OtpExternal.nilTag: + return true; + default: + try { + stringV = extract_string(); + return true; + } catch (Exception e) { + return false; + } + } + } + + if (ObjV instanceof com.ericsson.otp.erlang.OtpErlangString) + return true; + + try { + stringV = extract_string(); + return true; + } catch (Exception e) { + return false; + } + } + + /** + Guard method + @return true if the Term is an OtpErlangInteger or an OtpErlangFloat, false otherwize + **/ + public boolean isNumber() { + switch(tag) { + case com.ericsson.otp.erlang.OtpExternal.smallIntTag: + case com.ericsson.otp.erlang.OtpExternal.intTag: + case com.ericsson.otp.erlang.OtpExternal.smallBigTag: + case com.ericsson.otp.erlang.OtpExternal.floatTag: + return true; + default : + return false; + } + } + + + /** + Guard method + @return true if the Term is an OtpErlangPid or Pid, false otherwize + **/ + public boolean isPid() { + + if (ObjV == null) { + if (tag == com.ericsson.otp.erlang.OtpExternal.pidTag) + return true; + + return false; + } + + return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangPid) ; + } + + + /** + Guard method + @return true if the Term is an OtpErlangPort or Port, false otherwize + **/ + public boolean isPort() { + if (ObjV == null) { + if (tag == com.ericsson.otp.erlang.OtpExternal.portTag) + return true; + + return false; + } + + return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangPort); + } + + + /** + Guard method + @return true if the Term is an OtpErlangRef, false otherwize + **/ + public boolean isReference() { + if (ObjV == null) { + switch(tag) { + case com.ericsson.otp.erlang.OtpExternal.refTag: + case com.ericsson.otp.erlang.OtpExternal.newRefTag: + return true; + default : + return false; + } + } + + return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangRef) ; + } + + + /** + Guard method + @return true if the Term is an OtpErlangTuple, false otherwize + **/ + public boolean isTuple() { + if (ObjV == null) { + switch(tag) { + case com.ericsson.otp.erlang.OtpExternal.smallTupleTag: + case com.ericsson.otp.erlang.OtpExternal.largeTupleTag: + return true; + default : + return false; + } + } + + return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangTuple); + } + + + /** + Guard method + @return true if the Term is an OtpErlangBinary, false otherwize + **/ + public boolean isBinary() { + if (ObjV == null) { + if (tag == com.ericsson.otp.erlang.OtpExternal.binTag) + return true; + + return false; + } + + return (ObjV instanceof com.ericsson.otp.erlang.OtpErlangBinary); + } + + + + + // Equal function + /** + Term comparison method + @return true if the input Term is equal to the object, false otherwize + **/ + public boolean equal(Term _any) { + + try { + + /* Pids */ + if ((PidV != null) && (_any.PidV != null)) + if (PidV.equal(_any.PidV)) + return true; + + /* Refs */ + if ((RefV != null) && (_any.RefV != null)) + if (RefV.equal(_any.RefV)) + return true; + + /* Ports */ + if ((PortV != null) && (_any.PortV != null)) + if (PortV.equals(_any.PortV)) + return true; + + /* strings */ + if ((stringV != null) && (_any.stringV != null)) + if (stringV.equals(_any.stringV)) + return true; + + /* atoms and booleans */ + if ((atomV != null) && (_any.atomV != null)) + if (atomV.equals(_any.atomV)) + return true; + + /* booleans */ + if (atomV != null) + if (_any.booleanV == Boolean.valueOf(atomV).booleanValue()) + return true; + + if (_any.atomV != null) + if (booleanV == Boolean.valueOf(_any.atomV).booleanValue()) + return true; + + /* integer types plus floating point types */ + double _ownNS = + longV+doubleV; + + double _othersNS = + _any.longV+_any.doubleV; + + if ((equal(_ownNS,_othersNS)) && + (!equal(_ownNS,0))) + return true; + + /* All together, 0 or false */ + if ((equal(_ownNS,_othersNS)) && + booleanV == _any.booleanV) + return true; + + + return false; + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + Writes the value of Term to a stream + **/ + public void write_value(com.ericsson.otp.erlang.OtpOutputStream _os) + throws java.lang.Exception { + + if ((tcV == null) && (ObjV != null)) + _os.write_any(ObjV); // Type not generated by IC + + else { + + switch(tcV.kind().value()) { + + case TCKind._tk_octet : + case TCKind._tk_char : + case TCKind._tk_wchar : + case TCKind._tk_short : + case TCKind._tk_ushort : + case TCKind._tk_long : + case TCKind._tk_longlong : + case TCKind._tk_ulong : + case TCKind._tk_ulonglong : + _os.write_long(longV); + break; + + case TCKind._tk_float : + _os.write_double(doubleV); + break; + + case TCKind._tk_double : + _os.write_double(doubleV); + break; + + case TCKind._tk_boolean : + _os.write_boolean(booleanV); + break; + + case TCKind._tk_string : + case TCKind._tk_wstring : + _os.write_string(stringV); + break; + + case TCKind._tk_atom : + _os.write_atom(stringV); + break; + + case TCKind._tk_struct: + if (isPid()) + PidHelper.marshal(_os, PidV); + else { + if (isReference()) + RefHelper.marshal(_os, RefV); + else { + if (isPort()) + PortHelper.marshal(_os, PortV); + else + _os.write(os.toByteArray()); + } + } + break; + + case TCKind._tk_union: + case TCKind._tk_array: + case TCKind._tk_sequence: + case TCKind._tk_enum: + _os.write(os.toByteArray()); + break; + + case TCKind._tk_void : + _os.write_atom("ok"); + break; + + /* + * Not supported types + */ + default: + throw new java.lang.Exception("BAD KIND"); + } + } + } + + + + /* + * Insert and extract each primitive type + */ + + + /* short */ + + /** + Short value extractor method + @return short, the value of Term + **/ + public short extract_short() + throws java.lang.Exception { + + if (tcV == null) + return (short) longV; + + if (tcV.kind() == TCKind.tk_short) + return (short) longV; + + throw new java.lang.Exception(""); + } + + /** + Short value insertion method + **/ + public void insert_short(short s) { + longV = s; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_short); + }; + + /** + Short value insertion method + **/ + public void insert_short(long l) { + longV = l; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_short); + }; + + + /* long */ + + /** + Long value extractor method + @return int, the value of Term + **/ + public int extract_long() + throws java.lang.Exception { + + if (tcV == null) + return (int) longV; + + if (tcV.kind() == TCKind.tk_long) + return (int) longV; + + throw new java.lang.Exception(""); + } + + /** + Long value insertion method + **/ + public void insert_long(int i){ + longV = i; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_long); + } + + /** + Long value insertion method + **/ + public void insert_long(long l){ + longV = l; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_long); + } + + + /* longlong */ + + /** + Long Long value extractor method + @return long, the value of Term + **/ + public long extract_longlong() + throws java.lang.Exception { + + if (tcV == null) + return longV; + + if (tcV.kind() == TCKind.tk_longlong) + return longV; + + throw new java.lang.Exception(""); + } + + + /** + Long Long value insertion method + **/ + public void insert_longlong(long l){ + longV = l; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_longlong); + } + + + /* ushort */ + + /** + Unsigned Short value extractor method + @return short, the value of Term + **/ + public short extract_ushort() + throws java.lang.Exception { + + if (tcV == null) + return (short) longV; + + if (tcV.kind() == TCKind.tk_ushort) + return (short) longV; + + throw new java.lang.Exception(""); + } + + /** + Unsigned Short value insertion method + **/ + public void insert_ushort(short s){ + longV = s; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_ushort); + } + + /** + Unsigned Short value insertion method + **/ + public void insert_ushort(long l){ + longV = l; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_ushort); + } + + + /* ulong */ + + /** + Unsigned Long value extractor method + @return int, the value of Term + **/ + public int extract_ulong() + throws java.lang.Exception{ + + if (tcV == null) + return (int) longV; + + if (tcV.kind() == TCKind.tk_ulong) + return (int) longV; + + throw new java.lang.Exception(""); + } + + /** + Unsigned Long value insertion method + **/ + public void insert_ulong(int i){ + longV = i; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_ulong); + } + + + /** + Unsigned Long value insertion method + **/ + public void insert_ulong(long l){ + longV = l; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_ulong); + } + + + + /* ulonglong */ + + /** + Unsigned Long Long value extractor method + @return long, the value of Term + **/ + public long extract_ulonglong() + throws java.lang.Exception { + + if (tcV == null) + return longV; + + if (tcV.kind() == TCKind.tk_ulonglong) + return longV; + + throw new java.lang.Exception(""); + } + + + /** + Unsigned Long Long value insertion method + **/ + public void insert_ulonglong(long l){ + longV = l; + tag = com.ericsson.otp.erlang.OtpExternal.intTag; + tcV = new TypeCode(TCKind.tk_ulonglong); + } + + + + /* float */ + /** + Float value extractor method + @return float, the value of Term + **/ + public float extract_float() + throws java.lang.Exception{ + + if (tcV == null) + return (float) doubleV; + + if (tcV.kind() == TCKind.tk_float) + return (float) doubleV; + + throw new java.lang.Exception(""); + } + + + /** + Float value insertion method + **/ + public void insert_float(float f){ + doubleV = f; + tag = com.ericsson.otp.erlang.OtpExternal.floatTag; + tcV = new TypeCode(TCKind.tk_float); + } + + /** + Float value insertion method + **/ + public void insert_float(double f){ + doubleV = f; + tag = com.ericsson.otp.erlang.OtpExternal.floatTag; + tcV = new TypeCode(TCKind.tk_float); + } + + + /* double */ + /** + Double value extractor method + @return double, the value of Term + **/ + public double extract_double() + throws java.lang.Exception{ + + if (tcV == null) + return doubleV; + + if (tcV.kind() == TCKind.tk_double) + return doubleV; + + throw new java.lang.Exception(""); + } + + /** + Double value insertion method + **/ + public void insert_double(double d){ + doubleV = d; + tag = com.ericsson.otp.erlang.OtpExternal.floatTag; + tcV = new TypeCode(TCKind.tk_double); + } + + + /* boolean */ + /** + Boolean value extractor method + @return boolean, the value of Term + **/ + public boolean extract_boolean() + throws java.lang.Exception{ + + if ((tcV == null) && (atomV != null)) + return Boolean.valueOf(atomV).booleanValue(); + + if (tcV.kind() == TCKind.tk_boolean) + return booleanV; + + throw new java.lang.Exception(""); + } + + /** + Boolean value insertion method + **/ + public void insert_boolean(boolean b){ + booleanV = b; + tag = com.ericsson.otp.erlang.OtpExternal.atomTag; + tcV = new TypeCode(TCKind.tk_boolean); + } + + + /* char */ + /** + Char value extractor method + @return char, the value of Term + **/ + public char extract_char() + throws java.lang.Exception{ + + if (tcV == null) + return (char) longV; + + if (tcV.kind() == TCKind.tk_char) + return (char) longV; + + throw new java.lang.Exception(""); + } + + /** + Char value insertion method + **/ + public void insert_char(char c) { + longV = c; + tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag; + tcV = new TypeCode(TCKind.tk_char); + } + + /** + Char value insertion method + **/ + public void insert_char(long l) { + longV = l; + tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag; + tcV = new TypeCode(TCKind.tk_char); + } + + + + /* wchar */ + /** + Wchar value extractor method + @return char, the value of Term + **/ + public char extract_wchar() + throws java.lang.Exception{ + + if (tcV == null) + return (char) longV; + + if (tcV.kind() == TCKind.tk_wchar) + return (char) longV; + + throw new java.lang.Exception(""); + } + + /** + Wchar value insertion method + **/ + public void insert_wchar(char c) { + longV = c; + tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag; + tcV = new TypeCode(TCKind.tk_wchar); + } + + /** + Wchar value insertion method + **/ + public void insert_wchar(long l) { + longV = l; + tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag; + tcV = new TypeCode(TCKind.tk_wchar); + } + + + /* octet */ + /** + Octet value extractor method + @return byte, the value of Term + **/ + public byte extract_octet() + throws java.lang.Exception{ + + if (tcV == null) + return (byte) longV; + + if (tcV.kind() == TCKind.tk_octet) + return (byte) longV; + + throw new java.lang.Exception(""); + } + + /** + Octet value insertion method + **/ + public void insert_octet(byte b){ + longV = b; + tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag; + tcV = new TypeCode(TCKind.tk_octet); + } + + /** + Octet value insertion method + **/ + public void insert_octet(long l){ + longV = l; + tag = com.ericsson.otp.erlang.OtpExternal.smallIntTag; + tcV = new TypeCode(TCKind.tk_octet); + } + + + + /* string */ + + /** + String value extractor method + @return String, the value of Term + **/ + public java.lang.String extract_string() + throws java.lang.Exception{ + + if (tcV == null) { + if (stringV != null) + return stringV; + else { + is = this.extract_Streamable(); + stringV = is.read_string(); + return stringV; + } + } + else + if (tcV.kind() == TCKind.tk_string) + return stringV; + + throw new java.lang.Exception(""); + } + + /** + String value insertion method + **/ + public void insert_string(java.lang.String s) { + stringV = s; + tag = com.ericsson.otp.erlang.OtpExternal.stringTag; + tcV = new TypeCode(TCKind.tk_string); + } + + + + /* wstring */ + /** + Wstring value extractor method + @return String, the value of Term + **/ + public java.lang.String extract_wstring() + throws java.lang.Exception{ + + if (tcV == null) { + if (stringV != null) + return stringV; + else { + is = this.extract_Streamable(); + stringV = is.read_string(); + return stringV; + } + } + else + if (tcV.kind() == TCKind.tk_wstring) + return stringV; + + throw new java.lang.Exception(""); + } + + /** + Wstring value insertion method + **/ + public void insert_wstring(java.lang.String s) { + stringV = s; + tag = com.ericsson.otp.erlang.OtpExternal.stringTag; + tcV = new TypeCode(TCKind.tk_wstring); + } + + + + /* atom */ + /** + Atom value extractor method + @return atom, the value of Term + **/ + public java.lang.String extract_atom() + throws java.lang.Exception{ + + if ((tcV == null) && (atomV != null)) + return atomV; + + if (tcV.kind() == TCKind.tk_atom) + return stringV; + + throw new java.lang.Exception(""); + } + + + /** + Atom value insertion method + **/ + public void insert_atom(java.lang.String s) { + stringV = s; + tag = com.ericsson.otp.erlang.OtpExternal.atomTag; + tcV = new TypeCode(TCKind.tk_atom); + } + + + /* Pid */ + /** + Pid value extractor method + @return Pid, the value of Term + **/ + public Pid extract_Pid() + throws java.lang.Exception{ + + if ((tcV == null) && (PidV != null)) + return PidV; + + if (tcV.equal(PidHelper.type())) + return PidV; + + throw new java.lang.Exception(""); + } + + + /** + Pid value insertion method + **/ + public void insert_Pid(Pid p) { + PidV = p; + tag = com.ericsson.otp.erlang.OtpExternal.pidTag; + tcV = PidHelper.type(); + } + + + + /* Ref */ + /** + Ref value extractor method + @return Ref, the value of Term + **/ + public Ref extract_Ref() + throws java.lang.Exception{ + + if ((tcV == null) && (RefV != null)) + return RefV; + + if (tcV.equal(RefHelper.type())) + return RefV; + + throw new java.lang.Exception(""); + } + + /** + Ref value insertion method + **/ + public void insert_Ref(Ref r) { + RefV = r; + + if (r.isNewRef()) + tag = com.ericsson.otp.erlang.OtpExternal.newRefTag; + else + tag = com.ericsson.otp.erlang.OtpExternal.refTag; + + tcV = RefHelper.type(); + } + + + + /* Port */ + /** + Port value extractor method + @return Port, the value of Term + **/ + public Port extract_Port() + throws java.lang.Exception{ + + if ((tcV == null) && (PortV != null)) + return PortV; + + if (tcV.equal(PortHelper.type())) + return PortV; + + throw new java.lang.Exception(""); + } + + /** + Port value insertion method + **/ + public void insert_Port(Port p) { + PortV = p; + tag = com.ericsson.otp.erlang.OtpExternal.portTag; + tcV = PortHelper.type(); + } + + + /** + Object Stream extractor method + @return OtpInputStream, the stream value of Term + **/ + public com.ericsson.otp.erlang.OtpInputStream extract_Streamable() { + + if (is == null) { + if (os == null) { + if (stringV == null) + return null; + else { + // A sequence that become a string ! + os = new com.ericsson.otp.erlang.OtpOutputStream(); + os.write_string(stringV); + is = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray()); + } + } + else { + is = new com.ericsson.otp.erlang.OtpInputStream(os.toByteArray()); + } + } + + is.reset(); + return is; + } + + /** + Inserts Objects to Term + **/ + public void insert_Object(com.ericsson.otp.erlang.OtpErlangObject o) { + ObjV = o; + } + + /** + Extract Object value from Term + @return OtpErlangObject, the Object value of Term + **/ + public com.ericsson.otp.erlang.OtpErlangObject extract_Object() { + return ObjV; + } + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/ic/java_src/com/ericsson/otp/ic/TermHelper.java b/lib/ic/java_src/com/ericsson/otp/ic/TermHelper.java new file mode 100644 index 0000000..437d387 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/TermHelper.java @@ -0,0 +1,139 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + Helper class for Term. + **/ + +public class TermHelper { + + // Constructors + private TermHelper() {} + + // Methods + /** + Marshal method for the Term class, encodes the Term object to the output stream. + **/ + public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _out, Term _any) + throws java.lang.Exception { + + _any.write_value(_out); + } + + /** + Unmarshal method for the Term class, decodes a Term object from the stream. + @return Term, read from the input stream + **/ + public static Term unmarshal(com.ericsson.otp.erlang.OtpInputStream _in) + throws java.lang.Exception { + + Term _value = new Term(); + + int tag = _in.peek(); + if (tag == com.ericsson.otp.erlang.OtpExternal.versionTag) { + _in.read1(); + tag = _in.peek(); + } + _value.tag = tag; + + + // Allways save the object in OtpErlangObject form + _in.mark(0); + com.ericsson.otp.erlang.OtpErlangObject _obj = _in.read_any(); + _value.insert_Object(_obj); + + switch (tag) { + case com.ericsson.otp.erlang.OtpExternal.smallIntTag: + case com.ericsson.otp.erlang.OtpExternal.intTag: + case com.ericsson.otp.erlang.OtpExternal.smallBigTag: + _in.reset(); + _value.longV = _in.read_long(); + break; + + case com.ericsson.otp.erlang.OtpExternal.atomTag: + _in.reset(); + _value.atomV = _in.read_atom(); + break; + + case com.ericsson.otp.erlang.OtpExternal.floatTag: + _in.reset(); + _value.doubleV = _in.read_double(); + break; + + case com.ericsson.otp.erlang.OtpExternal.refTag: + case com.ericsson.otp.erlang.OtpExternal.newRefTag: + _in.reset(); + com.ericsson.otp.erlang.OtpErlangRef _eref = + _in.read_ref(); + + if (_eref.isNewRef()) + _value.RefV = new Ref(_eref.node(),_eref.ids(),_eref.creation()); + else + _value.RefV = new Ref(_eref.node(),_eref.id(),_eref.creation()); + + break; + + case com.ericsson.otp.erlang.OtpExternal.portTag: + _in.reset(); + com.ericsson.otp.erlang.OtpErlangPort _eport = + _in.read_port(); + + _value.PortV = new Port(_eport.node(),_eport.id(),_eport.creation()); + break; + + case com.ericsson.otp.erlang.OtpExternal.pidTag: + _in.reset(); + com.ericsson.otp.erlang.OtpErlangPid _epid = + _in.read_pid(); + + _value.PidV = new Pid(_epid.node(),_epid.id(),_epid.serial(),_epid.creation()); + break; + + case com.ericsson.otp.erlang.OtpExternal.stringTag: + _in.reset(); + _value.stringV = _in.read_string(); + break; + + case com.ericsson.otp.erlang.OtpExternal.listTag: + case com.ericsson.otp.erlang.OtpExternal.nilTag: + case com.ericsson.otp.erlang.OtpExternal.smallTupleTag: + case com.ericsson.otp.erlang.OtpExternal.largeTupleTag: + case com.ericsson.otp.erlang.OtpExternal.binTag: + + com.ericsson.otp.erlang.OtpOutputStream _os = + new com.ericsson.otp.erlang.OtpOutputStream(); + + _obj.encode(_os); + _value.insert_Streamable(_os); + break; + + case com.ericsson.otp.erlang.OtpExternal.largeBigTag: + default: + throw new com.ericsson.otp.erlang.OtpErlangDecodeException("Uknown data type: " + tag); + } + + return _value; + } + +} + + + diff --git a/lib/ic/java_src/com/ericsson/otp/ic/TermHolder.java b/lib/ic/java_src/com/ericsson/otp/ic/TermHolder.java new file mode 100644 index 0000000..9c92de9 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/TermHolder.java @@ -0,0 +1,58 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +package com.ericsson.otp.ic; + +/** + Holder class for Term. + **/ + +final public class TermHolder { + + /** + Term instance variable. + **/ + public Term value; + + // Constructors + public TermHolder() {} + + public TermHolder(Term initial) { + value = initial; + } + + // Methods + /** + Marshal method for the TermHolder class, encodes the Term object value to the output stream. + **/ + public void _marshal(com.ericsson.otp.erlang.OtpOutputStream out) + throws java.lang.Exception { + TermHelper.marshal(out, value); + } + + /** + Unmarshal method for the TermHolder class, decodes a Term object from the output stream + and assigns it to the Holder value field. + **/ + public void _unmarshal(com.ericsson.otp.erlang.OtpInputStream in) + throws java.lang.Exception { + value = TermHelper.unmarshal(in); + } + +} diff --git a/lib/ic/java_src/com/ericsson/otp/ic/TypeCode.java b/lib/ic/java_src/com/ericsson/otp/ic/TypeCode.java new file mode 100644 index 0000000..6d049f7 --- /dev/null +++ b/lib/ic/java_src/com/ericsson/otp/ic/TypeCode.java @@ -0,0 +1,875 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * The TypeCode class for Java IDL + * + */ +package com.ericsson.otp.ic; + +/** + The TypeCode class is the implementation of the OMG-IDL TypeCode type. + **/ + +public class TypeCode { + + private TCKind _kind; + private java.lang.String _id,_name; + private int _length,_member_count,_default_index; + private TypeCode _member_type,_discriminator_type,_content_type; + private Any _member_label; + private boolean extracted; + private TypeCode _members[]; + private java.lang.String _member_names[]; + private Any _member_labels[]; + + + + /* + * Constructors + */ + public TypeCode() { + extracted = false; + _members = null; + _member_names = null; + _member_labels = null; + _kind = null; + _id = null; + _name = null; + _length = -1; + _member_count = -1; + _default_index = -1; + _member_type = null; + _content_type = null; + _discriminator_type = null; + _member_label = null; + } + + public TypeCode(TCKind __kind) { + _kind = __kind; + } + + + /* + * Operation "TypeCode::equal" + */ + + /** + Comparisson method for TypeCode. + @return true if the input TypeCode value equals the value of the current object, false otherwize + **/ + public boolean equal(TypeCode tc) { + + try { + + TCKind tck = tc.kind(); + + switch (tck.value()) { + + case TCKind._tk_short: + case TCKind._tk_long: + case TCKind._tk_longlong: + case TCKind._tk_ushort: + case TCKind._tk_ulong: + case TCKind._tk_ulonglong: + case TCKind._tk_float: + case TCKind._tk_double: + case TCKind._tk_boolean: + case TCKind._tk_char: + case TCKind._tk_wchar: + case TCKind._tk_octet: + case TCKind._tk_string: + case TCKind._tk_wstring: + case TCKind._tk_any: + case TCKind._tk_void: + case TCKind._tk_atom: + + return (tck.value() == _kind.value()); + + case TCKind._tk_struct: + + if((tc.id().compareTo(_id) == 0) && + (tc.name().compareTo(_name) == 0) && + (tc.member_count() == _member_count)){ + + for (int i = 0; i < _member_count; i++) + if (!tc.member_type(i).equal(_members[i])) + return false; + + return true; + } + else + return false; + + case TCKind._tk_union: + + if((tc.id().compareTo(_id) == 0) && + (tc.name().compareTo(_name) == 0) && + (tc.member_count() == _member_count) && + (tc.discriminator_type().equal(_discriminator_type))){ + + for (int i = 0; i < _member_count; i++) + if ((!tc.member_type(i).equal(_members[i])) && + (tc.member_name(i).compareTo(_member_names[i]) != 0)) + return false; + + return true; + } + else + return false; + + case TCKind._tk_sequence: + case TCKind._tk_array: + + if((tck.value() == _kind.value()) && + (tc.content_type().equal(_content_type))) + return true; + else + return false; + + case TCKind._tk_enum: + if((tck.value() == _kind.value()) && + (tc.member_count() == _member_count)) { + + for (int i = 0; i < _member_count; i++) + if (tc.member_name(i).compareTo(_member_names[i]) != 0) + return false; + + return true; + } + else + return false; + + // Not used in real + case TCKind._tk_null: + case TCKind._tk_TypeCode: + case TCKind._tk_Principal: + case TCKind._tk_objref: + case TCKind._tk_alias: + case TCKind._tk_except: + case TCKind._tk_longdouble: + case TCKind._tk_fixed: + + return (tck.value() == _kind.value()); + + default : + return false; + + } + } catch (Exception e) { + return false; + } + + } + + + /* + * Operation "TypeCode::kind" + */ + + /** + Accessor method for the TCKind value of TypeCode. + @return TCKind, the TCKind value of the TypeCode object. + **/ + public TCKind kind() { + return _kind; + } + + /** + Insertion method for the TCKind value of TypeCode. + Sets the TCKind value of the object. + **/ + public void kind(TCKind __kind) { + _kind = __kind; + } + + /** + Insertion method for the TCKind value of TypeCode. + Sets the TCKind value of the object. + **/ + public static TCKind kind(java.lang.String atom) + throws java.lang.Exception { + + if (atom.equals("tk_null")) + return TCKind.tk_null; + else + if (atom.equals("tk_void")) + return TCKind.tk_void; + else + if (atom.equals("tk_short")) + return TCKind.tk_short; + else + if (atom.equals("tk_long")) + return TCKind.tk_long; + else + if (atom.equals("tk_ushort")) + return TCKind.tk_ushort; + else + if (atom.equals("tk_ulong")) + return TCKind.tk_ulong; + else + if (atom.equals("tk_float")) + return TCKind.tk_float; + else + if (atom.equals("tk_double")) + return TCKind.tk_double; + else + if (atom.equals("tk_boolean")) + return TCKind.tk_boolean; + else + if (atom.equals("tk_char")) + return TCKind.tk_char; + else + if (atom.equals("tk_octet")) + return TCKind.tk_octet; + else + if (atom.equals("tk_any")) + return TCKind.tk_any; + else + if (atom.equals("tk_TypeCode")) + return TCKind.tk_TypeCode; + else + if (atom.equals("tk_Principal")) + return TCKind.tk_Principal; + else + if (atom.equals("tk_objref")) + return TCKind.tk_objref; + else + if (atom.equals("tk_struct")) + return TCKind.tk_struct; + else + if (atom.equals("tk_union")) + return TCKind.tk_union; + else + if (atom.equals("tk_enum")) + return TCKind.tk_enum; + else + if (atom.equals("tk_string")) + return TCKind.tk_string; + else + if (atom.equals("tk_sequence")) + return TCKind.tk_sequence; + else + if (atom.equals("tk_array")) + return TCKind.tk_array; + else + if (atom.equals("tk_alias")) + return TCKind.tk_alias; + else + if (atom.equals("tk_except")) + return TCKind.tk_except; + else + if (atom.equals("tk_longlong")) + return TCKind.tk_longlong; + else + if (atom.equals("tk_ulonglong")) + return TCKind.tk_ulonglong; + else + if (atom.equals("tk_longdouble")) + return TCKind.tk_longdouble; + else + if (atom.equals("tk_wchar")) + return TCKind.tk_wchar; + else + if (atom.equals("tk_wstring")) + return TCKind.tk_wstring; + else + if (atom.equals("tk_fixed")) + return TCKind.tk_fixed; + else + if (atom.equals("tk_atom")) + return TCKind.tk_atom; + else + throw new java.lang.Exception("BAD KIND"); + + } + + + + /* + * Operation "TypeCode::id" + */ + + /** + Accessor method for the id value of TypeCode. + @return String, the id value of TypeCode object + **/ + public java.lang.String id() + throws java.lang.Exception{ + + if (_id == null) + throw new java.lang.Exception("BAD KIND"); + + return _id; + } + + + /** + Insertion method for the id value of TypeCode. + Sets the id value of the object. + **/ + public void id(java.lang.String __id) { + + _id = __id; + } + + + + /* + * Operation "TypeCode::name" + */ + + /** + Accessor method for the name value of TypeCode. + @return String, the name value of TypeCode object + **/ + public java.lang.String name() + throws java.lang.Exception{ + + if (_name == null) + throw new java.lang.Exception("BAD KIND"); + + return _name; + } + + /** + Insertion method for the name value of TypeCode. + Sets the name value of the object. + **/ + public void name(java.lang.String __name) { + _name = __name; + } + + + + /* + * Operation "TypeCode::member_count" + */ + + /** + Accessor method for the member number value of TypeCode. + @return int, the number of members of TypeCode object + **/ + public int member_count() + throws java.lang.Exception{ + + if (_member_count == -1) + throw new java.lang.Exception("BAD KIND"); + + return _member_count; + } + + /** + Insertion method for the member number value of TypeCode. + Sets the number of members value of the object. + **/ + public void member_count(int __member_count) { + + switch(_kind.value()) { + case TCKind._tk_struct: + _members = new TypeCode[__member_count]; + _member_names = new java.lang.String[__member_count]; + _member_count = __member_count; + break; + case TCKind._tk_union: + _members = new TypeCode[__member_count]; + _member_names = new java.lang.String[__member_count]; + _member_labels = new Any[__member_count]; + _member_count = __member_count; + break; + case TCKind._tk_enum: + _member_names = new java.lang.String[__member_count]; + _member_count = __member_count; + break; + default : + // Do nothing + } + } + + + /* + * Operation "TypeCode::member_name" + */ + + /** + Member name accessor method for TypeCode. + @return String, the name value of the member of the TypeCode object + on the selected index + **/ + public java.lang.String member_name(int __index) + throws java.lang.Exception{ + + return _member_names[__index]; + } + + /** + Insertion method for the indexed member name of TypeCode. + Sets the name of a member value of the object at the selected index.. + **/ + public void member_name(int __index, java.lang.String __member_name) { + _member_names[__index] = __member_name; + } + + + /* + * Operation "TypeCode::member_type" + */ + + /** + Member type accessor method for TypeCode. + @return TypeCOde, the type of the member of the TypeCode object + on the selected index + **/ + public TypeCode member_type(int __index) + throws java.lang.Exception{ + + return _members[__index]; + } + + /** + Insertion method for the indexed member type of TypeCode. + Sets the type of a member value of the object at the selected index.. + **/ + public void member_type(int __index, TypeCode __member_type) { + _members[__index] = __member_type; + } + + + /* + * Operation "TypeCode::member_label" + */ + + /** + Member label accessor method for TypeCode. + @return Any, the label of the member of the TypeCode object + on the selected index + **/ + public Any member_label(int __index) + throws java.lang.Exception{ + + return _member_labels[__index]; + } + + /** + Insertion method for the indexed member label of TypeCode. + Sets the label of a member value of the object at the selected index. + **/ + public void member_label(int __index, Any __member_label) { + _member_labels[__index] = __member_label; + } + + + /* + * Operation "TypeCode::discriminator_type" + */ + + /** + Discriminator type accessor method for TypeCode. + @return TypeCode, the type of the discriminator of the TypeCode object + **/ + public TypeCode discriminator_type() + throws java.lang.Exception{ + + if (_discriminator_type == null) + throw new java.lang.Exception("BAD KIND"); + + return _discriminator_type; + } + + /** + Insertion method for the type of the discriminator value of TypeCode. + Sets the discriminator type value of the object. + **/ + public void discriminator_type(TypeCode __discriminator_type) { + _discriminator_type = __discriminator_type; + } + + + /* + * Operation "TypeCode::default_index" + */ + + /** + Index accessor method for TypeCode. + @return int, the default index value of the member of the TypeCode object + **/ + public int default_index() + throws java.lang.Exception{ + + if (_default_index == -1) + throw new java.lang.Exception("BAD KIND"); + + return _default_index; + } + + /** + Insertion method for the default index value of TypeCode. + Sets the default index value of the object. + **/ + public void default_index(int __default_index) { + _default_index = __default_index; + } + + + /* + * Operation "TypeCode::length" + */ + + /** + Length accessor method for TypeCode. + @return int, the length of the TypeCode object + **/ + public int length() + throws java.lang.Exception{ + + if (_length == -1) + throw new java.lang.Exception("BAD KIND"); + + return _length; + } + + /** + Insertion method for the length value of TypeCode. + Sets the length value of the object. + **/ + public void length(int __length) { + _length = __length; + } + + + /* + * Operation "TypeCode::content_type" + */ + + /** + Content type accessor method for TypeCode. + @return TypeCode, the content type of the TypeCode object + **/ + public TypeCode content_type() + throws java.lang.Exception { + + if (_content_type == null) + throw new java.lang.Exception("BAD KIND"); + + return _content_type; + } + + /** + Insertion method for the content type value of TypeCode. + Sets the content type value of the object. + **/ + public void content_type(TypeCode __content_type) { + _content_type = __content_type; + } + + + /** + Marshal operation for TypeCode. + **/ + public static void marshal(com.ericsson.otp.erlang.OtpOutputStream _os, TypeCode _tc) + throws java.lang.Exception { + + TypeCode memberTC = null; + int len = -1; + + switch(_tc.kind().value()) { + + case TCKind._tk_short : + _os.write_atom("tk_short"); + break; + case TCKind._tk_ushort : + _os.write_atom("tk_ushort"); + break; + case TCKind._tk_long : + _os.write_atom("tk_long"); + break; + case TCKind._tk_longlong : + _os.write_atom("tk_longlong"); + break; + case TCKind._tk_ulong : + _os.write_atom("tk_ulong"); + break; + case TCKind._tk_ulonglong : + _os.write_atom("tk_ulonglong"); + break; + case TCKind._tk_float : + _os.write_atom("tk_float"); + break; + case TCKind._tk_double : + _os.write_atom("tk_double"); + break; + case TCKind._tk_boolean : + _os.write_atom("tk_boolean"); + break; + case TCKind._tk_char : + _os.write_atom("tk_char"); + break; + case TCKind._tk_wchar : + _os.write_atom("tk_wchar"); + break; + case TCKind._tk_octet : + _os.write_atom("tk_octet"); + break; + case TCKind._tk_string : + _os.write_tuple_head(2); + _os.write_atom("tk_string"); + _os.write_ulong(_tc.length()); + break; + case TCKind._tk_wstring : + _os.write_tuple_head(2); + _os.write_atom("tk_wstring"); + _os.write_ulong(_tc.length()); + break; + case TCKind._tk_struct: + len = _tc.member_count(); + _os.write_tuple_head(4); + _os.write_atom("tk_struct"); + _os.write_string(_tc.id()); + _os.write_string(_tc.name()); + // Member list + _os.write_list_head(len); + for(int i=0; i $@ + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +../ebin/icparse.beam: icparse.erl + $(ERLC) $(ERL_COMPILE_FLAGS) +nowarn_unused_vars +nowarn_unused_function -o$(EBIN) +pj $< + +icparse.erl: icparse.yrl icyeccpre.hrl + +### $(ERLC) $(YRL_FLAGS) $< + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(YRL_FILE) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/examples + $(INSTALL_DIR) $(RELSYSDIR)/examples/c-client + $(INSTALL_DATA) $(CCL_EX_FILES) $(RELSYSDIR)/examples/c-client + $(INSTALL_DIR) $(RELSYSDIR)/examples/c-server + $(INSTALL_DATA) $(CSRV_EX_FILES) $(RELSYSDIR)/examples/c-server + $(INSTALL_DIR) $(RELSYSDIR)/examples/erl-plain + $(INSTALL_DATA) $(EPL_EX_FILES) $(RELSYSDIR)/examples/erl-plain + $(INSTALL_DIR) $(RELSYSDIR)/examples/erl-genserv + $(INSTALL_DATA) $(ESRV_EX_FILES) $(RELSYSDIR)/examples/erl-genserv + $(INSTALL_DIR) $(RELSYSDIR)/examples/java-client-server + $(INSTALL_DATA) $(JAVA_EX_FILES) $(RELSYSDIR)/examples/java-client-server + $(INSTALL_DIR) $(RELSYSDIR)/examples/all-against-all + $(INSTALL_DATA) $(MIXED_EX_FILES) $(RELSYSDIR)/examples/all-against-all + +release_docs_spec: + diff --git a/lib/ic/src/ic.app.src b/lib/ic/src/ic.app.src new file mode 100644 index 0000000..29aa6de --- /dev/null +++ b/lib/ic/src/ic.app.src @@ -0,0 +1,52 @@ +{application, ic, + [{description, "The IDL Compiler"}, + {vsn, "%VSN%"}, + {modules, + [ + ic, + ic_cclient, + ic_cbe, + ic_cserver, + ic_erlbe, + ic_fetch, + ic_noc, + ic_plainbe, + ic_pp, + ic_pragma, + icenum, + iceval, + icparse, + icpreproc, + icscan, + icstruct, + ictk, + ictype, + ic_array_java, + ic_attribute_java, + ic_code, + ic_codegen, + ic_constant_java, + ic_enum_java, + ic_error, + ic_file, + ic_forms, + ic_genobj, + ic_java_type, + ic_jbe, + ic_options, + ic_sequence_java, + ic_struct_java, + ic_symtab, + ic_union_java, + ic_util, + icunion, + ic_erl_template + ] + }, + {registered, []}, + {applications, [stdlib, kernel]}, + {env, []}, + {mod, {ic, []}} +]}. + + diff --git a/lib/ic/src/ic.erl b/lib/ic/src/ic.erl new file mode 100644 index 0000000..3c6ce3d --- /dev/null +++ b/lib/ic/src/ic.erl @@ -0,0 +1,414 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic). + + +-export([sgen/1, gen/1, gen/2, help/0, compile/3]). + + +%%------------------------------------------------------------ +%% +%% Internal stuff +%% +%%------------------------------------------------------------ + +-export([filter_params/2, handle_preproc/4, do_gen/4]). + +-import(lists, [foldr/3]). + + +-include("icforms.hrl"). +-include("ic.hrl"). + +-include_lib("stdlib/include/erl_compile.hrl"). + +-export([make_erl_options/1]). % For erlc + +-export([main/3, do_scan/1, do_parse/2, do_type/2]). + + +%%------------------------------------------------------------ +%% +%% Entry point +%% +%%------------------------------------------------------------ + +%% compile(AbsFileName, Outfile, Options) +%% Compile entry point for erl_compile. + +compile(File, _OutFile, Options) -> + case gen(File, make_erl_options(Options)) of + ok -> ok; + Other -> Other + end. + + +%% Entry for the -s switch +sgen(ArgList) -> +%%% io:format("sgen called w ~p~n", [ArgList]), + apply(?MODULE, gen, ArgList). + + +gen(File) -> + gen(File, []). + +gen(File, Opts) -> + G = ic_genobj:new(Opts), + IdlFile = ic_file:add_dot_idl(File), + case ic_options:get_opt(G, show_opts) of + true -> + io:format("Opts: ~p~n", [ic_options:which_opts(G)]); + _ -> ok + end, + ic_genobj:set_idlfile(G, IdlFile), + case catch gen2(G, File, Opts) of + {_, {'EXIT', R}} -> + ic_genobj:free_table_space(G), %% Free space for all ETS tables + io:format("Fatal error : ~p~n",[R]), + error; + {_, {'EXIT', _, R}} -> + ic_genobj:free_table_space(G), %% Free space for all ETS tables + io:format("Fatal error : ~p~n",[R]), + error; + {'EXIT', R} -> + ic_genobj:free_table_space(G), %% Free space for all ETS tables + io:format("Fatal error : ~p~n",[R]), + error; + {'EXIT', _, R} -> + ic_genobj:free_table_space(G), %% Free space for all ETS tables + io:format("Fatal error : ~p~n",[R]), + error; + %% In this case, the pragma registration + %% found errors so this should return error. + error -> + ic_genobj:free_table_space(G), %% Free space for all ETS tables + error; + _ -> + X = ic_error:return(G), + ic_genobj:free_table_space(G), %% Free space for all ETS tables + X + end. + + +gen2(G, File, Opts) -> + case ic_options:get_opt(G, time) of + true -> + time("TOTAL ", ic, main, [G, File, Opts]); + _ -> + case main(G, File, Opts) of + error -> + error; + _ -> + ok + end + end. + + + +do_gen(erl_corba, G, File, T) -> + ic_erlbe:do_gen(G, File, T); +do_gen(erl_template, G, File, T) -> + ic_erl_template:do_gen(G, File, T); +do_gen(erl_genserv, G, File, T) -> + ic_erlbe:do_gen(G, File, T); +do_gen(c_genserv, G, File, T) -> + ic_cclient:do_gen(G, File, T); +do_gen(noc, G, File, T) -> + ic_noc:do_gen(G, File, T); +do_gen(erl_plain, G, File, T) -> + ic_plainbe:do_gen(G, File, T); +do_gen(c_server, G, File, T) -> + ic_cserver:do_gen(G, File, T); +do_gen(c_client, G, File, T) -> + ic_cclient:do_gen(G, File, T); +%% Java backend +do_gen(java, G, File, T) -> + ic_jbe:do_gen(G, File, T); +%% No language choice +do_gen(_,_,_,_) -> + ok. + +do_scan(G) -> + icscan:scan(G, ic_genobj:idlfile(G)). + + +do_parse(G, Tokens) -> + case icparse:parse(Tokens) of + {ok, L} -> L; + X when element(1, X) == error -> + Err = element(2, X), + ic_error:fatal_error(G, {parse_error, element(1, Err), + element(3, Err)}); + X -> exit(X) + end. + + +do_type(G, Form) -> + ictype:type_check(G, Form). + +time(STR,M,F,A) -> + case timer:tc(M, F, A) of + {_, {'EXIT', R}} -> exit(R); + {_, {'EXIT', _, R}} -> exit(R); + {_, _X} when element(1, _X)==error -> throw(_X); + {_T, _R} -> + io:format("Time for ~s: ~10.2f~n", [STR, _T/1000000]), + _R + end. + + + +%% Filters parameters so that only those with certain attributes are +%% seen. The filter parameter is a list of attributes that will be +%% seen, ex. [in] or [inout, out] +filter_params(Filter, Params) -> + lists:filter(fun(P) -> + lists:member(get_param_attr(P#param.inout), Filter) end, + Params). + + +%% Access primitive to get the attribute name (and discard the line +%% number). +get_param_attr({A, _N}) -> A. + + +%% +%% Fixing the preproc directives +%% +handle_preproc(G, _N, line_nr, X) -> + Id = ic_forms:get_id2(X), + Flags = X#preproc.aux, + case Flags of + [] -> ic_genobj:push_file(G, Id); + _ -> + foldr(fun({_, _, "1"}, Gprim) -> ic_genobj:push_file(Gprim, Id); + ({_, _, "2"}, Gprim) -> ic_genobj:pop_file(Gprim, Id); + ({_, _, "3"}, Gprim) -> ic_genobj:sys_file(Gprim, Id) end, + G, Flags) + end; +handle_preproc(G, _N, _Other, _X) -> + G. + + + +%%------------------------------------------------------------ +%% +%% The help department +%% +%% +%% +%%------------------------------------------------------------ + +help() -> + io:format("No help available at the moment~n", []), + ok. + +print_version_str(G) -> + case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of + {true, _} -> ok; + {_, true} -> ok; + _ -> + io:format("Erlang IDL compiler version ~s~n", [?COMPILERVSN]) + end. + + + +%% +%% Converts generic compiler options to specific options. +%% +%% Used by erlc +%% + +make_erl_options(Opts) -> + + %% This way of extracting will work even if the record passed + %% has more fields than known during compilation. + + Includes1 = Opts#options.includes, + Defines = Opts#options.defines, + Outdir = Opts#options.outdir, + Warning = Opts#options.warning, + Verbose = Opts#options.verbose, + Specific = Opts#options.specific, + Optimize = Opts#options.optimize, + PreProc = + lists:flatten( + lists:map(fun(D) -> io_lib:format("-I~s ", [ic_util:to_list(D)]) end, + Includes1)++ + lists:map( + fun ({Name, Value}) -> + io_lib:format("-D~s=~s ", [ic_util:to_list(Name), ic_util:to_list(Value)]); + (Name) -> + io_lib:format("-D~s ", [ic_util:to_list(Name)]) + end, + Defines)), + Options = + case Verbose of + true -> []; + false -> [] + end ++ + case Warning of + 0 -> [nowarn]; + _ -> ['Wall'] + end ++ + case Optimize of + 0 -> []; + _ -> [] + end, + + Options++[{outdir, Outdir}, {preproc_flags, PreProc}]++Specific. + + +%%% +%%% NEW main, avoids memory fragmentation +%%% +main(G, File, _Opts) -> + print_version_str(G), + ?ifopt(G, time, io:format("File ~p compilation started : ~p/~p/~p ~p:~2.2.0p~n", + [ic_genobj:idlfile(G), + element(1,date()), + element(2, date()), + element(3, date()), + element(1, time()), + element(2, time())])), + + case ic_options:get_opt(G, help) of + true -> help(); + + _ -> + scanning(G, File) + end. + + + +scanning(G, File) -> + S = ?ifopt2(G, time, + time("input file scanning ", ic, do_scan, [G]), + ic:do_scan(G)), + ?ifopt2(G, tokens, io:format("TOKENS: ~p~n", [S]), + parsing(G, File, S)). + +parsing(G, File, S) -> + T = ?ifopt2(G, + time, + time("input file parsing ", ic, do_parse, [G,S]), + ic:do_parse(G,S)), + ?ifopt2(G, form, io:format("PARSE FORM: ~p~n", [T]), + pragma(G, File, T)). + + + +pragma(G, File, T) -> + case ?ifopt2(G, + time, + time("pragma registration ", ic_pragma, pragma_reg, [G,T]), + ic_pragma:pragma_reg(G,T)) of + %% All pragmas were succesfully applied + {ok,Clean} -> + typing(G, File, Clean); + + error -> + error + end. + + +typing(G, File, Clean) -> + case catch ?ifopt2(G, + time, + time("type code appliance ", ic, do_type, [G,Clean]), + ic:do_type(G,Clean)) of + {'EXIT',Reason} -> + io:format("Error under type appliance : ~p~n",[Reason]), + error; + + T2 -> + ?ifopt2(G, tform, io:format("TYPE FORM: ~p~n", [T2]), + generation(G, File, T2)) + end. + + + +generation(G, File, T2) -> + case ic_options:get_opt(G, multiple_be) of + false -> + single_generation(G, File, T2); + List -> + OutDir = + case ic_options:get_opt(G, outdir) of + false -> + []; + Dir -> + Dir + end, + + case ic_options:get_opt(G, be) of + false -> + ok; + Be -> + %% Generate this first + ic_options:add_opt(G,[{outdir,OutDir++atom_to_list(Be)}],true), + single_generation(G, File, T2) + end, + multiple_generation(G, File, T2, OutDir, List) + end. + +multiple_generation(_G, _File, _T2, _RootDir, []) -> + ok; +multiple_generation(G, File, T2, RootDir, [Be|Bes]) -> + ic_options:add_opt(G,[{outdir,RootDir++atom_to_list(Be)}],true), + ic_options:add_opt(G,[{be,Be}],true), + single_generation(G, File, T2), + + case ic_error:get_error_count(G) of + 0 -> + multiple_generation(G,File,T2,RootDir,Bes); + _ -> + %% Errors reported, abort + ok + end. + + +single_generation(G, File, T2) -> + case ic_error:get_error_count(G) of + 0 -> + %% Check if user has sett backend option + case ic_options:get_opt(G, be) of + false -> + %% Use default backend option + DefaultBe = ic_options:defaultBe(), + ic_options:add_opt(G,[{be,DefaultBe}],true), + + ?ifopt2(G, + time, + time("code generation ", ic, do_gen, [DefaultBe, G, File, T2]), + ic:do_gen(DefaultBe, G, File, T2)); + Be -> + %% Use user defined backend + ?ifopt2(G, + time, + time("code generation ", ic, do_gen, [Be, G, File, T2]), + ic:do_gen(Be, G, File, T2)) + end; + _ -> + ok %% Does not matter + end. + + + diff --git a/lib/ic/src/ic.hrl b/lib/ic/src/ic.hrl new file mode 100644 index 0000000..974e608 --- /dev/null +++ b/lib/ic/src/ic.hrl @@ -0,0 +1,158 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + + +%%------------------------------------------------------------ +%% Configuration macros +-define(CORBAMOD, corba). +-define(ORBNAME, orber). +-define(CORBAHRL, "corba.hrl"). +-define(CALL, "call"). +-define(CAST, "cast"). +-define(IFRREGID, "register"). +-define(IFRTYPESHRL, "ifr_types.hrl"). + +-define(GENSERVMOD, gen_server). + +%%------------------------------------------------------------ +%% Flags. NOTE! Once assigned value may NOT be changed. Deprecate ok. +%% Default flags. Can be changed if we change the default behavior. +-define(IC_FLAG_TEMPLATE_1, 16#01). +-define(IC_FLAG_TEMPLATE_2, 16#02). + +-define(IC_INIT_FLAGS, 16#00). + +%% Flag operations +%% USAGE: Boolean = ?IC_FLAG_TEST(Flags, ?IC_ATTRIBUTE) +-define(IC_FLAG_TEST(_F1, _I1), ((_F1 band _I1) == _I1)). + +%% USAGE: NewFlags = ?IC_SET_TRUE(Flags, ?IC_ATTRIBUTE) +-define(IC_SET_TRUE(_F2, _I2), (_I2 bor _F2)). + +%% USAGE: NewFlags = ?IC_SET_FALSE(Flags, ?IC_ATTRIBUTE) +-define(IC_SET_FALSE(_F3, _I3), ((_I3 bxor 16#ff) band _F3)). + +%% USAGE: NewFlags = ?IC_SET_FALSE_LIST(Flags, [?IC_SEC_ATTRIBUTE, ?IC_SOME]) +-define(IC_SET_FALSE_LIST(_F4, _IList1), + lists:foldl(fun(_I4, _F5) -> + ((_I4 bxor 16#ff) band _F5) + end, + _F4, _IList1)). + +%% USAGE: NewFlags = ?IC_SET_TRUE_LIST(Flags, [?IC_ATTRIBUTE, ?IC_SOME]) +-define(IC_SET_TRUE_LIST(_F6, _IList2), + lists:foldl(fun(_I6, _F7) -> + (_I6 bor _F7) + end, + _F6, _IList2)). + +%% USAGE: Boolean = ?IC_FLAG_TEST_LIST(Flags, [?IC_CONTEXT, ?IC_THING]) +-define(IC_FLAG_TEST_LIST(_F8, _IList3), + lists:all(fun(_I7) -> + ((_F8 band _I7) == _I7) + end, + _IList3)). + + +%%------------------------------------------------------------ +%% Usefull macros + +-define(ifthen(P,ACTION), if P -> ACTION; true->true end). + + +%%------------------------------------------------------------ +%% Option macros + +-define(ifopt(G,OPT,ACTION), + case ic_options:get_opt(G,OPT) of true -> ACTION; _ -> ok end). + +-define(ifopt2(G,OPT,ACT1,ACT2), + case ic_options:get_opt(G,OPT) of true -> ACT1; _ -> ACT2 end). + +-define(ifnopt(G,OPT,ACTION), + case ic_options:get_opt(G,OPT) of false -> ACTION; _ -> ok end). + + +%% Internal record +-record(id_of, {id, type, tk}). + +%%-------------------------------------------------------------------- +%% The generator object definition + +-record(genobj, {symtab, impl, options, warnings, auxtab, + tktab, pragmatab, c_typedeftab, + skelfile=[], skelfiled=[], skelscope=[], + stubfile=[], stubfiled=[], stubscope=[], + includefile=[], includefiled=[], + interfacefile=[],interfacefiled=[], + helperfile=[],helperfiled=[], + holderfile=[],holderfiled=[], + filestack=0, do_gen=true, sysfile=false}). + +%%-------------------------------------------------------------------- +%% The scooped id definition +-record(scoped_id, {type=local, line=-1, id=""}). + + + + + + + + +%%-------------------------------------------------------------------- +%% Secret macros +%% +%% NOTE these macros are not general, they cannot be used +%% everywhere. +%% +-define(lookup(T,K), case ets:lookup(T, K) of [{_X, _Y}] -> _Y; _->[] end). +-define(insert(T,K,V), ets:insert(T, {K, V})). + + +%%--------------------------------------------------------------------- +%% +%% Java specific macros +%% +%% +-define(ERLANGPACKAGE,"com.ericsson.otp.erlang."). +-define(ICPACKAGE,"com.ericsson.otp.ic."). + + +%% +%% Macros for reporting encode/decode errors in C back-ends. +%% +%% + +-define(emit_c_enc_rpt(Fd, Fill, Fmt, Vals), + begin + CType = ic_cbe:mk_c_type2(G, N, T), + ic_codegen:emit_c_enc_rpt(Fd, Fill, "~s : " ++ Fmt, [CType| Vals]) + end). +-define(emit_c_dec_rpt(Fd, Fill, Fmt, Vals), + begin + CType = ic_cbe:mk_c_type2(G, N, T), + ic_codegen:emit_c_dec_rpt(Fd, Fill, "~s : " ++ Fmt, [CType| Vals]) + end). + + + + + diff --git a/lib/ic/src/ic_array_java.erl b/lib/ic/src/ic_array_java.erl new file mode 100644 index 0000000..e21d646 --- /dev/null +++ b/lib/ic/src/ic_array_java.erl @@ -0,0 +1,295 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_array_java). + +-export([gen/4]). + +-include("ic.hrl"). +-include("icforms.hrl"). + + +gen(G, N, X, Array) when is_record(X, member) -> + ArrayName = ic_forms:get_java_id(Array), + ArrayElement = ic_forms:get_type(X), + emit_holder_class(G, N, X, Array, ArrayName, ArrayElement), + emit_helper_class(G, N, X, Array, ArrayName, ArrayElement); +gen(G, N, X, Array) when is_record(X, case_dcl) -> + ArrayName = ic_forms:get_java_id(Array), + ArrayElement = ic_forms:get_type(X), + emit_holder_class(G, N, X, Array, ArrayName, ArrayElement), + emit_helper_class(G, N, X, Array, ArrayName, ArrayElement); +gen(G, N, X, Array) -> + ArrayName = ic_forms:get_java_id(Array), + ArrayElement = ic_forms:get_body(X), + emit_holder_class(G, N, X, Array, ArrayName, ArrayElement), + emit_helper_class(G, N, X, Array, ArrayName, ArrayElement). + + + +%%----------------------------------------------------------------- +%% Func: emit_holder_class/4 +%%----------------------------------------------------------------- +emit_holder_class(G, N, _X, Array, ArrayName, ArrayElement) -> + SName = string:concat(ArrayName, "Holder"), + {Fd, _}= ic_file:open_java_file(G, N, SName), + + ArrayElementName = ic_java_type:getType(G, N, ArrayElement), + EmptyDim = arrayEmptyDim(Array), + + ic_codegen:emit(Fd, "final public class ~sHolder {\n",[ArrayName]), + + ic_codegen:emit(Fd, " // instance variables\n", []), + ic_codegen:emit(Fd, " public ~s~s value;\n\n", + [ArrayElementName,EmptyDim]), + + ic_codegen:emit(Fd, " // constructors\n", []), + ic_codegen:emit(Fd, " public ~sHolder() {}\n", [ArrayName]), + ic_codegen:emit(Fd, " public ~sHolder(~s~s initial) {\n", + [ArrayName,ArrayElementName,EmptyDim]), + ic_codegen:emit(Fd, " value = initial;\n", []), + ic_codegen:emit(Fd, " }\n", []), + ic_codegen:nl(Fd), + + ic_codegen:emit(Fd, " // methods\n", []), + + ic_codegen:emit(Fd, " public void _marshal(~sOtpOutputStream out)\n", [?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n"), + ic_codegen:emit(Fd, " ~sHelper.marshal(out, value);\n", [ArrayName]), + ic_codegen:emit(Fd, " }\n"), + ic_codegen:nl(Fd), + ic_codegen:emit(Fd, " public void _unmarshal(~sOtpInputStream in)\n", [?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n"), + ic_codegen:emit(Fd, " value = ~sHelper.unmarshal(in);\n", [ArrayName]), + ic_codegen:emit(Fd, " }\n", []), + ic_codegen:nl(Fd), + + ic_codegen:emit(Fd, "}\n", []), + file:close(Fd). + + +%%----------------------------------------------------------------- +%% Func: emit_helper_class/4 +%%----------------------------------------------------------------- +emit_helper_class(G, N, X, Array, ArrayName, ArrayElement) -> + SName = string:concat(ArrayName, "Helper"), + {Fd, _}= ic_file:open_java_file(G, N, SName), + + ArrayElementName = ic_java_type:getType(G, N, ArrayElement), + EmptyDim = arrayEmptyDim(Array), +% Dim = arrayDim(G,N,Array), + + ic_codegen:emit(Fd, "public class ~sHelper {\n",[ArrayName]), + + ic_codegen:emit(Fd, " // constructors\n"), + ic_codegen:emit(Fd, " private ~sHelper() {}\n\n", [ArrayName]), + + ic_codegen:emit(Fd, " // methods\n"), + + ic_codegen:emit(Fd, " public static void marshal(~sOtpOutputStream _out, ~s~s _value)\n", + [?ERLANGPACKAGE,ArrayElementName,EmptyDim]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + emit_array_marshal_loop(G,N,X,Array,ArrayElement,Fd), + ic_codegen:emit(Fd, " }\n"), + ic_codegen:nl(Fd), + ic_codegen:emit(Fd, " public static ~s~s unmarshal(~sOtpInputStream _in)\n", + [ArrayElementName,EmptyDim,?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + ic_codegen:emit(Fd, " ~s~s _value = new ~s;\n\n", + [ArrayElementName,EmptyDim,ic_java_type:getFullType(G, N, X, Array)]), + emit_array_unmarshal_loop(G,N,X,Array,ArrayElement,Fd), + ic_codegen:emit(Fd, " return _value;\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static String id() {\n", []), + ic_codegen:emit(Fd, " return ~p;\n",[ictk:get_IR_ID(G, N, Array)]), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static String name() {\n", []), + ic_codegen:emit(Fd, " return ~p;\n",[ArrayName]), + ic_codegen:emit(Fd, " }\n\n"), + + ic_jbe:emit_type_function(G, N, X, Fd), + + ic_codegen:emit(Fd, " public static void insert(~sAny _any, ~s~s _this)\n", + [?ICPACKAGE,ArrayElementName,EmptyDim]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " ~sOtpOutputStream _os = \n",[?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " new ~sOtpOutputStream();\n\n",[?ERLANGPACKAGE]), + + ic_codegen:emit(Fd, " _any.type(type());\n"), + ic_codegen:emit(Fd, " marshal(_os, _this);\n"), + ic_codegen:emit(Fd, " _any.insert_Streamable(_os);\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static ~s~s extract(~sAny _any)\n", + [ArrayElementName,EmptyDim,?ICPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " return unmarshal(_any.extract_Streamable());\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, "}\n"), + file:close(Fd). + + + + +emit_array_marshal_loop(G,N,X,Array,AEl,Fd) -> + DimList = mk_array_dim_list(G,N,Array), + emit_array_marshal_loop_1(G,N,X,Array,AEl,DimList,0,Fd). + + +emit_array_marshal_loop_1(G,N,X,Array,AEl,[D],C,Fd) -> + + DimList = mk_array_dim_list(G,N,Array), + + ic_codegen:emit(Fd, " _out.write_tuple_head(~s);\n\n",[D]), + + ic_codegen:emit(Fd, " for(int _tmp~p = 0; _tmp~p < ~s; _tmp~p++)\n",[C,C,D,C]), + + case ic_java_type:isBasicType(G, N, AEl) of + true -> + ic_codegen:emit(Fd, " _out~s(_value", + [ic_java_type:marshalFun(G, N, X, AEl)]); + false -> + ic_codegen:emit(Fd, " ~s(_out, _value", + [ic_java_type:marshalFun(G, N, X, AEl)]) + end, + + emit_array_dimensions(DimList,0,Fd), + + ic_codegen:emit(Fd, ");\n\n"); + +emit_array_marshal_loop_1(G,N,X,Array,AEl,[D|Ds],C,Fd) -> +% DimList = mk_array_dim_list(G,N,Array), + + ic_codegen:emit(Fd, " _out.write_tuple_head(~s);\n\n",[D]), + + ic_codegen:emit(Fd, " for(int _tmp~p = 0; _tmp~p < ~s; _tmp~p++) {\n",[C,C,D,C]), + + emit_array_marshal_loop_1(G,N,X,Array,AEl,Ds,C+1,Fd), + + ic_codegen:emit(Fd, " }\n\n"). + + + + + +emit_array_unmarshal_loop(G,N,X,Array,AEl,Fd) -> + DimList = mk_array_dim_list(G,N,Array), + case length(DimList) > 0 of + true -> + ic_codegen:emit(Fd, " _in.read_tuple_head();\n\n"), + + ic_codegen:emit(Fd, " for(int _tmp0 = 0; _tmp0 < ~s; _tmp0++) {\n\n",[hd(DimList)]), + emit_array_unmarshal_loop_1(G,N,X,Array,AEl,tl(DimList),1,Fd), + ic_codegen:emit(Fd, " }\n\n"); + false -> + emit_array_unmarshal_loop_1(G,N,X,Array,AEl,DimList,0,Fd) + end. + +emit_array_unmarshal_loop_1(G,N,X,_Array,AEl,[],1,Fd) -> %% One dimensional array + case ic_java_type:isBasicType(G, N, AEl) of + true -> + ic_codegen:emit(Fd, " _value[_tmp0] = _in~s;\n", + [ic_java_type:unMarshalFun(G, N, X, AEl)]); + false -> + ic_codegen:emit(Fd, " _value[_tmp0] = ~s.unmarshal(_in);\n\n", + [ic_java_type:getUnmarshalType(G, N, X, AEl)]) + end; +emit_array_unmarshal_loop_1(G,N,X,Array,AEl,[],_C,Fd) -> + DimList = mk_array_dim_list(G,N,Array), + ic_codegen:emit(Fd, " _value"), + emit_array_dimensions(DimList,0,Fd), + case ic_java_type:isBasicType(G,N,AEl) of + true -> + ic_codegen:emit(Fd, " = _in~s;\n", + [ic_java_type:unMarshalFun(G, N, X, AEl)]); + false -> + ic_codegen:emit(Fd, " = ~s.unmarshal(_in);\n", + [ic_java_type:getUnmarshalType(G, N, X, AEl)]) + end; +emit_array_unmarshal_loop_1(G,N,X,Array,AEl,[D|Ds],C,Fd) -> + ic_codegen:emit(Fd, " _in.read_tuple_head();\n\n"), + + ic_codegen:emit(Fd, " for(int _tmp~p = 0; _tmp~p < ~s; _tmp~p++) {\n\n",[C,C,D,C]), + emit_array_unmarshal_loop_1(G,N,X,Array,AEl,Ds,C+1,Fd), + ic_codegen:emit(Fd, " }\n"). + + + + + +%%--------------------------------------------------- +%% Utilities +%%--------------------------------------------------- + +mk_array_dim_list(G,N,Array) -> + mk_array_dim_list2(G,N,Array#array.size). + + +mk_array_dim_list2(_G,_N,[]) -> + []; + +mk_array_dim_list2(G,N,[D |Ds]) when is_record(D,scoped_id) -> + {FSN, _, _, _} = ic_symtab:get_full_scoped_name(G, N, D), + [ ic_util:to_dot(G,FSN) | mk_array_dim_list2(G,N,Ds)]; + +mk_array_dim_list2(G,N,[D |Ds]) -> + [ic_util:eval_java(G,N,D) | mk_array_dim_list2(G,N,Ds)]. + + + +%% Array dimension string +%arrayDim(G,N,X) -> +% arrayDim2(G,N,X#array.size). + +%arrayDim2(_G,_N,[]) -> +% ""; +%arrayDim2(G,N,[D|Ds]) when record(D,scoped_id) -> +% {FSN, _, _, _} = ic_symtab:get_full_scoped_name(G, N, D), +% "[" ++ ic_util:to_dot(G,FSN) ++ "]" ++ arrayDim2(G,N,Ds); +%arrayDim2(G,N,[D|Ds]) -> +% "[" ++ ic_util:eval_java(G,N,D) ++ "]" ++ arrayDim2(G,N,Ds). + + +%% Array Empty dimension string +arrayEmptyDim(X) -> + arrayEmptyDim2(X#array.size). + +arrayEmptyDim2([_D]) -> + "[]"; +arrayEmptyDim2([_D |Ds]) -> + "[]" ++ arrayEmptyDim2(Ds). + + +emit_array_dimensions([_D],C,Fd) -> + ic_codegen:emit(Fd, "[_tmp~p]",[C]); +emit_array_dimensions([_D|Ds],C,Fd) -> + ic_codegen:emit(Fd, "[_tmp~p]",[C]), + emit_array_dimensions(Ds,C+1,Fd). + + + + + + diff --git a/lib/ic/src/ic_attribute_java.erl b/lib/ic/src/ic_attribute_java.erl new file mode 100644 index 0000000..6352dcf --- /dev/null +++ b/lib/ic/src/ic_attribute_java.erl @@ -0,0 +1,412 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_attribute_java). + +-include("icforms.hrl"). +-include("ic.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([emit_attribute_prototype/4, + emit_attribute_stub_code/4, + emit_atrribute_on_dictionary/5, + emit_attribute_switch_case/5]). + + + + + +%%%----------------------------------------------------- +%%% +%%% Generates operation in interface +%%% +%%%----------------------------------------------------- +emit_attribute_prototype(G, N, X, Fd) -> + emit_attribute_prototype(G, N, X, Fd, ic_forms:get_idlist(X)). + +emit_attribute_prototype(_G, _N, _X, _Fd, []) -> + ok; +emit_attribute_prototype(G, N, X, Fd, [V|Vs]) -> + WireAttrName = ic_forms:get_id(V), + AttrName = ic_forms:get_java_id(WireAttrName), + emit_attr_prototype(G, N, X, Fd, AttrName,WireAttrName), + emit_attribute_prototype(G, N, X, Fd, Vs). + + +emit_attr_prototype(G, N, X, Fd, OpName, WireOpName) -> + + ic_codegen:emit(Fd, "/****\n"), + ic_codegen:emit(Fd, " * Attribute ~p interface functions \n", [ic_util:to_colon([WireOpName|N])]), + ic_codegen:emit(Fd, " *\n"), + ic_codegen:emit(Fd, " */\n\n"), + + AT = ic_forms:get_type(X), + Type = ic_java_type:getType(G, N, AT), +% HolderType = ic_java_type:getHolderType(G, N, AT), + + ic_codegen:emit(Fd, " ~s ~s() throws java.lang.Exception;\n\n",[Type, OpName]), + + case X#attr.readonly of + {readonly, _} -> + ok; + _ -> + ic_codegen:emit(Fd, " void ~s(~s _value) throws java.lang.Exception;\n\n",[OpName, Type]) + end. + + + +%%%----------------------------------------------------- +%%% +%%% Generates attribute insertion in dictionary +%%% +%%%----------------------------------------------------- +emit_atrribute_on_dictionary(G, N, X, Fd, C) -> + emit_atrribute_on_dictionary(G, N, X, Fd, C, ic_forms:get_idlist(X)). + +emit_atrribute_on_dictionary(_G, _N, _X, _Fd, C, []) -> + C; +emit_atrribute_on_dictionary(G, N, X, Fd, C, [V|Vs]) -> + + WireAttrName = ic_forms:get_id(V), + + ic_codegen:emit(Fd, " _operations.put(\"_get_~s\", new java.lang.Integer(~p));\n", + [WireAttrName,C]), + + case X#attr.readonly of + {readonly, _} -> + + emit_atrribute_on_dictionary(G, N, X, Fd, C+1, Vs); + + _ -> + + ic_codegen:emit(Fd, " _operations.put(\"_set_~s\", new java.lang.Integer(~p));\n", + [WireAttrName,C+1]), + + emit_atrribute_on_dictionary(G, N, X, Fd, C+2, Vs) + end. + + + +%%%----------------------------------------------------- +%%% +%%% Generates attribute case in server switch +%%% +%%%----------------------------------------------------- +emit_attribute_switch_case(G, N, X, Fd, C) -> + Tk = ic_forms:get_tk(X), + emit_attribute_switch_case(G, N, X, Fd, Tk, C, ic_forms:get_idlist(X)). + +emit_attribute_switch_case(_G, _N, _X, _Fd, _Tk, C, []) -> + C; +emit_attribute_switch_case(G, N, X, Fd, Tk, C, [V|Vs]) -> + AttrName = ic_forms:get_java_id(V), + + emit_attribute_switch_case1(G,N,X,Fd,"_get_",AttrName,Tk,C), + + case X#attr.readonly of + {readonly, _} -> + emit_attribute_switch_case(G, N, X, Fd, Tk, C+1, Vs); + + _ -> + emit_attribute_switch_case1(G,N,X,Fd,"_set_",AttrName,Tk,C+1), + emit_attribute_switch_case(G, N, X, Fd, Tk, C+2, Vs) + end. + + +emit_attribute_switch_case1(G, N, X, Fd, "_get_", Name, _Tk, C) -> + + R = ic_forms:get_type(X), + RT = ic_java_type:getParamType(G,N,R,ret), + + ic_codegen:emit(Fd, " case ~p: { // Get operation for attribute ~s\n\n",[C,ic_util:to_dot([Name|N])]), + + ic_codegen:emit(Fd, " // Calling implementation function\n"), + ic_codegen:emit(Fd, " ~s _result = this.~s();\n\n", [RT, Name]), + + ic_codegen:emit(Fd, " // Marshalling output\n"), + ic_codegen:emit(Fd, " ~sOtpErlangRef __ref = __env.getSref();\n",[?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.id(),__ref.creation()); // Call reference\n"), + + case ic_java_type:isBasicType(G,N,R) of + true -> + ic_codegen:emit(Fd, " __os~s(_result); // Return value\n\n", + [ic_java_type:marshalFun(G,N,X,R)]); + false -> + ic_codegen:emit(Fd, " ~s(__os,_result); // Return value\n\n", + [ic_java_type:marshalFun(G,N,X,R)]) + end, + + ic_codegen:emit(Fd, " } break;\n\n"); + + +emit_attribute_switch_case1(G, N, X, Fd, "_set_", Name, _Tk, C) -> + ic_codegen:emit(Fd, " case ~p: { // Set operation for attribute ~s\n\n",[C,ic_util:to_dot([Name|N])]), + + Type = ic_forms:get_type(X), + + ic_codegen:emit(Fd, " // Preparing input\n"), + ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n",[?ERLANGPACKAGE]), + + case ic_java_type:isBasicType(G,N,Type) of + true -> + ic_codegen:emit(Fd, " ~s _value = __is~s; // In value\n\n", + [ic_java_type:getParamType(G,N,Type,in), + ic_java_type:unMarshalFun(G,N,X,Type)]); + false -> + ic_codegen:emit(Fd, " ~s _value = ~s.unmarshal(__is); // In value\n\n", + [ic_java_type:getParamType(G,N,Type,in), + ic_java_type:getUnmarshalType(G,N,X,Type)]) + end, + + + ic_codegen:emit(Fd, " // Calling implementation function\n"), + ic_codegen:emit(Fd, " this.~s(_value);\n\n", [Name]), + + ic_codegen:emit(Fd, " // Marshalling output\n"), + ic_codegen:emit(Fd, " ~sOtpErlangRef __ref = __env.getSref();\n",[?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.id(),__ref.creation()); // Call reference\n"), + ic_codegen:emit(Fd, " __os.write_atom(\"ok\");\n\n"), + + ic_codegen:emit(Fd, " } break;\n\n"). + + + + + + + +%%%----------------------------------------------------- +%%% +%%% Generates attribute function in stub +%%% +%%%----------------------------------------------------- +emit_attribute_stub_code(G, N, X, Fd) -> + emit_attribute_stub_code(G, N, X, Fd, ic_forms:get_idlist(X)). + +emit_attribute_stub_code(_G, _N, _X, _Fd, []) -> + ok; +emit_attribute_stub_code(G, N, X, Fd, [V|Vs]) -> + WireAttrName = ic_forms:get_id(V), + AttrName = ic_forms:get_java_id(WireAttrName), + + emit_attribute_stub_code1(G,N,X,Fd,"_get_",AttrName,WireAttrName), + + case X#attr.readonly of + {readonly, _} -> + emit_attribute_stub_code(G, N, X, Fd, Vs); + + _ -> + emit_attribute_stub_code1(G,N,X,Fd,"_set_",AttrName,WireAttrName), + emit_attribute_stub_code(G, N, X, Fd, Vs) + end. + + +emit_attribute_stub_code1(G,N,X,Fd,"_get_",Name,WireName) -> + + Type = ic_forms:get_type(X), + RT = ic_java_type:getType(G,N,Type), + + %% + %% Main get operation + %% + ic_codegen:emit(Fd, " // Attribute ~p get operation implementation\n", [ic_util:to_colon([WireName|N])]), + ic_codegen:emit(Fd, " public ~s ~s() throws java.lang.Exception {\n\n", [RT, Name]), + + %% Function marshal call + ic_codegen:emit(Fd, " // Calling the marshal function\n"), + ic_codegen:emit(Fd, " _~s_marshal(_env);\n\n", [Name]), + + %% Sending call + ic_codegen:emit(Fd, " // Message send\n"), + ic_codegen:emit(Fd, " _env.send();\n\n"), + + %% Receiving return value + ic_codegen:emit(Fd, " // Message receive\n"), + ic_codegen:emit(Fd, " _env.receive();\n\n"), + + ic_codegen:emit(Fd, " // Calling the unmarshal function\n"), + ic_codegen:emit(Fd, " return _~s_get_unmarshal(_env);\n", [Name]), + ic_codegen:emit(Fd, " }\n\n"), + + + %% + %% Marshal get operation + %% + ic_codegen:emit(Fd, " // Marshal operation for get attribute ~p\n", [Name]), + ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env)\n", + [Name, ?ICPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " // Get output stream\n"), + ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n\n",[?ERLANGPACKAGE]), + + %% Initiating Message header + ic_codegen:emit(Fd, " // Message header assembly\n"), + ic_codegen:emit(Fd, " __os.reset();\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(3);\n"), + ic_codegen:emit(Fd, " __os.write_atom(\"$gen_call\");\n\n"), + + + %% Creating call identity tuple + ic_codegen:emit(Fd, " // Message identity part creation\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __env.write_client_pid();\n"), + ic_codegen:emit(Fd, " __env.write_client_ref();\n\n"), + + OpCallName = case ic_options:get_opt(G, scoped_op_calls) of + true -> + ic_util:to_undersc(["_get_"++WireName|N]); + false -> + "_get_"++WireName + end, + + %% Creating operation identity + ic_codegen:emit(Fd, " // Message operation part creation\n"), + ic_codegen:emit(Fd, " __os.write_atom(~p);\n\n",[OpCallName]), + + ic_codegen:emit(Fd, " }\n\n"), + + + %% + %% Unmarshal get operation + %% + MRT = ic_java_type:getParamType(G,N,Type,ret), + + ic_codegen:emit(Fd, " // Unmarshal operation for get attribute ~p\n", [Name]), + ic_codegen:emit(Fd, " public static ~s _~s_get_unmarshal(~sEnvironment __env)\n", + [MRT, Name, ?ICPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + + ic_codegen:emit(Fd, " // Get input stream\n"), + ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n",[?ERLANGPACKAGE]), + + ic_codegen:emit(Fd, " // Extracting return value\n"), + case ic_java_type:isBasicType(G, N, Type) of + true -> + ic_codegen:emit(Fd, " return __is~s;\n", + [ic_java_type:unMarshalFun(G, N, X, Type)]); + false -> + ic_codegen:emit(Fd, " return ~s.unmarshal(__is);\n", + [ic_java_type:getUnmarshalType(G, N, X, Type)]) + end, + + ic_codegen:emit(Fd, " }\n\n"); + + +emit_attribute_stub_code1(G,N,X,Fd,"_set_",Name,WireName) -> + + Type = ic_forms:get_type(X), + + %% + %% Main set operation + %% + IT = ic_java_type:getType(G,N,Type), + + ic_codegen:emit(Fd, " // Attribute ~p set operation implementation\n", [ic_util:to_colon([WireName|N])]), + ic_codegen:emit(Fd, " public void ~s(~s _value) throws java.lang.Exception {\n\n", [Name,IT]), + + %% Function marshal call + ic_codegen:emit(Fd, " // Calling the marshal function\n"), + ic_codegen:emit(Fd, " _~s_marshal(_env, _value);\n\n", [Name]), + + %% Sending call + ic_codegen:emit(Fd, " // Message send\n"), + ic_codegen:emit(Fd, " _env.send();\n\n"), + + %% Receiving return value + ic_codegen:emit(Fd, " // Message receive\n"), + ic_codegen:emit(Fd, " _env.receive();\n\n"), + + ic_codegen:emit(Fd, " // Calling the unmarshal function\n"), + ic_codegen:emit(Fd, " _~s_set_unmarshal(_env);\n", [Name]), + + ic_codegen:emit(Fd, " }\n\n"), + + + %% + %% Marshal set operation + %% + IP = ic_java_type:getParamType(G, N, Type, in), + OpCallName = case ic_options:get_opt(G, scoped_op_calls) of + true -> + ic_util:to_undersc(["_set_"++WireName|N]); + false -> + "_set_"++WireName + end, + + ic_codegen:emit(Fd, " // Marshal operation for set attribute ~p\n", [Name]), + ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env, ~s _value)\n", + [Name, ?ICPACKAGE, IP]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " // Get output stream\n"), + ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n\n",[?ERLANGPACKAGE]), + + %% Initiating Message header + ic_codegen:emit(Fd, " // Message header assembly\n"), + ic_codegen:emit(Fd, " __os.reset();\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(3);\n"), + ic_codegen:emit(Fd, " __os.write_atom(\"$gen_call\");\n\n"), + + + %% Creating call identity tuple + ic_codegen:emit(Fd, " // Message identity part creation\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __env.write_client_pid();\n"), + ic_codegen:emit(Fd, " __env.write_client_ref();\n\n"), + + + %% Creating operation identity + ic_codegen:emit(Fd, " // Message operation part creation\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __os.write_atom(~p);\n",[OpCallName]), + + case ic_java_type:isBasicType(G, N, Type) of + true -> + ic_codegen:emit(Fd, " __os~s(_value);\n\n", + [ic_java_type:marshalFun(G, N, X, Type)]); + false -> + ic_codegen:emit(Fd, " ~s(__os, _value);\n\n", + [ic_java_type:marshalFun(G, N, X, Type)]) + end, + ic_codegen:emit(Fd, " }\n\n"), + + + ic_codegen:emit(Fd, " // Unmarshal operation for set attribute ~p\n", [Name]), + ic_codegen:emit(Fd, " public static void _~s_set_unmarshal(~sEnvironment __env)\n", + [Name, ?ICPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " // Get input stream\n"), + ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n",[?ERLANGPACKAGE]), + + ic_codegen:emit(Fd, " __is.read_atom();\n"), + ic_codegen:emit(Fd, " }\n\n"). + + + + + + diff --git a/lib/ic/src/ic_cbe.erl b/lib/ic/src/ic_cbe.erl new file mode 100644 index 0000000..1000e0d --- /dev/null +++ b/lib/ic/src/ic_cbe.erl @@ -0,0 +1,1306 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +%%------------------------------------------------------------ +%% +%% This module is a main module for generation of C code, both +%% for ic_cclient and ic_cserver. +%% +%% The former role of this module (ic_cbe) was to generate client +%% code only. +%% +-module(ic_cbe). + +-export([emit_malloc_size_stmt/7, emit_encoding_stmt/6, + emit_encoding_stmt/7, emit_decoding_stmt/10, + emit_decoding_stmt/11, emit_dealloc_stmts/3, + mk_variable_name/1, mk_c_type/3, mk_c_type/4, mk_c_type2/3, + is_variable_size/1, is_variable_size/3, mk_dim/1, + mk_slice_dim/1, emit_tmp_variables/1, store_tmp_decl/2, + extract_info/3, normalize_type/1]). + +%%------------------------------------------------------------ +%% +%% Internal stuff +%% +%%------------------------------------------------------------ + +-import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]). + +-include("icforms.hrl"). +-include ("ic.hrl"). + +%%------------------------------------------------------------ +%% ENCODING +%%------------------------------------------------------------ + +emit_encoding_stmt(G, N, Fd, T, LName, OutBuffer) when element(1, T) == scoped_id -> + case mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_pid(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_port" -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_port(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n} \n"); + "erlang_ref" -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ref(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + "ETERM*" -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_term(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + {enum, FSN} -> + emit_encoding_stmt(G, N, Fd, FSN, LName, OutBuffer); + FSN -> + emit_encoding_stmt(G, N, Fd, FSN, LName, OutBuffer) + end; + +%% XXX T is a string +emit_encoding_stmt(G, N, Fd, T, LName, _OutBuffer) when is_list(T) -> + %% Already a fullscoped name + Type = ictype:name2type(G,T), + case ictype:isBasicType(Type) of + true -> + emit_encoding_stmt_for_basic_type(G, N, T, Fd, Type, LName); + false -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, ~s))" + " < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), % XXX list + emit(Fd, " return oe_error_code;\n }\n") + end; +emit_encoding_stmt(G, N, Fd, T, LName, _OutBuffer) when is_record(T, string) -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = oe_ei_encode_string(oe_env, " + " ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); +emit_encoding_stmt(G, N, Fd, T, LName, _OutBuffer) when is_record(T, wstring) -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = oe_ei_encode_wstring(oe_env, " + "~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); +emit_encoding_stmt(G, N, Fd, T, LName, _OutBuffer) -> + case normalize_type(T) of + {basic, Type} -> + emit_encoding_stmt_for_basic_type(G, N, T, Fd, Type, LName); + %% XXX Why only returns? + {void, _} -> + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + {sequence, _, _} -> + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + {_ArrayType, {array, _, _}} -> + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + {union, _, _, _, _} -> + %% Union as a member in struct ! + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + {struct, _, _, _} -> + %% Struct as a member in struct ! + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end. + +%% Arity = 7. +%% +emit_encoding_stmt(G, N, X, Fd, T, LName, OutBuffer) when element(1, T) == scoped_id -> + case mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_pid(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_port" -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_port(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_ref" -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ref(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + "ETERM*" -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_term(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + {enum, FSN} -> + emit_encoding_stmt(G, N, X, Fd, FSN, LName, OutBuffer); + FSN -> + emit_encoding_stmt(G, N, X, Fd, FSN, LName, OutBuffer) + end; + +%% XXX T is a string +emit_encoding_stmt(G, N, X, Fd, T, LName, _OutBuffer) when is_list(T) -> + %% Already a fullscoped name + case get_param_tk(LName,X) of + error -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + ParamTK -> + case is_variable_size(ParamTK) of + true -> + if is_tuple(ParamTK) -> + case element(1,ParamTK) of + tk_array -> + %% Array of dynamic data + emit(Fd, + " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, + "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, + " return " + "oe_error_code;\n }\n"); + _ -> + emit(Fd, + " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, + "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return " + "oe_error_code;\n }\n") + end; + true -> + emit(Fd, + " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n") + end; + false -> + if is_atom(ParamTK) -> + case normalize_type(ParamTK) of + {basic, Type} -> + emit_encoding_stmt_for_basic_type(G, N, T, Fd, + Type, + LName); + _ -> + %% Why only return? + ?emit_c_enc_rpt(Fd, " ", "~/slist/~s", [T, LName]), + emit(Fd, " return oe_error_code;\n }\n"), + ok + end; + true -> + case element(1,ParamTK) of + tk_enum -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + tk_array -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + tk_struct -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + tk_union -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, &~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n") + end + end + end + end; +emit_encoding_stmt(G, N, _X, Fd, T, LName, _OutBuffer) when is_record(T, string) -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = oe_ei_encode_string(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); +emit_encoding_stmt(G, N, _X, Fd, T, LName, _OutBuffer) when is_record(T, wstring) -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_wstring(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"); +emit_encoding_stmt(G, N, _X, Fd, T, LName, _OutBuffer) -> + case normalize_type(T) of + {basic, Type} -> + emit_encoding_stmt_for_basic_type(G, N, T, Fd, Type, LName); + {void, _} -> + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"), + ok; + {sequence, _, _} -> + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"), + ok; + {_ArrayType, {array, _, _}} -> + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"), + ok; + {struct, _, _, _} -> %% Struct as a member in struct ! + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"), + ok; + _ -> + %%io:format("2 ------------> ~p~n", [T]), + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end. + +%%------------------------------------------------------------ +emit_encoding_stmt_for_basic_type(G, N, T, Fd, Type, LName) -> + {Cast, DecType} = + case Type of + ushort -> {"(unsigned long) ", "ulong"}; + ulong -> {"", "ulong"}; + ulonglong -> {"", "ulonglong"}; + short -> {"(long) ", "long"}; + long -> {"", "long"}; + longlong -> {"", "longlong"}; + float -> {"(double) ", "double"}; + double -> {"", "double"}; + boolean -> {"", "atom"}; + char -> {"", "char"}; + wchar -> {"", "wchar"}; + octet -> {"", "char"}; + any -> {"", "long"} % Fix for any + end, + case Type of + boolean -> + %% Note prefix: oe_ei + emit(Fd, " switch(~s) {\n",[LName]), + emit(Fd, " case 0 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, " + "\"false\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " case 1 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, " + "\"true\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " default :\n"), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n\n"); + _ -> + Fmt = + " if ((oe_error_code = oe_ei_encode_~s(oe_env, ~s~s)) < 0) {\n", + emit(Fd, Fmt, [DecType, Cast, LName]), + ?emit_c_enc_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n }\n") + end. + + +%%------------------------------------------------------------ +%% MALLOC SIZE (for Decode) +%%------------------------------------------------------------ + +emit_malloc_size_stmt(G, N, Fd, T, InBuffer, + Align, CalcType) when element(1, T) == scoped_id -> + case mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + emit(Fd, " oe_malloc_size += sizeof(erlang_pid);\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_pid(~s, " + "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]), + ?emit_c_dec_rpt(Fd, " ", "erlang_pid", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_port" -> + emit(Fd, " oe_malloc_size += sizeof(erlang_port);\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_port(~s, " + "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]), + ?emit_c_dec_rpt(Fd, " ", "erlang_port", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_ref" -> + emit(Fd, " oe_malloc_size += sizeof(erlang_ref);\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_ref(~s, " + "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]), + ?emit_c_dec_rpt(Fd, " ", "erlang_ref", []), + emit(Fd, " return oe_error_code;\n }\n"); + "ETERM*" -> + emit(Fd, " oe_malloc_size += sizeof(char*);\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_term(~s, " + "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]), + ?emit_c_dec_rpt(Fd, " ", "ETERM*", []), + emit(Fd, " return oe_error_code;\n }\n"); + {enum, FSN} -> + emit_malloc_size_stmt(G, N, Fd, FSN, InBuffer, Align, CalcType); + FSN -> + %% io:format("emit_malloc_size_stmt: ~p ~p~n",[FSN, + %% CalcType]), + emit_malloc_size_stmt(G, N, Fd, FSN, InBuffer, Align, CalcType) + end; + +%% XXX T is a string +emit_malloc_size_stmt(G, N, Fd, T, InBuffer, + _Align, CalcType) when is_list(T) -> + %% Already a fullscoped name + Type = ictype:name2type(G,T), + case ictype:isBasicType(Type) of + true -> + emit_malloc_size_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer); + false -> + case CalcType of + generator -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [ic_util:mk_oe_name(G, "sizecalc_"), T]), + ?emit_c_dec_rpt(Fd, " ", "~s", [T]), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "&oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [ic_util:mk_oe_name(G, "sizecalc_"), T]), + ?emit_c_dec_rpt(Fd, " ", "~s", [T]), + emit(Fd, " return oe_error_code;\n }\n") + end + end; +emit_malloc_size_stmt(G, N, Fd, T, InBuffer, _Align, + CalcType) when is_record(T, string) -> + Tname = mk_variable_name(op_variable_count), + store_tmp_decl(" int ~s = 0;\n",[Tname]), + case CalcType of + generator -> + emit(Fd, " if ((oe_error_code = ei_get_type(~s, " + "oe_size_count_index, &oe_type, &~s)) < 0) {\n", + [InBuffer, Tname]); + _ -> + emit(Fd, " int oe_type = 0;\n"), + emit(Fd, " int oe_temp = 0;\n\n"), + emit(Fd, " if ((oe_error_code = ei_get_type(~s, " + "&oe_size_count_index, &oe_type, &oe_temp)) < 0) {\n", + [InBuffer]) + end, + ?emit_c_dec_rpt(Fd, " ", "ei_get_type", []), + emit(Fd, " return oe_error_code;\n }\n"), + if + T#string.length == 0 -> + ok; + true -> + Length = ic_util:eval_c(G, N, T#string.length), + case CalcType of + generator -> + emit(Fd, " if (~s > ~s)\n",[Tname, Length]), + emit(Fd, " return -1;\n\n"); + _ -> + emit(Fd, " if (oe_temp > ~s)\n",[Length]), + emit(Fd, " return -1;\n\n") + end + end, + case CalcType of + generator -> + emit(Fd, " if ((oe_error_code = ei_decode_string(~s, " + "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]); + _ -> + emit(Fd, " if ((oe_error_code = ei_decode_string(~s, " + "&oe_size_count_index, NULL)) < 0) {\n", [InBuffer]) + end, + ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []), + emit(Fd, " return oe_error_code;\n }\n"), + case CalcType of + generator -> + emit(Fd, " oe_malloc_size = ~s;\n\n", + [ic_util:mk_align("oe_malloc_size + " ++ Tname ++"+1")]); + _ -> + emit(Fd, " oe_malloc_size = ~s;\n\n", + [ic_util:mk_align("oe_malloc_size + oe_temp+1")]) + end; +emit_malloc_size_stmt(G, N, Fd, T, InBuffer, _Align, + CalcType) when is_record(T, wstring) -> + Tname = mk_variable_name(op_variable_count), + store_tmp_decl(" int ~s = 0;\n",[Tname]), + case CalcType of + generator -> + emit(Fd, " if ((oe_error_code = ei_get_type(~s, " + "oe_size_count_index, &oe_type, &~s)) < 0) {\n", + [InBuffer, Tname]); + _ -> + emit(Fd, " int oe_type = 0;\n"), + emit(Fd, " int oe_temp = 0;\n\n"), + emit(Fd, " if ((oe_error_code = ei_get_type(~s, " + "&oe_size_count_index, &oe_type, &oe_temp)) < 0) {\n", + [InBuffer]) + end, + ?emit_c_dec_rpt(Fd, " ", "ei_get_type", []), + emit(Fd, " return oe_error_code;\n }\n"), + if + T#wstring.length == 0 -> + ok; + true -> + Length = ic_util:eval_c(G, N, T#wstring.length), + case CalcType of + generator -> + emit(Fd, " if (~s > ~s)\n",[Tname, Length]), + emit(Fd, " return -1;\n\n"); + _ -> + emit(Fd, " if (oe_temp > ~s)\n",[Length]), + emit(Fd, " return -1;\n\n") + end + end, + case CalcType of + generator -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = oe_ei_decode_wstring(~s, " + "oe_size_count_index, NULL)) < 0) {\n", [InBuffer]); + _ -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = oe_ei_decode_wstring(~s, " + "&oe_size_count_index, NULL)) < 0) {\n", [InBuffer]) + end, + ?emit_c_dec_rpt(Fd, " ", "oe_ei_decode_wstring", []), + emit(Fd, " return oe_error_code;\n }\n"), + case CalcType of + generator -> + emit(Fd, " oe_malloc_size =\n ~s;\n\n", + [ic_util:mk_align("oe_malloc_size + ((" + ++ Tname + ++"+ 1) * __OE_WCHAR_SIZE_OF__)")]); + _ -> + emit(Fd, " oe_malloc_size =\n ~s;\n\n", + [ic_util:mk_align("oe_malloc_size + ((" + "oe_temp + 1) * __OE_WCHAR_SIZE_OF__)")]) + end; +emit_malloc_size_stmt(G, N, Fd, T, InBuffer, Align, CalcType) -> + case Align of + 0 -> + emit(Fd, " oe_malloc_size += sizeof(~s);\n\n", + [mk_c_type(G, N, T)]); + _ -> + ok + end, + case normalize_type(T) of + {basic, Type} -> + emit_malloc_size_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer); + {void, _} -> + ok; + {sequence, _, _} -> + ok; + {_, {array, SId, _}} -> + case CalcType of + generator -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [ic_util:mk_oe_name(G, "sizecalc_"), + ic_forms:get_id2(SId)]), + ?emit_c_dec_rpt(Fd, " ", "array1", []), + emit(Fd, " return oe_error_code;\n\n"); + _ -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "&oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [ic_util:mk_oe_name(G, "sizecalc_"), + ic_forms:get_id2(SId)]), + ?emit_c_dec_rpt(Fd, " ", "array2", []), + emit(Fd, " return oe_error_code;\n\n") + end; + {union, UId, _, _, _} -> + case CalcType of + generator -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [ic_util:mk_oe_name(G, "sizecalc_"), + ic_forms:get_id2(UId)]), + ?emit_c_dec_rpt(Fd, " ", "union1", []), + emit(Fd, " return oe_error_code;\n\n"); + _ -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "&oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [ic_util:mk_oe_name(G, "sizecalc_"), + ic_forms:get_id2(UId)]), + ?emit_c_dec_rpt(Fd, " ", "union2", []), + emit(Fd, " return oe_error_code;\n\n") + end; + {struct, UId, _, _} -> %% Struct as a member in struct ! + case CalcType of + generator -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [ic_util:mk_oe_name(G, "sizecalc_"), + ic_forms:get_id2(UId)]), + ?emit_c_dec_rpt(Fd, " ", "struct1", []), + emit(Fd, " return oe_error_code;\n\n"); + _ -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "&oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [ic_util:mk_oe_name(G, "sizecalc_"), + ic_forms:get_id2(UId)]), + ?emit_c_dec_rpt(Fd, " ", "struct2", []), + emit(Fd, " return oe_error_code;\n\n") + end; + {any, _} -> %% Fix for any type + emit(Fd, " if ((oe_error_code = ei_decode_long(~s, " + "oe_size_count_index, NULL)) < 0) {\n", + [InBuffer]), + ?emit_c_dec_rpt(Fd, " ", "any", []), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end. + +%%------------------------------------------------------------ + +emit_malloc_size_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer) -> + {Pre, DecType} = + case Type of + ushort -> {"", "ulong"}; + ulong -> {"", "ulong"}; + ulonglong -> {"oe_", "ulonglong"}; + short -> {"", "long"}; + long -> {"", "long"}; + longlong -> {"oe_", "longlong"}; + float -> {"", "double"}; + double -> {"", "double"}; + boolean -> {"", "atom"}; + char -> {"", "char"}; + wchar -> {"oe_", "wchar"}; + octet -> {"", "char"}; + any -> {"", "long"} + end, + Fmt = + " if ((oe_error_code = ~sei_decode_~s(~s, oe_size_count_index, " + "NULL)) < 0) {\n", + emit(Fd, Fmt, [Pre, DecType, InBuffer]), + ?emit_c_dec_rpt(Fd, " ", "~s", [DecType]), + emit(Fd, " return oe_error_code;\n }\n"). + +%%------------------------------------------------------------ +%% DECODING +%%------------------------------------------------------------ + +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, Align, + NextPos, DecType) -> + emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, Align, + NextPos, DecType, []). + +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, Align, NextPos, + DecType, AllocedPars) when element(1, T) == scoped_id -> + Fmt = + " if ((oe_error_code = ei_decode_~s(~s, &oe_env->_iin, ~s~s)) < 0)" + " {\n", + Emit = fun(Type) -> + emit(Fd, Fmt, [Type, InBuffer, IndOp, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n") + end, + case mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + Emit("pid"); + "erlang_port" -> + Emit("port"); + "erlang_ref" -> + Emit("ref"); + "ETERM*" -> + Emit("term"); + {enum, FSN} -> + emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp, InBuffer, + Align, NextPos, DecType, AllocedPars); + FSN -> + emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp, InBuffer, + Align, NextPos, DecType, AllocedPars) + end; + +%% XXX T is a string +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, NextPos, + DecType, AllocedPars) when is_list(T) -> + %% Already a fullscoped name + Type = ictype:name2type(G,T), + case ictype:isBasicType(Type) of + true -> + emit_decoding_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer, IndOp, + LName, AllocedPars); + false -> + case DecType of + generator -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, oe_first, " + "~s, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "decode_"), + T, NextPos, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"); + caller -> %% No malloc used, define oe_first + emit(Fd, " {\n"), + emit(Fd, " void *oe_first = NULL;\n"), + emit(Fd, " int oe_outindex = 0;\n\n"), + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_first, ~s, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "decode_"), + T, NextPos, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n"); + caller_dyn -> %% Malloc used + emit(Fd, " {\n"), + emit(Fd, " int oe_outindex = 0;\n\n"), + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_first, ~s, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "decode_"), + T, NextPos, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n"); + array_dyn -> %% Malloc used + emit(Fd, " {\n"), + emit(Fd, " int oe_outindex = 0;\n\n"), + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_first, ~s, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "decode_"), + T, NextPos, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n"); + array_fix_ret -> + emit(Fd, " {\n"), + emit(Fd, " int oe_outindex = 0;\n\n"), + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_first, ~s,*~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "decode_"), + T, NextPos, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n"); + array_fix_out -> %% No malloc used, define oe_first + emit(Fd, " {\n"), + emit(Fd, " void *oe_first = NULL;\n"), + emit(Fd, " int oe_outindex = 0;\n\n"), + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_first, ~s, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "decode_"), + T, NextPos, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n") + end + end; +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos, + DecType, AllocedPars) when is_record(T, string) -> + case DecType of + caller_dyn -> + emit(Fd, " if ((oe_error_code = ei_decode_string(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"); + _ -> + emit(Fd, " ~s~s = oe_first + *oe_outindex;\n\n", + [IndOp, LName]), + emit(Fd, " {\n"), + emit(Fd, " int oe_type=0;\n"), + emit(Fd, " int oe_string_ctr=0;\n\n"), + + emit(Fd, " (int) ei_get_type(~s, " + "&oe_env->_iin, &oe_type, &oe_string_ctr);\n\n", + [InBuffer]), + + emit(Fd, " if ((oe_error_code = ei_decode_string(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " *oe_outindex = ~s;\n", + [ic_util:mk_align("*oe_outindex+oe_string_ctr+1")]), + emit(Fd, " }\n\n") + end; +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos, + DecType, AllocedPars) when is_record(T, wstring) -> + case DecType of + caller_dyn -> + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = oe_ei_decode_wstring(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }/* --- */\n"); % XXX + _ -> + emit(Fd, " ~s~s = oe_first + *oe_outindex;\n\n", + [IndOp, LName]), + + emit(Fd, " {\n"), + emit(Fd, " int oe_type=0;\n"), + emit(Fd, " int oe_string_ctr=0;\n\n"), + emit(Fd, " (int) ei_get_type(~s, " + "&oe_env->_iin, &oe_type, &oe_string_ctr);\n\n", + [InBuffer]), + %% Note prefix: oe_ei + emit(Fd, " if ((oe_error_code = oe_ei_decode_wstring(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " *oe_outindex = ~s;\n", + [ic_util:mk_align("*oe_outindex+oe_string_ctr+1")]), + emit(Fd, " }\n") + end; +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, NextPos, + _DecType, AllocedPars) -> + case normalize_type(T) of + {basic, Type} -> + emit_decoding_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer, IndOp, + LName, AllocedPars); + {void, _} -> + emit(Fd, " if ((oe_error_code = ei_decode_atom(~s, " + "&oe_env->_iin, NULL)) < 0) {\n", + [InBuffer]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"); + {sequence, _, _} -> + ok; + {_, {array, SId, Dims}} -> + AName = ic_forms:get_id2({array, SId, Dims}), + Ptr = "oe_out->"++AName, + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, " + "oe_first, ~s, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "decode_"), + ic_forms:get_id2(SId), + NextPos, Ptr]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"); + {struct, _, _, _} -> %% Struct as a member in struct ! + ok; + _ -> + %%io:format("3 ------------> ~p~n", [T]), + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end. + +%% XXX DecType used in two senses in this file. +emit_decoding_stmt_for_basic_type(G, N, T, Fd, Type, InBuffer, IndOp, + LName, AllocedPars) -> + Fmt = + " if ((oe_error_code = ~sei_decode_~s(~s, &oe_env->_iin, " + "~s~s)) < 0) {\n", + Ret = + " return oe_error_code;\n" + "}\n", + + {Pre, DecType} = + case Type of + ushort -> {"", "ulong"}; + ulong -> {"", "ulong"}; + ulonglong -> {"oe_", "ulonglong"}; + short -> {"", "long"}; + long -> {"", "long"}; + longlong -> {"oe_", "longlong"}; + float -> {"", "double"}; + double -> {"", "double"}; + boolean -> {"", "atom"}; + char -> {"", "char"}; + wchar -> {"oe_", "wchar"}; + octet -> {"", "char"}; + any -> {"", "long"} + end, + case Type of + ushort -> + emit(Fd, " {\n"), + emit(Fd, " unsigned long oe_ulong;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_ulong(~s, " + "&oe_env->_iin, &oe_ulong)) < 0) {\n", + [InBuffer]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, "}\n"), + emit(Fd, " *(~s) = (unsigned short) oe_ulong;\n\n", + [LName]), + emit(Fd, " if (*(~s) != oe_ulong){\n", + [LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n\n"); + short -> + emit(Fd, " {\n"), + emit(Fd, " long oe_long;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_long(~s, " + "&oe_env->_iin, &oe_long)) < 0){\n", + [InBuffer]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n\n"), + emit(Fd, "}\n"), + emit(Fd, " *(~s) = (short) oe_long;\n\n",[LName]), + emit(Fd, " if (*(~s) != oe_long){\n", [LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n"); + float -> + emit(Fd, " {\n"), + emit(Fd, " double oe_double;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_double(~s, " + "&oe_env->_iin, &oe_double)) < 0){\n", + [InBuffer]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n\n"), + emit(Fd, "}\n"), + emit(Fd, " *(~s) = (float) oe_double;\n",[LName]), + emit(Fd, " }\n"); + boolean -> + emit(Fd, " {\n"), + emit(Fd, " char oe_bool[25];\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_atom(~s, " + "&oe_env->_iin, oe_bool)) < 0){\n",[InBuffer]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, "}\n"), + emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"), + emit(Fd, " *(~s) = 0;\n",[LName]), + emit(Fd, " }\n"), + emit(Fd, " else if (strcmp(oe_bool, \"true\") == 0)" + " {\n"), + emit(Fd, " *(~s) = 1;\n",[LName]), + emit(Fd, " }\n"), + emit(Fd, " else {\n"), + emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n"); + _ -> + emit(Fd, Fmt, [Pre, DecType, InBuffer, IndOp, LName]), + ?emit_c_dec_rpt(Fd, " ", "~s", [LName]), + emit_dealloc_stmts(Fd, " ", AllocedPars), + emit(Fd, Ret) + end. + +%%------------------------------------------------------------ +%% +%%------------------------------------------------------------ +emit_dealloc_stmts(Fd, Prefix, AllocedPars) -> + Fmt = Prefix ++ "CORBA_free(~s);\n", + lists:foreach( + fun(Par) -> emit(Fd, Fmt, [Par]) end, + AllocedPars). + + +%%------------------------------------------------------------ +%% +%%------------------------------------------------------------ + +mk_variable_name(Var) -> + Nr = get(Var), + put(Var, Nr + 1), + "oe_tmp" ++ integer_to_list(Nr). + +%% IDL to C type conversion +%%------------------------------------------------------------ +mk_c_type(G, N, S) -> + mk_c_type(G, N, S, evaluate). + +mk_c_type(G, N, S, evaluate) when element(1, S) == scoped_id -> + {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)), + case BT of + "erlang_binary" -> + "erlang_binary"; + "erlang_pid" -> + "erlang_pid"; + "erlang_port" -> + "erlang_port"; + "erlang_ref" -> + "erlang_ref"; + "erlang_term" -> + "ETERM*"; + {enum, Type} -> + mk_c_type(G, N, Type, evaluate); + Type -> + mk_c_type(G, N, Type, evaluate) + end; + +mk_c_type(G, N, S, evaluate_not) when element(1, S) == scoped_id -> + {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)), + case BT of + "erlang_binary" -> + "erlang_binary"; + "erlang_pid" -> + "erlang_pid"; + "erlang_port" -> + "erlang_port"; + "erlang_ref" -> + "erlang_ref"; + "erlang_term" -> + "ETERM*"; + Type -> + Type + end; +mk_c_type(_G, _N, S, _) when is_list(S) -> + S; +mk_c_type(_G, _N, S, _) when is_record(S, string) -> + "CORBA_char *"; +mk_c_type(_G, _N, S, _) when is_record(S, wstring) -> + "CORBA_wchar *"; +mk_c_type(_G, _N, {boolean, _}, _) -> + "CORBA_boolean"; +mk_c_type(_G, _N, {octet, _}, _) -> + "CORBA_octet"; +mk_c_type(_G, _N, {void, _}, _) -> + "void"; +mk_c_type(_G, _N, {unsigned, U}, _) -> + case U of + {short,_} -> + "CORBA_unsigned_short"; + {long,_} -> + "CORBA_unsigned_long"; + {'long long',_} -> + "CORBA_unsigned_long_long" + end; + +mk_c_type(_G, _N, {'long long', _}, _) -> + "CORBA_long_long"; + +mk_c_type(_G, _N, S, _) when is_record(S, union)-> + ic_forms:get_id2(S); + +mk_c_type(_G, N, S, _) when is_record(S, struct) -> %% Locally defined member + Fullname = [ic_forms:get_id2(S) | N], + ic_util:to_undersc(Fullname); + +mk_c_type(_G, _N, {'any', _}, _) -> %% Fix for any type + "CORBA_long"; + +mk_c_type(_G, _N, {T, _}, _) -> + "CORBA_" ++ atom_to_list(T). + +%%------------------------------------------------------------------- +%% IDL to C type conversion used by the emit_c_*_rpt macros. +%%------------------------------------------------------------------- +mk_c_type2(G, N, S) when element(1, S) == scoped_id -> + {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)), + case BT of + "erlang_binary" -> + "erlang_binary"; + "erlang_pid" -> + "erlang_pid"; + "erlang_port" -> + "erlang_port"; + "erlang_ref" -> + "erlang_ref"; + "erlang_term" -> + "ETERM*"; + {enum, Type} -> + mk_c_type2(G, N, Type); + Type -> + mk_c_type2(G, N, Type) + end; + +mk_c_type2(_G, _N, S) when is_list(S) -> + S; +mk_c_type2(_G, _N, S) when is_record(S, string) -> + "CORBA_char *"; +mk_c_type2(_G, _N, S) when is_record(S, wstring) -> + "CORBA_wchar *"; +mk_c_type2(_G, _N, {boolean, _}) -> + "CORBA_boolean"; +mk_c_type2(_G, _N, {octet, _}) -> + "CORBA_octet"; +mk_c_type2(_G, _N, {void, _}) -> + "void"; +mk_c_type2(_G, _N, {unsigned, U}) -> + case U of + {short,_} -> + "CORBA_unsigned_short"; + {long,_} -> + "CORBA_unsigned_long"; + {'long long',_} -> + "CORBA_unsigned_long_long" + end; + +mk_c_type2(_G, _N, {'long long', _}) -> + "CORBA_long_long"; + +mk_c_type2(_G, _N, S) when is_record(S, union)-> + ic_forms:get_id2(S); + +mk_c_type2(_G, N, S) when is_record(S, struct) -> + Fullname = [ic_forms:get_id2(S) | N], + ic_util:to_undersc(Fullname); + +mk_c_type2(_G, _N, S) when is_record(S, sequence) -> + mk_c_type2(_G, _N, S#sequence.type); + +mk_c_type2(_G, _N, {'any', _}) -> %% Fix for any type + "CORBA_long"; + +mk_c_type2(_G, _N, {T, _}) -> + "CORBA_" ++ atom_to_list(T). + +%%----- + +is_variable_size_rec(Es) -> + lists:any( + fun({_N, T}) -> is_variable_size(T); + ({_, _N, T}) -> is_variable_size(T) + end, Es). + +is_variable_size({'tk_struct', _IFRId, "port", _ElementList}) -> + false; +is_variable_size({'tk_struct', _IFRId, "pid", _ElementList}) -> + false; +is_variable_size({'tk_struct', _IFRId, "ref", _ElementList}) -> + false; +is_variable_size({'tk_struct', _IFRId, "term", _ElementList}) -> + false; +is_variable_size({'tk_struct', _IFRId, _Name, ElementList}) -> + is_variable_size_rec(ElementList); +is_variable_size({'tk_array', ElemTC, _Length}) -> + is_variable_size(ElemTC); +is_variable_size({'tk_string', _}) -> + true; +is_variable_size({'tk_wstring', _}) -> + true; +is_variable_size({'tk_sequence', _ElemTC, _MaxLsextractength}) -> + true; +is_variable_size({'tk_union', _IFRId, _Name, _, _, ElementList}) -> + is_variable_size_rec(ElementList); +is_variable_size(_Other) -> + false. + + +is_variable_size(_G, _N, T) when is_record(T, string) -> + true; +is_variable_size(_G, _N, T) when is_record(T, wstring) -> + true; +is_variable_size(_G, _N, T) when is_record(T, sequence) -> + true; +is_variable_size(G, N, T) when is_record(T, union) -> + %%io:format("~n~p = ~p~n",[ic_forms:get_id2(T),ictype:fetchTk(G, N, T)]), + is_variable_size(ictype:fetchTk(G, N, T)); +is_variable_size(G, N, T) when is_record(T, struct) -> + is_variable_size(ictype:fetchTk(G, N, T)); +is_variable_size(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, TK, _} -> + is_variable_size(TK); + _ -> + ic_error:fatal_error(G, {name_not_found, T}) + end; +is_variable_size(_G, _N, _Other) -> + false. + +%% mk_dim produces +mk_dim([Arg | Args]) -> + "[" ++ Arg ++ "]" ++ mk_dim(Args); +mk_dim([]) -> []. + +mk_slice_dim(Args) -> + mk_dim(tl(Args)). + + +emit_tmp_variables(Fd) -> + DeclList = get(tmp_declarations), + emit_tmp_variables(Fd, DeclList), + ok. + +emit_tmp_variables(Fd, [Decl |Rest]) -> + emit_tmp_variables(Fd, Rest), + emit(Fd, "~s", [Decl]); +emit_tmp_variables(_Fd, []) -> + ok. + +store_tmp_decl(Format, Args) -> + Decl = io_lib:format(Format, Args), + DeclList = get(tmp_declarations), + put(tmp_declarations, [Decl |DeclList]). + +%%------------------------------------------------------------ +%% +%% Parser utilities +%% +%% Called from the yecc parser. Expands the identifier list of an +%% attribute so that the attribute generator never has to handle +%% lists. +%% +%%------------------------------------------------------------ + +extract_info(_G, N, X) when is_record(X, op) -> + Name = ic_util:to_undersc([ic_forms:get_id2(X) | N]), + Args = X#op.params, + ArgNames = mk_c_vars(Args), + TypeList = {ic_forms:get_type(X), + lists:map(fun(Y) -> ic_forms:get_type(Y) end, Args), + [] + }, + {Name, ArgNames, TypeList}; +extract_info(_G, N, X) -> + Name = ic_util:to_undersc([ic_forms:get_id2(X) | N]), + {Name, [], []}. + + + +%% Usefull functions +get_param_tk(Name, Op) -> + case get_param(Name, Op) of + error -> + error; + Param -> + ic_forms:get_tk(Param) + end. + +get_param(Name, Op) when is_record(Op, op) -> + get_param_loop(Name, Op#op.params); +get_param(_Name, _Op) -> + error. + +get_param_loop(Name,[Param|Params]) -> + case ic_forms:get_id2(Param) of + Name -> + Param; + _ -> + get_param_loop(Name,Params) + end; +get_param_loop(_Name, []) -> + error. + + +%% Input is a list of parameters (in parse form) and output is a list +%% of parameter attribute and variable names. +mk_c_vars(Params) -> + lists:map(fun(P) -> {A, _} = P#param.inout, + {A, ic_forms:get_id(P#param.id)} + end, + Params). + +normalize_type({unsigned, {short, _}}) -> {basic, ushort}; +normalize_type({unsigned, {long, _}}) -> {basic, ulong}; +normalize_type({unsigned, {'long long', _}}) -> {basic, ulonglong}; +normalize_type({short,_}) -> {basic, short}; +normalize_type({long, _}) -> {basic, long}; +normalize_type({'long long', _}) -> {basic, longlong}; +normalize_type({float,_}) -> {basic, float}; +normalize_type({double, _}) -> {basic, double}; +normalize_type({boolean, _}) -> {basic, boolean}; +normalize_type({char, _}) -> {basic, char}; +normalize_type({wchar, _}) -> {basic, wchar}; +normalize_type({octet, _}) -> {basic, octet}; +normalize_type({any, _}) -> {basic, any}; +normalize_type(tk_ushort) -> {basic, ushort}; +normalize_type(tk_ulong) -> {basic, ulong}; +normalize_type(tk_ulonglong) -> {basic, ulonglong}; +normalize_type(tk_short) -> {basic, short}; +normalize_type(tk_long) -> {basic, long}; +normalize_type(tk_longlong) -> {basic, longlong}; +normalize_type(tk_float) -> {basic, float}; +normalize_type(tk_double) -> {basic, double}; +normalize_type(tk_boolean) -> {basic, boolean}; +normalize_type(tk_char) -> {basic, char}; +normalize_type(tk_wchar) -> {basic, wchar}; +normalize_type(tk_octet) -> {basic, octet}; +normalize_type(tk_any) -> {basic, any}; +normalize_type(ushort) -> {basic, ushort}; +normalize_type(ulong) -> {basic, ulong}; +normalize_type(ulonglong) -> {basic, ulonglong}; +normalize_type(short) -> {basic, short}; +normalize_type(long) -> {basic, long}; +normalize_type(longlong) -> {basic, longlong}; +normalize_type(float) -> {basic, float}; +normalize_type(double) -> {basic, double}; +normalize_type(boolean) -> {basic, boolean}; +normalize_type(char) -> {basic, char}; +normalize_type(wchar) -> {basic, wchar}; +normalize_type(octet) -> {basic, octet}; +normalize_type(any) -> {basic, any}; +normalize_type(Type) -> Type. + diff --git a/lib/ic/src/ic_cclient.erl b/lib/ic/src/ic_cclient.erl new file mode 100644 index 0000000..ebe7e0c --- /dev/null +++ b/lib/ic/src/ic_cclient.erl @@ -0,0 +1,1209 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_cclient). + +%% This module implements generation of C client code, where the +%% client acts as an Erlang C-node, and where the communication thus +%% is according to the Erlang distribution protocol. +%% + +-export([do_gen/3]). + +%%------------------------------------------------------------ +%% IMPLEMENTATION CONVENTIONS +%%------------------------------------------------------------ +%% Functions: +%% +%% mk_* returns things to be used. No side effects. +%% emit_* Writes to file. Has Fd in arguments. +%% gen_* Same, but has no Fd. Usually for larger things. +%% +%% Terminology for generating C: +%% +%% par_list list of identifiers with types, types only, or with +%% parameters (arguments) only. +%% arg_list list of identifiers only (for function calls) +%% + +%%------------------------------------------------------------ +%% Internal stuff +%%------------------------------------------------------------ + +-import(lists, [foreach/2, foldl/3, foldr/3]). +-import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]). + +-include("icforms.hrl"). +-include("ic.hrl"). +-include_lib("stdlib/include/erl_compile.hrl"). + +-define(IC_HEADER, "ic.h"). +-define(ERL_INTERFACEHEADER, "erl_interface.h"). +-define(EICONVHEADER, "ei.h"). +-define(ERLANGATOMLENGTH, "256"). + + +%%------------------------------------------------------------ +%% ENTRY POINT +%%------------------------------------------------------------ +do_gen(G, File, Form) -> + OeName = ic_util:mk_oe_name(G, remove_ext(ic_util:to_list(File))), + G2 = ic_file:filename_push(G, [], OeName, c), + gen_headers(G2, [], Form), + R = gen(G2, [], Form), + ic_file:filename_pop(G2, c), + R. + +remove_ext(File) -> + filename:rootname(filename:basename(File)). + +%%------------------------------------------------------------ +%% +%% Generate client side C stubs. +%% +%% - each module definition results in a separate file. +%% - each interface definition results in a separate file. +%% +%% G = record(genobj) (see ic.hrl) +%% N = scoped names in reverse +%% X = current form to consider. +%%------------------------------------------------------------ + +gen(G, N, [X| Xs]) when is_record(X, preproc) -> + G1 = change_file_stack(G, N, X), + gen(G1, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, module) -> + CD = ic_code:codeDirective(G, X), + G2 = ic_file:filename_push(G, N, X, CD), + N2 = [ic_forms:get_id2(X)| N], + gen_headers(G2, N2, X), + gen(G2, N2, ic_forms:get_body(X)), + G3 = ic_file:filename_pop(G2, CD), + gen(G3, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, interface) -> + + G2 = ic_file:filename_push(G, N, X, c), + N2 = [ic_forms:get_id2(X)| N], + + %% Sets the temporary variable counter. + put(op_variable_count, 0), + put(tmp_declarations, []), + + gen_headers(G2, N2, X), + + gen(G2, N2, ic_forms:get_body(X)), + + lists:foreach( + fun({_Name, Body}) -> + gen(G2, N2, Body) end, + X#interface.inherit_body), + + %% Generate Prototypes + gen_prototypes(G2, N2, X), + + %% Generate generic preparation for decoding + gen_receive_info(G2, N2, X), + + G3 = ic_file:filename_pop(G2, c), + + gen(G3, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, const) -> + emit_constant(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, op) -> + {OpName, ArgNames, RetParTypes} = ic_cbe:extract_info(G, N, X), + %% XXX Note: N is the list of scoped ids of the *interface*. + gen_operation(G, N, X, OpName, ArgNames, RetParTypes), + gen_encoder(G, N, X, OpName, ArgNames, RetParTypes), + gen_decoder(G, N, X, OpName, ArgNames, RetParTypes), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, attr) -> + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, except) -> + icstruct:except_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, enum) -> + icenum:enum_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, typedef) -> + icstruct:struct_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, struct) -> + icstruct:struct_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, union) -> + icstruct:struct_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [_X| Xs]) -> + %% XXX Should have debug message here. + gen(G, N, Xs); + +gen(_G, _N, []) -> + ok. + +%%------------------------------------------------------------ +%% Change file stack +%%------------------------------------------------------------ + +change_file_stack(G, _N, X) when X#preproc.cat == line_nr -> + Id = ic_forms:get_id2(X), + Flags = X#preproc.aux, + case Flags of + [] -> + ic_genobj:push_file(G, Id); + _ -> + foldr( + fun({_, _, "1"}, G1) -> + ic_genobj:push_file(G1, Id); + ({_, _, "2"}, G1) -> + ic_genobj:pop_file(G1, Id); + ({_, _, "3"}, G1) -> + ic_genobj:sys_file(G1, Id) + end, G, Flags) + end; +change_file_stack(G, _N, _X) -> + G. + +%%------------------------------------------------------------ +%% Generate headers in stubfiles and header files +%%------------------------------------------------------------ + +gen_headers(G, N, X) when is_record(X, interface) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + %% Set the temporary variable counter + put(op_variable_count, 0), + put(tmp_declarations, []), + HFd = ic_genobj:hrlfiled(G), + IncludeFileStack = ic_genobj:include_file_stack(G), + L = length(N), + Filename = + if + L < 2 -> + lists:nth(L + 1, IncludeFileStack); + true -> + lists:nth(2, IncludeFileStack) + end, + emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]), + ic_code:gen_includes(HFd, G, X, c_client), + + IfName = ic_util:to_undersc(N), + IfNameUC = ic_util:to_uppercase(IfName), + emit(HFd, "\n#ifndef __~s__\n", [IfNameUC]), + emit(HFd, "#define __~s__\n", [IfNameUC]), + LCmt = io_lib:format("Interface object definition: ~s", [IfName]), + ic_codegen:mcomment_light(HFd, [LCmt], c), + case get_c_timeout(G, "") of + "" -> + ok; + {SendTmo, RecvTmo} -> + emit(HFd, "#define OE_~s_SEND_TIMEOUT ~s\n", + [IfNameUC, SendTmo]), + emit(HFd, "#define OE_~s_RECV_TIMEOUT ~s\n", + [IfNameUC, RecvTmo]), + emit(HFd, "#ifndef EI_HAVE_TIMEOUT\n"), + emit(HFd, "#error Functions for send and receive with " + "timeout not defined in erl_interface\n"), + emit(HFd, "#endif\n\n") + end, + + emit(HFd, "typedef CORBA_Object ~s;\n", [IfName]), + emit(HFd, "#endif\n\n"); + + false -> ok + end, + case ic_genobj:is_stubfile_open(G) of + true -> + Fd = ic_genobj:stubfiled(G), + ic_codegen:nl(Fd), + emit(Fd, "#include \n"), + emit(Fd, "#include \n"), + case ic_options:get_opt(G, c_report) of + true -> + emit(Fd, "#ifndef OE_C_REPORT\n"), + emit(Fd, "#define OE_C_REPORT\n"), + emit(Fd, "#include \n"), + emit(Fd, "#endif\n"); + _ -> + ok + end, + emit(Fd, "#include \"~s\"\n", [?IC_HEADER]), + emit(Fd, "#include \"~s\"\n", [?ERL_INTERFACEHEADER]), + emit(Fd, "#include \"~s\"\n", [?EICONVHEADER]), + emit(Fd, "#include \"~s\"\n", + [filename:basename(ic_genobj:include_file(G))]), + ic_codegen:nl(Fd), ic_codegen:nl(Fd), + Fd; % XXX ?? + false -> + ok + end; + +%% Some items have extra includes +gen_headers(G, N, X) when is_record(X, module) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + HFd = ic_genobj:hrlfiled(G), + IncludeFileStack = ic_genobj:include_file_stack(G), + Filename = lists:nth(length(N) + 1, IncludeFileStack), + emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]), + ic_code:gen_includes(HFd, G, X, c_client); + false -> ok + end; +gen_headers(G, [], _X) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + HFd = ic_genobj:hrlfiled(G), + case ic_options:get_opt(G, c_report) of + true -> + emit(HFd, "#ifndef OE_C_REPORT\n"), + emit(HFd, "#define OE_C_REPORT\n"), + emit(HFd, "#include \n"), + emit(HFd, "#endif\n"); + _ -> + ok + end, + emit(HFd, "#include \"~s\"\n", [?IC_HEADER]), + emit(HFd, "#include \"~s\"\n", [?ERL_INTERFACEHEADER]), + emit(HFd, "#include \"~s\"\n", [?EICONVHEADER]), + ic_code:gen_includes(HFd, G, c_client); + false -> ok + end; +gen_headers(_G, _N, _X) -> + ok. + + +%%------------------------------------------------------------ +%% Generate all prototypes (for interface) +%%------------------------------------------------------------ +gen_prototypes(G, N, X) -> + case ic_genobj:is_hrlfile_open(G) of + false -> + ok; + true -> + HFd = ic_genobj:hrlfiled(G), + IfName = ic_util:to_undersc(N), + + %% Emit generated function prototypes + emit(HFd, "\n/* Operation functions */\n"), + lists:foreach(fun({_Name, Body}) -> + emit_operation_prototypes(G, HFd, N, Body) + end, [{x, ic_forms:get_body(X)}| + X#interface.inherit_body]), + + UserProto = get_user_proto(G, false), + %% Emit generic function prototypes + case UserProto of + false -> + ok; + UserProto -> + emit(HFd, + "\n/* Generic user defined encoders */\n"), + emit(HFd, + "int ~s_prepare_notification_encoding(" + "CORBA_Environment*);" + "\n", [UserProto]), + emit(HFd, + "int ~s_prepare_request_encoding(CORBA_Environment*);" + "\n", [UserProto]) + end, + %% Emit encoding function prototypes + emit(HFd, "\n/* Input encoders */\n"), + lists:foreach(fun({_Name, Body}) -> + emit_encoder_prototypes(G, HFd, N, Body) + end, + [{x, ic_forms:get_body(X)}| + X#interface.inherit_body]), + + %% Emit generic function prototypes + emit(HFd, "\n/* Generic decoders */\n"), + emit(HFd, "int ~s__receive_info(~s, CORBA_Environment*);\n", + [IfName, IfName]), + + case UserProto of + false -> + ok; + UserProto -> + emit(HFd, "\n/* Generic user defined decoders */\n"), + emit(HFd, + "int ~s_prepare_reply_decoding(CORBA_Environment*);" + "\n", [UserProto]) + end, + %% Emit decode function prototypes + emit(HFd, "\n/* Result decoders */\n"), + lists:foreach(fun({_Name, Body}) -> + emit_decoder_prototypes(G, HFd, N, Body) + end, [{x, ic_forms:get_body(X)}| + X#interface.inherit_body]), + case UserProto of + false -> + ok; + UserProto -> + %% Emit generic send and receive_prototypes + {Sfx, TmoType} = case get_c_timeout(G, "") of + "" -> + {"", ""}; + _ -> + {"_tmo", ", unsigned int"} + end, + emit(HFd, + "\n/* Generic user defined send and receive " + "functions */\n"), + emit(HFd, + "int ~s_send_notification~s(CORBA_Environment*~s);\n", + [UserProto, Sfx, TmoType]), + emit(HFd, + "int ~s_send_request_and_receive_reply~s(" + "CORBA_Environment*~s~s);\n", + [UserProto, Sfx, TmoType, TmoType]) + end + end. + +%%------------------------------------------------------------ +%% Generate receive_info() (generic part for message reception) +%% (for interface). For backward compatibility only. +%%------------------------------------------------------------ + +gen_receive_info(G, N, _X) -> + case ic_genobj:is_stubfile_open(G) of + false -> + ok; + true -> + Fd = ic_genobj:stubfiled(G), + IfName = ic_util:to_undersc(N), + UserProto = get_user_proto(G, oe), + Code = + " +/* + * Generic function, used to return received message information. + * Not used by oneways. Always generated. For backward compatibility only. + */ + +int ~s__receive_info(~s oe_obj, CORBA_Environment *oe_env) +{ + return ~s_prepare_reply_decoding(oe_env); +}\n", + emit(Fd, Code, [IfName, IfName, UserProto]) +end. + +%%------------------------------------------------------------ +%% Emit constant +%%------------------------------------------------------------ + +emit_constant(G, N, ConstRecord) -> + case ic_genobj:is_hrlfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:hrlfiled(G), + CName = ic_util:to_undersc( + [ic_forms:get_id(ConstRecord#const.id)| N]), + UCName = ic_util:to_uppercase(CName), + + emit(Fd, "\n#ifndef __~s__\n", [UCName]), + emit(Fd, "#define __~s__\n", [UCName]), + + emit(Fd, "/* Constant: ~s */\n", [CName]), + + if is_record(ConstRecord#const.type, wstring) -> + %% If wstring, add 'L' + emit(Fd, "#define ~s L~p\n", + [CName, ConstRecord#const.val]); + true -> + emit(Fd, "#define ~s ~p\n", + [CName, ConstRecord#const.val]) + end, + emit(Fd, "#endif\n\n") + end. + +%%------------------------------------------------------------ +%% Generate operation (for interface) +%%------------------------------------------------------------ + +%% N is the list of scoped ids of the *interface*. +%% X is the operation +gen_operation(G, N, X, OpName, ArgNames, RetParTypes) -> + case ic_genobj:is_stubfile_open(G) of + true -> + do_gen_operation(G, N, X, OpName, ArgNames, RetParTypes); + false -> + ok + end. + +do_gen_operation(G, N, X, OpName, ArgNames, RetParTypes) -> + Fd = ic_genobj:stubfiled(G), + IfName = ic_util:to_undersc(N), + IfNameUC = ic_util:to_uppercase(IfName), + + {R, ParTypes, _} = RetParTypes, + + IsOneway = ic_forms:is_oneway(X), + + emit(Fd, "\n" + "/***\n" + " *** Operation function \"~s\" ~s\n" + " ***/\n\n", + [OpName, ifelse(IsOneway, "(oneway)", "")]), + + RV = element(1, R), + Ret = case IsOneway of + false -> + if RV /= void -> + mk_ret_type(G, N, R); + true -> + "void" + end; + true -> + "void" + end, + ParListStr = ic_util:chain(mk_par_type_list(G, N, X, [in, out], + [types, args], + ParTypes, ArgNames), ", "), + emit(Fd, + "~s ~s(~s, ~sCORBA_Environment *oe_env)\n{\n", + [Ret, OpName, [IfName, " ", "oe_obj"], ParListStr]), + + case IsOneway of + true -> + ok; + false -> + case ictype:isArray(G, N, R) of + true -> + emit(Fd, " ~s oe_return = NULL;\n\n", + [mk_ret_type(G, N, R)]); + false -> + if RV /= void -> + emit(Fd, " ~s oe_return;\n\n", + [Ret]); + true -> + ok + end + end, + emit(Fd, + " /* Initiating the message reference */\n" + " ic_init_ref(oe_env, &oe_env->_unique);\n") + end, + + emit(Fd, + " /* Initiating exception indicator */ \n" + " oe_env->_major = CORBA_NO_EXCEPTION;\n"), + + %% XXX Add pointer checks: checks of in-parameter + %% pointers, and non-variable out-parameter pointers. + + emit(Fd," /* Creating ~s message */ \n", + [ifelse(IsOneway, "cast", "call")]), + + EncParListStr = ic_util:chain(mk_arg_list_for_encoder(G, N, X, + ParTypes, ArgNames), + ", "), + emit(Fd, + " if (~s__client_enc(oe_obj, ~s""oe_env) < 0) {\n", + [OpName, EncParListStr]), + emit(Fd, + " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "DATA_CONVERSION, \"Cannot encode message\");\n"), + + RetVar = ifelse(RV /= void, " oe_return", ""), + emit_c_enc_rpt(Fd, " ", "client operation ~s\\n====\\n", [OpName]), + + emit(Fd, " return~s;\n }\n", [RetVar]), + + emit(Fd," /* Sending ~s message */ \n", + [ifelse(IsOneway, "cast", "call")]), + + UserProto = get_user_proto(G, oe), + {Sfx, SendTmo, RecvTmo} = case get_c_timeout(G, "") of + "" -> + {"", "", ""}; + _ -> + {"_tmo", + [", OE_", IfNameUC, "_SEND_TIMEOUT"], + [", OE_", IfNameUC, "_RECV_TIMEOUT"]} + end, + + case IsOneway of + true -> + emit(Fd, + " if (~s_send_notification~s(oe_env~s) < 0)\n" + " return~s;\n", [UserProto, Sfx, SendTmo, RetVar]); + false -> + emit(Fd, + " if (~s_send_request_and_receive_reply~s(oe_env~s~s) < 0)\n" + " return~s;\n", + [UserProto, Sfx, SendTmo, RecvTmo, RetVar]), + + DecParList0 = mk_arg_list_for_decoder(G, N, X, + ParTypes, ArgNames), + DecParList1 = case mk_ret_type(G, N, R) of + "void" -> + DecParList0; + _ -> + ["&oe_return"| DecParList0] + end, + + DecParListStr = ic_util:chain(DecParList1, ", "), + %% YYY Extracting results + emit(Fd, + " /* Extracting result value(s) */ \n" + " if (~s__client_dec(oe_obj, ~s""oe_env) < 0) {\n", + [OpName, DecParListStr]), + emit(Fd, + " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, DATA_CONVERSION, " + "\"Bad result value(s)\");\n"), + emit_c_dec_rpt(Fd, " ", "client operation ~s\\n=====\\n", [OpName]), + emit(Fd, + " return~s;\n" + " }\n", [RetVar]) + end, + emit(Fd, " return~s;\n", [RetVar]), + emit(Fd, "}\n\n\n"). + +%%------------------------------------------------------------ +%% Generate encoder +%%------------------------------------------------------------ +%% N is the list of scoped ids of the *interface*. +%% X is the operation +gen_encoder(G, N, X, OpName, ArgNames, RetParTypes)-> + case ic_genobj:is_stubfile_open(G) of + true -> + Fd = ic_genobj:stubfiled(G), + IfName = ic_util:to_undersc(N), + {_R, ParTypes, _} = RetParTypes, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + emit(Fd, "/*\n * Encode operation input for \"~s\"\n */\n\n", + [OpName]), + ParList = ic_util:chain( + mk_par_type_list(G, N, X, [in], [types, args], + ParTypes, ArgNames), ", "), + emit(Fd, + "int ~s__client_enc(~s oe_obj, ~s" + "CORBA_Environment *oe_env)\n{\n", + [OpName, IfName, ParList]), + + InTypeAttrArgs = lists:filter(fun({_, in, _}) -> true; + ({_, _, _}) -> false + end, TypeAttrArgs), + case InTypeAttrArgs of + [] -> + ok; + _ -> + emit(Fd, + " int oe_error_code = 0;\n\n") + end, + + emit_encodings(G, N, Fd, X, InTypeAttrArgs, + ic_forms:is_oneway(X)), + emit(Fd, " return 0;\n}\n\n"), + ok; + + false -> + ok + end. + +%%------------------------------------------------------------ +%% Generate decoder +%%------------------------------------------------------------ +%% N is the list of scoped ids of the *interface*. +%% X is the operation +gen_decoder(G, N, X, OpName, ArgNames, RetParTypes)-> + case ic_forms:is_oneway(X) of + true -> + ok; + false -> + case ic_genobj:is_stubfile_open(G) of + true -> + Fd = ic_genobj:stubfiled(G), + IfName = ic_util:to_undersc(N), + {R, ParTypes, _} = RetParTypes, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + emit(Fd, "/*\n * Decode operation results for " + "\"~s\"\n */\n\n", [OpName]), + ParList0 = mk_par_type_list(G, N, X, [out], + [types, args], + ParTypes, ArgNames), + PARLIST = case mk_ret_type(G, N, R) of + "void" -> + ParList0; + Else -> + [Else ++ "* oe_return"| ParList0] + end, + PLFCD = ic_util:chain(PARLIST, ", "), + emit(Fd, + "int ~s__client_dec(~s oe_obj, ~s" + "CORBA_Environment *oe_env)\n{\n", + [OpName, IfName, PLFCD]), + emit(Fd, " int oe_error_code = 0;\n"), + OutTypeAttrArgs = lists:filter(fun({_, out, _}) -> true; + ({_, _, _}) -> false + end, TypeAttrArgs), + emit_decodings(G, N, Fd, R, OutTypeAttrArgs), + emit(Fd, " return 0;\n}\n\n"), + ok; + + false -> + ok + end + end. + +%%------------------------------------------------------------ +%% EMIT ENCODINGS/DECODINGS +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% Emit encodings +%%------------------------------------------------------------ +%% N is the list of scoped ids of the *interface*. +%% X is the operation +%% emit_encodings(G, N, Fd, X, TypeAttrArgs, IsOneWay) +%% +emit_encodings(G, N, Fd, X, TypeAttrArgs, true) -> + %% Cast + UserProto = get_user_proto(G, oe), + emit(Fd, + " if (~s_prepare_notification_encoding(oe_env) < 0)\n" + " return -1;\n", [UserProto]), + emit_encodings_1(G, N, Fd, X, TypeAttrArgs); +emit_encodings(G, N, Fd, X, TypeAttrArgs, false) -> + %% Call + UserProto = get_user_proto(G, oe), + emit(Fd, + " if (~s_prepare_request_encoding(oe_env) < 0)\n" + " return -1;\n", [UserProto]), + emit_encodings_1(G, N, Fd, X, TypeAttrArgs). + +emit_encodings_1(G, N, Fd, X, TypeAttrArgs) -> + {ScopedName, _, _} = ic_cbe:extract_info(G, N, X), + Name = case ic_options:get_opt(G, scoped_op_calls) of + true -> + ScopedName; + false -> + ic_forms:get_id2(X) + end, + if + TypeAttrArgs /= [] -> + emit(Fd, " if (oe_ei_encode_tuple_header(oe_env, ~p) < 0) {\n", + [length(TypeAttrArgs) + 1]), + emit_c_enc_rpt(Fd, " ", "ei_encode_tuple_header", []), + emit(Fd, " return -1;\n }\n"); + true -> + ok + end, + emit(Fd, " if (oe_ei_encode_atom(oe_env, ~p) < 0) {\n", [Name]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []), + emit(Fd, " return -1;\n }\n"), + + foreach(fun({{'void', _}, _, _}) -> + ok; + ({T1, A1, N1}) -> + IndOp = mk_ind_op(A1), + emit_coding_comment(G, N, Fd, "Encode", IndOp, + T1, N1), + ic_cbe:emit_encoding_stmt(G, N, X, Fd, T1, IndOp ++ N1, + "oe_env->_outbuf") + end, TypeAttrArgs), + ok. + +%%------------------------------------------------------------ +%% Emit dedodings +%%------------------------------------------------------------ +%% XXX Unfortunately we have to retain the silly `oe_first' variable, +%% since its name is hardcoded in other modules (icstruct, icunion, +%% etc). +%% N is the list of scoped ids of the *interface*. +%% X is the operation +emit_decodings(G, N, Fd, RetType, TypeAttrArgs) -> + if + TypeAttrArgs /= [] -> + %% Only if there are out parameters + emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(" + "oe_env->_inbuf, &oe_env->_iin, " + "&oe_env->_received)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + Len = length(TypeAttrArgs) + 1, + emit(Fd, " if (oe_env->_received != ~p) {\n", [Len]), + emit_c_dec_rpt(Fd, " ", "tuple header size != ~p", [Len]), + emit(Fd, " return -1;\n }\n"); + true -> + ok + end, + + %% Fetch the return value + emit_coding_comment(G, N, Fd, "Decode return value", "*", RetType, "oe_return"), + APars = + case ic_cbe:is_variable_size(G, N, RetType) of + true -> + emit(Fd, + " {\n" + " int oe_size_count_index = oe_env->_iin;\n" + " int oe_malloc_size = 0;\n" + " void *oe_first = NULL;\n"), + ic_cbe:emit_malloc_size_stmt(G, N, Fd, RetType, + "oe_env->_inbuf", + 1, caller), + %% XXX Add malloc prefix from option + emit(Fd, + " OE_MALLOC_SIZE_CHECK(oe_env, oe_malloc_size);\n" + " if ((*oe_return = oe_first = " + "malloc(oe_malloc_size)) == NULL) {\n" + " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "NO_MEMORY, \"Cannot malloc\");\n" + " return -1;\n" + " }\n"), + Pars = ["*oe_return"], + DecType = case ictype:isArray(G, N, RetType) of + true -> array_dyn; + false -> caller_dyn + end, + ic_cbe:emit_decoding_stmt(G, N, Fd, RetType, + "(*oe_return)", + "", "oe_env->_inbuf", 1, + "&oe_outindex", DecType, + Pars), + emit(Fd, " }\n"), + Pars; + false -> + case ictype:isArray(G, N, RetType) of + true -> + Pars = ["*oe_return"], + emit(Fd, + " {\n" + " int oe_size_count_index = oe_env->_iin;\n" + " int oe_malloc_size = 0;\n" + " void *oe_first = NULL;\n"), + ic_cbe:emit_malloc_size_stmt(G, N, Fd, RetType, + "oe_env->_inbuf", + 1, caller), + %% XXX Add malloc prefix from option + emit(Fd, + " OE_MALLOC_SIZE_CHECK(oe_env, " + "oe_malloc_size);\n" + " if ((*oe_return = oe_first = " + "malloc(oe_malloc_size)) == NULL) {\n" + " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, NO_MEMORY, " + "\"Cannot malloc\");\n" + " return -1;" + " }\n"), + ic_cbe:emit_decoding_stmt(G, N, Fd, RetType, + "oe_return", "", + "oe_env->_inbuf", 1, + "&oe_outindex", + array_fix_ret, + Pars), + emit(Fd, " }\n"), + Pars; + false -> + Pars = [], + %% The last parameter "oe_outindex" is not interesting + %% in the static case. + ic_cbe:emit_decoding_stmt(G, N, Fd, RetType, + "oe_return", "", + "oe_env->_inbuf", 1, + "&oe_outindex", + caller, Pars), + ic_codegen:nl(Fd), + Pars + end + end, + + foldl(fun({{'void', _}, _, _}, Acc) -> + Acc; + ({T, A, N1}, Acc) -> + emit_one_decoding(G, N, Fd, T, A, N1, Acc) + end, APars, TypeAttrArgs), + ok. + +emit_one_decoding(G, N, Fd, T, A, N1, Acc) -> + IndOp = mk_ind_op(A), + case ic_cbe:is_variable_size(G, N, T) of + true -> + emit_coding_comment(G, N, Fd, "Decode", IndOp, + T, N1), + emit(Fd, + " {\n" + " int oe_size_count_index = oe_env->_iin;\n" + " int oe_malloc_size = 0;\n" + " void *oe_first = NULL;\n"), + ic_cbe:emit_malloc_size_stmt(G, N, Fd, T, + "oe_env->_inbuf", + 1, caller), + %% XXX Add malloc prefix from option + emit(Fd, + " OE_MALLOC_SIZE_CHECK(oe_env, oe_malloc_size);\n" + " if ((~s~s = oe_first = " + "malloc(oe_malloc_size)) == NULL) {\n", [IndOp, N1]), + ic_cbe:emit_dealloc_stmts(Fd, " ", Acc), + emit(Fd, + " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "NO_MEMORY, \"Cannot malloc\");\n" + " return -1;\n" + " }\n"), + NAcc = [IndOp ++ N1| Acc], + DecType = case ictype:isArray(G, N, T) of + true -> + array_dyn; + false -> + caller_dyn + end, + ic_cbe:emit_decoding_stmt(G, N, Fd, T, + "(" ++ IndOp + ++ N1 ++ ")", "", + "oe_env->_inbuf", 1, + "&oe_outindex", + DecType, NAcc), + emit(Fd, " }\n"), + NAcc; + false -> + case ictype:isArray(G, N, T) of + true -> + emit_coding_comment(G, N, Fd, "Decode", "", + T, N1), + ic_cbe:emit_decoding_stmt(G, N, Fd, T, N1, + "", "oe_env->_inbuf", + 1, "&oe_outindex", + array_fix_out, Acc), + ic_codegen:nl(Fd), + [N1| Acc]; + false -> + %% The last parameter "oe_outindex" is + %% not interesting in the static case, but + %% must be present anyhow. + emit_coding_comment(G, N, Fd, "Decode", + IndOp, T, N1), + ic_cbe:emit_decoding_stmt(G, N, Fd, T, N1, + "", "oe_env->_inbuf", + 1, "&oe_outindex", + caller, Acc), + ic_codegen:nl(Fd), + Acc + end + end. + +%%------------------------------------------------------------ +%% GENERATE PROTOTYPES +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% Generate operation prototypes +%%------------------------------------------------------------ +emit_operation_prototypes(G, Fd, N, Xs) -> + lists:foreach( + fun(X) when is_record(X, op) -> + {ScopedName, ArgNames, RetParTypes} = + ic_cbe:extract_info(G, N, X), + {R, ParTypes, _} = RetParTypes, + IfName = ic_util:to_undersc(N), + RT = mk_ret_type(G, N, R), + ParList = + ic_util:chain( + mk_par_type_list(G, N, X, [in, out], [types], + ParTypes, ArgNames), + ", "), + emit(Fd, "~s ~s(~s, ~sCORBA_Environment*);\n", + [RT, ScopedName, IfName, ParList]); + (_) -> + ok + end, Xs). + +%%------------------------------------------------------------ +%% Generate encoder prototypes +%%------------------------------------------------------------ +emit_encoder_prototypes(G, Fd, N, Xs) -> + lists:foreach( + fun(X) when is_record(X, op) -> + {ScopedName, ArgNames, RetParTypes} = + ic_cbe:extract_info(G, N, X), + {_R, ParTypes, _} = RetParTypes, + IfName = ic_util:to_undersc(N), + ParList = ic_util:chain( + mk_par_type_list(G, N, X, [in], [types], + ParTypes, ArgNames), + ", "), + emit(Fd, "int ~s__client_enc(~s, ~sCORBA_Environment*);\n", + [ScopedName, IfName, ParList]); + (_) -> + ok + end, Xs). + +%%------------------------------------------------------------ +%% Generate decoder prototypes +%%------------------------------------------------------------ +emit_decoder_prototypes(G, Fd, N, Xs) -> + lists:foreach( + fun(X) when is_record(X, op) -> + case ic_forms:is_oneway(X) of + true -> + true; + false -> + IfName = ic_util:to_undersc(N), + {ScopedName, ArgNames, RetParTypes} = + ic_cbe:extract_info(G, N, X), + {R, ParTypes, _} = RetParTypes, + ParList0 = + mk_par_type_list(G, N, X, [out], [types], + ParTypes, ArgNames), + PARLIST = case mk_ret_type(G, N, R) of + "void" -> + ParList0; + Else -> + [Else ++ "*"| ParList0] + end, + ParList = ic_util:chain(PARLIST, ", "), + emit(Fd, "int ~s__client_dec(~s, ~s" + "CORBA_Environment*);\n", + [ScopedName, IfName, ParList]) + end; + (_) -> + ok + end, Xs). + +%%------------------------------------------------------------ +%% PARAMETER TYPE LISTS +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% Make parameter type list +%% +%% InOrOut = in | out | [in | out] +%% TypesOrArgs = types | args | [types | args] +%%------------------------------------------------------------ +mk_par_type_list(G, N, X, InOrOut, TypesOrArgs, Types, Args) -> + TypeAttrArgs = + filterzip( + fun(_, {inout, Arg}) -> + ic_error:error(G, {inout_spec_for_c, X, Arg}), + false; + (Type, {Attr, Arg}) -> + case lists:member(Attr, InOrOut) of + true -> + {true, {Type, Attr, Arg}}; + false -> + false + end + end, Types, Args), + lists:map( + fun({Type, Attr, Arg}) -> + Ctype = ic_cbe:mk_c_type(G, N, Type), + IsArray = ictype:isArray(G, N, Type), + IsStruct = ictype:isStruct(G, N, Type), + IsUnion = ictype:isUnion(G, N, Type), + Dyn = + case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> ""; + Ctype == "CORBA_char *" -> ""; + is_record(Type, wstring) -> ""; + Ctype == "CORBA_wchar *" -> ""; + true -> + case IsArray of + true -> + "_slice*"; + false -> + "*" + end + end; + false -> + if + Attr == in, Ctype == "erlang_pid" -> + "*"; + Attr == in, Ctype == "erlang_port" -> + "*"; + Attr == in, Ctype == "erlang_ref" -> + "*"; + Attr == in, IsStruct == true -> + "*"; + Attr == in, IsUnion == true -> + "*"; + Attr == in, IsArray == true -> + "_slice*"; + Attr == out, IsArray == true -> + "_slice"; + true -> + "" + end + end, + IndOp = mk_ind_op(Attr), + case {lists:member(types, TypesOrArgs), + lists:member(args, TypesOrArgs)} of + {true, true} -> + Ctype ++ Dyn ++ IndOp ++ " " ++ Arg; + {true, false} -> + Ctype ++ Dyn ++ IndOp; + {false, true} -> + Arg; + {false, false} -> + "" + end + end, TypeAttrArgs). + +%%------------------------------------------------------------ +%% ENCODER ARG LIST +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% Make encoder argument list XXX +%%------------------------------------------------------------ +mk_arg_list_for_encoder(G, _N, X, Types, Args) -> + filterzip( + fun(_, {out, _}) -> + false; + (_, {inout, Arg}) -> + ic_error:error(G, {inout_spec_for_c, X, Arg}), + false; + (_Type, {in, Arg}) -> + {true, Arg} + end, Types, Args). + +%%------------------------------------------------------------ +%% DECODER ARG LIST +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% Make decoder argument list XXX +%%------------------------------------------------------------ +mk_arg_list_for_decoder(G, _N, X, Types, Args) -> + filterzip(fun(_, {in, _}) -> + false; + (_, {inout, Arg}) -> + ic_error:error(G, {inout_spec_for_c, X, Arg}), + false; + (_, {out, Arg}) -> + {true, Arg} + end, Types, Args). + +%%------------------------------------------------------------ +%% MISC +%%------------------------------------------------------------ +%%------------------------------------------------------------ +%% Make list of {Type, Attr, Arg} +%%------------------------------------------------------------ +mk_type_attr_arg_list(Types, Args) -> + filterzip(fun(Type, {Attr, Arg}) -> + {true, {Type, Attr, Arg}} + end, Types, Args). + +%%------------------------------------------------------------ +%% Make return type +%%------------------------------------------------------------ +mk_ret_type(G, N, Type) -> + Ctype = ic_cbe:mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + ""; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> + ""; + Ctype == "CORBA_wchar *" -> + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + "_slice*"; + false -> + "*" + end + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + "_slice*"; + false -> + "" + end + end, + Ctype ++ Dyn. + + +%%------------------------------------------------------------ +%% Make indirection operator (to "*" or not to "*"). +%%------------------------------------------------------------ +mk_ind_op(in) -> + ""; +mk_ind_op(inout) -> + error; +mk_ind_op(out) -> + "*". + +%%------------------------------------------------------------ +%% Emit encoding/decoding comment +%%------------------------------------------------------------ +emit_coding_comment(G, N, Fd, String, RefOrVal, Type, Name) -> + emit(Fd, " /* ~s parameter: ~s~s ~s */\n", + [String, ic_cbe:mk_c_type(G, N, Type), RefOrVal, Name]). + +%%------------------------------------------------------------ +%% User protocol prefix for generic functions +%%------------------------------------------------------------ +get_user_proto(G, Default) -> + case ic_options:get_opt(G, user_protocol) of + false -> + Default; + Pfx -> + Pfx + end. + +%%------------------------------------------------------------ +%% Timeout. Returns a string (or Default). +%%------------------------------------------------------------ +get_c_timeout(G, Default) -> + case ic_options:get_opt(G, c_timeout) of + Tmo when is_integer(Tmo) -> + TmoStr = integer_to_list(Tmo), + {TmoStr, TmoStr}; + {SendTmo, RecvTmo} when is_integer(SendTmo) andalso is_integer(RecvTmo) -> + {integer_to_list(SendTmo), integer_to_list(RecvTmo)}; + false -> + Default + end. + +%%------------------------------------------------------------ +%% ZIPPERS (merging of successive elements of two lists). +%%------------------------------------------------------------ + +%% zip([H1| T1], [H2| T2]) -> +%% [{H1, H2}| zip(T1, T2)]; +%% zip([], []) -> +%% []. + +filterzip(F, [H1| T1], [H2| T2]) -> + case F(H1, H2) of + false -> + filterzip(F, T1, T2); + {true, Val} -> + [Val| filterzip(F, T1, T2)] + end; +filterzip(_, [], []) -> + []. + + +ifelse(true, A, _) -> + A; +ifelse(false, _, B) -> + B. diff --git a/lib/ic/src/ic_code.erl b/lib/ic/src/ic_code.erl new file mode 100644 index 0000000..6802b9c --- /dev/null +++ b/lib/ic/src/ic_code.erl @@ -0,0 +1,584 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_code). + + +-include_lib("ic/src/ic.hrl"). +-include_lib("ic/src/icforms.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([get_basetype/2, insert_typedef/3, codeDirective/2]). +-export([gen_includes/3, gen_includes/4, mk_list/1]). + +-export([type_expand_op/4, type_expand_handle_op/4]). +-export([ type_expand_op_exec/4, type_expand_all/6, type_expand/7]). + +-export([type_expand_null/3, type_expand_void/3, type_expand_float/3, type_expand_double/3]). +-export([type_expand_short/3, type_expand_ushort/3, type_expand_long/3, type_expand_ulong/3]). +-export([type_expand_longlong/3, type_expand_ulonglong/3]). +-export([type_expand_char/3, type_expand_wchar/3, type_expand_boolean/3]). +-export([type_expand_octet/3, type_expand_any/3, type_expand_wstring/3]). +-export([type_expand_object/3, type_expand_string/3, type_expand_struct/7, type_expand_union/7]). +-export([type_expand_enum/4, type_expand_sequence/7, type_expand_array/7, type_expand_error/3]). + +-export([type_expand_struct_rule/3, type_expand_union_rule/2, type_expand_enum_rule/4]). +-export([type_expand_enum_elements/3, type_expand_longdouble/3, type_expand_typecode/3]). +-export([type_expand_principal/3, type_expand_exception/7]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%------------------------------------------------------------------------------------- +%% +%% Trackrecording of generated sequence type structs, thist is just used for C today. +%% +%%------------------------------------------------------------------------------------- + +get_basetype(G, MyId) -> + case ?lookup(ic_genobj:typedeftab(G), MyId) of + [] -> + MyId; + X -> + get_basetype(G, X) + end. + +insert_typedef(_G, "erlang_term", _) -> + ok; +insert_typedef(G, MyId, DefinedAsId) -> + ?insert(ic_genobj:typedeftab(G), MyId, DefinedAsId). + +codeDirective(G,X) -> + case produceCode(X) of + true -> + case ic_options:get_opt(G, be) of + c_genserv -> + c; + c_client -> + c; + c_server -> + c_server; + _ -> + erlang + end; + false -> + case ic_options:get_opt(G, be) of + c_genserv -> + c_no_stub; + c_client -> + c_no_stub; + c_server -> + c_server_no_stub; + _ -> + erlang_no_stub + end + end. + +%% Checks if X should produce code +produceCode(X) when is_record(X, module) -> + case ic_forms:get_body(X) of + [] -> + true; + List -> + produceModuleCode(List) + end; +produceCode(_X) -> + false. + +produceModuleCode([]) -> + false; +produceModuleCode([X|_Xs]) when is_record(X, const) -> + true; +produceModuleCode([_X|Xs]) -> + produceModuleCode(Xs). + +%% Includes needed c file headers for included idl files +gen_includes(Fd,G,Type) -> + case Type of + c_client -> + IncludeList = + ic_pragma:get_included_c_headers(G), + gen_includes_loop(Fd,IncludeList,Type); + c_server -> + IncludeList = + ic_pragma:get_included_c_headers(G), + gen_includes_loop(Fd,IncludeList,Type); + _ -> + ok + end, + ic_codegen:nl(Fd), + ic_codegen:emit(Fd, "#ifdef __cplusplus\n"), + ic_codegen:emit(Fd, "extern \"C\" {\n"), + ic_codegen:emit(Fd, "#endif\n\n"). + + +%% Includes needed c file headers for local interfaces +gen_includes(Fd,G,X,Type) -> + case Type of + c_client -> + IncludeList = + ic_pragma:get_local_c_headers(G,X), + gen_includes_loop(Fd,IncludeList,Type); + c_server -> + IncludeList = + ic_pragma:get_local_c_headers(G,X), + gen_includes_loop(Fd,IncludeList,Type); + _ -> + ok + end, + ic_codegen:nl(Fd), + ic_codegen:emit(Fd, "#ifdef __cplusplus\n"), + ic_codegen:emit(Fd, "extern \"C\" {\n"), + ic_codegen:emit(Fd, "#endif\n\n"). + + +gen_includes_loop(_,[],_) -> + ok; +gen_includes_loop(Fd,[I|Is],Type) -> + L = string:tokens(I,"/"), + File = lists:last(L), + case File of + "erlang" -> % Erlang is NOT generated that way ! + gen_includes_loop(Fd,Is,Type); + "oe_erlang" -> % Erlang is NOT generated that way ! + gen_includes_loop(Fd,Is,Type); + _ -> + case Type of + c_client -> + ic_codegen:emit(Fd, "#include \"~s.h\"\n", [File]); + c_server -> + ic_codegen:emit(Fd, "#include \"~s__s.h\"\n", [File]) + end, + gen_includes_loop(Fd,Is,Type) + end. + + + + +%% +%% Used in NOC only +%% + + +%% +%% Type expand on function head comments +%% +type_expand_op(G,N,X,Fd) -> + case catch type_expand_op_exec(G,N,X,Fd) of + {'EXIT',_Reason} -> + ic_codegen:nl(Fd), + ic_codegen:emit(Fd,"%% Error under type expansion, does not affect generated code.~n",[]), + ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]); + _ -> + ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]) + end. + + +type_expand_op_exec(G,N,X,Fd) -> + InArgs = ic:filter_params([in,inout], X#op.params), + OutArgs = ic:filter_params([out,inout], X#op.params), + ParamNr = length(InArgs)+1, + Tabs = "", + + ic_codegen:nl(Fd), + ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]), + + case ic_forms:is_oneway(X) of + false -> + ic_codegen:emit(Fd,"%% Operation: ~s/~p~n",[ic_forms:get_id2(X),ParamNr]); + true -> + ic_codegen:emit(Fd,"%% Operation: ~s/~p (oneway)~n",[ic_forms:get_id2(X),ParamNr]) + end, + + if X#op.raises == [] -> []; + true -> + ic_codegen:emit(Fd,"%%~n",[]), + RaisesList=["%% Raises: " ++ + mk_list(lists:map(fun(E) -> ic_util:to_colon(E) end, + X#op.raises))], + ic_codegen:emit(Fd,RaisesList,[]), + ic_codegen:nl(Fd) + end, + + %% Print argument names + ic_codegen:emit(Fd,"%%\n",[]), + InArgNames = ["OE_Ref"]++[ic_util:mk_var(ic_forms:get_id(InArg#param.id)) || InArg <- InArgs ], + OutArgNames = ["Ret"]++[ic_util:mk_var(ic_forms:get_id(OutArg#param.id)) || OutArg <- OutArgs ], + case length(InArgNames) > 1 of + true -> + ic_codegen:emit(Fd,"%% Input value(s) : ~s~n",[mk_list(InArgNames)]); + false -> + ic_codegen:emit(Fd,"%% Input value : ~s~n",[mk_list(InArgNames)]) + end, + case length(OutArgNames) > 1 of + true -> + ic_codegen:emit(Fd,"%% Return value(s) : ~s~n",[mk_list(OutArgNames)]); + false -> + ic_codegen:emit(Fd,"%% Return value : ~s~n",[mk_list(OutArgNames)]) + end, + ic_codegen:emit(Fd,"%%\n",[]), + + InArgsTypeList = + [{ic_util:mk_var(ic_forms:get_id(InArg#param.id)),ic_forms:get_tk(InArg)} || InArg <- InArgs ], + case InArgsTypeList of + [] -> %% no input parameters + ok; + _ -> + ic_codegen:emit(Fd,"%% --input-params-~n",[]), + type_expand_all(G,N,X,Fd,Tabs,InArgsTypeList) + end, + + ReturnTypeList =[{"Ret",X#op.tk}], + ic_codegen:emit(Fd,"%% --return-value-~n",[]), + type_expand_all(G,N,X,Fd,Tabs,ReturnTypeList), + + OutArgsTypeList = + [{ic_util:mk_var(ic_forms:get_id(OutArg#param.id)),ic_forms:get_tk(OutArg)} || OutArg <- OutArgs ], + case OutArgsTypeList of + [] -> %% no input parameters + ok; + _ -> + ic_codegen:emit(Fd,"%% -output-values-~n",[]), + type_expand_all(G,N,X,Fd,Tabs,OutArgsTypeList) + end. + + + + +type_expand_handle_op(G,N,X,Fd) -> + case catch type_expand_handle_op_exec(G,N,X,Fd) of + {'EXIT',_Reason} -> + ic_codegen:nl(Fd), + ic_codegen:emit(Fd,"%% Error under type expansion, does not affect generated code.~n",[]), + ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]); + _ -> + ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]) + end. + + +type_expand_handle_op_exec(_G,_N,X,Fd) -> + InArgs = ic:filter_params([in,inout], X#op.params), + ParamNr = length(InArgs)+1, + + ic_codegen:nl(Fd), + ic_codegen:emit(Fd,"%%------------------------------------------------------------~n",[]), + + case ic_forms:is_oneway(X) of + false -> + ic_codegen:emit(Fd,"%% Handle operation: handle_call/3~n",[]); + true -> + ic_codegen:emit(Fd,"%% Handle operation: handle_cast/3~n",[]) + end, + ic_codegen:emit(Fd,"%%~n",[]), + ic_codegen:emit(Fd,"%% Used for operation ~s/~p implementation~n",[ic_forms:get_id2(X),ParamNr]). + + + +type_expand_all(_G,_N,_X,_Fd,_Tabs,[]) -> + ok; +type_expand_all(G,N,X,Fd,Tabs,[{ArgName,Type}|Rest]) -> + type_expand(G,N,X,Fd,Tabs,ArgName,Type), + type_expand_all(G,N,X,Fd,Tabs,Rest); +type_expand_all(G,N,X,Fd,Tabs,[{default,_ArgName,Type}|Rest]) -> + type_expand(G,N,X,Fd,Tabs,"Def",Type), + type_expand_all(G,N,X,Fd,Tabs,Rest); +type_expand_all(G,N,X,Fd,Tabs,[{LabelNr,_ArgName,Type}|Rest]) when is_integer(LabelNr) -> + type_expand(G,N,X,Fd,Tabs,"V" ++ integer_to_list(LabelNr),Type), + type_expand_all(G,N,X,Fd,Tabs,Rest); +type_expand_all(G,N,X,Fd,Tabs,[{Label,_ArgName,Type}|Rest]) -> + type_expand(G,N,X,Fd,Tabs,Label,Type), + type_expand_all(G,N,X,Fd,Tabs,Rest). + + + +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_null) -> + type_expand_null(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_void) -> + type_expand_void(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_float) -> + type_expand_float(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_double) -> + type_expand_double(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_longdouble) -> + type_expand_longdouble(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_short) -> + type_expand_short(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_ushort) -> + type_expand_ushort(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_long) -> + type_expand_long(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_longlong) -> + type_expand_longlong(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_ulong) -> + type_expand_ulong(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_ulonglong) -> + type_expand_ulonglong(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_char) -> + type_expand_char(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_wchar) -> + type_expand_wchar(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_boolean) -> + type_expand_boolean(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_octet) -> + type_expand_octet(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_any) -> + type_expand_any(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_TypeCode) -> + type_expand_typecode(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,tk_Principal) -> + type_expand_principal(Fd,Tabs,Name); +type_expand(G, N, X,Fd,Tabs,Name, {tk_except, Id, ExcName, ElementList}) -> + type_expand_exception(G, N, X, Fd,Tabs,Name, + {tk_except, Id, ExcName, ElementList}); +type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_fixed, _Digits, _Scale}) -> + type_expand_fixed(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_objref, _IFRId, _ObjTabs, _ObjName}) -> + type_expand_object(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_objref, _IFRId, _ObjName}) -> + type_expand_object(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_string, _Length}) -> + type_expand_string(Fd,Tabs,Name); +type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_wstring, _Length}) -> + type_expand_wstring(Fd,Tabs,Name); +type_expand(G,N,X,Fd,Tabs,Name,{tk_union, IFRId, UnionName, DTC, DNr, LblList}) -> + type_expand_union(G,N,X,Fd,Tabs,Name,{tk_union, IFRId, UnionName, DTC, DNr, LblList}); +type_expand(_G,_N,_X,Fd,Tabs,Name,{tk_enum, IFRId, EnumName, ElemNameList}) -> + type_expand_enum(Fd,Tabs,Name,{tk_enum, IFRId, EnumName, ElemNameList}); +type_expand(G,N,X,Fd,Tabs,Name,{tk_sequence, ElemTC, Length}) -> + type_expand_sequence(G,N,X,Fd,Tabs,Name,{tk_sequence, ElemTC, Length}); +type_expand(G,N,X,Fd,Tabs,Name,{tk_array, ElemTC, Length}) -> + type_expand_array(G,N,X,Fd,Tabs,Name,{tk_array, ElemTC, Length}); +type_expand(G,N,X,Fd,Tabs,Name,{tk_struct, IFRId, StructName, TcList}) -> + type_expand_struct(G,N,X,Fd,Tabs,Name,{tk_struct, IFRId, StructName, TcList}); +type_expand(_G,_N,_X,Fd,Tabs,Name,_) -> + type_expand_error(Fd,Tabs,Name). + + +%% Basic OMG IDL types + +type_expand_null(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = null()~n",[Tabs,Name]). + +type_expand_void(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = void()~n",[Tabs,Name]). + +type_expand_float(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = float()~n",[Tabs,Name]). + +type_expand_double(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = double()~n",[Tabs,Name]). + +type_expand_longdouble(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = long_double()~n",[Tabs,Name]). + +type_expand_short(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = short()~n",[Tabs,Name]). + +type_expand_ushort(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = unsigned_Short()~n",[Tabs,Name]). + +type_expand_long(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = long()~n",[Tabs,Name]). + +type_expand_longlong(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = long_Long()~n",[Tabs,Name]). + +type_expand_ulong(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = unsigned_Long()~n",[Tabs,Name]). + +type_expand_ulonglong(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = unsigned_Long_Long()~n",[Tabs,Name]). + +type_expand_char(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = char()~n",[Tabs,Name]). + +type_expand_wchar(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = wchar()~n",[Tabs,Name]). + +type_expand_boolean(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = boolean()~n",[Tabs,Name]). + +type_expand_octet(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = octet()~n",[Tabs,Name]). + +type_expand_any(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = any()~n",[Tabs,Name]). + +type_expand_typecode(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = TypeCode()~n",[Tabs,Name]). + +type_expand_principal(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = principal()~n",[Tabs,Name]). + + +type_expand_fixed(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = fixed()~n",[Tabs,Name]). + +type_expand_object(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = Object_Ref()~n",[Tabs,Name]). + + +%% Constructed OMG IDL types + +type_expand_string(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = String()~n",[Tabs,Name]). + +type_expand_wstring(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = WString()~n",[Tabs,Name]). + +type_expand_exception(G, N, X, Fd, Tabs, Name, {tk_except, Id, ExcName, ElementList}) -> + ScopedStructName = getScopedName(G, N, ExcName, Id), + ic_codegen:emit(Fd,"%%~s ~s = ",[Tabs, Name]), + type_expand_exception_rule(Fd, ScopedStructName, ElementList), + type_expand_all(G, N, X, Fd, Tabs, ElementList). + +type_expand_struct(G,N,X,Fd,Tabs,Name,{tk_struct, IFRId, StructName, TcList}) -> + ScopedStructName = getScopedName(G,N,StructName,IFRId), + ic_codegen:emit(Fd,"%%~s ~s = ",[Tabs,Name]), + type_expand_struct_rule(Fd,ScopedStructName,TcList), + type_expand_all(G,N,X,Fd,Tabs,TcList). + +type_expand_union(G,N,X,Fd,Tabs,Name,{tk_union, IFRId, UnionName, DTC, _DNr, LblList}) -> + ScopedUnionName = getScopedName(G,N,UnionName,IFRId), + ic_codegen:emit(Fd,"%%~s ~s = #'~s'{label, value}\n",[Tabs,Name,ScopedUnionName]), + type_expand(G,N,X,Fd,Tabs,"label",DTC), + ic_codegen:emit(Fd,"%%~s value = ",[Tabs]), + type_expand_union_rule(Fd,LblList), + type_expand_all(G,N,X,Fd,Tabs,LblList). + +type_expand_enum(Fd,Tabs,Name,{tk_enum, _IFRId, EnumName, ElemNameList}) -> + ic_codegen:emit(Fd,"%%~s ~s = ~s~n",[Tabs,Name,EnumName]), + type_expand_enum_rule(Fd,Tabs,EnumName,ElemNameList). + +type_expand_sequence(G,N,X,Fd,Tabs,Name,{tk_sequence, ElemTC, _Length}) -> + ic_codegen:emit(Fd,"%%~s ~s = [ ~sElem ]~n",[Tabs,Name,Name]), + type_expand(G,N,X,Fd,Tabs,Name++"Elem",ElemTC). + +type_expand_array(G,N,X,Fd,Tabs,Name,{tk_array, ElemTC, _Length}) -> + ic_codegen:emit(Fd,"%%~s ~s = { ~sElem[,..~sElem] }~n",[Tabs,Name,Name,Name]), + type_expand(G,N,X,Fd,Tabs,Name++"Elem",ElemTC). + +type_expand_error(Fd,Tabs,Name) -> + ic_codegen:emit(Fd,"%%~s ~s = ????~n",[Tabs,Name]). + + +type_expand_exception_rule(Fd,_Name,[]) -> + ic_codegen:emit(Fd," ???? "); +type_expand_exception_rule(Fd,Name,TcList) -> + ic_codegen:emit(Fd,"#'~s'{",[Name]), + type_expand_exception_rule(Fd,TcList). + +type_expand_exception_rule(Fd,[{Name,_TC}]) -> + ic_codegen:emit(Fd,"~s}~n",[Name]); +type_expand_exception_rule(Fd,[{Name,_TC}|Rest]) -> + ic_codegen:emit(Fd,"~s,",[Name]), + type_expand_exception_rule(Fd,Rest). + +type_expand_struct_rule(Fd,_Name,[]) -> + ic_codegen:emit(Fd," ???? "); +type_expand_struct_rule(Fd,Name,TcList) -> + ic_codegen:emit(Fd,"#'~s'{",[Name]), + type_expand_struct_rule(Fd,TcList). + +type_expand_struct_rule(Fd,[{Name,_TC}]) -> + ic_codegen:emit(Fd,"~s}~n",[Name]); +type_expand_struct_rule(Fd,[{Name,_TC}|Rest]) -> + ic_codegen:emit(Fd,"~s,",[Name]), + type_expand_struct_rule(Fd,Rest). + + +type_expand_union_rule(Fd,[]) -> + ic_codegen:emit(Fd," ????"); +type_expand_union_rule(Fd,[{default,_Name,_TC}]) -> + ic_codegen:emit(Fd,"Def~n",[]); +type_expand_union_rule(Fd,[{LNr,_Name,_TC}]) when is_integer(LNr)-> + ic_codegen:emit(Fd,"V~p~n",[LNr]); +type_expand_union_rule(Fd,[{Label,_Name,_TC}]) -> + ic_codegen:emit(Fd,"~s~n",[Label]); +type_expand_union_rule(Fd,[{default,_Name,_TC}|Rest]) -> + ic_codegen:emit(Fd,"Default | "), + type_expand_union_rule(Fd,Rest); +type_expand_union_rule(Fd,[{LNr,_Name,_TC}|Rest]) when is_integer(LNr) -> + ic_codegen:emit(Fd,"V~p | ",[LNr]), + type_expand_union_rule(Fd,Rest); +type_expand_union_rule(Fd,[{Label,_Name,_TC}|Rest]) -> + ic_codegen:emit(Fd,"~s | ",[Label]), + type_expand_union_rule(Fd,Rest). + + +type_expand_enum_rule(Fd,Tabs,Name,[]) -> + ic_codegen:emit(Fd,"%%~s ~s = ????",[Tabs,Name]); +type_expand_enum_rule(Fd,Tabs,Name,ElList) -> + ic_codegen:emit(Fd,"%%~s ~s = ",[Tabs,Name]), + type_expand_enum_rule(Fd,ElList). + +type_expand_enum_rule(Fd,[ElName]) -> + ic_codegen:emit(Fd,"'~s' ~n",[ElName]); +type_expand_enum_rule(Fd,[First|Rest]) -> + ic_codegen:emit(Fd,"'~s' | ",[First]), + type_expand_enum_rule(Fd,Rest). + +type_expand_enum_elements(_Fd,_Tabs,[]) -> + ok; +type_expand_enum_elements(Fd,Tabs,[Elem|Elems]) -> + ic_codegen:emit(Fd,"%%~s ~s = Atom()~n",[Tabs,Elem]), + type_expand_enum_elements(Fd,Tabs,Elems). + + + +%% Returns the right scoped name to be used +%% along with the expansion comments +getScopedName(G,N,Name,IfrId) -> + PTab = ic_genobj:pragmatab(G), + case ets:match(PTab,{alias,'$0',IfrId}) of + [] -> %% No Alias - should never happen + ic_util:to_undersc(ic_pragma:mk_scope(IfrId)); + [[[_S|N]]] -> %% An alias + ic_util:to_undersc([Name|N]); + [[[S|FoundScope]]] -> %% Maybe inherited + case ic_pragma:is_inherited_by(FoundScope,N,PTab) of + false -> %% Not inherited + ic_util:to_undersc([S|FoundScope]); + true -> %% inherited + ic_util:to_undersc([Name|N]) + end + end. + + +%% mk_list produces a nice comma separated +%% string of variable names +mk_list([]) -> []; +mk_list([Arg | Args]) -> + Arg ++ mk_list2(Args). +mk_list2([Arg | Args]) -> + ", " ++ Arg ++ mk_list2(Args); +mk_list2([]) -> []. + + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- + + + diff --git a/lib/ic/src/ic_codegen.erl b/lib/ic/src/ic_codegen.erl new file mode 100644 index 0000000..f611c69 --- /dev/null +++ b/lib/ic/src/ic_codegen.erl @@ -0,0 +1,419 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_codegen). + +-include_lib("ic/src/ic.hrl"). +-include_lib("ic/src/icforms.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([emit/2, emit/3]). +-export([emit_c_enc_rpt/4, emit_c_dec_rpt/4]). +-export([comment/2, comment/3, comment/4, comment_inlined/5, comment_prefixed/4]). +-export([mcomment/2, mcomment/3, mcomment_inlined/5, mcomment_prefixed/3]). +-export([mcomment_light/2, mcomment_light/3, mcomment_light_inlined/5, mcomment_light_prefixed/3]). +-export([nl/1, export/2]). +-export([record/5]). +-export([emit_stub_head/4, emit_hrl_head/4, emit_hrl_foot/2]). +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% Emit output as a formatted string, (old emit) +%%-------------------------------------------------------------------- +emit(nil, _) -> ok; +emit(Fd, Str) -> + file:write(Fd, Str). + +emit(nil, _, _) -> ok; +emit(Fd, Fmt, Args) -> + file:write(Fd, io_lib:format(Fmt, Args)). + +emit_c_enc_rpt(Fd, Prefix, Fmt, Args) -> + emit(Fd, Prefix ++ "OE_RPT_ERR(\"Encode error: " ++ Fmt ++ "\");\n", Args). + +emit_c_dec_rpt(Fd, Prefix, Fmt, Args) -> + emit(Fd, Prefix ++ "OE_RPT_ERR(\"Decode error: " ++ Fmt ++ "\");\n", Args). + +%%-------------------------------------------------------------------- +%% Emit comments +%%-------------------------------------------------------------------- +comment(Fd, C) -> + comment_prefixed(Fd, C, [], "%%"). + +comment(Fd, C, A) -> + comment_prefixed(Fd, C, A, "%%"). + +comment(Fd, C, A, c) -> + comment_inlined(Fd, C, A, "/*", "*/"); +comment(Fd, C, A, erl) -> + comment_prefixed(Fd, C, A, "%%"); +comment(Fd, C, A, java) -> + comment_prefixed(Fd, C, A, "//"); +%% Should be removed after a check if it's used !!!!! (LTH) +comment(Fd, C, A, CommentSequence) when is_list(CommentSequence) -> + comment_prefixed(Fd, C, A, CommentSequence). + +comment_inlined(Fd, C, A, Start, End) -> + emit(Fd, Start ++ " " ++ C ++ " " ++ End ++"\n", A). + +comment_prefixed(Fd, C, A, Prefix) -> + emit(Fd, Prefix ++ " " ++ C ++ "\n", A). + +%%-------------------------------------------------------------------- +%% Emit multiline comments with nice delimiters +%%-------------------------------------------------------------------- +mcomment(Fd, List) -> + mcomment_prefixed(Fd, List, "%%"). + +mcomment(Fd, List, c) -> + mcomment_inlined(Fd, List, "/*", "*/", " *"); +mcomment(Fd, List, erl) -> + mcomment_prefixed(Fd, List, "%%"); +mcomment(Fd, List, java) -> + mcomment_prefixed(Fd, List, "//"). + +mcomment_inlined(Fd, List, Start, End, Intermediate) -> + emit(Fd, Start ++ + "------------------------------------------------------------\n"), + emit(Fd, Intermediate ++ "\n"), + lists:foreach(fun(C) -> comment(Fd, C, [], Intermediate) end, List), + emit(Fd, Intermediate ++ "\n"), + emit(Fd, Intermediate ++ + "------------------------------------------------------------" ++ End ++ "\n"), + ok. +mcomment_prefixed(Fd, List, Prefix) -> + emit(Fd, Prefix ++ + "------------------------------------------------------------\n"), + emit(Fd, Prefix ++ "\n"), + lists:foreach(fun(C) -> comment(Fd, C, [], Prefix) end, List), + emit(Fd, Prefix ++ "\n"), + emit(Fd, Prefix ++ + "------------------------------------------------------------\n"), + ok. + + +%%-------------------------------------------------------------------- +%% Emit multiline comments with nice delimiters as above but a +%% little lighter +%%-------------------------------------------------------------------- +mcomment_light(Fd, List) -> + mcomment_light_prefixed(Fd, List, "%%"). + +mcomment_light(Fd, List, c) -> + mcomment_light_inlined(Fd, List, "/*", " */", " *"); +mcomment_light(Fd, List, erl) -> + mcomment_light_prefixed(Fd, List, "%%"); +mcomment_light(Fd, List, java) -> + mcomment_light_prefixed(Fd, List, "//"); +%% Should be removed after a check if it's used !!!!! (LTH) +mcomment_light(Fd, List, Prefix) when is_list(Prefix) -> + mcomment_light_prefixed(Fd, List, Prefix). + +mcomment_light_inlined(Fd, List, Start, End, Intermediate) -> + emit(Fd, "\n" ++ Start ++ "\n"), + lists:foreach(fun(C) -> comment(Fd, C, [], Intermediate) end, List), + emit(Fd, End ++ "\n"), + ok. + +mcomment_light_prefixed(Fd, List, Prefix) -> + emit(Fd, Prefix), + lists:foreach(fun(C) -> comment(Fd, C, [], Prefix) end, List), + emit(Fd, Prefix ++ "\n"), + ok. + +%%-------------------------------------------------------------------- +%% New line +%%-------------------------------------------------------------------- +nl(Fd) -> + emit(Fd, "\n"). + + +%%-------------------------------------------------------------------- +-define(IFRIDFIELD(G), ic_util:mk_name(G, "ID")). + +%%-------------------------------------------------------------------- +%% Emit record definitions for erlang +%%-------------------------------------------------------------------- +record(G, X, Name, _IFRID, Recs) when is_record(X, struct) -> + F = ic_genobj:hrlfiled(G), + emit(F, "-record(~p, {~p", [ic_util:to_atom(Name),hd(Recs)]), + lists:foreach(fun(Y) -> emit(F, ", ~p", [Y]) end, tl(Recs)), + emit(F, "}).\n"); +record(G, X, Name, _IFRID, _Recs) when is_record(X, union) -> + F = ic_genobj:hrlfiled(G), + emit(F, "-record(~p, {label, value}).\n",[ic_util:to_atom(Name)]); +record(G, _X, Name, IFRID, Recs) when length(Recs) > 3 -> + F = ic_genobj:hrlfiled(G), + emit(F, "-record(~p,~n {~p=~p", + [ic_util:to_atom(Name), ic_util:to_atom(?IFRIDFIELD(G)), IFRID]), + rec2(F, "", ", ", Recs), + emit(F, "}).\n"); +record(G, _X, Name, IFRID, Recs) -> + F = ic_genobj:hrlfiled(G), + emit(F, "-record(~p, {~p=~p", [ic_util:to_atom(Name), + ic_util:to_atom(?IFRIDFIELD(G)), + IFRID]), + lists:foreach(fun(Y) -> emit(F, ", ~p", [Y]) end, Recs), + emit(F, "}).\n"). + + +rec2(F, Align, Delim, [M1 , M2, M3 | Ms]) -> + emit(F, "~s~s~p, ~p, ~p", [Delim, Align, M1, M2, M3]), + rec2(F, " ", ",\n", Ms); +rec2(F, Align, Delim, [M1 , M2]) -> + emit(F, "~s~s~p, ~p", [Delim, Align, M1, M2]); +rec2(F, Align, Delim, [M]) -> + emit(F, "~s~s~p", [Delim, Align, M]); +rec2(_F, _Align, _Delim, []) -> + ok. + + +%%-------------------------------------------------------------------- +%% Emit export lists for erlang +%%-------------------------------------------------------------------- +export(F, [E1, E2, E3 | Exports]) -> + emit(F, "-export([~s]).\n", [exp_list([E1, E2, E3])]), + export(F, Exports); +export(_F, []) -> ok; +export(F, Exports) -> + emit(F, "-export([~s]).\n", [exp_list(Exports)]). + +exp_list([E1 | L]) -> + exp_to_string(E1) ++ + lists:map(fun(E) -> ", " ++ exp_to_string(E) end, L). + + +exp_to_string({F,N}) -> io_lib:format("~p/~p", [ic_util:to_atom(F), N]). + + +%%-------------------------------------------------------------------- +%% Emit Stub file header +%%-------------------------------------------------------------------- +emit_stub_head(_G, ignore, _Name, _) -> ignore; +emit_stub_head(G, F1, Name, erlang) -> + mcomment(F1, stub_header(G, Name)), + nl(F1), + emit(F1, "-module(~p).\n", [list_to_atom(Name)]), + emit(F1, "-ic_compiled(~p).\n", [compiler_vsn(?COMPILERVSN)]), + emit(F1, "\n\n"), F1; +emit_stub_head(G, F1, Name, erlang_template) -> + ic_erl_template:emit_header(G, F1, Name), + F1; +emit_stub_head(_G, F1, _Name, erlang_template_no_gen) -> + F1; +emit_stub_head(G, F1, Name, c) -> + mcomment(F1, stub_header(G, Name), c), + emit(F1, "int ic_compiled_~s_~s;\n", [compiler_vsn(?COMPILERVSN), Name]), + emit(F1, "\n\n"), F1; +emit_stub_head(G, F1, Name, c_server) -> + CSName = [Name, "__s"], + mcomment(F1, stub_header(G, CSName), c), + emit(F1, "int ic_compiled_~s_~s;\n", [compiler_vsn(?COMPILERVSN), CSName]), + emit(F1, "\n\n"), F1; +emit_stub_head(G, F1, Name, java) -> + mcomment(F1, stub_header(G, Name), java), + emit(F1, "\n\n"), F1. + +stub_header(G, Name) -> + ["Implementation stub file", + "", + io_lib:format("Target: ~s", [Name]), + io_lib:format("Source: ~s", [ic_genobj:idlfile(G)]), + io_lib:format("IC vsn: ~s", [?COMPILERVSN]), + "", + "This file is automatically generated. DO NOT EDIT IT."]. + +compiler_vsn(Vsn) -> + lists:map(fun($.) -> $_; + (C) -> C + end, Vsn). + +%%-------------------------------------------------------------------- +%% Emit include file header +%%-------------------------------------------------------------------- +%% Name is Fully scoped (undescore) name of interface or module +emit_hrl_head(_G, ignore, _Name, _) -> ignore; +emit_hrl_head(G, Fd, Name, erlang) -> + mcomment(Fd, ["Erlang header file" | + hrl_header(G, Name)]), + nl(Fd), + nl(Fd), + IfdefName = ic_util:to_uppercase(Name++"_HRL"), + emit(Fd, "-ifndef(~s).~n", [IfdefName]), + emit(Fd, "-define(~s, true).~n", [IfdefName]), + nl(Fd), + nl(Fd), + Fd; +emit_hrl_head(G, Fd, Name, c) -> + mcomment(Fd, ["C header file" | + hrl_header(G, Name)], c), + nl(Fd), + nl(Fd), + IfdefName = ic_util:to_uppercase(Name++"_H"), + emit(Fd, "#ifndef ~s~n", [IfdefName]), + emit(Fd, "#define ~s ~n", [IfdefName]), + nl(Fd), + nl(Fd), + Fd; +emit_hrl_head(G, Fd, Name, c_server) -> + mcomment(Fd, ["C header file" | + hrl_header(G, [Name, "__s"])], c), + nl(Fd), + nl(Fd), + IfdefName = ic_util:to_uppercase(Name++"__S_H"), + emit(Fd, "#ifndef ~s~n", [IfdefName]), + emit(Fd, "#define ~s ~n", [IfdefName]), + nl(Fd), + nl(Fd), + Fd. + +hrl_header(G, Name) -> + ["", + io_lib:format("Target: ~s", [Name]), + io_lib:format("Source: ~s", [ic_genobj:idlfile(G)]), + io_lib:format("IC vsn: ~s", [?COMPILERVSN]), + "", + "This file is automatically generated. DO NOT EDIT IT."]. + + + + +%%-------------------------------------------------------------------- +%% Emit include file footer +%%-------------------------------------------------------------------- +emit_hrl_foot(_G, erlang_template) -> + ok; +emit_hrl_foot(_G, erlang_template_no_gen) -> + ok; +emit_hrl_foot(G, erlang) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + nl(Fd), + nl(Fd), + emit(Fd, "-endif.\n"), + nl(Fd), + nl(Fd), + Fd; + false -> + ok + end; +emit_hrl_foot(G, erlang_no_stub) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + nl(Fd), + nl(Fd), + emit(Fd, "-endif.\n"), + nl(Fd), + nl(Fd), + Fd; + false -> + ok + end; +emit_hrl_foot(G, c) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + nl(Fd), + nl(Fd), + emit(Fd, "#ifdef __cplusplus\n"), + emit(Fd, "}\n"), + emit(Fd, "#endif\n"), + nl(Fd), + emit(Fd, "#endif\n"), + nl(Fd), + nl(Fd), + Fd; + false -> + ok + end; +emit_hrl_foot(G, c_server) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + nl(Fd), + nl(Fd), + emit(Fd, "#ifdef __cplusplus\n"), + emit(Fd, "}\n"), + emit(Fd, "#endif\n"), + nl(Fd), + emit(Fd, "#endif\n"), + nl(Fd), + nl(Fd), + Fd; + false -> + ok + end; +emit_hrl_foot(G, c_no_stub) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + nl(Fd), + nl(Fd), + emit(Fd, "#ifdef __cplusplus\n"), + emit(Fd, "}\n"), + emit(Fd, "#endif\n"), + nl(Fd), + emit(Fd, "#endif\n"), + nl(Fd), + nl(Fd), + Fd; + false -> + ok + end; +emit_hrl_foot(G, c_server_no_stub) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + nl(Fd), + nl(Fd), + emit(Fd, "#ifdef __cplusplus\n"), + emit(Fd, "}\n"), + emit(Fd, "#endif\n"), + nl(Fd), + emit(Fd, "#endif\n"), + nl(Fd), + nl(Fd), + Fd; + false -> + ok + end. + + + + + + + + + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- diff --git a/lib/ic/src/ic_constant_java.erl b/lib/ic/src/ic_constant_java.erl new file mode 100644 index 0000000..0a31723 --- /dev/null +++ b/lib/ic/src/ic_constant_java.erl @@ -0,0 +1,99 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_constant_java). + + +-include("icforms.hrl"). +-include("ic.hrl"). +-include("ic_debug.hrl"). +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([gen/3]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: gen/3 +%%----------------------------------------------------------------- +gen(G, N, X) when is_record(X, const) -> + ConstantName = ic_forms:get_java_id(X), + case inInterface(G, N) of + true -> + emit_constant(G, N, X, ConstantName); + false -> + emit_constant_interface(G, N, X, ConstantName) + end; +gen(_G, _N, _X) -> + ok. + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: emit_constant/4 +%%----------------------------------------------------------------- +emit_constant(G, N, X, ConstantName) -> + Fd = ic_genobj:interfacefiled(G), + %%?PRINTDEBUG2("~p", [Fd]), + Type = ic_java_type:getType(G, N, ic_forms:get_type(X)), + ic_codegen:emit(Fd, " public static final ~s ~s = (~s) ~p;\n", + [Type, ConstantName, Type, X#const.val]), + ic_codegen:nl(Fd). + +%%----------------------------------------------------------------- +%% Func: emit_constant_interface/4 +%%----------------------------------------------------------------- +emit_constant_interface(G, N, X, ConstantName) -> + {Fd, _} = ic_file:open_java_file(G, N, ConstantName), + + ic_codegen:emit(Fd, "final public class ~s {\n",[ConstantName]), + + Type = ic_java_type:getType(G, N, ic_forms:get_type(X)), + ic_codegen:emit(Fd, " public static final ~s value = (~s) ~p;\n", + [Type, Type, X#const.val]), + ic_codegen:emit(Fd, "}\n", []), + file:close(Fd). + +%%----------------------------------------------------------------- +%% Func: emit_constant_interface/4 +%%----------------------------------------------------------------- +inInterface(_G, []) -> % Global constant + false; +inInterface(G, N) -> + [N1 |Ns] = N, + {_FullScopedName, T, _TK, _} = + ic_symtab:get_full_scoped_name(G, Ns, ic_symtab:scoped_id_new(N1)), + case T of + interface -> % Constant declare in an interface + true; + _ -> % Constant declared in a module + false + end. + diff --git a/lib/ic/src/ic_cserver.erl b/lib/ic/src/ic_cserver.erl new file mode 100644 index 0000000..52d98c5 --- /dev/null +++ b/lib/ic/src/ic_cserver.erl @@ -0,0 +1,2419 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_cserver). + +%% This module implements generation of C server code, where the +%% server acts as an Erlang C-node, where the functionality is that of +%% a gen_server (in C), and where the communication thus is according +%% to the Erlang distribution protocol. +%% + +-export([do_gen/3]). + +%% Silly dialyzer. +-export([filterzip/3]). + +%%------------------------------------------------------------ +%% +%% Internal stuff +%% +%%------------------------------------------------------------ + +-import(lists, [foreach/2, foldl/3, foldr/3, map/2]). +-import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]). + +-include("icforms.hrl"). +-include("ic.hrl"). +-include_lib("stdlib/include/erl_compile.hrl"). + +-define(IC_HEADER, "ic.h"). +-define(ERL_INTERFACEHEADER, "erl_interface.h"). +-define(EICONVHEADER, "ei.h"). +-define(OE_MSGBUFSIZE, "OE_MSGBUFSIZE"). +-define(ERLANGATOMLENGTH, "256"). + +%%------------------------------------------------------------ +%% +%% Entry point +%% +%%------------------------------------------------------------ +do_gen(G, File, Form) -> + OeName = ic_util:mk_oe_name(G, remove_ext(ic_util:to_list(File))), + G2 = ic_file:filename_push(G, [], OeName, c_server), + gen_headers(G2, [], Form), + R = gen(G2, [], Form), + ic_file:filename_pop(G2, c), + R. + +remove_ext(File) -> + filename:rootname(filename:basename(File)). + +%%------------------------------------------------------------ +%% +%% Generate the server side C stub and header files. +%% +%% For each module a separate file is generated. +%% +%% +%%------------------------------------------------------------ + +gen(G, N, [X| Xs]) when is_record(X, preproc) -> + NewG = change_file_stack(G, N, X#preproc.cat, X), + gen(NewG, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, module) -> + CD = ic_code:codeDirective(G, X), + G2 = ic_file:filename_push(G, N, X, CD), + N2 = [ic_forms:get_id2(X)| N], + gen_headers(G2, N2, X), + gen(G2, N2, ic_forms:get_body(X)), + G3 = ic_file:filename_pop(G2, CD), + gen(G3, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, interface) -> + G2 = ic_file:filename_push(G, N, X, c_server), + N2 = [ic_forms:get_id2(X)| N], + gen_prototypes(G2, N2, X), + gen_serv(G2, N2, X), + G3 = ic_file:filename_pop(G2, c), + gen(G3, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, const) -> + emit_constant(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, op) -> + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, attr) -> + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, except) -> + icstruct:except_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, enum) -> + icenum:enum_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, typedef) -> + icstruct:struct_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, struct) -> + icstruct:struct_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [X| Xs]) when is_record(X, union) -> + icstruct:struct_gen(G, N, X, c), + gen(G, N, Xs); + +gen(G, N, [_| Xs]) -> + gen(G, N, Xs); + +gen(_G, _N, []) -> + ok. + +%%------------------------------------------------------------ +%% Change file stack +%%------------------------------------------------------------ + +change_file_stack(G, _N, line_nr, X) -> + Id = ic_forms:get_id2(X), + Flags = X#preproc.aux, + case Flags of + [] -> ic_genobj:push_file(G, Id); + _ -> + foldr( + fun({_, _, "1"}, G1) -> ic_genobj:push_file(G1, Id); + ({_, _, "2"}, G1) -> ic_genobj:pop_file(G1, Id); + ({_, _, "3"}, G1) -> ic_genobj:sys_file(G1, Id) + end, G, Flags) + end; +change_file_stack(G, _N, _Other, _X) -> + G. + +%%------------------------------------------------------------ +%% Generate headers +%%------------------------------------------------------------ + +%% Some items have extra includes +gen_headers(G, N, X) when is_record(X, module) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + HFd = ic_genobj:hrlfiled(G), + IncludeFileStack = ic_genobj:include_file_stack(G), + Filename = lists:nth(length(N) + 1, IncludeFileStack), + emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]), + ic_code:gen_includes(HFd, G, X, c_server); + false -> ok + end; +gen_headers(G, [], _X) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + HFd = ic_genobj:hrlfiled(G), + emit(HFd, "#include \n"), + case ic_options:get_opt(G, c_report) of + true -> + emit(HFd, "#ifndef OE_C_REPORT\n"), + emit(HFd, "#define OE_C_REPORT\n"), + emit(HFd, "#include \n"), + emit(HFd, "#endif\n"); + _ -> + ok + end, + emit(HFd, "#include \"~s\"\n", [?IC_HEADER]), + emit(HFd, "#include \"~s\"\n", [?ERL_INTERFACEHEADER]), + emit(HFd, "#include \"~s\"\n", [?EICONVHEADER]), + ic_code:gen_includes(HFd, G, c_server); + false -> ok + end; +gen_headers(_G, _N, _X) -> + ok. + +%%------------------------------------------------------------ +%% Generate prototypes +%%------------------------------------------------------------ + +gen_prototypes(G, N, X) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + HFd = ic_genobj:hrlfiled(G), + IncludeFileStack = ic_genobj:include_file_stack(G), + L = length(N), + Filename = + if + L < 2 -> + lists:nth(L + 1, IncludeFileStack); + true -> + lists:nth(2, IncludeFileStack) + end, + + IName = ic_util:to_undersc(N), + INameUC = ic_util:to_uppercase(IName), + + emit(HFd, "#include \"~s\"\n", [filename:basename(Filename)]), + ic_code:gen_includes(HFd, G, X, c_server), + ic_codegen:nl(HFd), + + emit(HFd, "\n#ifndef __~s__\n", [ic_util:to_uppercase(IName)]), + emit(HFd, "#define __~s__\n", [ic_util:to_uppercase(IName)]), + ic_codegen:mcomment_light(HFd, + [io_lib:format("Interface " + "object " + "definition: ~s", + [IName])], c), + case get_c_timeout(G, "") of + "" -> + ok; + {SendTmo, RecvTmo} -> + emit(HFd, "#define OE_~s_SEND_TIMEOUT ~s\n", + [INameUC, SendTmo]), + emit(HFd, "#define OE_~s_RECV_TIMEOUT ~s\n", + [INameUC, RecvTmo]), + emit(HFd, "#ifndef EI_HAVE_TIMEOUT\n"), + emit(HFd, "#error Functions for send and receive with " + "timeout not defined in erl_interface\n"), + emit(HFd, "#endif\n\n") + end, + + emit(HFd, "typedef CORBA_Object ~s;\n\n", [IName]), + emit(HFd, "#endif\n\n"), + + Bodies = [{N, ic_forms:get_body(X)}| X#interface.inherit_body], + + emit(HFd, "\n/* Structure definitions */\n", []), + foreach(fun({N2, Body}) -> + emit_structs_inside_module(G, HFd, N2, Body) end, + Bodies), + + emit(HFd, "\n/* Switch and exec functions */\n", []), + emit(HFd, "int ~s__switch(~s oe_obj, CORBA_Environment " + "*oe_env);\n", [IName, IName]), + foreach(fun({_N2, Body}) -> + emit_exec_prototypes(G, HFd, N, Body) end, + Bodies), + + emit(HFd, "\n/* Generic decoder */\n", []), + emit(HFd, "int ~s__call_info(~s oe_obj, CORBA_Environment " + "*oe_env);\n", [IName, IName]), + + emit(HFd, "\n/* Restore function typedefs */\n", []), + foreach(fun({_N2, Body}) -> + emit_restore_typedefs(G, HFd, N, Body) end, + Bodies), + + emit(HFd, "\n/* Callback functions */\n", []), + foreach(fun({_N2, Body}) -> + emit_callback_prototypes(G, HFd, N, Body) end, + Bodies), + + emit(HFd, "\n/* Parameter decoders */\n", []), + foreach(fun({_N2, Body}) -> + emit_decoder_prototypes(G, HFd, N, Body) end, + Bodies), + + emit(HFd, "\n/* Message encoders */\n", []), + foreach(fun({_N2, Body}) -> + emit_encoder_prototypes(G, HFd, N, Body) end, + Bodies), + + %% Emit operation mapping structures + emit_operation_mapping_declaration(G, HFd, N, Bodies), + + ok; + + false -> + ok + end. + +%%------------------------------------------------------------ +%% Generate the server encoding/decoding function +%%------------------------------------------------------------ + + +gen_serv(G, N, X) -> + case ic_genobj:is_stubfile_open(G) of + true -> + Fd = ic_genobj:stubfiled(G), + + emit_switch(G, Fd, N, X), + emit_server_generic_decoding(G, Fd, N), + + %% Sets the temporary variable counter. + put(op_variable_count, 0), + put(tmp_declarations, []), + + %% Generate exec, decode and encoding functions, and + %% table of exec functions. + Bodies = [{N, ic_forms:get_body(X)}| + X#interface.inherit_body], + + foreach(fun({_N2, Body}) -> + emit_dispatch(G, Fd, N, Body) end, + Bodies), + emit_operation_mapping(G, Fd, N, Bodies); + false -> + ok + end. + +%%------------------------------------------------------------ +%% Emit structs inside module +%%------------------------------------------------------------ + +emit_structs_inside_module(G, _Fd, N, Xs)-> + lists:foreach( + fun(X) when is_record(X, enum) -> + icenum:enum_gen(G, N, X, c); + (X) when is_record(X, typedef) -> + icstruct:struct_gen(G, N, X, c); + (X) when is_record(X, struct) -> + icstruct:struct_gen(G, N, X, c); + (X) when is_record(X, union) -> + icstruct:struct_gen(G, N, X, c); + (_) -> + ok + end, Xs). + +%%------------------------------------------------------------ +%% Emit exec prototypes +%%------------------------------------------------------------ + +emit_exec_prototypes(G, Fd, N, Xs) -> + lists:foreach( + fun(X) when is_record(X, op) -> + {ScopedName, _, _} = ic_cbe:extract_info(G, N, X), + emit(Fd, + "int ~s__exec(~s oe_obj, CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N)]); + (X) when is_record(X, const) -> + emit_constant(G, N, X); + (_) -> + ok + end, Xs). + +%%------------------------------------------------------------ +%% Emit restore typedefs +%%------------------------------------------------------------ + +emit_restore_typedefs(G, Fd, N, [X| Xs]) when is_record(X, op) -> + %% Check if to use scoped call names + {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + RT = mk_c_ret_type(G, N, RetType), + + PL = ic_util:mk_list(mk_par_list_for_callback_prototypes(G, N, X, + TypeAttrArgs)), + RPL = case PL of + "" -> + ""; + _PL -> + ", " ++ PL + end, + + case RT of + "void" -> + case PL of + "" -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N)]); + _ -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), PL]) + end; + + "erlang_port*" -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]); + + "erlang_pid*" -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]); + + "erlang_ref*" -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]); + + _ -> + case ictype:isArray(G, N, RetType) of + true -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]); + false -> + emit(Fd, "typedef void (*~s__rs(~s oe_obj, ~s*~s, " + "CORBA_Environment *oe_env));\n", + [ScopedName, ic_util:to_undersc(N), RT, RPL]) + end + end, + emit_restore_typedefs(G, Fd, N, Xs); +emit_restore_typedefs(G, Fd, N, [X| Xs]) when is_record(X, attr) -> + emit_restore_typedefs(G, Fd, N, Xs); +emit_restore_typedefs(G, Fd, N, [_X| Xs]) -> + emit_restore_typedefs(G, Fd, N, Xs); +emit_restore_typedefs(_G, _Fd, _N, []) -> ok. + + +%%------------------------------------------------------------ +%% Emit call-back prototypes +%%------------------------------------------------------------ + +emit_callback_prototypes(G, Fd, N, [X| Xs]) when is_record(X, op) -> + %% Check scoped names XXX + {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + RT = mk_c_ret_type(G, N, RetType), + + PL = ic_util:mk_list(mk_par_list_for_callback_prototypes(G, N, X, + TypeAttrArgs)), + CBPL = case PL of + "" -> + ""; + _PL -> + ", " ++ PL + end, + case RT of + "void" -> + case PL of + "" -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N)]); + _ -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), PL]) + end; + "erlang_port*" -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, CBPL]); + + "erlang_pid*" -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, CBPL]); + + "erlang_ref*" -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, CBPL]); + + _ -> + case ictype:isArray(G, N, RetType) of + true -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, + CBPL]); + false -> + emit(Fd, "~s__rs* ~s__cb(~s oe_obj, ~s*~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ScopedName, ic_util:to_undersc(N), RT, + CBPL]) + end + end, + emit_callback_prototypes(G, Fd, N, Xs); +emit_callback_prototypes(G, Fd, N, [X| Xs]) when is_record(X, attr) -> + emit_callback_prototypes(G, Fd, N, Xs); +emit_callback_prototypes(G, Fd, N, [_X| Xs]) -> + emit_callback_prototypes(G, Fd, N, Xs); +emit_callback_prototypes(_G, _Fd, _N, []) -> ok. + +%%------------------------------------------------------------ +%% Emit decoder prototypes +%%------------------------------------------------------------ + +emit_decoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, op) -> + %% Check if to use scoped call names + {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {_RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + case ic_util:mk_list(mk_par_list_for_decoder_prototypes(G, N, X, + TypeAttrArgs)) of + "" -> + ok; + PLFDP -> + emit(Fd, "int ~s__dec(~s oe_obj, ~s, CORBA_Environment " + "*oe_env);\n", + [ScopedName, ic_util:to_undersc(N), PLFDP]) + end, + emit_decoder_prototypes(G, Fd, N, Xs); +emit_decoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, attr) -> + emit_decoder_prototypes(G, Fd, N, Xs); +emit_decoder_prototypes(G, Fd, N, [_X| Xs]) -> + emit_decoder_prototypes(G, Fd, N, Xs); +emit_decoder_prototypes(_G, _Fd, _N, []) -> ok. + + +%%------------------------------------------------------------ +%% Emit encoder prototypes +%%------------------------------------------------------------ + +emit_encoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, op) -> + case ic_forms:is_oneway(X) of + true -> + emit_encoder_prototypes(G, Fd, N, Xs); + false -> + %% Check if to use scoped call names + {ScopedName, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + RType = mk_c_ret_type(G, N, RetType), + case ic_util:mk_list(mk_par_list_for_encoder_prototypes( + G, N, X, TypeAttrArgs)) of + "" -> + case RType of + "void" -> + emit(Fd, "int ~s__enc(~s oe_obj, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N)]); + _ -> + emit(Fd, "int ~s__enc(~s oe_obj, ~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N), RType]) + end; + PLFEP -> + case RType of + "void" -> + emit(Fd, "int ~s__enc(~s oe_obj, ~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N), PLFEP]); + _ -> + emit(Fd, "int ~s__enc(~s oe_obj, ~s, ~s, " + "CORBA_Environment *oe_env);\n", + [ScopedName, ic_util:to_undersc(N), RType, + PLFEP]) + end + end, + emit_encoder_prototypes(G, Fd, N, Xs) + end; +emit_encoder_prototypes(G, Fd, N, [X| Xs]) when is_record(X, attr) -> + emit_encoder_prototypes(G, Fd, N, Xs); +emit_encoder_prototypes(G, Fd, N, [_X| Xs]) -> + emit_encoder_prototypes(G, Fd, N, Xs); +emit_encoder_prototypes(_G, _Fd, _N, []) -> ok. + +%%------------------------------------------------------------ +%% Emit operation mapping declaration +%%------------------------------------------------------------ + +emit_operation_mapping_declaration(G, Fd, N, Bodies) -> + Interface = ic_util:to_undersc(N), + Length = erlang:length(get_all_opnames(G, N, Bodies)), + emit(Fd, "\n/* Operation mapping */\n", []), + emit(Fd, "extern oe_map_t oe_~s_map;\n", [Interface]), + emit(Fd, "/* For backward compatibility */\n"), + emit(Fd, "#define ___~s_map___ oe_~s_map\n", + [Interface, Interface]), + case Length of + 0 -> + ok; + _ -> + emit(Fd, "extern oe_operation_t oe_~s_operations[];\n", + [Interface]), + emit(Fd, "/* For backward compatibility */\n"), + emit(Fd, "#define ___~s_operations___ oe_~s_operations\n", + [Interface, Interface]) + end. + + +%% Returns a list of {OpName, ScopedOpName} for all operations, where +%% OpName == ScopedOpName in case the `scoped_op_calls' option has +%% been set. +%% +get_all_opnames(G, N, Bodies) -> + ScNF = fun(X) -> + {ScName, _, _} = ic_cbe:extract_info(G, N, X), + ScName + end, + NF = case ic_options:get_opt(G, scoped_op_calls) of + true -> + ScNF; + false -> + fun(X) -> ic_forms:get_id2(X) end + end, + Filter = fun(X) when is_record(X, op) -> + {true, {NF(X), ScNF(X)}}; + (_) -> + false + end, + %% zf == filtermap + lists:flatmap(fun({_, Xs}) -> lists:zf(Filter, Xs) end, Bodies). + +%%------------------------------------------------------------ +%% Emit switch +%%------------------------------------------------------------ + +emit_switch(G, Fd, N, _X) -> + emit(Fd, "#include \n"), + case ic_options:get_opt(G, c_report) of + true -> + emit(Fd, "#ifndef OE_C_REPORT\n"), + emit(Fd, "#define OE_C_REPORT\n"), + emit(Fd, "#include \n"), + emit(Fd, "#endif\n"); + _ -> + ok + end, + StartCode = + "#include \"ic.h\"\n" + "#include \"erl_interface.h\"\n" + "#include \"ei.h\"\n" + "#include \"~s__s.h\"\n\n" + "/*\n" + " * Main switch\n" + " */\n\n" + "int ~s__switch(~s oe_obj, CORBA_Environment *oe_env)\n" + "{\n" + " return oe_exec_switch(oe_obj, oe_env, &oe_~s_map);\n" + "}\n\n", + ScopedName = ic_util:to_undersc(N), + emit(Fd, StartCode, [ScopedName, ScopedName, ScopedName, ScopedName]). + +%%------------------------------------------------------------ +%% Emit server generic decoding. +%%------------------------------------------------------------ + +emit_server_generic_decoding(G, Fd, N) -> + UserProto = get_user_proto(G, oe), + Code = + "/*\n" + " * Returns call identity (left only for backward compatibility)\n" + " */\n\n" + "int ~s__call_info(~s oe_obj, CORBA_Environment *oe_env)\n" + "{\n" + " return ~s_prepare_request_decoding(oe_env);\n" + "}\n\n", + IName = ic_util:to_undersc(N), + emit(Fd, Code, [IName, IName, UserProto]). + +%%------------------------------------------------------------ +%% Emit dispatch +%%------------------------------------------------------------ + +emit_dispatch(G, Fd, N, Xs) -> + lists:foreach( + fun(X) when is_record(X, op) -> + {Name, ArgNames, Types} = ic_cbe:extract_info(G, N, X), + {RetType, ParTypes, _} = Types, + TypeAttrArgs = mk_type_attr_arg_list(ParTypes, ArgNames), + emit_exec_function(G, Fd, N, X, Name, RetType, TypeAttrArgs), + emit_parameter_decoder(G, Fd, N, X, Name, RetType, TypeAttrArgs), + emit_message_encoder(G, Fd, N, X, Name, RetType, TypeAttrArgs); + (_) -> + ok + end, Xs). + +%%------------------------------------------------------------ +%% Emit operation mapping +%%------------------------------------------------------------ + +emit_operation_mapping(G, Fd, N, Bodies) -> + OpNames = get_all_opnames(G, N, Bodies), + Interface = ic_util:to_undersc(N), + Length = erlang:length(OpNames), + emit(Fd, "\n/* Operation mapping */\n\n", []), + case Length of + 0 -> + emit(Fd, "oe_map_t oe_~s_map = { 0, NULL };\n\n", [Interface]); + _ -> + emit(Fd, "\noe_operation_t oe_~s_operations[~p] = {\n", + [Interface, Length]), + Members = lists:map( + fun({OpN, ScOpN}) -> + Name = ic_util:to_undersc([OpN]), + ScName = ic_util:to_undersc([ScOpN]), + io_lib:fwrite(" {~p, ~p, ~s__exec}", + [Interface, Name, ScName]) + end, OpNames), + emit(Fd, ic_util:join(Members, ",\n")), + emit(Fd, "};\n\n", []), + emit(Fd, "oe_map_t oe_~s_map = " + "{~p, oe_~s_operations};\n\n", + [Interface, Length, Interface]) + end. + +%%------------------------------------------------------------ +%% Emit constant +%%------------------------------------------------------------ + +emit_constant(G, N, ConstRecord) -> + case ic_genobj:is_hrlfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:hrlfiled(G), + CName = ic_util:to_undersc( + [ic_forms:get_id(ConstRecord#const.id)| N]), + UCName = ic_util:to_uppercase(CName), + + emit(Fd, "\n#ifndef __~s__\n", [UCName]), + emit(Fd, "#define __~s__\n\n", [UCName]), + + emit(Fd, "/* Constant: ~s */\n", [CName]), + + if is_record(ConstRecord#const.type, wstring) -> + %% If wstring, add 'L' + emit(Fd, "#define ~s L~p\n\n", [CName, + ConstRecord#const.val]); + true -> + emit(Fd, "#define ~s ~p\n\n", [CName, + ConstRecord#const.val]) + end, + + emit(Fd, "#endif\n\n") + end. + +%%------------------------------------------------------------ +%% Emit exec function +%%------------------------------------------------------------ + +emit_exec_function(G, Fd, N, X, Name, RetType, TypeAttrArgs) -> + %% Decoding operation specific part + InTypeAttrArgs = lists:filter(fun({_, in, _}) -> true; + ({_, _, _}) -> false + end, TypeAttrArgs), + ic_codegen:nl(Fd), + + emit(Fd, + "int ~s__exec(~s oe_obj, CORBA_Environment *oe_env)\n" + "{\n", + [Name, ic_util:to_undersc(N)]), + + emit(Fd, " if (oe_env->_received != ~p) {\n", [length(InTypeAttrArgs)]), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, BAD_PARAM, " + "\"Wrong number of operation parameters\");\n"), + emit_c_dec_rpt(Fd, " ", "wrong number of parameters", []), + emit_c_dec_rpt(Fd, " ", "server exec ~s\\n====\\n", [Name]), + emit(Fd, " return -1;\n", []), + emit(Fd, " }\n"), + emit(Fd, " else {\n", []), + + case InTypeAttrArgs of + [] -> + true; + _ -> + emit(Fd, " int oe_error_code = 0;\n") + end, + + %% Callback variable definition + emit_variable_defs(G, Fd, N, X, Name, RetType, TypeAttrArgs), + + %% Call to parameter decoder + emit_parameter_decoder_call(G, Fd, N, X, Name, RetType, TypeAttrArgs), + + %% Callback to user code + emit_callback(G, Fd, N, X, Name, RetType, TypeAttrArgs), + + %% Call to return message encoder + case ic_forms:is_oneway(X) of + true -> + true; + false -> + emit_message_encoder_call(G, Fd, N, X, Name, RetType, TypeAttrArgs) + end, + + %% Restore function call + emit_restore(G, Fd, N, X, Name, RetType, TypeAttrArgs), + + emit(Fd, " }\n return 0;\n}\n\n"). + +%%------------------------------------------------------------ +%% Emit parameter decoder +%%------------------------------------------------------------ + +emit_parameter_decoder(G, Fd, N, X, Name, _RetType, TypeAttrArgs) -> + %% Decoding operation specific part + InTypeAttrArgs = + lists:filter(fun({_, in, _}) -> true; + ({_, _, _}) -> false + end, TypeAttrArgs), + case InTypeAttrArgs of + [] -> + ok; + _ -> + case ic_util:mk_list(mk_par_list_for_decoder(G, N, X, + TypeAttrArgs)) of + "" -> + emit(Fd, "int ~s__dec(~s oe_obj, CORBA_Environment " + "*oe_env)\n{\n int oe_error_code;\n\n", + [Name, ic_util:to_undersc(N)]); + PLFD -> + emit(Fd, "int ~s__dec(~s oe_obj, ~s, CORBA_Environment " + "*oe_env)\n{\n", + [Name, ic_util:to_undersc(N), PLFD]), + emit(Fd, " int oe_error_code;\n\n") + end, + + APars = [], % XXX Alloced parameters + foldl( + fun({{'void', _}, _, _}, _Acc) -> + ok; + ({T1, A1, N1}, Acc) -> + emit_one_decoding(G, N, Fd, T1, A1, N1, Acc) + end, APars, InTypeAttrArgs), + + emit(Fd, " return 0;\n}\n\n") + end. + +%%------------------------------------------------------------ +%% Emit one decoding +%%------------------------------------------------------------ + +emit_one_decoding(G, N, Fd, T1, A1, N1, AllocedPars) -> + IndOp = mk_ind_op(A1), + case ic_cbe:is_variable_size(G, N, T1) of + false -> + %% The last parameter "oe_outindex" is not used in + %% the static case but must be there anyhow. + emit_decoding_stmt(G, N, Fd, T1, + N1, "", "oe_env->_inbuf", 1, "&oe_outindex", + caller, AllocedPars), + ic_codegen:nl(Fd), + AllocedPars; + true -> + emit_encoding_comment(G, N, Fd, "Decode", IndOp, T1, N1), + emit(Fd, " {\n"), + emit(Fd, " int oe_size_count_index = oe_env->_iin;\n"), + emit(Fd, " int oe_malloc_size = 0;\n"), + emit(Fd, " void *oe_first = NULL;\n"), + ic_cbe:emit_malloc_size_stmt(G, N, Fd, T1, + "oe_env->_inbuf", 1, caller), + %% This is the only malloc call in this file + emit(Fd, + " OE_MALLOC_SIZE_CHECK(oe_env, oe_malloc_size);\n" + " if ((*~s = oe_first = " + "malloc(oe_malloc_size)) == NULL) {\n", [N1]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit(Fd, + " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "NO_MEMORY, \"Cannot malloc\");\n" + " return -1;\n" + " }\n"), + ParName = "*" ++ N1, % XXX Why not IndOp? + NAllocedPars = [ParName| AllocedPars], + case ictype:isArray(G, N, T1) of + true -> + emit_decoding_stmt(G, N, Fd, T1, + "(*" ++ IndOp ++ N1 ++ ")", "", + "oe_env->_inbuf", 1, "&oe_outindex", + array_dyn, NAllocedPars); + false -> + emit_decoding_stmt(G, N, Fd, T1, + "(*" ++ IndOp ++ N1 ++ ")", "", + "oe_env->_inbuf", 1, "&oe_outindex", + caller_dyn, NAllocedPars) + end, + emit(Fd, " }\n\n"), + NAllocedPars + end. + +%%------------------------------------------------------------ +%% Emit message encoder +%%------------------------------------------------------------ + +emit_message_encoder(G, Fd, N, X, Name, RetType, TypeAttrArgs) -> + case ic_forms:is_oneway(X) of + false -> + %% Encoding operation specific part + emit(Fd, + "\nint ~s__enc(~s oe_obj", + [Name, ic_util:to_undersc(N)]), + RType = mk_c_ret_type(G, N, RetType), + ParList = mk_par_list_for_encoder(G, N, X, TypeAttrArgs), + case ic_util:mk_list(ParList) of + "" -> + case RType of + "void" -> + emit(Fd, ", CORBA_Environment *oe_env)\n{"); + _ -> + emit(Fd, ", ~s oe_return, CORBA_Environment " + "*oe_env)\n{", [RType]) + end; + PLFD -> + case RType of + "void" -> + emit(Fd, ", ~s, CORBA_Environment " + "*oe_env)\n{", [PLFD]); + _ -> + emit(Fd, ", ~s oe_return~s, CORBA_Environment " + "*oe_env)\n{", [RType, ", " ++ PLFD]) + end + end, + + + emit(Fd, "\n"), + emit(Fd, " int oe_error_code;\n\n"), + UserProto = get_user_proto(G, oe), + emit(Fd, " ~s_prepare_reply_encoding(oe_env);\n", [UserProto]), + + OutTypeAttrArgs = + lists:filter(fun({_, out, _}) -> true; + ({_, _, _}) -> false + end, TypeAttrArgs), + + OutLength = length(OutTypeAttrArgs), + case OutLength > 0 of + false -> + ic_codegen:nl(Fd); + true -> + emit(Fd, " oe_ei_encode_tuple_header(oe_env, ~p);\n\n", + [OutLength+1]) + + end, + + emit_encoding_comment(G, N, Fd, "Encode", "", RetType, + "oe_return"), + emit_encoding_stmt(G, N, X, Fd, RetType, "oe_return"), + + foreach(fun({T1, _A1, N1}) -> + case T1 of + {'void', _} -> + ok; + _ -> + emit_encoding_comment(G, N, Fd, "Encode", + "", T1, N1), + emit_encoding_stmt(G, N, X, Fd, T1, N1) + end + end, OutTypeAttrArgs), + emit(Fd, " return 0;\n}\n\n"); + _ -> + %% Oneway + ok + end. + +%%------------------------------------------------------------ +%% Emit message encoder call +%%------------------------------------------------------------ + +emit_message_encoder_call(G, Fd, N, X, Name, RetType, TypeAttrArgs) -> + emit(Fd, " /* Encoding reply message */\n"), + RType = mk_c_ret_type(G, N, RetType), + case ic_util:mk_list(mk_enc_par_list(G, N, X, TypeAttrArgs)) of + "" -> + case RType of + "void" -> + emit(Fd, " ~s(oe_obj, oe_env);\n", + [Name ++ "__enc"]); + "erlang_pid*" -> + emit(Fd, " ~s(oe_obj, &oe_return, oe_env);\n", + [Name ++ "__enc"]); + "erlang_port*" -> + emit(Fd, " ~s(oe_obj, &oe_return, oe_env);\n", + [Name ++ "__enc"]); + "erlang_ref*" -> + emit(Fd, " ~s(oe_obj, &oe_return, oe_env);\n", + [Name ++ "__enc"]); + _ -> + emit(Fd, " ~s(oe_obj, oe_return, oe_env);\n", + [Name ++ "__enc"]) + end; + + PLFE -> + case RType of + "void" -> + emit(Fd, " ~s(oe_obj, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]); + "erlang_pid*" -> + emit(Fd, " ~s(oe_obj, &oe_return, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]); + "erlang_port*" -> + emit(Fd, " ~s(oe_obj, &oe_return, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]); + "erlang_ref*" -> + emit(Fd, " ~s(oe_obj, &oe_return, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]); + _ -> + emit(Fd, " ~s(oe_obj, oe_return, ~s, oe_env);\n", + [Name ++ "__enc", PLFE]) + end + end, + ic_codegen:nl(Fd). + +%%------------------------------------------------------------ +%% Emit parameter decoding call +%%------------------------------------------------------------ + +emit_parameter_decoder_call(G, Fd, N, X, Name, _R, TypeAttrArgs) -> + case ic_util:mk_list(mk_dec_par_list(G, N, X, TypeAttrArgs)) of + "" -> %% No parameters ! skip it ! + ok; + PLFDC -> + ParDecName = Name ++ "__dec", + emit(Fd, + " /* Decode parameters */\n" + " if((oe_error_code = ~s(oe_obj, ~s, oe_env)) < 0) {\n", + [ParDecName, PLFDC]), + emit_c_dec_rpt(Fd, " ", "parmeters", []), + emit(Fd, + " if(oe_env->_major == CORBA_NO_EXCEPTION)\n" + " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad parameter on decode\");\n" + " return oe_error_code;\n }\n\n") + end. + +%%------------------------------------------------------------ +%% Emit call-back +%%------------------------------------------------------------ + +emit_callback(G, Fd, N, X, Name, RetType, TypeAttrArgs) -> + CallBackName = Name ++ "__cb", + emit(Fd, " /* Callback function call */\n"), + PL = ic_util:mk_list(mk_cb_par_list(G, N, X, TypeAttrArgs)), + case ic_forms:is_oneway(X) of + true -> + case PL of + "" -> + emit(Fd, " oe_restore = ~s(oe_obj, oe_env);\n\n", + [CallBackName]); + _ -> + emit(Fd, " oe_restore = ~s(oe_obj, ~s, oe_env);\n\n", + [CallBackName, PL]) + end; + false -> + CBPL = case PL of + "" -> + ""; + _PL -> + ", " ++ PL + end, + case mk_c_ret_type(G, N, RetType) of + "void" -> + case PL of + "" -> + emit(Fd, " oe_restore = ~s(oe_obj, oe_env);" + "\n\n", [CallBackName]); + _ -> + emit(Fd, " oe_restore = ~s(oe_obj, ~s, oe_env);" + "\n\n", [CallBackName, PL]) + end; + _ -> + case ictype:isArray(G, N, RetType) of + true -> + emit(Fd, + " oe_restore = ~s(oe_obj, oe_return~s, " + " oe_env);\n\n", [CallBackName, CBPL]); + false -> + emit(Fd, " oe_restore = ~s(oe_obj, " + "&oe_return~s, oe_env);\n\n", + [CallBackName, CBPL]) + end + end + end. + +%%------------------------------------------------------------ +%% Emit restore +%%------------------------------------------------------------ + +emit_restore(G, Fd, N, X, _Name, RetType, TypeAttrArgs) -> + emit(Fd, " /* Restore function call */\n"), + emit(Fd, " if (oe_restore != NULL)\n"), + PL = ic_util:mk_list(mk_cb_par_list(G, N, X, TypeAttrArgs)), + case ic_forms:is_oneway(X) of + true -> + case PL of + "" -> + emit(Fd, " (*oe_restore)(oe_obj, oe_env);\n\n"); + _ -> + emit(Fd, " (*oe_restore)(oe_obj, ~s, oe_env);\n\n", + [PL]) + end; + false -> + RPL = case PL of + "" -> + ""; + _PL -> + ", " ++ PL + end, + case mk_c_ret_type(G, N, RetType) of + "void" -> + case PL of + "" -> + emit(Fd, " (*oe_restore)(oe_obj, oe_env);" + "\n\n"); + _ -> + emit(Fd, " (*oe_restore)(oe_obj, ~s, oe_env);" + "\n\n", [PL]) + end; + _ -> + case ictype:isArray(G, N, RetType) of + true -> + emit(Fd, + " (*oe_restore)(oe_obj, oe_return~s, " + " oe_env);\n\n", [RPL]); + false -> + emit(Fd, " (*oe_restore)(oe_obj, " + "&oe_return~s, oe_env);\n\n", [RPL]) + end + end + end. + +%%------------------------------------------------------------ +%% Emit variable defs +%%------------------------------------------------------------ + +emit_variable_defs(G, Fd, N, X, _Name, RetType, TypeAttrArgs) -> + {ScopedName, _, _} = ic_cbe:extract_info(G, N, X), + emit(Fd, " ~s__rs* oe_restore = NULL;\n", [ScopedName]), + RestVars = mk_var_list(mk_var_decl_list(G, N, X, TypeAttrArgs)), + case ic_forms:is_oneway(X) of + true -> + emit(Fd, "~s\n\n", [RestVars]); + false -> + RType = mk_c_ret_type(G, N, RetType), + case RType of + "void" -> + emit(Fd, "~s\n\n", [RestVars]); + "CORBA_unsigned_long" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_unsigned_long_long" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_unsigned_short" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_short" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_long" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_long_long" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_float" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_double" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_char" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_wchar" -> %% WCHAR + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_boolean" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + "CORBA_octet" -> + emit(Fd, "~s ~s oe_return = 0;\n\n", [RestVars, RType]); + _ -> + case ic_cbe:is_variable_size(G, N, RetType) of + true -> + emit(Fd, "~s ~s oe_return;\n\n", + [RestVars, RType]); + false -> + TK = ic_forms:get_tk(X), + case TK of + {tk_enum, _, _, _List} -> + emit(Fd, "~s ~s oe_return;\n\n", + [RestVars, RType]); + _ -> + case RType of + "erlang_binary*" -> + emit(Fd, "~s erlang_binary " + "oe_return;\n\n", [RestVars]); + "erlang_pid*" -> + emit(Fd, "~s erlang_pid " + "oe_return;\n\n", [RestVars]); + "erlang_port*" -> + emit(Fd, "~s erlang_port " + "oe_return;\n\n", [RestVars]); + "erlang_ref*" -> + emit(Fd, "~s erlang_ref " + "oe_return;\n\n", [RestVars]); + _ -> + %% Structures are + %% initiated by memset + emit(Fd, "~s ~s " + "oe_return;\n\n", + [RestVars, RType]) + end, + emit(Fd, " memset(&oe_return, 0, " + "sizeof(oe_return));\n\n") + end + end + end + end. + +%%------------------------------------------------------------ +%% Make variable list +%%------------------------------------------------------------ + +%% XXX Modify +mk_var_list([]) -> + ""; +mk_var_list([Arg| Args]) -> + " " ++ Arg ++ ";\n" ++ mk_var_list(Args). + +%%------------------------------------------------------------ +%% Make return type +%%------------------------------------------------------------ + +mk_c_ret_type(G, N, Type) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "*"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "*"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end; + false -> + if + Ctype == "erlang_pid" -> + "*"; + Ctype == "erlang_port" -> + "*"; + Ctype == "erlang_ref" -> + "*"; + true -> + "" + end + end, + Ctype ++ Dyn. + +%%------------------------------------------------------------ +%% Make call-back parameter list +%%------------------------------------------------------------ + +mk_cb_par_list(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in, out], TypeAttrArgs0), + lists:map( + fun({Type, Attr, Arg}) -> + case ic_cbe:is_variable_size(G, N, Type) of + true -> + case Attr of + in -> + Arg; + out -> + case ictype:isArray(G, N, Type) of + true -> + Arg; + _ -> + "&" ++ Arg + end + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + Arg; + _ -> + "&" ++ Arg + end + end + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make decoder parameter list +%%------------------------------------------------------------ + +mk_dec_par_list(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in], + TypeAttrArgs0), + lists:map( + fun({Type, _Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "&" ++ Arg; + Ctype == "CORBA_char *" -> + Arg; + is_record(Type, wstring) -> + "&" ++ Arg; + Ctype == "CORBA_wchar *" -> + Arg; + true -> + "&" ++ Arg + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + Arg; + _ -> + "&" ++ Arg + end + end + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make encoder parameter list +%%------------------------------------------------------------ + +mk_enc_par_list(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [out], + TypeAttrArgs0), + lists:map( + fun({Type, _Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + case Ctype of + "erlang_pid" -> + "&" ++ Arg; + "erlang_port" -> + "&" ++ Arg; + "erlang_ref" -> + "&" ++ Arg; + _ -> + Arg + end + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make type argument list +%%------------------------------------------------------------ + +mk_type_attr_arg_list(Types, Args) -> + filterzip( + fun(Type, {Attr, Arg}) -> + {true, {Type, Attr, Arg}} + end, Types, Args). + +%%------------------------------------------------------------ +%% Filter type argument list +%%------------------------------------------------------------ + +filter_type_attr_arg_list(G, X, InOrOut, TypeAttrArgs) -> + lists:filter( + + fun({_Type, inout, Arg}) -> + ic_error:error(G, {inout_spec_for_c, X, Arg}), + false; + ({_Type, Attr, _Arg}) -> + lists:member(Attr, InOrOut) + end, TypeAttrArgs). + +%%------------------------------------------------------------ +%% Make indirection operator +%%------------------------------------------------------------ + +mk_ind_op(in) -> + ""; +mk_ind_op(inout) -> + error; +mk_ind_op(_) -> + "*". + +%%------------------------------------------------------------ +%% Make parameter list for decoder +%%------------------------------------------------------------ + +mk_par_list_for_decoder(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in], TypeAttrArgs0), + lists:map( + fun({Type, Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "**"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "**"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + slice(Attr) ++ "*"; + _ -> + "**" + end + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end, + Ctype ++ Dyn ++ " " ++ Arg + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make parameter list for encoder +%%------------------------------------------------------------ + +mk_par_list_for_encoder(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [out], TypeAttrArgs0), + lists:map( + fun({Type, _Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "*"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "*"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end; + false -> + if + Ctype == "erlang_pid" -> + "*"; + Ctype == "erlang_port" -> + "*"; + Ctype == "erlang_ref" -> + "*"; + true -> + "" + end + end, + Ctype ++ " " ++ Dyn ++ Arg + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make parameter list for decoder prototypes +%%------------------------------------------------------------ + +mk_par_list_for_decoder_prototypes(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in], TypeAttrArgs0), + lists:map( + fun({Type, Attr, _Arg}) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "**"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "**"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + slice(Attr) ++ "*"; + _ -> + "**" + end + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end, + Ctype ++ Dyn + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make parameter list for encoder prototypes +%%------------------------------------------------------------ + +mk_par_list_for_encoder_prototypes(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [out], TypeAttrArgs0), + lists:map( + fun({Type, _Attr, _Arg}) -> + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "*"; + Ctype == "CORBA_char *" -> + ""; + is_record(Type, wstring) -> %% WSTRING + "*"; + Ctype == "CORBA_wchar *" -> %% WSTRING + ""; + true -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" + end + end; + false -> + if + Ctype == "erlang_pid" -> + "*"; + Ctype == "erlang_port" -> + "*"; + Ctype == "erlang_ref" -> + "*"; + true -> + "" + end + end, + Ctype ++ Dyn + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make parameter list for call-back prototypes +%%------------------------------------------------------------ + +mk_par_list_for_callback_prototypes(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in, out], + TypeAttrArgs0), + lists:map( + fun({Type, Attr, _Arg}) -> + IndOp = mk_ind_op(Attr), + Ctype = mk_c_type(G, N, Type), + Dyn = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + "*" ++ IndOp; + Ctype == "CORBA_char *" -> + "" ++ IndOp; + is_record(Type, wstring) -> %% WSTRING + "*" ++ IndOp; + Ctype == "CORBA_wchar *" -> %% WSTRING + "" ++ IndOp; + true -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + "*" ++ IndOp + end + end; + false -> + case ictype:isArray(G, N, Type) of + true -> + ""; + _ -> + case Attr of %% Should just be IndOp + in -> + "*" ++ IndOp; + out -> + IndOp + end + end + end, + Ctype ++ Dyn + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Make variable declaration list +%%------------------------------------------------------------ + +mk_var_decl_list(G, N, X, TypeAttrArgs0) -> + TypeAttrArgs1 = filter_type_attr_arg_list(G, X, [in, out], + TypeAttrArgs0), + lists:map( + fun({Type, Attr, Arg}) -> + Ctype = mk_c_type(G, N, Type), + VarDecl = case ic_cbe:is_variable_size(G, N, Type) of + true -> + if + is_record(Type, string) -> + Ctype ++ "* " ++ Arg ++ " = NULL"; + Ctype == "CORBA_char *" -> + Ctype ++ " " ++ Arg ++ " = NULL"; + is_record(Type, wstring) -> %% WSTRING + Ctype ++ "* " ++ Arg ++ " = NULL"; + Ctype == "CORBA_wchar *" -> %% WSTRING + Ctype ++ " " ++ Arg ++ " = NULL"; + true -> + case ictype:isArray(G, N, Type) of + true -> + Ctype ++ slice(Attr) ++ " " ++ + Arg; + _ -> + Ctype ++ "* " ++ Arg + end + end; + false -> + Ctype ++ " " ++ Arg + end, + + VarDecl + end, TypeAttrArgs1). + +%%------------------------------------------------------------ +%% Slice +%%------------------------------------------------------------ + +slice(in) -> + "_slice*"; +slice(_) -> + "". + +%%------------------------------------------------------------ +%% Special comment functions +%%------------------------------------------------------------ + +emit_encoding_comment(G, N, F, String, RefOrVal, Type, Name) -> + emit(F, [io_lib:format(" /* ~s parameter: ~s~s ~s */\n", + [String, mk_c_type(G, N, Type), + RefOrVal, Name])]). + + +%%------------------------------------------------------------ +%% Make C type +%%------------------------------------------------------------ + +%% +%% Warning this is NOT identical to mk_c_type in ic_cbe.erl +%% +mk_c_type(G, N, S) -> + mk_c_type(G, N, S, evaluate). + +mk_c_type(G, N, S, evaluate) when element(1, S) == scoped_id -> + {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)), + case BT of + "erlang_binary" -> + "erlang_binary"; + "erlang_pid" -> + "erlang_pid"; + "erlang_port" -> + "erlang_port"; + "erlang_ref" -> + "erlang_ref"; + "erlang_term" -> + "ETERM*"; + {enum, Type} -> + mk_c_type(G, N, Type, evaluate); + Type -> + mk_c_type(G, N, Type, evaluate) + end; +mk_c_type(G, N, S, evaluate_not) when element(1, S) == scoped_id -> + {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)), + case BT of + "erlang_binary" -> + "erlang_binary"; + "erlang_pid" -> + "erlang_pid"; + "erlang_port" -> + "erlang_port"; + "erlang_ref" -> + "erlang_ref"; + "erlang_term" -> + "ETERM*"; + Type -> + Type + end; +mk_c_type(_G, _N, S, _) when is_list(S) -> + S; +mk_c_type(_G, _N, S, _) when is_record(S, string) -> + "CORBA_char"; +mk_c_type(_G, _N, S, _) when is_record(S, wstring) -> %% WSTRING + "CORBA_wchar"; +mk_c_type(_G, _N, {boolean, _}, _) -> + "CORBA_boolean"; +mk_c_type(_G, _N, {octet, _}, _) -> + "CORBA_octet"; +mk_c_type(_G, _N, {void, _}, _) -> + "void"; +mk_c_type(_G, _N, {unsigned, U}, _) -> + case U of + {short, _} -> + "CORBA_unsigned_short"; + {long, _} -> + "CORBA_unsigned_long"; + {'long long', _} -> + "CORBA_unsigned_long_long" + end; +mk_c_type(_G, _N, {'long long', _}, _) -> + "CORBA_long_long"; +mk_c_type(_G, _N, {'any', _}, _) -> %% Fix for any type + "CORBA_long"; +mk_c_type(_G, _N, {T, _}, _) -> + "CORBA_" ++ atom_to_list(T). + +%%------------------------------------------------------------ +%% Emit encoding statement +%%------------------------------------------------------------ + +%% emit_encoding_stmt(G, N, X, Fd, T, LName) +%% +%% +emit_encoding_stmt(G, N, X, Fd, T, LName) when element(1, T) == scoped_id -> + case mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_pid(oe_env, ~s)) < 0) {\n", + [LName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_pid", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_port" -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_port(oe_env, ~s)) < 0) {\n", + [LName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_port", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_ref" -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ref(oe_env, ~s)) < 0) {\n", + [LName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_ref", []), + emit(Fd, " return oe_error_code;\n }\n"); + "ETERM*" -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_term(oe_env, ~s)) < 0) {\n", + [LName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_term", []), + emit(Fd, " return oe_error_code;\n }\n"); + {enum, FSN} -> + emit_encoding_stmt(G, N, X, Fd, FSN, LName); + FSN -> + emit_encoding_stmt(G, N, X, Fd, FSN, LName) + end; +emit_encoding_stmt(G, N, X, Fd, T, LName) when is_list(T) -> + %% Already a fullscoped name + case get_param_tk(LName, X) of + error -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), T, LName]); + ParamTK -> + case ic_cbe:is_variable_size(ParamTK) of + true -> + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, ~s)) < 0)" + " {\n", + [ic_util:mk_oe_name(G, "encode_"), T, LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");" + "\n"), + ?emit_c_enc_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n }\n\n"); + false -> + if is_atom(ParamTK) -> + case ParamTK of + tk_ushort -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulong(oe_env, " + "(unsigned long) ~s)) < 0) {\n", + [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "ushort", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_ulong -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulong(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "ulong", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_ulonglong -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulonglong(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "ulonglong", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_short -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, " + "(long) ~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "short", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_long -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "long", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_longlong -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_longlong(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "longlong", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_float -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_double(oe_env, " + "(double) ~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "float", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_double -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_double(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "double", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_boolean -> + emit(Fd, " switch(~s) {\n", [LName]), + emit(Fd, " case 0 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, " + "\"false\")) < 0) {\n"), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " return " + "oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " case 1 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, " + "\"true\")) < 0) {\n"), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " return " + "oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " default :\n"), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n\n"); + tk_char -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_char(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "char", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_wchar -> %% WCHAR + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_wchar(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "wchar", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_octet -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_char(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "octet", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + tk_any -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, " + "~s)) < 0) {\n", [LName]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "any", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"); + _ -> + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + ?emit_c_enc_rpt(Fd, " ", "tk_unknown", []), + emit(Fd, " return " + "oe_error_code;\n }\n\n"), + ok + end; + true -> + case element(1, ParamTK) of + tk_enum -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "enum", []); + tk_array -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "array", []); + _ -> + emit(Fd, " if ((oe_error_code = " + "~s~s(oe_env, &~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "encode_"), + T, LName]), + ?emit_c_enc_rpt(Fd, " ", "", []) + end, + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation " + "parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n") + end + end + end; +emit_encoding_stmt(G, N, _X, Fd, T, LName) when is_record(T, string) -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_string(oe_env, (const char*) ~s)) < 0) {\n", + [LName]), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Cannot encode string\");\n"), + ?emit_c_enc_rpt(Fd, " ", "string", []), + emit(Fd, " return oe_error_code;\n }\n\n"); +emit_encoding_stmt(G, N, _X, Fd, T, LName) when is_record(T, wstring) -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_wstring(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "wstring", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Cannot encode string\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); +emit_encoding_stmt(G, N, _X, Fd, T, LName) -> + case T of + {unsigned, {short, _}} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulong(oe_env, (unsigned long) ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "ushort", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {unsigned, {long, _}} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulong(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "ulong", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {unsigned, {'long long', _}} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_ulonglong(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "ulonglong", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {short, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, (long) ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "short", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {long, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "long", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {'long long', _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_longlong(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "longlong", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {float, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_double(oe_env, (double) ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "float", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {double, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_double(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "double", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {boolean, _} -> + emit(Fd, " switch(~s) {\n", [LName]), + emit(Fd, " case 0 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, \"false\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " case 1 :\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, \"true\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " default :\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n\n"); + {char, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_char(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "char", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {wchar, _} -> %% WCHAR + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_wchar(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "wchar", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {octet, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_char(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "octet", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {void, _} -> + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, \"void\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "void", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {sequence, _, _} -> + ?emit_c_enc_rpt(Fd, " ", "sequence", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + {any, _} -> %% Fix for any type + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_long(oe_env, ~s)) < 0) {\n", + [LName]), + ?emit_c_enc_rpt(Fd, " ", "any", []), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "BAD_PARAM, \"Bad operation parameter on encode\");\n"), + emit(Fd, " return oe_error_code;\n }\n\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end. + +%%------------------------------------------------------------ +%% Get type kind parameter +%%------------------------------------------------------------ + +%% Useful functions +get_param_tk("oe_return", Op) -> + ic_forms:get_tk(Op); +get_param_tk(Name, Op) -> + case get_param(Name, Op) of + error -> + error; + Param -> + ic_forms:get_tk(Param) + end. + +%%------------------------------------------------------------ +%% Get parameter (for what? XXX) +%%------------------------------------------------------------ + +get_param(Name, Op) when is_record(Op, op) -> + get_param_loop(Name, Op#op.params); +get_param(_Name, _Op) -> + error. + +get_param_loop(_Name, []) -> + error; +get_param_loop(Name, [Param| Params]) -> + case ic_forms:get_id2(Param) of + Name -> + Param; + _ -> + get_param_loop(Name, Params) + end. + +%%------------------------------------------------------------ +%% Emit decoding statement +%%------------------------------------------------------------ + +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, Align, NextPos, + DecType, AllocedPars) when element(1, T) == scoped_id -> + case mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + emit(Fd, " if ((oe_error_code = ei_decode_pid(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n\n"); + "erlang_port" -> + emit(Fd, " if ((oe_error_code = ei_decode_port(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n\n"); + "erlang_ref" -> + emit(Fd, " if ((oe_error_code = ei_decode_ref(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n\n"); + "ETERM*" -> + emit(Fd, " if ((oe_error_code = ei_decode_term(~s, " + "&oe_env->_iin, (void**)~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n\n"); + {enum, FSN} -> + emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp, + InBuffer, Align, NextPos, DecType, AllocedPars); + FSN -> + emit_decoding_stmt(G, N, Fd, FSN, LName, IndOp, + InBuffer, Align, NextPos, DecType, AllocedPars) + end; +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, NextPos, + DecType, AllocedPars) when is_list(T) -> + %% Already a fullscoped name + Type = ictype:name2type(G, T), + case ictype:isBasicType(Type) of + true -> + emit_decoding_stmt_for_basic_type(Fd, Type, InBuffer, IndOp, + LName, AllocedPars); + false -> + emit(Fd, " {\n"), + case DecType of + caller -> %% No malloc used, define oe_first anyhow. + emit(Fd, " void *oe_first = NULL;\n"), + emit(Fd, " int oe_outindex = 0;\n\n"); + array_dyn -> %% Malloc used + emit(Fd, " int oe_outindex = 0;\n\n"); + %% [ic_util:mk_align(io_lib:format("sizeof(~s)", [T]))]); + caller_dyn -> %% Malloc used + emit(Fd, " int oe_outindex = 0;\n\n") + end, + emit(Fd, " if ((oe_error_code = ~s~s(oe_env, oe_first, " + "~s, ~s)) < 0) {\n", + [ic_util:mk_oe_name(G, "decode_"), + T, NextPos, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n") + end; +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos, + _DecType, AllocedPars) when is_record(T, string) -> + emit(Fd, " if ((oe_error_code = ei_decode_string(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"); +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos, + _DecType, AllocedPars) when is_record(T, wstring) -> + %% WSTRING + emit(Fd, " if ((oe_error_code = " + "oe_ei_decode_wstring(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n\n"), + emit(Fd, " }\n"); +emit_decoding_stmt(G, N, Fd, T, LName, IndOp, InBuffer, _Align, _NextPos, + _DecType, AllocedPars) -> + case ic_cbe:normalize_type(T) of + {basic, Type} -> + emit_decoding_stmt_for_basic_type(Fd, Type, InBuffer, IndOp, + LName, AllocedPars); + _ -> + case T of + {void, _} -> + emit(Fd, + " if ((oe_error_code = ei_decode_atom(~s, " + "&oe_env->_iin, 0)) < 0) {\n", + [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"); + {sequence, _, _} -> + %% XXX XXX Why? + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n\n"); + {any, _} -> %% Fix for any type + emit(Fd, + " if ((oe_error_code = ei_decode_long(~s, " + "&oe_env->_iin, ~s~s)) < 0) {\n", + [InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + ?emit_c_dec_rpt(Fd, " ", "", []), + emit(Fd, " return oe_error_code;\n\n"), + emit(Fd, " }\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end + end. + +emit_decoding_stmt_for_basic_type(Fd, Type, InBuffer, IndOp, + LName, AllocedPars) -> + Fmt = + " if ((oe_error_code = ~sei_decode_~s(~s, &oe_env->_iin, " + "~s~s)) < 0) {\n", + Ret = + " return oe_error_code;\n" + "}\n", + + {Pre, DecType} = + case Type of + ushort -> {"", "ulong"}; + ulong -> {"", "ulong"}; + ulonglong -> {"oe_", "ulonglong"}; + short -> {"", "long"}; + long -> {"", "long"}; + longlong -> {"oe_", "longlong"}; + float -> {"", "double"}; + double -> {"", "double"}; + boolean -> {"", "atom"}; + char -> {"", "char"}; + wchar -> {"oe_", "wchar"}; + octet -> {"", "char"}; + any -> {"", "long"} + end, + case Type of + ushort -> + emit(Fd, " {\n"), + emit(Fd, " unsigned long oe_ulong;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_ulong(~s, " + "&oe_env->_iin, &oe_ulong)) < 0) {\n", [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "ushort", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " *~s = (unsigned short) oe_ulong;\n", [LName]), + emit(Fd, " }\n\n"); + short -> + emit(Fd, " {\n"), + emit(Fd, " long oe_long;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_long(~s, " + "&oe_env->_iin, &oe_long)) < 0) {\n", [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "short", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " *~s = (short) oe_long;\n", [LName]), + emit(Fd, " }\n\n"); + float -> + emit(Fd, " {\n"), + emit(Fd, " double oe_double;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_double(~s, " + "&oe_env->_iin, &oe_double)) < 0) {\n", [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "float", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " *~s = (float) oe_double;\n", [LName]), + emit(Fd, " }\n\n"); + boolean -> + emit(Fd, " {\n"), + emit(Fd, " char oe_bool[25];\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_atom(~s, " + "&oe_env->_iin, oe_bool)) < 0) {\n", [InBuffer]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "boolean", []), + emit(Fd, " return oe_error_code;\n"), + emit(Fd, " }\n"), + emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"), + emit(Fd, " *(~s) = 0;\n", [LName]), + emit(Fd, " }\n"), + emit(Fd, " else if (strcmp(oe_bool, \"true\") == 0) {\n"), + emit(Fd, " *(~s) = 1;\n", [LName]), + emit(Fd, " } else {\n"), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit_c_dec_rpt(Fd, " ", "boolean", []), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n"), + emit(Fd, " }\n\n"); + _ -> + emit(Fd, Fmt, [Pre, DecType, InBuffer, IndOp, LName]), + ic_cbe:emit_dealloc_stmts(Fd, " ", AllocedPars), + emit(Fd, Ret) + end. + + +%%------------------------------------------------------------ +%% Prefix for generic functions +%%------------------------------------------------------------ +get_user_proto(G, Default) -> + case ic_options:get_opt(G, user_protocol) of + false -> + Default; + Pfx -> + Pfx + end. + +%%------------------------------------------------------------ +%% Timeout. Returns a string (or Default). +%%------------------------------------------------------------ +get_c_timeout(G, Default) -> + case ic_options:get_opt(G, c_timeout) of + Tmo when is_integer(Tmo) -> + TmoStr = integer_to_list(Tmo), + {TmoStr, TmoStr}; + {SendTmo, RecvTmo} when is_integer(SendTmo) andalso is_integer(RecvTmo) -> + {integer_to_list(SendTmo), integer_to_list(RecvTmo)}; + false -> + Default + end. + +%%------------------------------------------------------------ +%% ZIPPERS (merging of successive elements of two lists). +%%------------------------------------------------------------ + +%% zip([H1| T1], [H2| T2]) -> +%% [{H1, H2}| zip(T1, T2)]; +%% zip([], []) -> +%% []. + +filterzip(F, [H1| T1], [H2| T2]) -> + case F(H1, H2) of + false -> + filterzip(F, T1, T2); + {true, Val} -> + [Val| filterzip(F, T1, T2)] + end; +filterzip(_, [], []) -> + []. + + diff --git a/lib/ic/src/ic_debug.hrl b/lib/ic/src/ic_debug.hrl new file mode 100644 index 0000000..c0490b4 --- /dev/null +++ b/lib/ic/src/ic_debug.hrl @@ -0,0 +1,37 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +%%---------------------------------------------------------------------- +%% Debug macro +%%---------------------------------------------------------------------- +-ifndef(ic_debug_hrl). +-define(ic_debug_hrl, true). + +-ifdef(debug). + -define(PRINTDEBUG(Msg), + io:format("~p :~p ~p~n", [Msg, ?FILE, ?LINE])). + -define(PRINTDEBUG2(F, A), + io:format(F ++ ":~p ~p~n", A ++ [?FILE, ?LINE])). +-else. + -define(PRINTDEBUG(Msg), ok). + -define(PRINTDEBUG2(F, A), ok). +-endif. + +-endif. diff --git a/lib/ic/src/ic_enum_java.erl b/lib/ic/src/ic_enum_java.erl new file mode 100644 index 0000000..5978c34 --- /dev/null +++ b/lib/ic/src/ic_enum_java.erl @@ -0,0 +1,312 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_enum_java). + +-include("icforms.hrl"). +-include("ic.hrl"). +-include("ic_debug.hrl"). +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([gen/3]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: gen/3 +%%----------------------------------------------------------------- +gen(G, N, X) when is_record(X, enum) -> + %%?PRINTDEBUG2("enum: ~p", [X]), + EnumName = ic_forms:get_java_id(X), + N2 = ["_" ++ EnumName |N], + ic_jbe:gen(G, N2, ic_forms:get_body(X)), + + emit_enum_class(G, N, X, EnumName), + emit_holder_class(G, N, X, EnumName), + emit_helper_class(G, N, X, EnumName); +gen(_G, _N, _X) -> + ok. + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: emit_enum_class/4 +%%----------------------------------------------------------------- +emit_enum_class(G, N, X, EnumName) -> + {Fd, _} = ic_file:open_java_file(G, N, EnumName), + + EList = enum_member_name_list(G, N, X), + %%?PRINTDEBUG2("EList: ~p", [EList]), + ic_codegen:emit(Fd, ["final public class ",EnumName," {\n\n" + + " // instance variables\n"]), + + emit_enum_member_int_values_initialization(G, N, X, Fd, EList), + emit_enum_public_instance_variables(G, N, X, Fd, EnumName, EList), + + ic_codegen:emit(Fd, [" private int _value;\n\n" + + " // constructors\n" + " private ",EnumName,"(int __value) {\n" + " _value = __value;\n" + " }\n\n" + + " // methods\n" + " public int value() {\n" + " return _value;\n" + " }\n"]), + + emit_enum_from_int_function(G, N, X, Fd, EnumName, EList), + + ic_codegen:emit(Fd, "\n}\n"), + file:close(Fd). + +%%----------------------------------------------------------------- +%% Func: emit_holder_class/4 +%%----------------------------------------------------------------- +emit_holder_class(G, N, _X, EnumName) -> + EName = string:concat(EnumName, "Holder"), + {Fd, _} = ic_file:open_java_file(G, N, EName), + + ic_codegen:emit(Fd, ["final public class ",EnumName,"Holder {\n\n" + + " // instance variables\n" + " public ",EnumName," value;\n\n" + + " // constructors\n" + " public ",EnumName,"Holder() {}\n\n" + + " public ",EnumName,"Holder(",EnumName," initial) {\n" + " value = initial;\n" + " }\n\n" + + " // methods\n" + " public void _marshal(",?ERLANGPACKAGE,"OtpOutputStream out) throws java.lang.Exception {\n" + " ",EnumName,"Helper.marshal(out, value);\n" + " }\n\n" + + " public void _unmarshal(",?ERLANGPACKAGE,"OtpInputStream in) throws java.lang.Exception {\n" + " value = ",EnumName,"Helper.unmarshal(in);\n" + " }\n\n" + "}\n"]), + file:close(Fd). + + +%%----------------------------------------------------------------- +%% Func: emit_helper_class/4 +%%----------------------------------------------------------------- +emit_helper_class(G, N, X, EnumName) -> + EName = string:concat(EnumName, "Helper"), + WEList = enum_member_atom_list(G, N, X), + {Fd, _} = ic_file:open_java_file(G, N, EName), + + ic_codegen:emit(Fd, ["public class ",EnumName,"Helper {\n\n" + + " // constructors\n" + " private ",EnumName,"Helper() {}\n\n" + + " // methods\n" + + " public static void marshal(",?ERLANGPACKAGE,"OtpOutputStream _out, ",EnumName," _value)\n" + " throws java.lang.Exception {\n\n"]), + + emit_enum_write_function(G, N, X, Fd, EnumName), + + ic_codegen:emit(Fd, [" }\n\n" + + " public static ",EnumName," unmarshal(",?ERLANGPACKAGE,"OtpInputStream _in)\n" + " throws java.lang.Exception {\n\n"]), + + emit_enum_read_function(G, N, X, Fd, EnumName), + + ic_codegen:emit(Fd, "\n }\n\n"), + + emit_enum_private_member_variables(Fd, WEList), + + ic_codegen:emit(Fd, ["\n // Get integer value of enum from string\n" + " private static int _getIntFromName(String name) throws java.lang.Exception {\n" + " for(int i = 0; i < _memberCount; i++) {\n" + " if (name.equals(_members[i]))\n" + " return i;\n" + " }\n" + " throw new java.lang.Exception(\"\");\n" + " }\n\n" + + " public static String id() {\n" + " return \"",ictk:get_IR_ID(G, N, X),"\";\n" + " }\n\n" + + " public static String name() {\n" + " return \"",EnumName,"\";\n" + " }\n\n"]), + + ic_jbe:emit_type_function(G, N, X, Fd), + + ic_codegen:emit(Fd, [" public static void insert(",?ICPACKAGE,"Any _any, ",EnumName," _this)\n" + " throws java.lang.Exception {\n\n" + + " ",?ERLANGPACKAGE,"OtpOutputStream _os = \n" + " new ",?ERLANGPACKAGE,"OtpOutputStream();\n\n" + + " _any.type(type());\n" + " marshal(_os, _this);\n" + " _any.insert_Streamable(_os);\n" + " }\n\n" + + " public static ",EnumName," extract(",?ICPACKAGE,"Any _any)\n" + " throws java.lang.Exception {\n\n" + + " return unmarshal(_any.extract_Streamable());\n" + " }\n\n" + + "}\n"]), + file:close(Fd). + +%%----------------------------------------------------------------- +%% Func: emit_enum_public_instance_variables/6 +%%----------------------------------------------------------------- +emit_enum_public_instance_variables(_G, _N, _X, _Fd, _EnumName, []) -> + ok; +emit_enum_public_instance_variables(G, N, X, Fd, EnumName, [Enumerator |EList]) -> + ic_codegen:emit(Fd, [" public static final ",EnumName," ",Enumerator," = new ",EnumName,"(_",Enumerator,");\n"]), + emit_enum_public_instance_variables(G, N, X, Fd, EnumName, EList). + +%%----------------------------------------------------------------- +%% Func: emit_enum_member_int_values_initialization/5 +%%----------------------------------------------------------------- +emit_enum_member_int_values_initialization(G, N, X, Fd, EList) -> + InitString = emit_enum_member_int_values_initialization_1(G, N, X, Fd, EList, 0), + ic_codegen:emit(Fd, [" public static final int ",InitString,";\n"]). + + +%%----------------------------------------------------------------- +%% Func: emit_enum_member_int_values_initialization_1/6 +%%----------------------------------------------------------------- +emit_enum_member_int_values_initialization_1(_G, _N, _X, _Fd, [Enumerator], Num) -> + " _" ++ Enumerator ++ " = " ++ ic_util:to_list(Num); +emit_enum_member_int_values_initialization_1(G, N, X, Fd, [Enumerator |EList], Num) -> + Spaces = if + Num == 0 -> + ""; + true -> + " " + end, + Spaces ++ "_" ++ Enumerator ++ " = " ++ ic_util:to_list(Num) ++ ",\n" ++ + emit_enum_member_int_values_initialization_1(G, N, X, Fd, EList, Num + 1). + +%%----------------------------------------------------------------- +%% Func: emit_enum_from_int_function/6 +%%----------------------------------------------------------------- +emit_enum_from_int_function(_G, _N, _X, Fd, EnumName, EList) -> + ic_codegen:emit(Fd, + [" public static final ",EnumName," from_int(int __value) throws java.lang.Exception {\n" + " switch (__value) {\n"]), + emit_enum_from_int_function_switchbody(Fd, EList), + ic_codegen:emit(Fd, [" }\n" + " }\n"]). + +%%----------------------------------------------------------------- +%% Func: emit_enum_from_int_function_switchbody/2 +%%----------------------------------------------------------------- +emit_enum_from_int_function_switchbody(Fd, []) -> + ic_codegen:emit(Fd, [" default:\n" + " throw new java.lang.Exception(\"\");\n"]); +emit_enum_from_int_function_switchbody(Fd, [Enumerator |EList]) -> + ic_codegen:emit(Fd, [" case _",Enumerator,":\n" + " return ",Enumerator,";\n"]), + emit_enum_from_int_function_switchbody(Fd, EList). + +%%----------------------------------------------------------------- +%% Func: emit_enum_private_member_variables/2 +%%----------------------------------------------------------------- +emit_enum_private_member_variables(Fd, EList) -> + ic_codegen:emit(Fd, [" private static final int _memberCount = ",integer_to_list(length(EList)),";\n" + " private static String[] _members = {\n"]), + emit_enum_private_member_variables_1(Fd, EList), + ic_codegen:emit(Fd, " };\n"). + +%%----------------------------------------------------------------- +%% Func: emit_enum_private_member_variables_1/2 +%%----------------------------------------------------------------- +emit_enum_private_member_variables_1(Fd, [Enumerator]) -> + ic_codegen:emit(Fd, [" \"",Enumerator,"\"\n"]); +emit_enum_private_member_variables_1(Fd, [Enumerator |EList]) -> + ic_codegen:emit(Fd, [" \"",Enumerator,"\",\n"]), + emit_enum_private_member_variables_1(Fd, EList). + +%%----------------------------------------------------------------- +%% Func: emit_enum_read_function/5 +%%----------------------------------------------------------------- +emit_enum_read_function(_G, _N, _X, Fd, EnumName) -> + ic_codegen:emit(Fd, [" return ",EnumName,".from_int(_getIntFromName(_in.read_atom()));"]). + +%%----------------------------------------------------------------- +%% Func: emit_enum_write_function/5 +%%----------------------------------------------------------------- +emit_enum_write_function(_G, _N, _X, Fd, _EnumName) -> + ic_codegen:emit(Fd, " _out.write_atom(_members[_value.value()]);\n"). + + +%%----------------------------------------------------------------- +%% Func: enum_member_name_list/3 +%% +%% Note: The names generated are checked for name coalition +%% with java keywords. If so the name is always prefixed +%% by "_" +%%----------------------------------------------------------------- +enum_member_name_list(_G, _N, X) -> + lists:map( + fun(Enumerator) -> + ic_forms:get_java_id(Enumerator) + end, + ic_forms:get_body(X)). + +%%----------------------------------------------------------------- +%% Func: enum_member_atom_list/3 +%% +%% Note : Similar to the emit_member_list/3 but does not +%% solves name coalitions with java keywords. +%% Used for wire encoding only +%%----------------------------------------------------------------- +enum_member_atom_list(_G, _N, X) -> + lists:map( + fun(Enumerator) -> + ic_forms:get_id2(Enumerator) + end, + ic_forms:get_body(X)). + + + + + + + + diff --git a/lib/ic/src/ic_erl_template.erl b/lib/ic/src/ic_erl_template.erl new file mode 100644 index 0000000..f5983a5 --- /dev/null +++ b/lib/ic/src/ic_erl_template.erl @@ -0,0 +1,639 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_erl_template). + + +-export([do_gen/3, emit_header/3]). + +-import(ic_codegen, [emit/2, emit/3, nl/1]). + +-include("icforms.hrl"). +-include("ic.hrl"). + +-include_lib("stdlib/include/erl_compile.hrl"). + +-define(TAB, " "). +-define(TAB2, "% "). + +-define(TEMPLATE_1_A, + "%%----------------------------------------------------------------------\n" + "%% \n" + "%% \n" + "%% $Id$\n" + "%%\n" + "%%----------------------------------------------------------------------\n" + "%% Module : ~s.erl\n" + "%% \n" + "%% Source : ~s\n" + "%% \n" + "%% Description : \n" + "%% \n" + "%% Creation date: ~s\n" + "%%\n" + "%%----------------------------------------------------------------------\n" + "-module(~p).\n\n"). + +-define(TEMPLATE_1_B, + "%%----------------------------------------------------------------------\n" + "%% Internal Exports\n" + "%%----------------------------------------------------------------------\n" + "-export([init/1,\n" + " terminate/2,\n" + " code_change/3,\n" + " handle_info/2]).\n\n" + "%%----------------------------------------------------------------------\n" + "%% Include Files\n" + "%%----------------------------------------------------------------------\n" + "\n\n" + "%%----------------------------------------------------------------------\n" + "%% Macros\n" + "%%----------------------------------------------------------------------\n" + "\n\n" + "%%----------------------------------------------------------------------\n" + "%% Records\n" + "%%----------------------------------------------------------------------\n" + "-record(state, {}).\n\n" + "%%======================================================================\n" + "%% API Functions\n" + "%%======================================================================\n"). + +-define(TEMPLATE_1_C, + "%%======================================================================\n" + "%% Internal Functions\n" + "%%======================================================================\n" + "%%----------------------------------------------------------------------\n" + "%% Function : init/1\n" + "%% Arguments : Env = term()\n" + "%% Returns : {ok, State} |\n" + "%% {ok, State, Timeout} |\n" + "%% ignore |\n" + "%% {stop, Reason}\n" + "%% Raises : -\n" + "%% Description: Initiates the server\n" + "%%----------------------------------------------------------------------\n" + "init(_Env) ->\n" + "\t{ok, #state{}}.\n\n\n" + "%%----------------------------------------------------------------------\n" + "%% Function : terminate/2\n" + "%% Arguments : Reason = normal | shutdown | term()\n" + "%% State = term()\n" + "%% Returns : ok\n" + "%% Raises : -\n" + "%% Description: Invoked when the object is terminating.\n" + "%%----------------------------------------------------------------------\n" + "terminate(_Reason, _State) ->\n" + "\tok.\n\n\n" + "%%----------------------------------------------------------------------\n" + "%% Function : code_change/3\n" + "%% Arguments : OldVsn = undefined | term()\n" + "%% State = NewState = term()\n" + "%% Extra = term()\n" + "%% Returns : {ok, NewState}\n" + "%% Raises : -\n" + "%% Description: Invoked when the object should update its internal state\n" + "%% due to code replacement.\n" + "%%----------------------------------------------------------------------\n" + "code_change(_OldVsn, State, _Extra) ->\n" + "\t{ok, State}.\n\n\n" + "%%----------------------------------------------------------------------\n" + "%% Function : handle_info/2\n" + "%% Arguments : Info = normal | shutdown | term()\n" + "%% State = NewState = term()\n" + "%% Returns : {noreply, NewState} |\n" + "%% {noreply, NewState, Timeout} |\n" + "%% {stop, Reason, NewState}\n" + "%% Raises : -\n" + "%% Description: Invoked when, for example, the server traps exits.\n" + "%%----------------------------------------------------------------------\n" + "handle_info(_Info, State) ->\n" + "\t{noreply, State}.\n\n\n"). + +-define(TEMPLATE_2_A, + "%%% #0. BASIC INFORMATION\n" + "%%% ----------------------------------------------------------------------\n" + "%%% %CCaseFile : ~s.erl %\n" + "%%% Author : \n" + "%%% Description : \n" + "%%%\n" + "%%% Modules used: \n" + "%%%\n" + "%%%\n" + "%%% ----------------------------------------------------------------------\n" + "-module(~p).\n" + "-author('unknown').\n" + "-id('').\n" + "-vsn('').\n" + "-date('~s').\n\n" + "%%% ----------------------------------------------------------------------\n" + "%%% Template Id: \n" + "%%%\n" + "%%% #Copyright (C) 2004\n" + "%%% by \n" + "%%%

\n" + "%%% \n" + "%%% \n" + "%%% \n" + "%%% \n" + "%%% \n" + "%%% ----------------------------------------------------------------------\n" + "%%% #1. REVISION LOG\n" + "%%% ----------------------------------------------------------------------\n" + "%%% Rev Date Name What\n" + "%%% ----- ------- -------- --------------------------\n" + "%%% \n" + "%%% ----------------------------------------------------------------------\n" + "%%%\n" + "%%% \n" + "%%% #2. EXPORT LISTS\n" + "%%% ----------------------------------------------------------------------\n" + "%%% #2.1 EXPORTED INTERFACE FUNCTIONS\n" + "%%% ----------------------------------------------------------------------\n"). + +-define(TEMPLATE_2_B, + "%%% ----------------------------------------------------------------------\n" + "%%% #2.2 EXPORTED INTERNAL FUNCTIONS\n" + "%%% ----------------------------------------------------------------------\n" + "-export([init/1,\n" + " terminate/2,\n" + " code_change/3,\n" + " handle_info/2]).\n\n" + "%%% ----------------------------------------------------------------------\n" + "%%% #2.3 INCLUDE FILES\n" + "%%% ----------------------------------------------------------------------\n" + "\n\n" + "%%% ----------------------------------------------------------------------\n" + "%%% #2.4 MACROS\n" + "%%% ----------------------------------------------------------------------\n" + "\n\n" + "%%% ----------------------------------------------------------------------\n" + "%%% #2.5 RECORDS\n" + "%%% ----------------------------------------------------------------------\n" + "-record(state, {}).\n\n" + "%%% ----------------------------------------------------------------------\n" + "%%% #3. CODE\n" + "%%% #---------------------------------------------------------------------\n" + "%%% #3.1 CODE FOR EXPORTED INTERFACE FUNCTIONS\n" + "%%% #---------------------------------------------------------------------\n"). + +-define(TEMPLATE_2_C, + "%%% ----------------------------------------------------------------------\n" + "%%% #3.3 CODE FOR INTERNAL FUNCTIONS\n" + "%%% ----------------------------------------------------------------------\n" + "%%% ----------------------------------------------------------------------\n" + "%%% # init/1\n" + "%%% Input : Env = term()\n" + "%%% Output : {ok, State} |\n" + "%%% {ok, State, Timeout} |\n" + "%%% ignore |\n" + "%%% {stop, Reason}\n" + "%%% Exceptions : -\n" + "%%% Description: Initiates the server\n" + "%%% ----------------------------------------------------------------------\n" + "init(_Env) ->\n" + "\t{ok, #state{}}.\n\n\n" + "%%% ----------------------------------------------------------------------\n" + "%%% # terminate/2\n" + "%%% Input : Reason = normal | shutdown | term()\n" + "%%% State = term()\n" + "%%% Output : ok\n" + "%%% Exceptions : -\n" + "%%% Description: Invoked when the object is terminating.\n" + "%%% ----------------------------------------------------------------------\n" + "terminate(_Reason, _State) ->\n" + "\tok.\n\n\n" + "%%% ----------------------------------------------------------------------\n" + "%%% # code_change/3\n" + "%%% Input : OldVsn = undefined | term()\n" + "%%% State = NewState = term()\n" + "%%% Extra = term()\n" + "%%% Output : {ok, NewState}\n" + "%%% Exceptions : -\n" + "%%% Description: Invoked when the object should update its internal state\n" + "%%% due to code replacement.\n" + "%%% ----------------------------------------------------------------------\n" + "code_change(_OldVsn, State, _Extra) ->\n" + "\t{ok, State}.\n\n\n" + "%%% ----------------------------------------------------------------------\n" + "%%% # handle_info/2\n" + "%%% Input : Info = normal | shutdown | term()\n" + "%%% State = NewState = term()\n" + "%%% Output : {noreply, NewState} |\n" + "%%% {noreply, NewState, Timeout} |\n" + "%%% {stop, Reason, NewState}\n" + "%%% Exceptions : -\n" + "%%% Description: Invoked when, for example, the server traps exits.\n" + "%%% ----------------------------------------------------------------------\n" + "handle_info(_Info, State) ->\n" + "\t{noreply, State}.\n\n\n" + "%%% ----------------------------------------------------------------------\n" + "%%% #4 CODE FOR TEMPORARY CORRECTIONS\n" + "%%% ----------------------------------------------------------------------\n\n"). + + +%%------------------------------------------------------------ +%% +%% Generate the client side Erlang stubs. +%% +%% Each module is generated to a separate file. +%% +%% Export declarations for all interface functions must be +%% generated. Each function then needs to generate a function head and +%% a body. IDL parameters must be converted into Erlang parameters +%% (variables, capitalised) and a type signature list must be +%% generated (for later encode/decode). +%% +%%------------------------------------------------------------ +do_gen(G, _File, Form) -> + gen_head(G, [], Form), + gen(G, [], Form). + + +gen(G, N, [X|Xs]) when is_record(X, preproc) -> + NewG = ic:handle_preproc(G, N, X#preproc.cat, X), + gen(NewG, N, Xs); +gen(G, N, [X|Xs]) when is_record(X, module) -> + G2 = ic_file:filename_push(G, N, X, erlang_template_no_gen), + N2 = [ic_forms:get_id2(X) | N], + gen_head(G2, N2, X), + gen(G2, N2, ic_forms:get_body(X)), + G3 = ic_file:filename_pop(G2, erlang_template_no_gen), + gen(G3, N, Xs); +gen(G, N, [X|Xs]) when is_record(X, interface) -> + G2 = ic_file:filename_push(G, N, X, erlang_template), + N2 = [ic_forms:get_id2(X) | N], + gen_head(G2, N2, X), + gen(G2, N2, ic_forms:get_body(X)), + lists:foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end, + X#interface.inherit_body), + Fd = ic_genobj:stubfiled(G2), + case get_template_version(G2) of + ?IC_FLAG_TEMPLATE_2 -> + emit(Fd, ?TEMPLATE_2_C, []); + _ -> + emit(Fd, ?TEMPLATE_1_C, []) + end, + G3 = ic_file:filename_pop(G2, erlang_template), + gen(G3, N, Xs); +gen(G, N, [X|Xs]) when is_record(X, op) -> + {Name, InArgNames, OutArgNames, Reply} = extract_info(X), + emit_function(G, N, X, ic_genobj:is_stubfile_open(G), + ic_forms:is_oneway(X), Name, InArgNames, OutArgNames, Reply), + gen(G, N, Xs); +gen(G, N, [X|Xs]) when is_record(X, attr) -> + emit_attr(G, N, X, ic_genobj:is_stubfile_open(G), fun emit_function/9), + gen(G, N, Xs); +gen(G, N, [_X|Xs]) -> + gen(G, N, Xs); +gen(_G, _N, []) -> + ok. + +%% Module Header +emit_header(G, Fd, Name) -> + Date = get_date(), + case get_template_version(G) of + ?IC_FLAG_TEMPLATE_2 -> + emit(Fd, ?TEMPLATE_2_A, [Name, list_to_atom(Name), Date]); + _ -> + IDLFile = ic_genobj:idlfile(G), + emit(Fd, ?TEMPLATE_1_A, [Name, IDLFile, Date, list_to_atom(Name)]) + end. + + +emit_attr(G, N, X, Open, F) -> + XX = #id_of{type=X}, + lists:foreach(fun(Id) -> + X2 = XX#id_of{id=Id}, + IsOneWay = ic_forms:is_oneway(X2), + {Get, Set} = mk_attr_func_names(N, ic_forms:get_id(Id)), + F(G, N, X2, Open, IsOneWay, Get, [], [], + [{ic_util:mk_var(ic_forms:get_id(Id)), + ic_forms:get_tk(X)}]), + case X#attr.readonly of + {readonly, _} -> + ok; + _ -> + F(G, N, X2, Open, IsOneWay, Set, + [{ic_util:mk_var(ic_forms:get_id(Id)), + ic_forms:get_tk(X)}], [], ["ok"]) + end + end, ic_forms:get_idlist(X)). + + +%% The automaticly generated get and set operation names for an +%% attribute. +mk_attr_func_names(_Scope, Name) -> + {"_get_" ++ Name, "_set_" ++ Name}. + + +extract_info(X) when is_record(X, op) -> + Name = ic_forms:get_id2(X), + InArgs = ic:filter_params([in,inout], X#op.params), + OutArgs = ic:filter_params([out,inout], X#op.params), + Reply = case ic_forms:get_tk(X) of + tk_void -> + ["ok"]; + Type -> + [{"OE_Reply", Type}] + end, + InArgsTypeList = + [{ic_util:mk_var(ic_forms:get_id(InArg#param.id)), + ic_forms:get_tk(InArg)} || InArg <- InArgs ], + OutArgsTypeList = + [{ic_util:mk_var(ic_forms:get_id(OutArg#param.id)), + ic_forms:get_tk(OutArg)} || OutArg <- OutArgs ], + {Name, InArgsTypeList, OutArgsTypeList, Reply}. + +get_template_version(G) -> + case ic_options:get_opt(G, flags) of + Flags when is_integer(Flags) -> + case ?IC_FLAG_TEST(Flags, ?IC_FLAG_TEMPLATE_2) of + true -> + ?IC_FLAG_TEMPLATE_2; + false -> + ?IC_FLAG_TEMPLATE_1 + end; + _ -> + ?IC_FLAG_TEMPLATE_1 + end. + + +get_date() -> + {{Y,M,D}, _} = calendar:now_to_datetime(now()), + if + M < 10, D < 10 -> + lists:concat([Y, "-0", M, "-0",D]); + M < 10 -> + lists:concat([Y, "-0", M, "-", D]); + D < 10 -> + lists:concat([Y, "-", M, "-0", D]); + true -> + lists:concat([Y, "-", M, "-", D]) + end. + + +%%------------------------------------------------------------ +%% +%% Export stuff +%% +%% Gathering of all names that should be exported from a stub +%% file. +%% + + +gen_head_special(G, N, X) when is_record(X, interface) -> + Fd = ic_genobj:stubfiled(G), + lists:foreach(fun({_Name, Body}) -> + ic_codegen:export(Fd, exp_top(G, N, Body, [])) + end, X#interface.inherit_body), + nl(Fd), + ok; +gen_head_special(_G, _N, _X) -> + ok. + + +%% Generate all export declarations +gen_head(G, N, X) -> + case ic_genobj:is_stubfile_open(G) of + true -> + Fd = ic_genobj:stubfiled(G), + ic_codegen:export(Fd, exp_top(G, N, X, [])), + gen_head_special(G, N, X), + case get_template_version(G) of + ?IC_FLAG_TEMPLATE_2 -> + emit(Fd, ?TEMPLATE_2_B, []); + _ -> + emit(Fd, ?TEMPLATE_1_B, []) + end; + false -> + ok + end. + +exp_top(_G, _N, X, Acc) when element(1, X) == preproc -> + Acc; +exp_top(G, N, L, Acc) when is_list(L) -> + exp_list(G, N, L, Acc); +exp_top(G, N, M, Acc) when is_record(M, module) -> + exp_list(G, N, ic_forms:get_body(M), Acc); +exp_top(G, N, I, Acc) when is_record(I, interface) -> + exp_list(G, N, ic_forms:get_body(I), Acc); +exp_top(G, N, X, Acc) -> + exp3(G, N, X, Acc). + +exp3(G, N, Op, Acc) when is_record(Op, op) -> + FuncName = ic_forms:get_id(Op#op.id), + Arity = length(ic:filter_params([in, inout], Op#op.params)) + 1 + + count_extras(G, N, Op), + [{FuncName, Arity} | Acc]; +exp3(G, N, A, Acc) when is_record(A, attr) -> + Extra = count_extras(G, N, A), + lists:foldr(fun(Id, Acc2) -> + {Get, Set} = mk_attr_func_names([], ic_forms:get_id(Id)), + case A#attr.readonly of + {readonly, _} -> + [{Get, 1 + Extra} | Acc2]; + _ -> + [{Get, 1 + Extra}, {Set, 2 + Extra} | Acc2] + end + end, Acc, ic_forms:get_idlist(A)); +exp3(_G, _N, _X, Acc) -> + Acc. + +exp_list(G, N, L, OrigAcc) -> + lists:foldr(fun(X, Acc) -> + exp3(G, N, X, Acc) + end, OrigAcc, L). + +count_extras(G, N, Op) -> + case {use_this(G, N, Op), use_from(G, N, Op)} of + {[], []} -> + 0; + {[], _} -> + 1; + {_, []} -> + 1; + _ -> + 2 + end. + +%%------------------------------------------------------------ +%% +%% Emit stuff +%% +%% Low level generation primitives +%% + +emit_function(_G, _N, _X, false, _, _, _, _, _) -> + ok; +emit_function(G, N, X, true, false, Name, InArgs, OutArgs, Reply) -> + Fd = ic_genobj:stubfiled(G), + This = use_this(G, N, Name), + From = use_from(G, N, Name), + State = ["State"], + Vers = get_template_version(G), + case OutArgs of + [] -> + ReplyString = create_string(Reply), + emit_function_header(G, Fd, X, N, Name, create_extra(This, From, Vers), + InArgs, length(InArgs), OutArgs, Reply, + ReplyString, Vers), + emit(Fd, "~p(~s) ->\n\t{reply, ~s, State}.\n\n", + [ic_util:to_atom(Name), create_string(This ++ From ++ State ++ InArgs), + ReplyString]); + _ -> + ReplyString = "{" ++ create_string(Reply ++ OutArgs) ++ "}", + emit_function_header(G, Fd, X, N, Name, create_extra(This, From, Vers), + InArgs, length(InArgs), OutArgs, Reply, + ReplyString, Vers), + emit(Fd, "~p(~s) ->\n\t{reply, ~s, State}.\n\n", + [ic_util:to_atom(Name), create_string(This ++ From ++ State ++ InArgs), + ReplyString]) + end; +emit_function(G, N, X, true, true, Name, InArgs, _OutArgs, _Reply) -> + Fd = ic_genobj:stubfiled(G), + This = use_this(G, N, Name), + State = ["State"], + Vers = get_template_version(G), + emit_function_header(G, Fd, X, N, Name, create_extra(This, [], Vers), + InArgs, length(InArgs), "", "", "", Vers), + emit(Fd, "~p(~s) ->\n\t{noreply, State}.\n\n", + [ic_util:to_atom(Name), create_string(This ++ State ++ InArgs)]). + +create_string([]) -> + ""; +create_string([{Name, _Type}|T]) -> + Name ++ create_string2(T); +create_string([Name|T]) -> + Name ++ create_string2(T). + +create_string2([{Name, _Type}|T]) -> + ", " ++ Name ++ create_string2(T); +create_string2([Name|T]) -> + ", " ++ Name ++ create_string2(T); +create_string2([]) -> + "". + +create_extra([], [], _Vers) -> + {"State - term()", 1}; +create_extra([], _From, ?IC_FLAG_TEMPLATE_2) -> + {"OE_From - term()\n%%% " ++ ?TAB ++ "State - term()", 2}; +create_extra([], _From, _Vers) -> + {"OE_From - term()\n%% " ++ ?TAB ++ "State - term()", 2}; +create_extra(_This, [], ?IC_FLAG_TEMPLATE_2) -> + {"OE_This - #objref{} (i.e., self())\n%%% " ++ ?TAB ++ "State - term()", 2}; +create_extra(_This, [], _Vers) -> + {"OE_This - #objref{} (i.e., self())\n%% " ++ ?TAB ++ "State - term()", 2}; +create_extra(_This, _From, ?IC_FLAG_TEMPLATE_2) -> + {"OE_This - #objref{} (i.e., self())\n%%% " ++ ?TAB ++ + "OE_From - term()\n%%% " ++ ?TAB ++ "State - term()", 3}; +create_extra(_This, _From, _Vers) -> + {"OE_This - #objref{} (i.e., self())\n%% " ++ ?TAB ++ + "OE_From - term()\n%% " ++ ?TAB ++ "State - term()", 3}. + +use_this(G, N, OpName) -> + FullOp = ic_util:to_colon([OpName|N]), + FullIntf = ic_util:to_colon(N), + case {ic_options:get_opt(G, {this, FullIntf}), + ic_options:get_opt(G, {this, FullOp}), + ic_options:get_opt(G, {this, true})} of + {_, force_false, _} -> + []; + {force_false, false, _} -> + []; + {false, false, false} -> + []; + _ -> + ["OE_This"] + end. + +use_from(G, N, OpName) -> + FullOp = ic_util:to_colon([OpName|N]), + FullIntf = ic_util:to_colon(N), + case {ic_options:get_opt(G, {from, FullIntf}), + ic_options:get_opt(G, {from, FullOp}), + ic_options:get_opt(G, {from, true})} of + {_, force_false, _} -> + []; + {force_false, false, _} -> + []; + {false, false, false} -> + []; + _ -> + ["OE_From"] + end. + + +emit_function_header(G, Fd, X, N, Name, {Extra, ExtraNo}, InP, Arity, OutP, + Reply, ReplyString, ?IC_FLAG_TEMPLATE_2) -> + emit(Fd, + "%%% ----------------------------------------------------------------------\n" + "%%% # ~p/~p\n" + "%%% Input : ~s\n", + [ic_util:to_atom(Name), (ExtraNo+Arity), Extra]), + ic_code:type_expand_all(G, N, X, Fd, ?TAB2, InP), + case Reply of + ["ok"] -> + emit(Fd, "%%% Output : ReturnValue = ~s\n", [ReplyString]); + _ -> + emit(Fd, "%%% Output : ReturnValue = ~s\n", [ReplyString]), + ic_code:type_expand_all(G, N, X, Fd, "% ", Reply) + end, + ic_code:type_expand_all(G, N, X, Fd, ?TAB2, OutP), + emit(Fd, + "%%% Exceptions : ~s\n" + "%%% Description: \n" + "%%% ----------------------------------------------------------------------\n", + [get_raises(X, ?IC_FLAG_TEMPLATE_2)]); +emit_function_header(G, Fd, X, N, Name, {Extra, ExtraNo}, InP, Arity, OutP, + Reply, ReplyString, Vers) -> + emit(Fd, + "%%----------------------------------------------------------------------\n" + "%% Function : ~p/~p\n" + "%% Arguments : ~s\n", + [ic_util:to_atom(Name), (ExtraNo+Arity), Extra]), + ic_code:type_expand_all(G, N, X, Fd, ?TAB, InP), + case Reply of + ["ok"] -> + emit(Fd, "%% Returns : ReturnValue = ~s\n", [ReplyString]); + _ -> + emit(Fd, "%% Returns : ReturnValue = ~s\n", [ReplyString]), + ic_code:type_expand_all(G, N, X, Fd, " ", Reply) + end, + ic_code:type_expand_all(G, N, X, Fd, ?TAB, OutP), + emit(Fd, + "%% Raises : ~s\n" + "%% Description: \n" + "%%----------------------------------------------------------------------\n", + [get_raises(X, Vers)]). + +get_raises(#op{raises = []}, _Vers) -> + ""; +get_raises(#op{raises = ExcList}, Vers) -> + get_raises2(ExcList, [], Vers); +get_raises(_X, _Vers) -> + []. + +get_raises2([H], Acc, _Vers) -> + lists:flatten(lists:reverse([ic_util:to_colon(H)|Acc])); +get_raises2([H|T], Acc, ?IC_FLAG_TEMPLATE_2) -> + get_raises2(T, ["\n%%% ", ic_util:to_colon(H) |Acc], + ?IC_FLAG_TEMPLATE_2); +get_raises2([H|T], Acc, _Vers) -> + get_raises2(T, ["\n%% ", ic_util:to_colon(H) |Acc], _Vers). + diff --git a/lib/ic/src/ic_erlbe.erl b/lib/ic/src/ic_erlbe.erl new file mode 100644 index 0000000..75c8792 --- /dev/null +++ b/lib/ic/src/ic_erlbe.erl @@ -0,0 +1,1141 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_erlbe). + + +-export([do_gen/3]). +%%------------------------------------------------------------ +%% +%% Internal stuff +%% +%%------------------------------------------------------------ + +-export([unfold/1, mk_attr_func_names/2]). + + +-import(ic_util, [mk_name/2, mk_var/1, mk_oe_name/2, to_atom/1, to_list/1]). +-import(ic_forms, [get_id/1, get_id2/1, get_body/1, is_oneway/1]). +-import(ic_codegen, [emit/2, emit/3, nl/1]). +-import(ic_options, [get_opt/2]). + +-import(lists, [foreach/2, foldr/3, map/2]). + + +-include("icforms.hrl"). +-include("ic.hrl"). + +-include_lib("stdlib/include/erl_compile.hrl"). + + +%%------------------------------------------------------------ +%% +%% Generate the client side Erlang stubs. +%% +%% Each module is generated to a separate file. +%% +%% Export declarations for all interface functions must be +%% generated. Each function then needs to generate a function head and +%% a body. IDL parameters must be converted into Erlang parameters +%% (variables, capitalised) and a type signature list must be +%% generated (for later encode/decode). +%% +%%------------------------------------------------------------ +do_gen(G, File, Form) -> + GT = get_opt(G, be), + G2 = ic_file:filename_push(G, [], mk_oe_name(G, + ic_file:remove_ext(to_list(File))), + erlang), + Light = ic_options:get_opt(G, light_ifr), + R = if + GT == erl_corba, Light == false -> + case ic_genobj:is_stubfile_open(G2) of + true -> + emit(ic_genobj:stubfiled(G2), "-include_lib(\"~s/include/~s\").\n\n", + [?ORBNAME, ?IFRTYPESHRL]); + false -> ok + end, + gen_head(G2, [], Form), + ic_codegen:export(ic_genobj:stubfiled(G2), + [{ictk:register_name(G2), 0}, + {ictk:unregister_name(G2), 0}, + {oe_get_module,5}, + {oe_dependency,0}]), + R0= gen(G2, [], Form), + ictk:reg_gen(G2, [], Form), + ictk:unreg_gen(G2, [], Form), % "new" unreg_gen/3 + genDependency(G2), % creates code for dependency list + R0; + GT == erl_corba, Light == true -> + case ic_genobj:is_stubfile_open(G2) of + true -> + emit(ic_genobj:stubfiled(G2), "-include_lib(\"~s/include/~s\").\n\n", + [?ORBNAME, ?IFRTYPESHRL]); + false -> ok + end, + gen_head(G2, [], Form), + ic_codegen:export(ic_genobj:stubfiled(G2), + [{ictk:register_name(G2), 0}, + {ictk:register_name(G2), 1}, + {ictk:unregister_name(G2), 0}, + {ictk:unregister_name(G2), 1}]), + R0= gen(G2, [], Form), + ictk:reg_gen(G2, [], Form), + ictk:unreg_gen(G2, [], Form), % "new" unreg_gen/3 + R0; + true -> + gen_head(G2, [], Form), + gen(G2, [], Form) + end, + ic_file:filename_pop(G2, erlang), + R. + + +gen(G, N, [X|Xs]) when is_record(X, preproc) -> + NewG = ic:handle_preproc(G, N, X#preproc.cat, X), + gen(NewG, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, module) -> + CD = ic_code:codeDirective(G,X), + G2 = ic_file:filename_push(G, N, X, CD), + N2 = [get_id2(X) | N], + gen_head(G2, N2, X), + gen(G2, N2, get_body(X)), + G3 = ic_file:filename_pop(G2, CD), + gen(G3, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, interface) -> + G2 = ic_file:filename_push(G, N, X, erlang), + N2 = [get_id2(X) | N], + gen_head(G2, N2, X), + gen(G2, N2, get_body(X)), + foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end, + X#interface.inherit_body), + gen_serv(G2, N, X), + G3 = ic_file:filename_pop(G2, erlang), + gen(G3, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, const) -> +% N2 = [get_id2(X) | N], + emit_constant_func(G, X#const.id, X#const.val), + gen(G, N, Xs); %% N2 or N? + +gen(G, N, [X|Xs]) when is_record(X, op) -> + {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), + emit_stub_func(G, N, X, Name, ArgNames, TypeList, OutArgs, + is_oneway(X), get_opt(G, be)), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, attr) -> + emit_attr(G, N, X, fun emit_stub_func/9), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, except) -> + icstruct:except_gen(G, N, X, erlang), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) -> + case may_contain_structs(X) of + true -> icstruct:struct_gen(G, N, X, erlang); + false -> ok + end, + gen(G, N, Xs); + +gen(_G, _N, []) -> ok. + + +may_contain_structs(X) when is_record(X, typedef) -> true; +may_contain_structs(X) when is_record(X, struct) -> true; +may_contain_structs(X) when is_record(X, union) -> true; +may_contain_structs(_X) -> false. + + + +%%-------------------------------------------------------------------- +%% +%% Generate the server side (handle_call and handle_cast) +%% + +gen_serv(G, N, X) -> + case ic_genobj:is_stubfile_open(G) of + true -> + GT = get_opt(G, be), + gen_oe_is_a(G, N, X, GT), + N2 = [get_id2(X) | N], + gen_oe_tc(G, N2, X, GT), + + emit_serv_std(GT, G, N, X), + + gen_calls(G, N2, get_body(X)), + lists:foreach(fun({_Name, Body}) -> + gen_calls(G, N2, Body) end, + X#interface.inherit_body), + gen_end_of_call(GT, G), + + gen_casts(G, N2, get_body(X)), + lists:foreach(fun({_Name, Body}) -> + gen_casts(G, N2, Body) end, + X#interface.inherit_body), + gen_end_of_cast(GT, G), + emit_skel_footer(GT, G, N, X); % Note N instead of N2 + false -> + ok + end. + +gen_oe_is_a(G, N, X, erl_corba) when is_record(X, interface) -> + Fd = ic_genobj:stubfiled(G), + ic_codegen:mcomment(Fd, ["Inherited Interfaces"]), + emit(Fd, "oe_is_a(~p) -> true;\n", [ictk:get_IR_ID(G, N, X)]), + lists:foreach(fun(ScopedName) -> + emit(Fd, "oe_is_a(~p) -> true;\n", + [ic_pragma:scope2id(G, ScopedName)]) + end, X#interface.inherit), + emit(Fd, "oe_is_a(_) -> false.\n"), + nl(Fd), + ok; +gen_oe_is_a(_G, _N, _X, _BE) -> ok. + + +%% Generates the oe_tc function +gen_oe_tc(G, N, X, erl_corba) -> + Fd = ic_genobj:stubfiled(G), + ic_codegen:mcomment(Fd, ["Interface TypeCode"]), + LocalInterface = gen_oe_tc2(G, N, get_body(X), Fd, []), + CompleteInterface = + lists:foldl(fun({Name, Body}, FunAcc) -> + AName = ic_util:to_atom(ic_util:to_undersc(Name)), + gen_oe_tc3(G, AName, Body, Fd, FunAcc) + end, LocalInterface, X#interface.inherit_body), + emit(Fd, "oe_tc(_) -> undefined.\n"), + nl(Fd), + emit(Fd, "oe_get_interface() -> \n\t["), + emit_oe_get_interface(Fd, CompleteInterface), + nl(Fd), + ok; +gen_oe_tc(_, _, _, _) -> + ok. + +emit_oe_get_interface(Fd, []) -> + emit(Fd, "].\n"); +emit_oe_get_interface(Fd, [Item]) -> + emit(Fd, "~s].\n", [lists:flatten(Item)]); +emit_oe_get_interface(Fd, [H|T]) -> + emit(Fd, "~s,\n\t", [lists:flatten(H)]), + emit_oe_get_interface(Fd, T). + +gen_oe_tc2(_,_,[],_, Acc) -> + Acc; +gen_oe_tc2(G, N, [X|Rest], Fd, Acc) when is_record(X, op) -> + R = ic_forms:get_tk(X), + IN = lists:map(fun(P) -> ic_forms:get_tk(P) end, + ic:filter_params([in, inout], X#op.params)), + OUT = lists:map(fun(P) -> ic_forms:get_tk(P) end, + ic:filter_params([out, inout], X#op.params)), + Function = get_id2(X), + FunctionAtom = ic_util:to_atom(Function), + emit(Fd, "oe_tc(~p) -> \n\t~p;\n",[FunctionAtom, {R, IN, OUT}]), + GI = io_lib:format("{~p, oe_tc(~p)}",[Function, FunctionAtom]), + gen_oe_tc2(G, N, Rest, Fd, [GI|Acc]); + +gen_oe_tc2(G, N, [X|Rest], Fd, Acc) when is_record(X, attr) -> + {GetT, SetT} = mk_attr_func_types([], X), + NewAcc = + lists:foldl(fun(Id, FunAcc) -> + {Get, Set} = mk_attr_func_names([], get_id(Id)), + GetAttrAtom = ic_util:to_atom(Get), + emit(Fd, "oe_tc(~p) -> \n\t~p;\n", + [GetAttrAtom, GetT]), + case X#attr.readonly of + {readonly, _} -> + GI = io_lib:format("{~p, oe_tc(~p)}", + [Get, GetAttrAtom]), + [GI|FunAcc]; + _ -> + SetAttrAtom = ic_util:to_atom(Set), + + emit(Fd, "oe_tc(~p) -> \n\t~p;\n", + [SetAttrAtom, SetT]), + GetGI = io_lib:format("{~p, oe_tc(~p)}", + [Get, GetAttrAtom]), + SetGI = io_lib:format("{~p, oe_tc(~p)}", + [Set, SetAttrAtom]), + [GetGI, SetGI|FunAcc] + end + end, Acc, ic_forms:get_idlist(X)), + gen_oe_tc2(G, N, Rest, Fd, NewAcc); + +gen_oe_tc2(G,N,[_X|Rest], Fd, Acc) -> + gen_oe_tc2(G,N,Rest, Fd, Acc). + + +gen_oe_tc3(_,_,[],_, Acc) -> + Acc; +gen_oe_tc3(G, N, [X|Rest], Fd, Acc) when is_record(X, op) -> + Function = get_id2(X), + FunctionAtom = ic_util:to_atom(get_id2(X)), + GI = io_lib:format("{~p, ~p:oe_tc(~p)}",[Function, N, FunctionAtom]), + emit(Fd, "oe_tc(~p) -> ~p:oe_tc(~p);\n", + [FunctionAtom, N, FunctionAtom]), + gen_oe_tc3(G, N, Rest, Fd, [GI|Acc]); + +gen_oe_tc3(G, N, [X|Rest], Fd, Acc) when is_record(X, attr) -> + NewAcc = lists:foldl(fun(Id, FunAcc) -> + {Get, Set} = mk_attr_func_names([], get_id(Id)), + GetAttrAtom = ic_util:to_atom(Get), + emit(Fd, "oe_tc(~p) -> ~p:oe_tc(~p);\n", + [GetAttrAtom, N, GetAttrAtom]), + case X#attr.readonly of + {readonly, _} -> + [io_lib:format("{~p, ~p:oe_tc(~p)}", + [Get, N, GetAttrAtom])|FunAcc]; + _ -> + SetAttrAtom = ic_util:to_atom(Set), + emit(Fd, "oe_tc(~p) -> ~p:oe_tc(~p);\n", + [SetAttrAtom, N, SetAttrAtom]), + [io_lib:format("{~p, ~p:oe_tc(~p)}", + [Get, N, GetAttrAtom]), + io_lib:format("{~p, ~p:oe_tc(~p)}", + [Set, N, SetAttrAtom])|FunAcc] + end + end, Acc, ic_forms:get_idlist(X)), + gen_oe_tc3(G, N, Rest, Fd, NewAcc); + +gen_oe_tc3(G,N,[_X|Rest], Fd, Acc) -> + gen_oe_tc3(G,N,Rest, Fd, Acc). + +gen_calls(G, N, [X|Xs]) when is_record(X, op) -> + case is_oneway(X) of + false -> + {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), + emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs, false, + get_opt(G, be)), + gen_calls(G, N, Xs); + true -> + gen_calls(G, N, Xs) + end; + +gen_calls(G, N, [X|Xs]) when is_record(X, attr) -> + emit_attr(G, N, X, fun emit_skel_func/9), + gen_calls(G, N, Xs); + +gen_calls(G, N, [_X|Xs]) -> gen_calls(G, N, Xs); +gen_calls(_G, _N, []) -> ok. + +gen_casts(G, N, [X|Xs]) when is_record(X, op) -> + case is_oneway(X) of + true -> + {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), + emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs, true, + get_opt(G, be)), + gen_casts(G, N, Xs); + false -> + gen_casts(G, N, Xs) + end; + +gen_casts(G, N, [_X|Xs]) -> gen_casts(G, N, Xs); +gen_casts(_G, _N, []) -> ok. + +emit_attr(G, N, X, F) -> + XX = #id_of{type=X}, + BE = get_opt(G, be), + {GetType, SetType} = mk_attr_func_types(N, X), + lists:foreach(fun(Id) -> + X2 = XX#id_of{id=Id}, + {Get, Set} = mk_attr_func_names(N, get_id(Id)), + F(G, N, X2, Get, [], GetType, [], + is_oneway(X2), BE), + case X#attr.readonly of + {readonly, _} -> ok; + _ -> + F(G, N, X2, Set, [mk_name(G, "Value")], + SetType, [], + is_oneway(X2), BE) + end end, ic_forms:get_idlist(X)). + + +extract_info(G, _N, X) when is_record(X, op) -> + Name = get_id2(X), + InArgs = ic:filter_params([in,inout], X#op.params), + OutArgs = ic:filter_params([out,inout], X#op.params), + ArgNames = mk_erl_vars(G, InArgs), + TypeList = {ic_forms:get_tk(X), + map(fun(Y) -> ic_forms:get_tk(Y) end, InArgs), + map(fun(Y) -> ic_forms:get_tk(Y) end, OutArgs) + }, + {Name, ArgNames, TypeList, OutArgs}. + + + +%% This function generates the standard functions of an object +%% gen_server +emit_serv_std(erl_corba, G, N, X) -> + Fd = ic_genobj:stubfiled(G), + Impl = ic_genobj:impl(G), + TypeID = ictk:get_IR_ID(G, N, X), + + nl(Fd), nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Object server implementation."]), + nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Function for fetching the interface type ID."]), + nl(Fd), + emit(Fd, "typeID() ->\n"), + emit(Fd, " \"~s\".\n", [TypeID]), + nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Object creation functions."]), + nl(Fd), + emit(Fd, "oe_create() ->\n"), + emit(Fd, " corba:create(?MODULE, \"~s\").\n", [TypeID]), + nl(Fd), + emit(Fd, "oe_create_link() ->\n"), + emit(Fd, " corba:create_link(?MODULE, \"~s\").\n", [TypeID]), + nl(Fd), + emit(Fd, "oe_create(Env) ->\n"), + emit(Fd, " corba:create(?MODULE, \"~s\", Env).\n", [TypeID]), + nl(Fd), + emit(Fd, "oe_create_link(Env) ->\n"), + emit(Fd, " corba:create_link(?MODULE, \"~s\", Env).\n", [TypeID]), + nl(Fd), + emit(Fd, "oe_create(Env, RegName) ->\n"), + emit(Fd, " corba:create(?MODULE, \"~s\", Env, RegName).\n", [TypeID]), + nl(Fd), + emit(Fd, "oe_create_link(Env, RegName) ->\n"), + emit(Fd, " corba:create_link(?MODULE, \"~s\", Env, RegName).\n", [TypeID]), + nl(Fd), + ic_codegen:mcomment(Fd, ["Init & terminate functions."]), + nl(Fd), + emit(Fd, "init(Env) ->\n"), + ic_codegen:comment(Fd, "Call to implementation init"), + emit(Fd, " corba:handle_init(~p, Env).\n", [to_atom(Impl)]), + nl(Fd), + emit(Fd, "terminate(Reason, State) ->\n"), + emit(Fd, " corba:handle_terminate(~p, Reason, State).\n", + [to_atom(Impl)]), + nl(Fd), nl(Fd), + Fd; +emit_serv_std(erl_genserv, G, N, X) -> + Fd = ic_genobj:stubfiled(G), + Impl = ic_genobj:impl(G), + TypeID = ictk:get_IR_ID(G, N, X), + + nl(Fd), nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Server implementation."]), + nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Function for fetching the interface type ID."]), + nl(Fd), + emit(Fd, "typeID() ->\n"), + emit(Fd, " \"~s\".\n", [TypeID]), + nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Server creation functions."]), + nl(Fd), + emit(Fd, "oe_create() ->\n"), + emit(Fd, " start([], []).\n", []), + nl(Fd), + emit(Fd, "oe_create_link() ->\n"), + emit(Fd, " start_link([], []).\n", []), + nl(Fd), + emit(Fd, "oe_create(Env) ->\n"), + emit(Fd, " start(Env, []).\n", []), + nl(Fd), + emit(Fd, "oe_create_link(Env) ->\n"), + emit(Fd, " start_link(Env, []).\n", []), + nl(Fd), + emit(Fd, "oe_create(Env, RegName) ->\n"), + emit(Fd, " start(RegName, Env, []).\n", []), + nl(Fd), + emit(Fd, "oe_create_link(Env, RegName) ->\n"), + emit(Fd, " start_link(RegName, Env, []).\n", []), + nl(Fd), + ic_codegen:mcomment(Fd, ["Start functions."]), + nl(Fd), + emit(Fd, "start(Env, Opt) ->\n"), + emit(Fd, " gen_server:start(?MODULE, Env, Opt).\n"), + nl(Fd), + emit(Fd, "start_link(Env, Opt) ->\n"), + emit(Fd, " gen_server:start_link(?MODULE, Env, Opt).\n"), + nl(Fd), + emit(Fd, "start(RegName, Env, Opt) ->\n"), + emit(Fd, " gen_server:start(RegName, ?MODULE, Env, Opt).\n"), + nl(Fd), + emit(Fd, "start_link(RegName, Env, Opt) ->\n"), + emit(Fd, " gen_server:start_link(RegName, ?MODULE, Env, Opt).\n"), + nl(Fd), + ic_codegen:comment(Fd, "Standard gen_server termination"), + emit(Fd, "stop(OE_THIS) ->\n"), + emit(Fd, " gen_server:cast(OE_THIS,stop).\n"), + nl(Fd), + ic_codegen:comment(Fd, "Call to implementation init"), + emit(Fd, "init(Env) ->\n"), + emit(Fd, " ~p:~p(Env).\n", [to_atom(Impl), init]), + nl(Fd), + emit(Fd, "terminate(Reason, State) ->\n"), + emit(Fd, " ~p:~p(Reason, State).\n", + [to_atom(Impl), terminate]), + nl(Fd), nl(Fd), + Fd. + +gen_end_of_call(erl_corba, G) -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + ic_codegen:mcomment_light(Fd, ["Standard gen_server call handle"]), + emit(Fd, "handle_call(stop, _, State) ->\n"), + emit(Fd, " {stop, normal, ok, State}"), + case get_opt(G, serv_last_call) of + exception -> + emit(Fd, ";\n"), + nl(Fd), + emit(Fd, "handle_call(_, _, State) ->\n"), + emit(Fd, " {reply, catch corba:raise(#'BAD_OPERATION'{minor=1163001857, completion_status='COMPLETED_NO'}), State}.\n"); + exit -> + emit(Fd, ".\n"), + nl(Fd), + nl(Fd) + end, + ok; +gen_end_of_call(erl_genserv, G) -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + ic_codegen:mcomment_light(Fd, ["Standard gen_server call handle"]), + emit(Fd, "handle_call(stop, _, State) ->\n"), + emit(Fd, " {stop, normal, ok, State}"), + emit(Fd, ".\n"), + nl(Fd), nl(Fd), + ok. + +gen_end_of_cast(erl_corba, G) -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + ic_codegen:mcomment_light(Fd, ["Standard gen_server cast handle"]), + emit(Fd, "handle_cast(stop, State) ->\n"), + emit(Fd, " {stop, normal, State}"), + case get_opt(G, serv_last_call) of + exception -> + emit(Fd, ";\n"), + nl(Fd), + emit(Fd, "handle_cast(_, State) ->\n"), + emit(Fd, " {noreply, State}.\n"); + exit -> + emit(Fd, ".\n"), + nl(Fd), nl(Fd) + end, + ok; +gen_end_of_cast(erl_genserv, G) -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + ic_codegen:mcomment_light(Fd, ["Standard gen_server cast handle"]), + emit(Fd, "handle_cast(stop, State) ->\n"), + emit(Fd, " {stop, normal, State}"), + emit(Fd, ".\n"), + nl(Fd), nl(Fd), + ok. + +emit_skel_footer(erl_corba, G, N, X) -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + ic_codegen:mcomment_light(Fd, ["Standard gen_server handles"]), + case use_impl_handle_info(G, N, X) of + true -> + emit(Fd, "handle_info(Info, State) ->\n"), + emit(Fd, " corba:handle_info(~p, Info, State).\n\n", + [list_to_atom(ic_genobj:impl(G))]); + false -> + emit(Fd, "handle_info(_, State) ->\n"), + emit(Fd, " {noreply, State}.\n\n") + end, + nl(Fd), + case get_opt(G, no_codechange) of + false -> + emit(Fd, "code_change(OldVsn, State, Extra) ->\n"), + emit(Fd, " corba:handle_code_change(~p, OldVsn, State, Extra).\n\n", + [list_to_atom(ic_genobj:impl(G))]); + true -> + emit(Fd, "code_change(_, State, _) ->\n"), + emit(Fd, " {ok, State}.\n\n") + end, + ok; +emit_skel_footer(erl_genserv, G, N, X) -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + ic_codegen:mcomment_light(Fd, ["Standard gen_server handles"]), + case use_impl_handle_info(G, N, X) of + true -> + emit(Fd, "handle_info(Info, State) ->\n"), + emit(Fd, " ~p:handle_info(Info, State).\n\n", + [list_to_atom(ic_genobj:impl(G))]); + false -> + emit(Fd, "handle_info(_, State) ->\n"), + emit(Fd, " {noreply, State}.\n\n") + end, + nl(Fd), nl(Fd), + case get_opt(G, no_codechange) of + false -> + emit(Fd, "code_change(OldVsn, State, Extra) ->\n"), + emit(Fd, " ~p:code_change(OldVsn, State, Extra).\n\n", + [list_to_atom(ic_genobj:impl(G))]); + true -> + emit(Fd, "code_change(_, State, _) ->\n"), + emit(Fd, " {ok, State}.\n\n") + end, + ok. + + +use_impl_handle_info(G, N, X) -> + FullName = ic_util:to_colon([get_id2(X) | N]), + case {get_opt(G, {handle_info, true}), get_opt(G, {handle_info, FullName})} of + {_, force_false} -> false; + {false, false} -> false; + _ -> true + end. + +use_timeout(G, N, _X) -> + FullName = ic_util:to_colon(N), + case {get_opt(G, {timeout, true}), get_opt(G, {timeout, FullName})} of + {_, force_false} -> false; + {false, false} -> false; + _ -> true + end. + +use_precond(G, N, X) -> + FullName = ic_util:to_colon([get_id2(X) | N]), + case get_opt(G, {precond, FullName}) of + false -> + InterfaceName = ic_util:to_colon(N), + case get_opt(G, {precond, InterfaceName}) of + false -> + case get_opt(G, precond) of + false -> false; + V2 -> V2 + end; + V2 -> V2 + end; + V1 -> V1 + end. + +use_postcond(G, N, X) -> + FullName = ic_util:to_colon([get_id2(X) | N]), + case get_opt(G, {postcond, FullName}) of + false -> + InterfaceName = ic_util:to_colon(N), + case get_opt(G, {postcond, InterfaceName}) of + false -> + case get_opt(G, postcond) of + false -> false; + V3 -> V3 + end; + V2 -> V2 + end; + V1 -> V1 + end. + + +%%------------------------------------------------------------ +%% +%% Export stuff +%% +%% Gathering of all names that should be exported from a stub +%% file. +%% + + +gen_head_special(G, N, X) when is_record(X, interface) -> + Fd = ic_genobj:stubfiled(G), + + foreach(fun({Name, Body}) -> + ic_codegen:comment(Fd, "Exports from ~p", + [ic_util:to_colon(Name)]), + ic_codegen:export(Fd, exp_top(G, N, Body, [], get_opt(G, be))), + nl(Fd) + end, X#interface.inherit_body), + + ic_codegen:comment(Fd, "Type identification function"), + ic_codegen:export(Fd, [{typeID, 0}]), + nl(Fd), + ic_codegen:comment(Fd, "Used to start server"), + ic_codegen:export(Fd, [{oe_create, 0}, {oe_create_link, 0}, {oe_create, 1}, {oe_create_link, 1}, + {oe_create, 2}, {oe_create_link, 2}]), + nl(Fd), + case get_opt(G, be) of + erl_corba -> + ic_codegen:comment(Fd, "TypeCode Functions and inheritance"), + ic_codegen:export(Fd, [{oe_tc, 1}, {oe_is_a, 1}, {oe_get_interface, 0}]); + _ -> + ic_codegen:export(Fd, [{start, 2}, {start_link, 3}]) + end, + nl(Fd), + ic_codegen:comment(Fd, "gen server export stuff"), + emit(Fd, "-behaviour(gen_server).\n"), + + case get_opt(G, be) of + erl_genserv -> %% stop/1 is only for erl_genserv backend + ic_codegen:export(Fd, [{stop, 1}, {init, 1}, {terminate, 2}, {handle_call, 3}, + {handle_cast, 2}, {handle_info, 2}, {code_change, 3}]); + _ -> + ic_codegen:export(Fd, [{init, 1}, {terminate, 2}, {handle_call, 3}, + {handle_cast, 2}, {handle_info, 2}, {code_change, 3}]) + end, + + case get_opt(G, be) of + erl_corba -> + nl(Fd), + emit(Fd, "-include_lib(\"~s/include/~s\").\n", [?ORBNAME, ?CORBAHRL]); + _ -> + ok + end, + nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Object interface functions."]), + nl(Fd), nl(Fd), nl(Fd), + Fd; +gen_head_special(_G, _N, _X) -> ok. + + + +%% Shall generate all export declarations +gen_head(G, N, X) -> + case ic_genobj:is_stubfile_open(G) of + true -> + F = ic_genobj:stubfiled(G), + ic_codegen:comment(F, "Interface functions"), + ic_codegen:export(F, exp_top(G, N, X, [], get_opt(G, be))), + nl(F), + gen_head_special(G, N, X); + false -> ok + end. + +exp_top(_G, _N, X, Acc, _) when element(1, X) == preproc -> + Acc; +exp_top(G, N, L, Acc, BE) when is_list(L) -> + exp_list(G, N, L, Acc, BE); +exp_top(G, N, M, Acc, BE) when is_record(M, module) -> + exp_list(G, N, get_body(M), Acc, BE); +exp_top(G, N, I, Acc, BE) when is_record(I, interface) -> + exp_list(G, N, get_body(I), Acc, BE); +exp_top(G, N, X, Acc, BE) -> + exp3(G, N, X, Acc, BE). + +exp3(_G, _N, C, Acc, _BE) when is_record(C, const) -> + [{get_id(C#const.id), 0} | Acc]; +exp3(_G, _N, Op, Acc, erl_corba) when is_record(Op, op) -> + FuncName = get_id(Op#op.id), + Arity = length(ic:filter_params([in, inout], Op#op.params)) + 1, + [{FuncName, Arity}, {FuncName, Arity+1} | Acc]; +exp3(G, N, Op, Acc, _BE) when is_record(Op, op) -> + FuncName = get_id(Op#op.id), + Arity = + case use_timeout(G,N,Op) of + true -> + %% NO TimeOut on ONEWAYS here !!!! + case is_oneway(Op) of + true -> + length(ic:filter_params([in, inout], Op#op.params)) + 1; + false -> + length(ic:filter_params([in, inout], Op#op.params)) + 2 + end; + false -> + length(ic:filter_params([in, inout], Op#op.params)) + 1 + end, + [{FuncName, Arity} | Acc]; + +exp3(_G, _N, A, Acc, erl_corba) when is_record(A, attr) -> + lists:foldr(fun(Id, Acc2) -> + {Get, Set} = mk_attr_func_names([], get_id(Id)), + case A#attr.readonly of + {readonly, _} -> [{Get, 1}, {Get, 2} | Acc2]; + _ -> [{Get, 1}, {Get, 2}, + {Set, 2}, {Set, 3} | Acc2] + end end, Acc, ic_forms:get_idlist(A)); +exp3(_G, _N, A, Acc, _BE) when is_record(A, attr) -> + lists:foldr(fun(Id, Acc2) -> + {Get, Set} = mk_attr_func_names([], get_id(Id)), + case A#attr.readonly of + {readonly, _} -> [{Get, 1} | Acc2]; + _ -> [{Get, 1}, {Set, 2} | Acc2] + end end, Acc, ic_forms:get_idlist(A)); + +exp3(_G, _N, _X, Acc, _BE) -> Acc. + +exp_list(G, N, L, OrigAcc, BE) -> + lists:foldr(fun(X, Acc) -> exp3(G, N, X, Acc, BE) end, OrigAcc, L). + + + + +%%------------------------------------------------------------ +%% +%% Emit stuff +%% +%% Low level generation primitives +%% + +emit_stub_func(G, N, X, Name, ArgNames, _TypeList, OutArgs, Oneway, Backend) -> + case ic_genobj:is_stubfile_open(G) of + false -> + ok; + true -> + Fd = ic_genobj:stubfiled(G), + StubName = list_to_atom(Name), + UsingTimeout = use_timeout(G, N, X), + Timeout = case UsingTimeout of + true -> + mk_name(G, "Timeout"); + false -> + "infinity" + end, + Options = mk_name(G, "Options"), + This = mk_name(G, "THIS"), + CallOrCast = + case is_oneway(X) of + true -> ?CAST; + _ -> ?CALL + end, + emit_op_comment(G, Fd, X, StubName, ArgNames, OutArgs), + case Backend of + erl_corba -> + emit(Fd, "~p(~s) ->\n", + [StubName, mk_list([This | ArgNames])]), + emit(Fd, " ~s:~s(~s, ~p, [~s], ?MODULE).\n\n", + [?CORBAMOD, CallOrCast, This, StubName, mk_list(ArgNames)]), + emit(Fd, "~p(~s) ->\n", + [StubName, mk_list([This, Options| ArgNames])]), + emit(Fd, " ~s:~s(~s, ~p, [~s], ?MODULE, ~s).\n\n", + [?CORBAMOD, CallOrCast, This, StubName, mk_list(ArgNames), + Options]); + _ -> + FunName = case ic_options:get_opt(G, scoped_op_calls) of + true -> + list_to_atom(ic_util:to_undersc([Name | N])); + false -> + StubName + end, + %% NO TimeOut on ONEWAYS here !!!! + case Oneway of + true -> + emit(Fd, "~p(~s) ->\n", + [StubName, mk_list([This | ArgNames])]); + false -> + case UsingTimeout of + true -> + emit(Fd, "~p(~s) ->\n", + [StubName, mk_list([This, Timeout| ArgNames])]); + false -> + emit(Fd, "~p(~s) ->\n", + [StubName, mk_list([This | ArgNames])]) + end + end, + + %% NO TimeOut on ONEWAYS here !!!! + if + length(ArgNames) == 0 -> + case is_oneway(X) of + true -> + emit(Fd, " ~s:~s(~s, ~p).\n\n", + [?GENSERVMOD, CallOrCast, This, FunName]); + false -> + emit(Fd, " ~s:~s(~s, ~p, ~s).\n\n", + [?GENSERVMOD, CallOrCast, This, FunName, Timeout]) + end; + true -> + case is_oneway(X) of + true -> + emit(Fd, " ~s:~s(~s, {~p, ~s}).\n\n", + [?GENSERVMOD, CallOrCast, This, FunName, + mk_list(ArgNames)]); + false -> + emit(Fd, " ~s:~s(~s, {~p, ~s}, ~s).\n\n", + [?GENSERVMOD, CallOrCast, This, FunName, + mk_list(ArgNames), Timeout]) + end + end + end + end. + +emit_skel_func(G, N, X, OpName, ArgNames, TypeList, OutArgs, Oneway, Backend) -> + case ic_genobj:is_stubfile_open(G) of + false -> + ok; + true -> + emit_skel_func_helper(G, N, X, OpName, ArgNames, TypeList, OutArgs, + Oneway, Backend) + end. + +emit_skel_func_helper(G, N, X, OpName, ArgNames, _TypeList, OutArgs, Oneway, + erl_corba) -> + Fd = ic_genobj:stubfiled(G), + Name = list_to_atom(OpName), + ImplF = Name, + ImplM = list_to_atom(ic_genobj:impl(G)), + ThisStr = mk_name(G, "THIS"), + FromStr = mk_name(G, "From"), + State = mk_name(G, "State"), + Context = mk_name(G, "Context"), + + {UseFrom, From} = + case Oneway of + false -> + case use_from(G, N, OpName) of + true -> + {FromStr, FromStr}; + false -> + {"false", "_"} + end; + true -> + {"false", "_"} + end, + {UseThis, This} = + case use_this(G, N, OpName) of + true -> + {ThisStr, ThisStr}; + false -> + {"false", "_"} + end, + %% Create argument list string + CallArgs = mk_list(ArgNames), + emit_op_comment(G, Fd, X, Name, ArgNames, OutArgs), + + %% Check if pre and post conditions are specified for this operation + Precond = use_precond(G, N, X), + Postcond = use_postcond(G, N, X), + + case Oneway of + true -> + emit(Fd, "handle_cast({~s, ~s, ~p, [~s]}, ~s) ->\n", + [This, Context, Name, CallArgs, State]), + case {Precond, Postcond} of + {false, false} -> + emit(Fd, " corba:handle_cast(~p, ~p, [~s], ~s, ~s, ~s);\n\n", + [ImplM, ImplF, CallArgs, State, Context, UseThis]); + _ -> + emit(Fd, " corba:handle_cast(~p, ~p, [~s], ~s, ~s, ~s, ~p, ~p, ?MODULE);\n\n", + [ImplM, ImplF, CallArgs, State, Context, UseThis, + Precond, Precond]) + end; + false -> + emit(Fd, "handle_call({~s, ~s, ~p, [~s]}, ~s, ~s) ->\n", + [This, Context, Name, CallArgs, From, State]), + case {Precond, Postcond} of + {false, false} -> + emit(Fd, " corba:handle_call(~p, ~p, [~s], ~s, ~s, ~s, ~s);\n\n", + [ImplM, ImplF, CallArgs, State, Context, UseThis, UseFrom]); + _-> + emit(Fd, " corba:handle_call(~p, ~p, [~s], ~s, ~s, ~s, ~s, ~p, ~p, ?MODULE);\n\n", + [ImplM, ImplF, CallArgs, State, Context, UseThis, UseFrom, + Precond, Postcond]) + end + end; +emit_skel_func_helper(G, N, X, OpName, ArgNames, _TypeList, OutArgs, Oneway, + _Backend) -> + Fd = ic_genobj:stubfiled(G), + Name = list_to_atom(OpName), + ImplF = Name, + ImplM = list_to_atom(ic_genobj:impl(G)), + FromStr = mk_name(G, "From"), + State = mk_name(G, "State"), + + %% Create argument list + CallArgs1 = [State | ArgNames], + {CallArgs2, From} = + case is_oneway(X) of + false -> + case use_from(G, N, OpName) of + true -> + {[FromStr | CallArgs1], FromStr}; + false -> + {CallArgs1, "_"} + end; + true -> + {CallArgs1, "_"} + end, + %% Create argument list string + CallArgs = mk_list(CallArgs2), + emit_op_comment(G, Fd, X, Name, ArgNames, OutArgs), + FunName = case ic_options:get_opt(G, scoped_op_calls) of + true -> + list_to_atom(ic_util:to_undersc([OpName | N])); + false -> + list_to_atom(OpName) + end, + case Oneway of + true -> + if + length(ArgNames) == 0 -> + emit(Fd, "handle_cast(~p, ~s) ->\n", [FunName, State]); + true -> + emit(Fd, "handle_cast({~p, ~s}, ~s) ->\n", + [FunName, mk_list(ArgNames), State]) + end, + emit(Fd, " ~p:~p(~s);\n\n", [ImplM, ImplF, CallArgs]); + false -> + if + length(ArgNames) == 0 -> + emit(Fd, "handle_call(~p, ~s, ~s) ->\n", + [FunName, From, State]); + true -> + emit(Fd, "handle_call({~p, ~s}, ~s, ~s) ->\n", + [FunName, mk_list(ArgNames), From, State]) + end, + emit(Fd, " ~p:~p(~s);\n\n", [ImplM, ImplF, CallArgs]) + end. + +use_this(G, N, OpName) -> + FullOp = ic_util:to_colon([OpName|N]), + FullIntf = ic_util:to_colon(N), + case {get_opt(G, {this, FullIntf}), get_opt(G, {this, FullOp}), + get_opt(G, {this, true})} of + {_, force_false, _} -> false; + {force_false, false, _} -> false; + {false, false, false} -> false; + _ -> true + end. + +use_from(G, N, OpName) -> + FullOp = ic_util:to_colon([OpName|N]), + FullIntf = ic_util:to_colon(N), + case {get_opt(G, {from, FullIntf}), get_opt(G, {from, FullOp}), + get_opt(G, {from, true})} of + {_, force_false, _} -> false; + {force_false, false, _} -> false; + {false, false, false} -> false; + _ -> true + end. + + +emit_constant_func(G, Id, Val) -> + case ic_genobj:is_stubfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:stubfiled(G), + N = list_to_atom(get_id(Id)), + emit_const_comment(G, Fd, Id, N), + emit(Fd, "~p() -> ~p.\n\n", [N, Val]) + end. + + + +emit_const_comment(_G, F, _X, Name) -> + ic_codegen:mcomment_light(F, + [io_lib:format("Constant: ~p", [Name])]). + + +emit_op_comment(G, F, X, Name, InP, OutP) -> + ic_codegen:mcomment_light(F, + [io_lib:format("~s: ~p", [get_title(X), Name]), + "", + get_returns(G, X, InP, OutP) | + get_raises(X)]). + +get_title(X) when is_record(X, attr) -> "Attribute Operation"; +get_title(_X) -> "Operation". + +get_raises(X) when is_record(X, op) -> + if X#op.raises == [] -> []; + true -> + [" Raises: " ++ + mk_list(lists:map(fun(E) -> ic_util:to_colon(E) end, + X#op.raises))] + end; +get_raises(_X) -> []. + +get_returns(_G, _X, _InP, []) -> + " Returns: RetVal"; +get_returns(G, _X, _InP, OutP) -> + " Returns: "++mk_list(["RetVal" | mk_erl_vars(G, OutP)]). + + + + +%%------------------------------------------------------------ +%% +%% Utilities +%% +%% Convenient little go-get functions +%% +%%------------------------------------------------------------ + +%% The automaticly generated get and set operation names for an +%% attribute. +mk_attr_func_names(_Scope, Name) -> + {"_get_" ++ Name, "_set_" ++ Name}. +%% {scoped_name(Scope, "_get_"++Name), scoped_name(Scope, "_set_"++Name)}. + +%% Returns TK of the Get and Set attribute functions. +mk_attr_func_types(_N, X) -> + TK = ic_forms:get_tk(X), + {{TK, [], []}, {tk_void, [TK], []}}. + + + +%%------------------------------------------------------------ +%% +%% Generation utilities and common stuff +%% +%% Convenient stuff for generation +%% +%%------------------------------------------------------------ + + +%% Input is a list of parameters (in parse form) and output is a list +%% of capitalised variable names. mk_var is in icgen +mk_erl_vars(_G, Params) -> + map(fun(P) -> mk_var(get_id(P#param.id)) end, Params). + + +%% mk_list produces a nice comma separated string of variable names +mk_list([]) -> []; +mk_list([Arg | Args]) -> + Arg ++ mk_list2(Args). +mk_list2([Arg | Args]) -> + ", " ++ Arg ++ mk_list2(Args); +mk_list2([]) -> []. + + +%%------------------------------------------------------------ +%% +%% Parser utilities +%% +%% Called from the yecc parser. Expands the identifier list of an +%% attribute so that the attribute generator never has to handle +%% lists. +%% +%%------------------------------------------------------------ + + +%% Unfold identifier lists or nested lists. Note that many records +%% contain an entry named id that is a list before unfold and a single +%% id afterwards. +unfold(L) when is_list(L) -> + lists:flatten(map(fun(X) -> unfold2(X) end, L)); +unfold(X) -> unfold2(X). + +unfold2(A) when is_record(A, attr) -> + map(fun(Id) -> A#attr{id=Id} end, A#attr.id); +unfold2(M) when is_record(M, member) -> + map(fun(Id) -> M#member{id=Id} end, M#member.id); +unfold2(M) when is_record(M, case_dcl) -> + map(fun(Id) -> M#case_dcl{label=Id} end, M#case_dcl.label); +unfold2(T) when is_record(T, typedef) -> + map(fun(Id) -> T#typedef{id=Id} end, T#typedef.id). + + + + +%% Code produce for dependency function +genDependency(G) -> + Fd = ic_genobj:stubfiled(G), + nl(Fd),nl(Fd), + ic_codegen:comment(Fd, "Idl file dependency list function"), + emit(Fd, "oe_dependency() ->\n\n", []), + emit(Fd, " ~p.\n\n", [ic_pragma:get_dependencies(G)]). diff --git a/lib/ic/src/ic_error.erl b/lib/ic/src/ic_error.erl new file mode 100644 index 0000000..f41e78a --- /dev/null +++ b/lib/ic/src/ic_error.erl @@ -0,0 +1,375 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_error). + +-include_lib("ic/src/ic.hrl"). +-include_lib("ic/src/ic_debug.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([error/2, + fatal_error/2, + init_errors/1, + return/1, + warn/2, + get_error_count/1]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% +%% Error and warning utilities. +%% +%% Note that errors are somewhat brutal and that warnings are kept in +%% a list for the user to extract at a later stage. The handling of +%% warnings is entirely up to the user while handling of errors is +%% never left to the user. +%% +%%-------------------------------------------------------------------- + +return(G) -> + case ic_options:get_opt(G, silent2) of + true -> + case get_error_count(G) of + 0 -> {ok, get_list(G, warn_list)}; + _X -> {error, get_list(G, warn_list), get_list(G, error_list)} + end; + false -> + case get_error_count(G) of + 0 -> ok; + X -> print_error(G, {error, g, ic_genobj:idlfile(G), {error_count, X}}), + error + end + end. + + +get_list(G, ListName) -> + ?lookup(G#genobj.options, ListName). + + +%% Public function for reporting an error +error(G, Err) -> + Error = {error, g, ic_genobj:idlfile(G), Err}, + case insert_in_list(G, Error, error_list) of + new -> + print_error(G, Error), + MaxErrs = ic_options:get_opt(G, maxerrs), + case incr_counter(G, error_count) of + X when X >= MaxErrs -> + fatal_error(G, {error_count_exceeded, X}); + _ -> Error + end; + old -> + Error + end. + +%% Public function for reporting an error. NOTE: also stops execution +fatal_error(G, Err) -> + Error = {error, g, ic_genobj:idlfile(G), Err}, + insert_in_list(G, Error, error_list), + incr_counter(G, error_count), + print_error(G, Error), + throw(Error). + + +%% Public function for reporting a warning +warn(G, Warn) -> + Warning = {warn, g, ic_genobj:idlfile(G), Warn}, + case insert_in_list(G, Warning, warn_list) of + new -> + print_warn(G, Warning), + MaxErrs = ic_options:get_opt(G, maxwarns), + case incr_counter(G, warn_count) of + X when X >= MaxErrs -> + fatal_error(G, {warn_count_exceeded, X}); + _ -> ok + end; + old -> ok +end. + + +%% Initialisation of all counters and lists associated with errors and +%% warnings. +init_errors(G) -> + reset_counter(G, error_count), + reset_counter(G, warn_count), + reset_list(G, error_list), + reset_list(G, warn_list), + ok. + + + +%%-------------------------------------------------------------------- +%% Counter and list (warn and error) handling +%% + +incr_counter(G, Counter) -> + Num = ?lookup(G#genobj.options, Counter) + 1, + ?insert(G#genobj.options, Counter, Num), + Num. + +reset_counter(G, Counter) -> + ?insert(G#genobj.options, Counter, 0). + +get_error_count(G) -> + ?lookup(G#genobj.options, error_count). + +reset_list(G, ListName) -> + ?insert(G#genobj.options, ListName, []). + +insert_in_list(G, Item, ListName) -> + List = ?lookup(G#genobj.options, ListName), + case lists:member(Item, List) of + true -> old; + false -> + ?insert(G#genobj.options, ListName, [Item| List]), + new + end. + + +%%-------------------------------------------------------------------- +%% +%% Nice printouts of errors and warnings +%% + + +%% Errors + +print_error(G, Error) -> + case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of + {true, _} -> ok; + {_, true} -> ok; + _ -> format_error(Error) + end, + error. + +format_error({error, _, File, {parse_error, Line, Args}}) -> + Fmt = lists:foldl(fun(_, Acc) -> [$~, $s | Acc] end, [], Args), + display(File, Line, Fmt, Args); +format_error({error, _, File, {error_count, X}}) -> + display(File, "~p errors found", [X]); +format_error({error, _, File, {error_count_exceeded, X}}) -> + display(File, "too many errors found (~p)", [X]); +format_error({error, _, File, {warn_count_exceeded, X}}) -> + display(File, "too many warnings found (~p)", [X]); +format_error({error, _, File, {inherit_name_collision, + {Orig, Item}, {Base, NewItem}}}) -> + display(File, ic_forms:get_line(Item), "~s collides with ~s", + [pp([ic_forms:get_id2(Item) | Orig]), pp([ic_forms:get_id2(NewItem) | Base])]); +format_error({error, _, File, {unsupported_op, {'~', Line}}}) -> + display(File, Line, "unsupported unary operation ~~", []); +format_error({error, _, File, {multiply_defined, X}}) -> + display(File, ic_forms:get_line(X), "multiple defined identifier ~p", [ic_forms:get_id2(X)]); +format_error({error, _, File, {illegal_spelling, X}}) -> + display(File, ic_forms:get_line(X), +% "illegal spelling of identifier ~s (capitalisation?)", + "identifier ~p multiply declared - differs in case only", + [ic_forms:get_id2(X)]); +format_error({error, _, File, {illegal_enumerant_value, X}}) -> + display(File, ic_forms:get_line(X), + "Enumerant ~s's value collide by name with other type", + [ic_forms:get_id2(X)]); +format_error({error, _, File, {illegal_forward, X}}) -> + display(File, ic_forms:get_line(X), + "cannot inherit from forwarded interface ~s", [ic_forms:get_id2(X)]); +format_error({error, _, File, {illegal_const_t, X, Type}}) -> + display(File, ic_forms:get_line(X), + "Illegal constant type ~s of ~s", [pp(Type), ic_forms:get_id2(X)]); +format_error({error, _, File, {multiple_cases, X}}) -> + display(File, ic_forms:get_line(X), "multiple case values ~s", [pp(X)]); +format_error({error, _, File, {symtab_not_found, X}}) -> + display(File, ic_forms:get_line(X), "undeclared identifier ~s", [ic_forms:get_id2(X)]); +format_error({error, _, File, {preproc, Lines}}) -> + display(File, "preprocessor error: ~s", [hd(Lines)]); +format_error({error, _, File, {ic_pp_error, Lines}}) -> + display(File, "preprocessor error: ~s", [Lines]); +format_error({error, _, File, {illegal_float, Line}}) -> + display(File, Line, "illegal floating point number", []); +format_error({error, _, File, {bad_type_combination, E, V1, V2}}) -> + display(File, ic_forms:get_line(E), "incompatible types, ~p and ~p", [V1, V2]); +format_error({error, _, File, {bad_oneway_type, X, _TK}}) -> + display(File, ic_forms:get_line(X), "oneway operations must be declared void", []); +format_error({error, _, File, {inout_spec_for_c, X, Arg}}) -> + display(File, ic_forms:get_line(X), "inout parameter ~s specified in native c mode", + [Arg]); +format_error({error, _, File, {sequence_not_defined, X, Arg}}) -> + display(File, ic_forms:get_line(X), "sequence ~s not defined", [Arg]); +format_error({error, _, File, {illegal_typecode_for_c, Arg}}) -> + display(File, not_specified, "illegal typecode ~s used in native c mode", + [Arg]); +format_error({error, _, File, {name_not_found, N}}) -> + display(File, not_specified, "name ~s not found", [N]); +format_error({error, _, File, {illegal_typecode_for_c, Arg, N}}) -> + display(File, not_specified, "illegal typecode ~p used for ~p in native c mode", [Arg, N]); +format_error({error, _, File, {oneway_outparams, X}}) -> + display(File, ic_forms:get_line(X), + "oneway operations may not have out or inout parameters", []); +format_error({error, _, File, {oneway_raises, X}}) -> + display(File, ic_forms:get_line(X), "oneway operations may not raise exceptions", + []); +format_error({error, _, File, {bad_tk_match, T, TK, V}}) -> + display(File, ic_forms:get_line(T), + "value ~p does not match declared type ~s", [V, pp(TK)]); +format_error({error, _, File, {bad_scope_enum_case, ScopedId}}) -> + display(File, ic_forms:get_line(ScopedId), + "scoped enum identifiers not allowed as case (~s)", + [pp(ScopedId)]); +format_error({error, _, File, {bad_type, Expr, Op, _TypeList, V}}) -> + display(File, ic_forms:get_line(Expr), + "parameter value ~p to ~s is of illegal type", [V, pp(Op)]); +format_error({error, _, File, {bad_case_type, TK, X, Val}}) -> + display(File, ic_forms:get_line(X), + "case value ~s does not match discriminator type ~s", + [case_pp(X, Val), pp(TK)]); +format_error({error, _, File, {tk_not_found, X}}) -> + display(File, ic_forms:get_line(X), "undeclared identifier ~s", [pp(X)]); +%%% New format_errors +format_error({error, _, File, {bad_fixed, Format, Args, Line}}) -> + display(File, Line, Format, Args); +format_error({error, _, File, {illegal_switch_t, Arg, _N}}) -> + display(File, ic_forms:get_line(Arg), "illegal switch", []); +format_error({error, _, File, {inherit_resolve, Arg, N}}) -> + display(File, ic_forms:get_line(Arg), "cannot resolve ~s", [N]); +format_error({error, _, File, {bad_escape_character, Line, Char}}) -> + display(File, Line, "bad escape character \"~c\"", [Char]); +format_error({error, _, File, {pragma_code_opt_bad_option_list, Line}}) -> + display(File, Line, "bad option list on pragma \"CODEOPT\"", []); +format_error({error, _, File, {bad_string, Line}}) -> + display(File, Line, "bad string", []); +format_error({error, _, File, {create_dir, Path, Reason}}) -> + display(File, not_specified, "couldn't create directory ~p due to ~p", [Path, Reason]); +format_error({error, _, File, {open_file, Path, Reason}}) -> + display(File, not_specified, "couldn't open ~p due to ~p", [Path, Reason]); +format_error({error, _, File, {plain_error_string, ErrString}}) -> + display(File, not_specified, "~s", [ErrString]); +format_error({error, _, File, {plain_error_string, T, ErrString}}) -> + display(File, ic_forms:get_line(T), "~s", [ErrString]); +format_error({error, _, File, {ErrString, Line}}) -> + display(File, Line, ErrString, []). + + +%% Warnings +print_warn(G, Warn) -> + case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2)} of + {true, _} -> ok; + {_, true} -> ok; + _ -> format_warn(Warn) + end. + +format_warn({warn, _, File, {ic_pp_warning, Lines}}) -> + display(File, "preprocessor warning: ~s", [Lines]); +format_warn({warn, _, _File, {cfg_open, _Reason, File}}) -> + display(File, "warning: could not open file: ~p", [File]); +format_warn({warn, _, _File, {cfg_read, File}}) -> + display(File, "warning: syntax error in configuration file", []); +format_warn({warn, _, File, {multi_modules, Id}}) -> + display(File, ic_forms:get_line(Id), "warning: multiple modules in file", []); +format_warn({warn, _, File, {illegal_opt, Opt}}) -> + display(File, "warning: unrecognised option: ~p", [Opt]); +format_warn({warn, _, File, {nested_mod, Id}}) -> + display(File, ic_forms:get_line(Id), "warning: nested module: ~s", [ic_forms:get_id(Id)]); +format_warn({warn, _, File, {inherit_name_shadow, {Orig, Item}, + {Base, NewItem}}}) -> + display(File, ic_forms:get_line(Item), + "warning: ~s shadows ~s", [pp([ic_forms:get_id2(Item) | Orig]), + pp([ic_forms:get_id2(NewItem) | Base])]); +format_warn({warn, _, File, {internal_307, X, Y}}) -> + %% If global Scope variable is not [] at top level constant + display(File, ic_forms:get_line(X), "warning: internal 307: ~p ~p", [X, Y]); +format_warn({warn, _, File, {WarnString, Line}}) -> + display(File, Line, WarnString, []). + +%% Display an error or warning +display(File, not_specified, F, A) -> + io:format("~p : ~s~n", [File, io_lib:format(F, A)]); +display(File, Line, F, A) -> + io:format("~p on line ~p: ~s~n", [File, Line, io_lib:format(F, A)]). +display(File, F, A) -> + io:format("~p: ~s~n", [File, io_lib:format(F, A)]). + + + +%%format_warn2(G, WarnStr) -> +%% case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2), +%% ic_options:get_opt(G, nowarn)} of +%% {false, false, false} -> +%% io:format("~p: warning: ~s~n", [ic_genobj:idlfile(G), WarnStr]); +%% _ -> ok +%% end. + +%%format_warn2(G, Line, WarnStr) -> +%% case {ic_options:get_opt(G, silent), ic_options:get_opt(G, silent2), +%% ic_options:get_opt(G, nowarn)} of +%% {false, false, false} -> +%% io:format("~p on line ~p: warning: ~s~n", +%% [ic_genobj:idlfile(G), Line, WarnStr]); +%% _ -> ok +%% end. + + + + +%% pretty print various stuff + +pp({tk_string, _}) -> "string"; +pp({tk_wstring, _}) -> "wstring"; +pp(tk_long) -> "long"; +pp(tk_short) -> "short"; +pp(tk_ushort) -> "unsigned short"; +pp(tk_ulong) -> "unsigned long"; +pp(tk_float) -> "float"; +pp(tk_double) -> "double"; +pp(tk_boolean) -> "boolean"; +pp(tk_char) -> "char"; +pp(tk_wchar) -> "wchar"; +pp(tk_octet) -> "octet"; +pp(tk_null) -> "null"; +pp(tk_void) -> "void"; +pp(tk_any) -> "any"; +pp({tk_fixed, _, _}) -> "fixed"; +pp({tk_objref, _, _}) -> "object reference"; +pp(rshift) -> ">>"; +pp(lshift) -> "<<"; +pp(X) when element(1, X) == tk_enum -> "enum"; +pp(X) when is_record(X, scoped_id) -> ic_util:to_colon(X); +pp(X) when element(1, X) == '' -> ic_forms:get_id(X); +pp(X) when is_list(X) andalso is_list(hd(X)) -> ic_util:to_colon(X); +pp({_, Num, Beef}) when is_integer(Num) -> Beef; +pp({Beef, Num}) when is_integer(Num) -> ic_util:to_list(Beef); +pp(X) -> ic_util:to_list(X). + +%% special treatment of case label names +case_pp(X, _Val) when is_record(X, scoped_id) -> pp(X); +case_pp(_X, Val) -> pp(Val). + + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- diff --git a/lib/ic/src/ic_fetch.erl b/lib/ic/src/ic_fetch.erl new file mode 100644 index 0000000..c1b140e --- /dev/null +++ b/lib/ic/src/ic_fetch.erl @@ -0,0 +1,388 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_fetch). + +-include("icforms.hrl"). + +-export([member2type/3]). + +-export([fetchTk/3, isArray/3, isBasicType/1, isBasicType/2, + isBasicType/3, isBasicTypeOrEterm/3, isEterm/3, isString/3, + isStruct/3, isUnion/3, name2type/2, searchIncludedTk/2, + searchInsideTks/2, searchTk/2, searchTk/3]). + +name2type(G, Name) -> + S = ic_genobj:tktab(G), + ScopedName = lists:reverse(string:tokens(Name,"_")), + InfoList = ets:lookup( S, ScopedName ), + filter( InfoList ). + + + +%% This is en overloaded function, +%% differs in input on unions +member2type(_G, X, I) when is_record(X, union)-> + Name = ic_forms:get_id2(I), + case lists:keysearch(Name,2,element(6,X#union.tk)) of + false -> + error; + {value,Rec} -> + fetchType(element(3,Rec)) + end; +member2type( G, SName, MName ) -> + + S = ic_genobj:tktab( G ), + SNList = lists:reverse(string:tokens(SName,"_")), + ScopedName = [MName | SNList], + InfoList = ets:lookup( S, ScopedName ), + + case filter( InfoList ) of + error -> + %% Try a little harder, seeking inside tktab + case lookup_member_type_in_tktab(S, ScopedName, MName) of + error -> + %% Check if this is the "return to return1" case + case MName of + "return1" -> + %% Do it all over again ! + ScopedName2 = ["return" | SNList], + InfoList2 = ets:lookup( S, ScopedName2 ), + case filter( InfoList2 ) of + error -> + %% Last resort: seek in pragma table + lookup_type_in_pragmatab(G, SName); + + Other -> + Other + end; + _ -> + %% Last resort: seek in pragma table + lookup_type_in_pragmatab(G, SName) + end; + Other -> + Other + end; + Other -> + Other + end. + + +lookup_member_type_in_tktab(S, ScopedName, MName) -> + case ets:match_object(S, {'_',member,{MName,'_'},nil}) of + [] -> + error; + [{_FullScopedName,member,{MName,TKInfo},nil}]-> + fetchType( TKInfo ); + List -> + lookup_member_type_in_tktab(List,ScopedName) + end. + +lookup_member_type_in_tktab([],_ScopedName) -> + error; +lookup_member_type_in_tktab([{FullScopedName,_,{_,TKInfo},_}|Rest],ScopedName) -> + case lists:reverse(string:tokens(ic_util:to_undersc(FullScopedName),"_")) of + ScopedName -> + fetchType(TKInfo); + _ -> + lookup_member_type_in_tktab(Rest,ScopedName) + end. + + +lookup_type_in_pragmatab(G, SName) -> + S = ic_genobj:pragmatab(G), + + %% Look locally first + case ets:match(S,{file_data_local,'_','_','$2','_','_',SName,'_','_'}) of + [] -> + %% No match, seek included + case ets:match(S,{file_data_included,'_','_','$2','_','_',SName,'_','_'}) of + + [] -> + error; + [[Type]] -> + io:format("1 Found(~p) : ~p~n",[SName,Type]), + Type + end; + + [[Type]] -> + io:format("2 Found(~p) : ~p~n",[SName,Type]), + Type + end. + + + + +filter( [] ) -> + error; +filter( [I | Is ] ) -> + case I of + { _, member, { _, TKINFO }, _ } -> + fetchType( TKINFO ); + + { _, struct, _, _ } -> + struct; + + { _, typedef, TKINFO, _ } -> + fetchType( TKINFO ); + + { _, module, _, _ } -> + module; + + { _, interface, _, _ } -> + interface; + + { _, op, _, _ } -> + op; + + { _,enum, _, _ } -> + enum; + + { _, spellcheck } -> + filter( Is ); + + _ -> + error + end. + + +fetchType( { tk_sequence, _, _ } ) -> + sequence; +fetchType( { tk_array, _, _ } ) -> + array; +fetchType( { tk_struct, _, _, _} ) -> + struct; +fetchType( { tk_string, _} ) -> + string; +fetchType( tk_short ) -> + short; +fetchType( tk_long ) -> + long; +fetchType( tk_ushort ) -> + ushort; +fetchType( tk_ulong ) -> + ulong; +fetchType( tk_float ) -> + float; +fetchType( tk_double ) -> + double; +fetchType( tk_boolean ) -> + boolean; +fetchType( tk_char ) -> + char; +fetchType( tk_octet ) -> + octet; +fetchType( { tk_enum, _, _, _ } ) -> + enum; +fetchType( { tk_union, _, _, _, _, _ } ) -> + union; +fetchType( tk_any ) -> + any; +fetchType( _ ) -> + error. + +isBasicTypeOrEterm(G, N, S) -> + case isBasicType(G, N, S) of + true -> + true; + false -> + isEterm(G, N, S) + end. + + +isEterm(G, N, S) when element(1, S) == scoped_id -> + {FullScopedName, _, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + case ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)) of + "erlang_term" -> + true; + "ETERM*" -> + true; + _X -> + false + end; +isEterm(_G, _Ni, _X) -> + false. + +isBasicType(G, N, S) when element(1, S) == scoped_id -> + {_, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + isBasicType(fetchType(TK)); +isBasicType(_G, _N, {string, _} ) -> + false; +isBasicType(_G, _N, {Type, _} ) -> + isBasicType(Type). + + +isBasicType(G, Name) -> + isBasicType(name2type(G, Name )). + + +isBasicType(Type) -> + lists:member(Type, + [tk_short,short, + tk_long,long, + tk_ushort,ushort, + tk_ulong,ulong, + tk_float,float, + tk_double,double, + tk_boolean,boolean, + tk_char,char, + tk_octet,octet]). + + + +isString(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_string',_}, _} -> + true; + _ -> + false + end; +isString(_G, _N, T) when is_record(T, string) -> + true; +isString(_G, _N, _Other) -> + false. + + +isArray(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_array', _, _}, _} -> + true; + _ -> + false + end; +isArray(_G, _N, T) when is_record(T, array) -> + true; +isArray(_G, _N, _Other) -> + false. + + + +isStruct(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_struct', _, _, _}, _} -> + true; + _ -> + false + end; +isStruct(_G, _N, T) when is_record(T, struct) -> + true; +isStruct(_G, _N, _Other) -> + false. + + + +isUnion(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_union', _, _, _,_,_}, _} -> + true; + _Other -> + false + end; +isUnion(_G, _N, T) when is_record(T, union) -> + true; +isUnion(_G, _N, _Other) -> + false. + + + +%%------------------------------------------------------------ +%% +%% Always fetchs TK of a record. +%% +%%------------------------------------------------------------ +fetchTk(G,N,X) -> + case ic_forms:get_tk(X) of + undefined -> + searchTk(G,ictk:get_IR_ID(G, N, X)); + TK -> + TK + end. + + +%%------------------------------------------------------------ +%% +%% seek type code when not accessible by get_tk/1 +%% +%%------------------------------------------------------------ +searchTk(G,IR_ID) -> + S = ic_genobj:tktab(G), + case catch searchTk(S,IR_ID,typedef) of + {value,TK} -> + TK; + _ -> %% false / exit + case catch searchTk(S,IR_ID,struct) of + {value,TK} -> + TK; + _ -> %% false / exit + case catch searchTk(S,IR_ID,union) of + {value,TK} -> + TK; + _ -> + undefined + end + end + end. + + +searchTk(S,IR_ID,Type) -> + L = lists:flatten(ets:match(S,{'_',Type,'$1','_'})), + case lists:keysearch(IR_ID,2,L) of + {value,TK} -> + {value,TK}; + false -> + searchInsideTks(L,IR_ID) + end. + + +searchInsideTks([],_IR_ID) -> + false; +searchInsideTks([{tk_array,TK,_}|Xs],IR_ID) -> + case searchIncludedTk(TK,IR_ID) of + {value,TK} -> + {value,TK}; + false -> + searchInsideTks(Xs,IR_ID) + end. + + +searchIncludedTk({tk_array,TK,_},IR_ID) -> + searchIncludedTk(TK,IR_ID); +searchIncludedTk({tk_sequence,TK,_},IR_ID) -> + searchIncludedTk(TK,IR_ID); +searchIncludedTk(TK,_IR_ID) when is_atom(TK) -> + false; +searchIncludedTk(TK,IR_ID) -> + case element(2,TK) == IR_ID of + true -> + {value,TK}; + false -> + false + end. + + + + + + + + + + + diff --git a/lib/ic/src/ic_file.erl b/lib/ic/src/ic_file.erl new file mode 100644 index 0000000..6a99d6c --- /dev/null +++ b/lib/ic/src/ic_file.erl @@ -0,0 +1,447 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_file). + +-include_lib("ic/src/ic.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([filename_push/4, filename_pop/2, open/2, close/1, remove_ext/1, join/2, + add_dot_erl/1, add_dot_hrl/1, add_dot_c/1, add_dot_h/1, add_dot_java/1, + add_dot_idl/1, javaInterfaceFilePush/3, javaInterfaceFilePop/1, + createDirectory/2, createJavaDirectory/2, open_java_file/3]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: filename_push +%% +%% Pushes a file name, can also push ignore in which case means that +%% no files should ever be opened at this scope. Note that empty in +%% the file descriptor entries means that the file just isn't open +%% yet. +%%----------------------------------------------------------------- +filename_push(G, _N, ignore, _) -> + G#genobj{stubfile=[ignore | G#genobj.stubfile], + stubfiled=[ignore | G#genobj.stubfiled], + skelfile=[ignore | G#genobj.skelfile], + skelfiled=[ignore | G#genobj.skelfiled], + includefile=[ignore | G#genobj.includefile], + includefiled=[ignore | G#genobj.includefiled]}; + +filename_push(G, N, X, Lang) -> + Fullname = [ic_forms:get_id2(X) | N], + EName0 = ic_util:to_undersc(Fullname), + + DoGen = ic_genobj:do_gen(G), + + ImplName = find_impl_name(G, Fullname), + + {StubName, EName} = + case Lang of + erlang -> + {join(ic_options:get_opt(G, stubdir), add_dot_erl(EName0)), + EName0}; + erlang_template -> + {join(ic_options:get_opt(G, stubdir), add_dot_erl(ImplName)), + ImplName}; + c -> + {join(ic_options:get_opt(G, stubdir), add_dot_c(EName0)), + EName0}; + c_server -> + {join(ic_options:get_opt(G, stubdir), add_dot_c(EName0++"__s")), + EName0}; + erlang_template_no_gen -> + {undefined, EName0}; + erlang_no_stub -> + {undefined, EName0}; + c_no_stub -> + {undefined, EName0}; + c_server_no_stub -> + {undefined, EName0} + end, + Stub = if DoGen==true -> + case StubName of + undefined -> + ignore; + _ -> + ic_codegen:emit_stub_head(G, open(empty, StubName), EName, Lang) + end; + true -> ignore end, + + HrlName = case Lang of + erlang_template -> + ignore; + erlang_template_no_gen -> + ignore; + erlang -> + ?ifopt2(G, gen_hrl, + join(ic_options:get_opt(G, stubdir), add_dot_hrl(EName)), + ignore); + c -> + ?ifopt2(G, gen_hrl, + join(ic_options:get_opt(G, stubdir), add_dot_h(EName)), + ignore); + c_server -> + ?ifopt2(G, gen_hrl, + join(ic_options:get_opt(G, stubdir), + add_dot_h(EName++"__s")), + ignore); + erlang_no_stub -> + ?ifopt2(G, gen_hrl, + join(ic_options:get_opt(G, stubdir), add_dot_hrl(EName)), + ignore); + c_no_stub -> + ?ifopt2(G, gen_hrl, + join(ic_options:get_opt(G, stubdir), add_dot_h(EName)), + ignore); + c_server_no_stub -> + ?ifopt2(G, gen_hrl, + join(ic_options:get_opt(G, stubdir), + add_dot_h(EName++"__s")), + ignore) + end, + Hrl = if DoGen==true -> + case Lang of + erlang_template -> + ignore; + erlang_template_no_gen -> + ignore; + erlang_no_stub -> + ic_codegen:emit_hrl_head(G, open(empty, HrlName), + EName, erlang); + c_no_stub -> + ic_codegen:emit_hrl_head(G, open(empty, HrlName), + EName, c); + c_server_no_stub -> + ic_codegen:emit_hrl_head(G, open(empty, HrlName), + EName, c_server); + _ -> + ic_codegen:emit_hrl_head(G, open(empty, HrlName), + EName, Lang) + end; + true -> ignore end, + + G#genobj{impl=ImplName, + stubfile=[StubName | G#genobj.stubfile], + stubfiled=[Stub | G#genobj.stubfiled], + includefile=[HrlName | G#genobj.includefile], + includefiled=[Hrl | G#genobj.includefiled]}. + +%%----------------------------------------------------------------- +%% Func: join/2 +%% +%% Special version of filename join. +%%----------------------------------------------------------------- +join([], File) -> + File; +join(Path, File) -> + filename:join(Path, File). + + +%%----------------------------------------------------------------- +%% Func: filename_pop/2 +%%----------------------------------------------------------------- +filename_pop(G, Lang) -> +%% io:format("Popped file names: ~p~n", [hd(G#genobj.stubfile)]), +%% case is_skelfile_open(G) of +%% true -> emit_skel_footer(G); +%% false -> ok end, +%% close(hd(G#genobj.skelfiled)), + close(hd(G#genobj.stubfiled)), + ic_codegen:emit_hrl_foot(G, Lang), + close(hd(G#genobj.includefiled)), + G#genobj{stubfile=tl(G#genobj.stubfile), + stubfiled=tl(G#genobj.stubfiled), +%% skelfile=tl(G#genobj.skelfile), +%% skelfiled=tl(G#genobj.skelfiled), + includefile=tl(G#genobj.includefile), + includefiled=tl(G#genobj.includefiled)}. + + + +%%----------------------------------------------------------------- +%% Func: javaInterfaceFilePush/3 +%%----------------------------------------------------------------- +javaInterfaceFilePush(G, N, X) -> + Name = ic_forms:get_java_id(X), + {InterfaceFd, InterfaceFileName} = open_java_file(G, N, Name), + + StubClassName = "_" ++ Name ++ "Stub", + {StubFd, StubFileName} = open_java_file(G, N, StubClassName), + + SkelClassName = "_" ++ Name ++ "ImplBase", + {SkelFd, SkelFileName} = open_java_file(G, N, SkelClassName), + + HelperClassName = Name ++ "Helper", + {HelperFd, HelperFileName} = open_java_file(G, N, HelperClassName), + + HolderClassName = Name ++ "Holder", + {HolderFd, HolderFileName} = open_java_file(G, N, HolderClassName), + + G#genobj{ + interfacefile=[InterfaceFileName | G#genobj.interfacefile], + interfacefiled=[InterfaceFd | G#genobj.interfacefiled], + stubfile=[StubFileName | G#genobj.stubfile], + stubfiled=[StubFd | G#genobj.stubfiled], + skelfile=[SkelFileName | G#genobj.skelfile], + skelfiled=[SkelFd | G#genobj.skelfiled], + helperfile=[HelperFileName | G#genobj.helperfile], + helperfiled=[HelperFd | G#genobj.helperfiled], + holderfile=[HolderFileName | G#genobj.holderfile], + holderfiled=[HolderFd | G#genobj.holderfiled]}. + + + + + +%%----------------------------------------------------------------- +%% Func: javaInterfaceFilePop/1 +%%----------------------------------------------------------------- +javaInterfaceFilePop(G) -> + close(hd(G#genobj.interfacefiled)), + close(hd(G#genobj.stubfiled)), + close(hd(G#genobj.skelfiled)), + close(hd(G#genobj.helperfiled)), + close(hd(G#genobj.holderfiled)), + G#genobj{ + interfacefile=tl(G#genobj.interfacefile), + interfacefiled=tl(G#genobj.interfacefiled), + stubfile=tl(G#genobj.stubfile), + stubfiled=tl(G#genobj.stubfiled), + skelfile=tl(G#genobj.skelfile), + skelfiled=tl(G#genobj.skelfiled), + helperfile=tl(G#genobj.helperfile), + helperfiled=tl(G#genobj.helperfiled), + holderfile=tl(G#genobj.holderfile), + holderfiled=tl(G#genobj.holderfiled)}. + +%%----------------------------------------------------------------- +%% Func: createDirectory/2 +%%----------------------------------------------------------------- +createDirectory(_G, []) -> + ok; +createDirectory(G, Scope) -> + Path = ic_file:join(ic_options:get_opt(G, stubdir), ic_pragma:slashify(Scope)), + case file:make_dir(Path) of + ok -> + ok; + {error, eexist} -> + ok; + {error, Reason} -> + ic_error:fatal_error(G, {create_dir, Path, Reason}) + end. + + +%%----------------------------------------------------------------- +%% Func: createJavaDirectory/2 +%%----------------------------------------------------------------- +createJavaDirectory(_G, []) -> + ok; +createJavaDirectory(G, Scope) -> + JavaScope = ic_util:adjustScopeToJava(G,Scope), + Path = ic_file:join(ic_options:get_opt(G, stubdir), ic_pragma:slashify(JavaScope)), + case file:make_dir(Path) of + ok -> + ok; + {error, eexist} -> + ok; + {error, Reason} -> + ic_error:fatal_error(G, {create_dir, Path, Reason}) + end. + + + + +%%----------------------------------------------------------------- +%% Func: createJavaFileName/3 +%%----------------------------------------------------------------- +createJavaFileName(G, Scope, FName) -> + JavaScope = ic_util:adjustScopeToJava(G,Scope), + join(ic_options:get_opt(G, stubdir), + ic_pragma:slashify([FName++".java"|JavaScope])). + +%%----------------------------------------------------------------- +%% Func: close/2 (used to be file_close) +%%----------------------------------------------------------------- +close(empty) -> ok; +close(ignore) -> ok; +close(Fd) -> + file:close(Fd). + +%%----------------------------------------------------------------- +%% Func: remove_ext/1 +%%----------------------------------------------------------------- +remove_ext(File) -> + filename:rootname(filename:basename(File)). + +%%----------------------------------------------------------------- +%% Func: open/2 (used to be file_open) +%%----------------------------------------------------------------- +open(_, ignore) -> ignore; +open(empty, Name) -> + case file:open(Name, [raw, binary, write]) of + {ok, Fd} -> + Fd; + {error, Reason} -> + exit({error, Reason}) +%% ic_error:fatal_error(G, {open_file, Name, Reason}) + end. + +%%----------------------------------------------------------------- +%% Func: open_java_file/3 +%%----------------------------------------------------------------- +open_java_file(G, N, Name) -> + createJavaDirectory(G, N), + FName = createJavaFileName(G, N, Name), + case file:open(FName, [raw, binary, write]) of + {ok, Fd} -> + ic_codegen:emit_stub_head(G, Fd, Name, java), + emit_package(G, N, Fd), + {Fd, FName}; + {error, Reason} -> + ic_error:fatal_error(G, {open_file, FName, Reason}) + end. + +%%----------------------------------------------------------------- +%% Func: emit_package/3 +%%----------------------------------------------------------------- +emit_package(_G, [], _Fd) -> + ok; +emit_package(G, N, Fd) -> + ic_codegen:emit(Fd, "package ~s;\n", [ic_util:to_dot(G,N)]), + ic_codegen:nl(Fd). + +%%----------------------------------------------------------------- +%% Func: add_dot_erl/1 +%%----------------------------------------------------------------- +add_dot_erl(F) -> + File = ic_util:to_list(F), + F2 = lists:reverse(File), + case F2 of + [$l, $r, $e, $. | _Rest] -> + File; + _ -> + File ++ ".erl" + end. + +%%----------------------------------------------------------------- +%% Func: add_dot_hrl/1 +%%----------------------------------------------------------------- +add_dot_hrl(F) -> + File = ic_util:to_list(F), + F2 = lists:reverse(File), + case F2 of + [$l, $r, $h, $. | _Rest] -> + File; + _ -> + File ++ ".hrl" + end. + +%%----------------------------------------------------------------- +%% Func: add_dot_c/1 +%%----------------------------------------------------------------- +add_dot_c(F) -> + File = ic_util:to_list(F), + F2 = lists:reverse(File), + case F2 of + [$c, $. | _Rest] -> + File; + _ -> + File ++ ".c" + end. + +%%----------------------------------------------------------------- +%% Func: add_dot_h/1 +%%----------------------------------------------------------------- +add_dot_h(F) -> + File = ic_util:to_list(F), + F2 = lists:reverse(File), + case F2 of + [$h, $. | _Rest] -> + File; + _ -> + File ++ ".h" + end. + +%%----------------------------------------------------------------- +%% Func: add_dot_java/1 +%%----------------------------------------------------------------- +add_dot_java(F) -> + File = ic_util:to_list(F), + F2 = lists:reverse(File), + case F2 of + [$a, $v, $a, $j, $. | _Rest] -> + File; + _ -> + File ++ ".java" + end. + +%%----------------------------------------------------------------- +%% Func: add_dot_idl/1 +%%----------------------------------------------------------------- +add_dot_idl(F) -> + File = ic_util:to_list(F), + F2 = lists:reverse(File), + case F2 of + [$l, $d, $i, $. | _Rest] -> + File; + _ -> + File ++ ".idl" + end. + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% +%% File handling stuff +%% +%% +%% Shall open a file for writing. Also sets up the generator with +%% usefull bits of information +%% +%%-------------------------------------------------------------------- +find_impl_name(G, Name) -> + N1 = ic_util:to_colon(Name), + N2 = ic_util:to_undersc(Name), + case {ic_options:get_opt(G, {impl, N1}), + ic_options:get_opt(G, {impl, N2})} of + {false, false} -> + case {ic_options:get_opt(G, {impl, "::"++N1}), + ic_options:get_opt(G, {impl, N2})} of + {false, false} -> N2 ++ "_impl"; + {X, _Y} when X /= false -> ic_util:to_list(X); + {_X, Y} when Y /= false -> ic_util:to_list(Y) + end; + {X, _Y} when X /= false -> ic_util:to_list(X); + {_X, Y} when Y /= false -> ic_util:to_list(Y) + end. diff --git a/lib/ic/src/ic_forms.erl b/lib/ic/src/ic_forms.erl new file mode 100644 index 0000000..7409dde --- /dev/null +++ b/lib/ic/src/ic_forms.erl @@ -0,0 +1,437 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_forms). + +-include_lib("ic/src/ic.hrl"). +-include_lib("ic/src/icforms.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([get_id/1, get_id2/1, get_java_id/1, get_line/1]). +-export([get_type_code/3, search_tk/2, clean_up_scope/1]). +-export([get_body/1, get_dimension/1, get_idlist/1, get_type/1, get_tk/1, is_oneway/1]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% +%% Generation go-get utilities +%% +%% Feeble attempt at virtual funtions. +%% +%%-------------------------------------------------------------------- + +get_dimension(X) when is_record(X, array) -> + [element(3, L) || L <- X#array.size]. + +%% Should find the name hidden in constructs +get_id( [{'', _LineNo, Id}] ) -> Id; +get_id( {'', _LineNo, Id} ) -> Id; +get_id(Id) when is_list(Id) andalso is_integer(hd(Id)) -> Id; +get_id(X) when is_record(X, scoped_id) -> X#scoped_id.id; +get_id(X) when is_record(X, array) -> get_id(X#array.id); +get_id( {'', _LineNo, Id} ) -> Id; +get_id( {'', _LineNo, Id} ) -> Id. + +get_line([{'', LineNo, _Id}]) -> LineNo; +get_line({'', LineNo, _Id}) -> LineNo; +get_line(X) when is_record(X, scoped_id) -> X#scoped_id.line; +get_line(X) when is_record(X, module) -> get_line(X#module.id); +get_line(X) when is_record(X, interface) -> get_line(X#interface.id); +get_line(X) when is_record(X, forward) -> get_line(X#forward.id); +get_line(X) when is_record(X, const) -> get_line(X#const.id); +get_line(X) when is_record(X, typedef) -> get_line(X#typedef.id); +get_line(X) when is_record(X, struct) -> get_line(X#struct.id); +get_line(X) when is_record(X, member) -> get_line(X#member.id); +get_line(X) when is_record(X, union) -> get_line(X#union.id); +get_line(X) when is_record(X, case_dcl) -> get_line(X#case_dcl.id); +get_line(X) when is_record(X, enum) -> get_line(X#enum.id); +get_line(X) when is_record(X, enumerator) -> get_line(X#enumerator.id); +get_line(X) when is_record(X, array) -> get_line(X#array.id); +get_line(X) when is_record(X, attr) -> get_line(X#attr.id); +get_line(X) when is_record(X, except) -> get_line(X#except.id); +get_line(X) when is_record(X, op) -> get_line(X#op.id); +get_line(X) when is_record(X, param) -> get_line(X#param.id); +get_line(X) when is_record(X, id_of) -> get_line(X#id_of.id); + +get_line({'or', T1, _T2}) -> get_line(T1); +get_line({'xor', T1, _T2}) -> get_line(T1); +get_line({'and', T1, _T2}) -> get_line(T1); +get_line({'rshift', T1, _T2}) ->get_line(T1); +get_line({'lshift', T1, _T2}) ->get_line(T1); +get_line({'+', T1, _T2}) -> get_line(T1); +get_line({'-', T1, _T2}) -> get_line(T1); +get_line({'*', T1, _T2}) -> get_line(T1); +get_line({'/', T1, _T2}) -> get_line(T1); +get_line({'%', T1, _T2}) -> get_line(T1); +get_line({{'-', _Line}, T}) -> get_line(T); +get_line({{'+', _Line}, T}) -> get_line(T); +get_line({{'~', _Line}, T}) -> get_line(T); +get_line({_, X, _}) when is_integer(X) -> X; +get_line({_A, N}) when is_integer(N) -> N; +get_line(_) -> -1. + + +%%-------------------------------------------------------------------- +%% +%% High level get functions. +%% +%% These are highly polymorphic functions that will get the id, +%% body and type of a record (those records output from the +%% parser). +%% +%% NOTE: The typedef node (the alias) is special, because the type +%% field is a type definition and therefore considered a body, +%% and the type of a typedef is its name. +%% + +get_id2(X) when is_record(X, module) -> get_id(X#module.id); +get_id2(X) when is_record(X, interface) -> get_id(X#interface.id); +get_id2(X) when is_record(X, forward) -> get_id(X#forward.id); +get_id2(X) when is_record(X, const) -> get_id(X#const.id); +get_id2(X) when is_record(X, typedef) -> get_id(hd(X#typedef.id)); +get_id2(X) when is_record(X, struct) -> get_id(X#struct.id); +get_id2(X) when is_record(X, member) -> get_id(hd(X#member.id)); +get_id2(X) when is_record(X, union) -> get_id(X#union.id); +get_id2(X) when is_record(X, case_dcl) -> get_id(X#case_dcl.id); +get_id2(X) when is_record(X, enum) -> get_id(X#enum.id); +get_id2(X) when is_record(X, enumerator) -> get_id(X#enumerator.id); +get_id2(X) when is_record(X, array) -> get_id(X#array.id); +get_id2(X) when is_record(X, attr) -> get_id(X#attr.id); +get_id2(X) when is_record(X, except) -> get_id(X#except.id); +get_id2(X) when is_record(X, op) -> get_id(X#op.id); +get_id2(X) when is_record(X, param) -> get_id(X#param.id); +get_id2(X) when is_record(X, type_dcl) -> get_id2(X#type_dcl.type); +get_id2(X) when is_record(X, scoped_id) -> ic_symtab:scoped_id_strip(X); +get_id2(X) when is_record(X, preproc) -> get_id(X#preproc.id); +get_id2(X) when is_record(X, id_of) -> get_id2(X#id_of.id); +get_id2(X) -> get_id(X). + +get_body(X) when is_record(X, module) -> X#module.body; +get_body(X) when is_record(X, interface) -> X#interface.body; +get_body(X) when is_record(X, struct) -> X#struct.body; +get_body(X) when is_record(X, union) -> X#union.body; +get_body(X) when is_record(X, enum) -> X#enum.body; +get_body(X) when is_record(X, typedef) -> X#typedef.type; % See Note +get_body(X) when is_record(X, except) -> X#except.body. + +get_type(X) when is_record(X, const) -> X#const.type; +get_type(X) when is_record(X, type_dcl) -> X#type_dcl.type; +get_type(X) when is_record(X, typedef) -> X#typedef.id; % See Note +get_type(X) when is_record(X, member) -> X#member.type; +get_type(X) when is_record(X, union) -> X#union.type; +get_type(X) when is_record(X, case_dcl) -> X#case_dcl.type; +get_type(X) when is_record(X, sequence) -> X#sequence.type; +get_type(X) when is_record(X, attr) -> X#attr.type; +get_type(X) when is_record(X, op) -> X#op.type; +get_type(X) when is_record(X, param) -> X#param.type. +%%get_type(X) when record(X, id_of) -> get_type(X#id_of.type). + +%% Temporary place +get_tk(X) when is_record(X, interface) -> X#interface.tk; +get_tk(X) when is_record(X, forward) -> X#forward.tk; +get_tk(X) when is_record(X, const) -> X#const.tk; +get_tk(X) when is_record(X, type_dcl) -> X#type_dcl.tk; +get_tk(X) when is_record(X, typedef) -> X#typedef.tk; +get_tk(X) when is_record(X, struct) -> X#struct.tk; +get_tk(X) when is_record(X, union) -> X#union.tk; +get_tk(X) when is_record(X, enum) -> X#enum.tk; +get_tk(X) when is_record(X, attr) -> X#attr.tk; +get_tk(X) when is_record(X, except) -> X#except.tk; +get_tk(X) when is_record(X, op) -> X#op.tk; +get_tk(X) when is_record(X, id_of) -> X#id_of.tk; +get_tk(X) when is_record(X, param) -> X#param.tk. + + +%% Get idlist returns the list of identifiers found in typedefs, case +%% dcls etc. +get_idlist(X) when is_record(X, typedef) -> X#typedef.id; +get_idlist(X) when is_record(X, member) -> X#member.id; +get_idlist(X) when is_record(X, case_dcl) -> X#case_dcl.label; +get_idlist(X) when is_record(X, attr) -> X#attr.id. + + +is_oneway(X) when is_record(X, op) -> + case X#op.oneway of + {oneway, _} -> true; + _ -> false + end; +is_oneway(_X) -> false. + + + + + +%%------------------------------------------------------------ +%% +%% Analyze the record and seek the correct type code. +%% +%% NOT equal to get_tk, this will always succed ! +%% +%%------------------------------------------------------------ +get_type_code(G, N, X) -> + case get_type_code2(G, N, X) of + undefined -> + %% Remove "Package" suffix from scope + N2 = clean_up_scope(N), + search_tk(G,ictk:get_IR_ID(G, N2, X)); + TC -> + TC + end. + +clean_up_scope(N) -> + clean_up_scope(N,[]). + +clean_up_scope([],N) -> + lists:reverse(N); +clean_up_scope([N|Ns],Found) -> + case lists:suffix("Package",N) of + true -> + Len = length(N), + case Len > 7 of + true -> + N2 = string:substr(N,1,Len-7), + clean_up_scope(Ns,[N2|Found]); + false -> + clean_up_scope(Ns,[N|Found]) + end; + false -> + clean_up_scope(Ns,[N|Found]) + end. + + +get_type_code2(_, _, X) when is_record(X, interface) -> X#interface.tk; +get_type_code2(_, _, X) when is_record(X, forward) -> X#forward.tk; +get_type_code2(_, _, X) when is_record(X, const) -> X#const.tk; +get_type_code2(_, _, X) when is_record(X, type_dcl) -> X#type_dcl.tk; +get_type_code2(_, _, X) when is_record(X, typedef) -> + Id = X#typedef.id, + ET = X#typedef.tk, + if is_list(Id) -> + Head = hd(Id), + if is_tuple(Head) -> + case element(1,Head) of + array -> + get_array_tc(ET, element(3,Head)); + _ -> + ET + end; + true -> + ET + end; + true -> + ET + end; + +get_type_code2(_, _, X) when is_record(X, struct) -> X#struct.tk; +get_type_code2(_, _, X) when is_record(X, union) -> X#union.tk; +get_type_code2(_, _, X) when is_record(X, enum) -> X#enum.tk; +get_type_code2(_, _, X) when is_record(X, attr) -> X#attr.tk; +get_type_code2(_, _, X) when is_record(X, except) -> X#except.tk; +get_type_code2(_, _, X) when is_record(X, op) -> X#op.tk; +get_type_code2(_, _, X) when is_record(X, id_of) -> X#id_of.tk; +get_type_code2(_, _, X) when is_record(X, param) -> X#param.tk; + +get_type_code2(G, N, X) when is_record(X, member) -> + ET = get_type_code(G, N, element(2,X)), + Id = element(3,X), + + if is_list(Id) -> + Head = hd(Id), + if is_tuple(Head) -> + case element(1,Head) of + array -> + get_array_tc(ET, element(3,Head)); + _ -> + ET + end; + true -> + ET + end; + true -> + ET + end; + +get_type_code2(G, N, X) when is_record(X, scoped_id) -> + element(3,ic_symtab:get_full_scoped_name(G, N, X)); + +get_type_code2(G, N, X) when is_record(X, sequence) -> + if is_tuple(X#sequence.length) -> + {tk_sequence, + get_type_code(G, N, X#sequence.type), + list_to_integer(element(3,X#sequence.length))}; + true -> + {tk_sequence, + get_type_code(G, N, X#sequence.type), + X#sequence.length} + end; + +get_type_code2(_G, _N, {unsigned,{short,_}}) -> tk_ushort; + +get_type_code2(_G, _N, {unsigned,{long,_}}) -> tk_ulong; + +get_type_code2(_G, _N, {unsigned,{'long long',_}}) -> tk_ulonglong; + +get_type_code2(_G, _N, X) when is_record(X, fixed) -> + {tk_fixed, X#fixed.digits, X#fixed.scale}; + +get_type_code2(G, N, {X,_}) -> + get_type_code2(G, N, X); + +get_type_code2(_, _, short) -> tk_short; +get_type_code2(_, _, long) -> tk_long; +get_type_code2(_, _, 'long long') -> tk_longlong; +get_type_code2(_, _, float) -> tk_float; +get_type_code2(_, _, double) -> tk_double; +get_type_code2(_, _, boolean) -> tk_boolean; +get_type_code2(_, _, char) -> tk_char; +get_type_code2(_, _, wchar) -> tk_wchar; +get_type_code2(_, _, octet) -> tk_octet; +get_type_code2(_, _, string) -> tk_string; +get_type_code2(_, _, wstring) -> tk_wstring; +get_type_code2(_, _, any) -> tk_any. + + +get_array_tc(ET, []) -> + ET; +get_array_tc(ET, [L|Ls]) -> + {tk_array, + get_array_tc(ET,Ls), + list_to_integer(element(3,L))}. + + + + +%%------------------------------------------------------------ +%% +%% seek type code when not accessible by ic_forms:get_tk/1 ( should be +%% a part of "do_gen" related functions later ) +%% +%%------------------------------------------------------------ +search_tk(G, IR_ID) -> + S = ic_genobj:tktab(G), + case catch search_tk(S,IR_ID,typedef) of + {value,TK} -> + TK; + _ -> %% false / exit + case catch search_tk(S,IR_ID,struct) of + {value,TK} -> + TK; + _ -> %% false / exit + case catch search_tk(S,IR_ID,union) of + {value,TK} -> + TK; + _ -> + undefined + end + end + end. + + +search_tk(S, IR_ID, Type) -> + L = lists:flatten(ets:match(S,{'_',Type,'$1','_'})), + case lists:keysearch(IR_ID,2,L) of + {value,TK} -> + {value,TK}; + false -> + search_inside_tks(L,IR_ID) + end. + + +search_inside_tks([],_IR_ID) -> + false; +search_inside_tks([{tk_array,TK,_}|Xs],IR_ID) -> + case search_included_tk(TK,IR_ID) of + {value,TK} -> + {value,TK}; + false -> + search_inside_tks(Xs,IR_ID) + end. + + +search_included_tk({tk_array,TK,_}, IR_ID) -> + search_included_tk(TK,IR_ID); +search_included_tk({tk_sequence,TK,_}, IR_ID) -> + search_included_tk(TK,IR_ID); +search_included_tk(TK, _IR_ID) when is_atom(TK) -> + false; +search_included_tk(TK, IR_ID) -> + case element(2,TK) == IR_ID of + true -> + {value,TK}; + false -> + false + end. + + + + +%% This is similar to get_id2 but in everything else +%% than a module it will generate an id prefixed +get_java_id(Id) when is_list(Id) -> + case java_keyword_coalition(Id) of + true -> + "_" ++ Id; + false -> + Id + end; +get_java_id(Id_atom) when is_atom(Id_atom) -> + Id = atom_to_list(Id_atom), + case java_keyword_coalition(Id) of + true -> + "_" ++ Id; + false -> + Id + end; +get_java_id(X) -> + Id = get_id2(X), + case java_keyword_coalition(Id) of + true -> + "_" ++ Id; + false -> + Id + end. + +java_keyword_coalition(Id) -> + lists:member(list_to_atom(Id), + [abstract, default, 'if', private, throw, boolean, + do, implements, protected, throws, break, + double, import, public, transient, byte, + else, instanceof, return, 'try', 'case', extends, + int, short, void, 'catch', final, interface, static, + volatile, char, finally, long, super, while, class, + float, native, switch, const, for, new, synchronized, + continue, goto, package, this, true, false]). + + + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- diff --git a/lib/ic/src/ic_genobj.erl b/lib/ic/src/ic_genobj.erl new file mode 100644 index 0000000..afb00ee --- /dev/null +++ b/lib/ic/src/ic_genobj.erl @@ -0,0 +1,244 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_genobj). + + +-include_lib("ic/src/ic.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([new/1, free_table_space/1, process_space/0]). +-export([skelfiled/1, stubfiled/1, hrlfiled/1, includefiled/1]). +-export([interfacefiled/1, helperfiled/1, holderfiled/1]). +-export([is_skelfile_open/1, is_stubfile_open/1, is_hrlfile_open/1]). +-export([include_file/1, include_file_stack/1]). +-export([push_file/2, pop_file/2, sys_file/2]). + +-export([skelscope/1, stubscope/1, impl/1, do_gen/1]). +-export([symtab/1, auxtab/1, tktab/1, pragmatab/1, optiontab/1, typedeftab/1]). +-export([idlfile/1, module/1, set_idlfile/2, set_module/2]). + + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% +%% Initialisation stuff +%% +%% +%% +%%-------------------------------------------------------------------- + + +new(Opts) -> + OptDB = ets:new(options, [set, public]), + Warns = ets:new(warnings, [set, public]), + Aux = ets:new(aux, [set, public]), + Tk = ets:new(tktab, [set, public]), + PragmaTab = ets:new(pragmatab, [bag, public]), + TypeDefTab = ets:new(c_typedeftab, [set, public]), + G = #genobj{options=OptDB, + warnings=Warns, + symtab=ic_symtab:new(), + auxtab=Aux, + tktab=Tk, + pragmatab=PragmaTab, + c_typedeftab=TypeDefTab}, + ic_error:init_errors(G), + ic_options:add_opt(G, default_opts, true), + ic_options:read_cfg(G, Opts), % Read any config files + ic_options:add_opt(G, Opts, true), + ic_symtab:symtab_add_faked_included_types(G), % Add CORBA:: that as if they + % were defined in an included file + case ic_options:get_opt(G, be) of + false -> + DefBE = ic_options:defaultBe(), + case ic_options:get_opt(G, multiple_be) of + false -> + ic_options:add_opt(G, be, DefBE), + G; + List -> + case lists:member(DefBE, List) of + true -> + %% Delete the default be from the list to avoid + %% generating it twice. + NewList = lists:delete(DefBE, List), + ic_options:add_opt(G, multiple_be, NewList), + ic_options:add_opt(G, be, DefBE), + G; + false -> + G + end + end; + _ -> + G + end. + + +%%-------------------------------------------------------------------- +%% +%% Table removal +%% +%% +%% +%%-------------------------------------------------------------------- + + +free_table_space(G) -> + %% Free ets tables + ets:delete(G#genobj.options), + ets:delete(G#genobj.symtab), + ets:delete(G#genobj.warnings), + ets:delete(G#genobj.auxtab), + ets:delete(G#genobj.tktab), + ets:delete(G#genobj.pragmatab), + ets:delete(G#genobj.c_typedeftab), + %% Close file descriptors + close_fd(G#genobj.skelfiled), + close_fd(G#genobj.stubfiled), + close_fd(G#genobj.interfacefiled), + close_fd(G#genobj.helperfiled), + close_fd(G#genobj.holderfiled), + close_fd(G#genobj.includefiled). + +close_fd([]) -> + ok; +close_fd([Fd|Fds]) -> + file_close(Fd), + close_fd(Fds). + +file_close(empty) -> ok; +file_close(ignore) -> ok; +file_close(Fd) -> + file:close(Fd). + + +%%-------------------------------------------------------------------- +%% +%% Process memory usage +%% +%% +%% +%%-------------------------------------------------------------------- + +process_space() -> + Pheap=4*element(2,element(2,lists:keysearch(heap_size,1,process_info(self())))), + Pstack=4*element(2,element(2,lists:keysearch(stack_size,1,process_info(self())))), + io:format("Process current heap = ~p bytes\n",[Pheap]), + io:format("Symbol current stack = ~p bytes\n",[Pstack]), + io:format("-----------------------------------------------\n"), + io:format("Totally used ~p bytes\n\n",[Pheap+Pstack]). + + + + + + +skelfiled(G) -> hd(G#genobj.skelfiled). +stubfiled(G) -> hd(G#genobj.stubfiled). +includefiled(G) -> hd(G#genobj.includefiled). +hrlfiled(G) -> hd(G#genobj.includefiled). +interfacefiled(G) -> hd(G#genobj.interfacefiled). +helperfiled(G) -> hd(G#genobj.helperfiled). +holderfiled(G) -> hd(G#genobj.holderfiled). + +include_file(G) -> hd(G#genobj.includefile). +include_file_stack(G) -> G#genobj.includefile. + +is_skelfile_open(G) -> + if hd(G#genobj.skelfiled) /= empty, hd(G#genobj.skelfiled) /= ignore + -> true; + true -> false + end. +is_stubfile_open(G) -> + if hd(G#genobj.stubfiled) /= empty, hd(G#genobj.stubfiled) /= ignore + -> true; + true -> false + end. + +is_hrlfile_open(G) -> + if hd(G#genobj.includefiled) /= empty, hd(G#genobj.includefiled) /= ignore + -> true; + true -> false + end. + +%%-------------------------------------------------------------------- +%% +%% Handling of pre processor file commands +%% +%%-------------------------------------------------------------------- + +push_file(G, Id) -> + New = G#genobj.filestack+1, + set_idlfile(G, Id), + G#genobj{filestack=New, do_gen=true_or_not(New)}. +pop_file(G, Id) -> + New = G#genobj.filestack-1, + set_idlfile(G, Id), + G#genobj{filestack=New, do_gen=true_or_not(New)}. +sys_file(G, _Id) -> G#genobj{sysfile=true}. + + +do_gen(G) -> G#genobj.do_gen. + +%%-------------------------------------------------------------------- +%% +%% Storage routines +%%i +%% The generator object G is used to store many usefull bits of +%% information so that the information doesn't need to get passed +%% around everywhere. +%% +%%-------------------------------------------------------------------- + + +skelscope(G) -> G#genobj.skelscope. +stubscope(G) -> G#genobj.stubscope. +symtab(G) -> G#genobj.symtab. +auxtab(G) -> G#genobj.auxtab. +tktab(G) -> G#genobj.tktab. +impl(G) -> G#genobj.impl. +pragmatab(G) -> G#genobj.pragmatab. +optiontab(G) -> G#genobj.options. +typedeftab(G) -> G#genobj.c_typedeftab. + +idlfile(G) -> ?lookup(G#genobj.options, idlfile). +module(G) -> ?lookup(G#genobj.options, module). + +set_idlfile(G, X) -> ?insert(G#genobj.options, idlfile, X). +set_module(G, X) -> ?insert(G#genobj.options, module, ic_forms:get_id(X)). + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- +true_or_not(X) when X < 2 -> + true; +true_or_not(_) -> + false. diff --git a/lib/ic/src/ic_java_type.erl b/lib/ic/src/ic_java_type.erl new file mode 100644 index 0000000..b8979b6 --- /dev/null +++ b/lib/ic/src/ic_java_type.erl @@ -0,0 +1,1213 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_java_type). + + +-include("icforms.hrl"). +-include("ic.hrl"). +-include("ic_debug.hrl"). +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([getType/3, getHolderType/3, + getParamType/4, inlinedTypes/2, + marshalFun/4, unMarshalFun/4, getFullType/4, + getFullType/3, getMarshalType/4, getUnmarshalType/4, + getdim/1]). +-export([isBasicType/3, isBasicType/1]). +-export([isIntegerType/3, isIntegerType/1]). +-export([isTermType/3]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- +%%----------------------------------------------------------------- +%% Func: getType/3 +%%----------------------------------------------------------------- +getType(G, N, T) when is_record(T, scoped_id) -> + {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T), + BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)), + case BT of + "erlang.pid" -> + ?ICPACKAGE ++ "Pid"; + "erlang.port" -> + ?ICPACKAGE ++ "Port"; + "erlang.ref" -> + ?ICPACKAGE ++ "Ref"; + "erlang.term" -> + ?ICPACKAGE ++ "Term"; + {enum, Type} -> + getType(G, N, Type); + Type -> + case TK of + {tk_array,_,_} -> + tk2type(G,N,T,TK); + {tk_sequence,_,_} -> + tk2type(G,N,T,TK); + tk_any -> + ?ICPACKAGE ++ "Any"; + _ -> + case isBasicType(G,N,TK) of + true -> + tk2type(G,N,T,TK); + false -> + Type %% Other types + end + end + end; + +getType(_G, _N, S) when is_list(S) -> + S; + +getType(_G, _N, T) when is_record(T, string) -> + "java.lang.String"; + +getType(_G, _N, T) when is_record(T, wstring) -> %% WSTRING + "java.lang.String"; + +getType(G, N, T) when is_record(T, struct) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]); + +getType(G, N, T) when is_record(T, union) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]); + +getType(G, N, T) when is_record(T, sequence) -> + getType(G, N, ic_forms:get_type(T)) ++ "[]"; + +getType(G, N, T) when is_record(T, enum) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]); + +%% NOTE i am using the new isJavaElementaryType +%% to avoid members declared as keywords (except +%% all java elementary types) to be used as a +%% class +getType(G, N, T) when is_record(T, member) -> + Type = tk2type(G,N,T,ic_forms:get_type_code(G, N, T)), + case isJavaElementaryType(list_to_atom(Type)) of + true -> + Type; + false -> + Prefix = list_to_atom(lists:flatten(string:tokens(Type,"[]"))), + case isJavaElementaryType(Prefix) of %% Checks if Type is an array + %% of elementary java types + true -> + Type; + false -> + ic_forms:get_java_id(getType(G,N,ic_forms:get_type(T))) ++ + if is_record(hd(T#member.id),array) -> + arrayEmptyDim(hd(T#member.id)); + true -> + "" + end + end + end; + +getType(_G, _N, {boolean, _}) -> + "boolean"; + +getType(_G, _N, {octet, _}) -> + "byte"; + +getType(_G, _N, {void, _}) -> + "void"; + +getType(_G, _N, {unsigned, U}) -> + case U of + {short,_} -> + "short"; + {long,_} -> + "int"; + {'long long',_} -> + "long" + end; + +getType(_G, _N, {char, _}) -> + "char"; + +getType(_G, _N, {wchar, _}) -> %% WCHAR + "char"; + +getType(_G, _N, {short, _}) -> + "short"; + +getType(_G, _N, {long, _}) -> + "int"; + +getType(_G, _N, {'long long', _}) -> + "long"; + +getType(_G, _N, {float, _}) -> + "float"; + +getType(_G, _N, {double, _}) -> + "double"; + +getType(_G, _N, {any, _}) -> + ?ICPACKAGE ++ "Any". + + + + + + +%%----------------------------------------------------------------- +%% Func: getHolderType/3 +%%----------------------------------------------------------------- +getHolderType(G, N, T) when element(1, T) == scoped_id -> + {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T), + BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)), + case BT of + "erlang.pid" -> + ?ICPACKAGE ++ "PidHolder"; + "erlang.port" -> + ?ICPACKAGE ++ "PortHolder"; + "erlang.ref" -> + ?ICPACKAGE ++ "RefHolder"; + "erlang.term" -> + ?ICPACKAGE ++ "TermHolder"; + {enum, Type} -> + getHolderType(G, N, Type); + + Type -> + case TK of + {'tk_struct', _, _, _} -> + Type ++ "Holder"; + + {'tk_union', _, _, _, _, _} -> + Type ++ "Holder"; + + {'tk_array', _ , _} -> + Type ++ "Holder"; + + {'tk_sequence', _ , _} -> + Type ++ "Holder"; + + {'tk_string', _} -> + ?ICPACKAGE ++ "StringHolder"; + + {'tk_wstring', _} -> %% WSTRING + ?ICPACKAGE ++ "StringHolder"; + + {'tk_enum', _, _, _} -> + Type ++ "Holder"; + + 'tk_boolean' -> + ?ICPACKAGE ++ "BooleanHolder"; + + 'tk_octet' -> + ?ICPACKAGE ++ "ByteHolder"; + + 'tk_ushort' -> + ?ICPACKAGE ++ "ShortHolder"; + + 'tk_ulong' -> + ?ICPACKAGE ++ "IntHolder"; + + 'tk_ulonglong' -> %% ULLONG + ?ICPACKAGE ++ "LongHolder"; + + 'tk_short' -> + ?ICPACKAGE ++ "ShortHolder"; + + 'tk_long' -> + ?ICPACKAGE ++ "IntHolder"; + + 'tk_longlong' -> + ?ICPACKAGE ++ "LongHolder"; %% LLONG + + 'tk_float' -> + ?ICPACKAGE ++ "FloatHolder"; + + 'tk_double' -> + ?ICPACKAGE ++ "DoubleHolder"; + + 'tk_char' -> + ?ICPACKAGE ++ "CharHolder"; + + 'tk_wchar' -> %% WCHAR + ?ICPACKAGE ++ "CharHolder"; + + 'tk_any' -> + ?ICPACKAGE ++ "AnyHolder"; + + _ -> + case isBasicType(G,N,TK) of + true -> + %% Faked the type ! + getHolderType(G, N, {list_to_atom(tk2type(G,N,T,TK)), -1}); + false -> + %%io:format("TK = ~p, Type = ~p\n",[TK,Type]), + ic_util:to_dot(G,FullScopedName) ++ "Holder" + end + end + end; + +getHolderType(G, N, S) when is_list(S) -> + ic_util:to_dot(G,[S|N]) ++ "Holder"; + +getHolderType(_G, _N, T) when is_record(T, string) -> + ?ICPACKAGE ++"StringHolder"; + +getHolderType(_G, _N, T) when is_record(T, wstring) -> %% WSTRING + ?ICPACKAGE ++"StringHolder"; + +getHolderType(G, N, T) when is_record(T, struct) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Holder"; + +getHolderType(G, N, T) when is_record(T, union) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Holder"; + +getHolderType(G, N, T) when is_record(T, array) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Holder"; + +getHolderType(G, N, T) when is_record(T, sequence) -> + getType(G, N, ic_forms:get_type(T)) ++ "Holder[]"; + +getHolderType(G, N, T) when is_record(T, enum) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Holder"; + +getHolderType(_G, _N, {boolean, _}) -> + ?ICPACKAGE ++"BooleanHolder"; + +getHolderType(_G, _N, {octet, _}) -> + ?ICPACKAGE ++"ByteHolder"; + +getHolderType(_G, _N, {void, _}) -> + "void"; + +getHolderType(_G, _N, {unsigned, U}) -> + case U of + {short,_} -> + ?ICPACKAGE ++"ShortHolder"; + {long,_} -> + ?ICPACKAGE ++"IntHolder"; + {'long long',_} -> + ?ICPACKAGE ++"LongHolder" + end; + +getHolderType(_G, _N, {char, _}) -> + ?ICPACKAGE ++"CharHolder"; + +getHolderType(_G, _N, {wchar, _}) -> %% WCHAR + ?ICPACKAGE ++"CharHolder"; + +getHolderType(_G, _N, {short, _}) -> + ?ICPACKAGE ++"ShortHolder"; + +getHolderType(_G, _N, {long, _}) -> + ?ICPACKAGE ++"IntHolder"; + +getHolderType(_G, _N, {'long long', _}) -> + ?ICPACKAGE ++"LongHolder"; + +getHolderType(_G, _N, {float, _}) -> + ?ICPACKAGE ++"FloatHolder"; + +getHolderType(_G, _N, {double, _}) -> + ?ICPACKAGE ++"DoubleHolder"; + +getHolderType(_G, _N, {any,_}) -> + ?ICPACKAGE ++ "AnyHolder". + + +%%----------------------------------------------------------------- +%% Func: getParamType/4 +%%----------------------------------------------------------------- +getParamType(G, N, S, in) -> + getType(G, N, S); +getParamType(G, N, S, ret) -> + getType(G, N, S); +getParamType(G, N, S, out) -> + getHolderType(G, N, S); +getParamType(G, N, S, inout) -> + getHolderType(G, N, S). + + +%%----------------------------------------------------------------- +%% Func: getUnmarshalType/4 +%%----------------------------------------------------------------- +getUnmarshalType(G, N, X, T) when element(1, T) == scoped_id -> + {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T), + BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)), + case BT of + "erlang.pid" -> + ?ICPACKAGE ++ "PidHelper"; + "erlang.port" -> + ?ICPACKAGE ++ "PortHelper"; + "erlang.ref" -> + ?ICPACKAGE ++ "RefHelper"; + "erlang.term" -> + ?ICPACKAGE ++ "TermHelper"; + {enum, Type} -> + getUnmarshalType(G, N, X, Type); + Type -> + case TK of + {'tk_struct', _, _, _} -> + Type ++ "Helper"; + + {'tk_union', _, _, _, _, _} -> + Type ++ "Helper"; + + {'tk_sequence', _ , _} -> + Type ++ "Helper"; + + {'tk_array', _ , _} -> + Type ++ "Helper"; + + {'tk_enum', _, _, _} -> + Type ++ "Helper"; + + {'tk_string',_} -> + ?ERLANGPACKAGE ++ "OtpErlangString"; + + {'tk_wstring',_} -> %% WSTRING + ?ERLANGPACKAGE ++ "OtpErlangString"; + + 'tk_char' -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + + 'tk_wchar' -> %% WCHAR + ?ERLANGPACKAGE ++ "OtpErlangLong"; + + 'tk_octet' -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + + 'tk_ushort' -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + + 'tk_ulong' -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + + 'tk_ulonglong' -> %% ULLONG + ?ERLANGPACKAGE ++ "OtpErlangLong"; + + 'tk_short' -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + + 'tk_long' -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + + 'tk_longlong' -> %% LLONG + ?ERLANGPACKAGE ++ "OtpErlangLong"; + + 'tk_float' -> + ?ERLANGPACKAGE ++ "OtpErlangDouble"; + + 'tk_double' -> + ?ERLANGPACKAGE ++ "OtpErlangDouble"; + + 'tk_boolean' -> + ?ERLANGPACKAGE ++ "OtpErlangAtom"; + + 'tk_void' -> + ?ERLANGPACKAGE ++ "OtpErlangAtom"; + + 'tk_any' -> + ?ICPACKAGE ++ "AnyHelper"; + + _ -> + case isBasicType(G,N,TK) of + true -> + %% Faked the type ! + getUnmarshalType(G, N, X, {list_to_atom(tk2type(G,N,T,TK)), -1}); + false -> + ic_util:to_dot(G,FullScopedName) ++ "Helper" + end + end + end; + +getUnmarshalType(_G, _N, _X, S) when is_list(S) -> + S ++ "Helper"; + +getUnmarshalType(_G, _N, _X, T) when is_record(T, string) -> + ?ERLANGPACKAGE ++ "OtpErlangString"; + +getUnmarshalType(_G, _N, _X, T) when is_record(T, wstring) -> %% WSTRING + ?ERLANGPACKAGE ++ "OtpErlangString"; + +getUnmarshalType(G, N, _X, T) when is_record(T, struct) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Helper"; + +getUnmarshalType(G, N, _X, T) when is_record(T, union) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Helper"; + +getUnmarshalType(G, N, X, T) when is_record(T, sequence) andalso + is_record(X, member) -> + ic_util:to_dot(G,[ic_forms:get_id2(X)|N]) ++ "Helper"; + +getUnmarshalType(G, N, X, T) when is_record(T, sequence) andalso + is_record(X, case_dcl) -> + ic_util:to_dot(G,[ic_forms:get_id2(X)|N]) ++ "Helper"; + +getUnmarshalType(G, N, X, T) when is_record(T, sequence) -> + getUnmarshalType(G, N, X, ic_forms:get_type(T)) ++ "Helper"; + +getUnmarshalType(G, N, X, T) when is_record(T, array) andalso + is_record(X, case_dcl) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ "Helper"; + +getUnmarshalType(G, N, _X, T) when is_record(T, enum) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ + "Helper"; + +getUnmarshalType(_G, _N, _X, {boolean, _}) -> + ?ERLANGPACKAGE ++ "OtpErlangAtom"; + +getUnmarshalType(_G, _N, _X, {octet, _}) -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + +getUnmarshalType(_G, _N, _X, {void, _}) -> + ?ERLANGPACKAGE ++ "OtpErlangAtom"; + +getUnmarshalType(_G, _N, _X, {unsigned, U}) -> + case U of + {short,_} -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + {long,_} -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + {'long long',_} -> + ?ERLANGPACKAGE ++ "OtpErlangLong" + end; + +getUnmarshalType(_G, _N, _X, {char, _}) -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + +getUnmarshalType(_G, _N, _X, {wchar, _}) -> %% WCHAR + ?ERLANGPACKAGE ++ "OtpErlangLong"; + +getUnmarshalType(_G, _N, _X, {short, _}) -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + +getUnmarshalType(_G, _N, _X, {long, _}) -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + +getUnmarshalType(_G, _N, _X, {'long long', _}) -> + ?ERLANGPACKAGE ++ "OtpErlangLong"; + +getUnmarshalType(_G, _N, _X, {float, _}) -> + ?ERLANGPACKAGE ++ "OtpErlangDouble"; + +getUnmarshalType(_G, _N, _X, {double, _}) -> + ?ERLANGPACKAGE ++ "OtpErlangDouble"; + +getUnmarshalType(_G, _N, _X, {any, _}) -> + ?ICPACKAGE ++ "AnyHelper". + +%%----------------------------------------------------------------- +%% Func: getMarshalType/4 +%%----------------------------------------------------------------- +getMarshalType(G, N, X, T) when element(1, T) == scoped_id -> + {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T), + BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)), + case BT of + "erlang.pid" -> + ?ICPACKAGE ++ "PidHelper"; + "erlang.port" -> + ?ICPACKAGE ++ "PortHelper"; + "erlang.ref" -> + ?ICPACKAGE ++ "RefHelper"; + "erlang.term" -> + ?ICPACKAGE ++ "TermHelper"; + {enum, Type} -> + getMarshalType(G, N, X, Type); + Type -> + case TK of + {'tk_struct', _, _, _} -> + Type ++ "Helper"; + + {'tk_union', _, _, _, _, _} -> + Type ++ "Helper"; + + {'tk_array', _ , _} -> + Type ++ "Helper"; + + {'tk_sequence', _ , _} -> + Type ++ "Helper"; + + {'tk_enum', _, _, _} -> + Type ++ "Helper"; + + {'tk_string',_} -> + "string"; + + {'tk_wstring',_} -> %% WSTRING + "string"; + + 'tk_char' -> + "char"; + + 'tk_wchar' -> %% WCHAR + "char"; + + 'tk_octet' -> + "byte"; + + 'tk_ushort' -> + "ushort"; + + 'tk_ulong' -> + "uint"; + + 'tk_ulonglong' -> %% ULLONG + "ulong"; + + 'tk_short' -> + "short"; + + 'tk_long' -> + "int"; + + 'tk_longlong' -> %% LLONG + "long"; + + 'tk_float' -> + "float"; + + 'tk_double' -> + "double"; + + 'tk_boolean' -> + "boolean"; + + 'tk_void' -> + "atom"; + + 'tk_any' -> + ?ICPACKAGE ++ "AnyHelper"; + + _ -> + case isBasicType(G,N,TK) of + true -> + %% Faked the type ! + getMarshalType(G, N, X, {list_to_atom(tk2type(G,N,T,TK)), -1}); + false -> + ic_util:to_dot(G,FullScopedName) ++ "Helper" + end + end + end; + +getMarshalType(_G, _N, _X, S) when is_list(S) -> + S ++ "Helper"; + +getMarshalType(_G, _N, _X, T) when is_record(T, string) -> + "string"; + +getMarshalType(_G, _N, _X, T) when is_record(T, wstring) -> %% WSTRING + "string"; + +getMarshalType(G, N, _X, T) when is_record(T, struct) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ + "Helper"; + +getMarshalType(G, N, _X, T) when is_record(T, union) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ + "Helper"; + +getMarshalType(G, N, X, T) when is_record(T, array) andalso + is_record(X, case_dcl) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ + "Helper"; + +getMarshalType(G, N, X, T) when is_record(T, sequence) andalso + is_record(X, member) -> + ic_util:to_dot(G,[ic_forms:get_id2(X)|N]) ++ + "Helper"; + +getMarshalType(G, N, _X, T) when is_record(T, sequence) -> + getType(G, N, ic_forms:get_type(T)) ++ + "Helper"; + +getMarshalType(G, N, _X, T) when is_record(T, enum) -> + ic_util:to_dot(G,[ic_forms:get_id2(T)|N]) ++ + "Helper"; + +getMarshalType(_G, _N, _X, {boolean, _}) -> + "boolean"; + +getMarshalType(_G, _N, _X, {octet, _}) -> + "byte"; + +getMarshalType(_G, _N, _X, {void, _}) -> + ""; % <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +getMarshalType(_G, _N, _X, {unsigned, U}) -> + case U of + {short,_} -> + "ushort"; + {long,_} -> + "uint"; + {'long long',_} -> + "ulong" + end; + +getMarshalType(_G, _N, _X, {short, _}) -> + "short"; +getMarshalType(_G, _N, _X, {long, _}) -> + "int"; +getMarshalType(_G, _N, _X, {'long long', _}) -> + "long"; +getMarshalType(_G, _N, _X, {float, _}) -> + "float"; +getMarshalType(_G, _N, _X, {double, _}) -> + "double"; +getMarshalType(_G, _N, _X, {char, _}) -> + "char"; +getMarshalType(_G, _N, _X, {wchar, _}) -> %% WCHAR + "char"; +getMarshalType(_G, _N, _X, {any, _}) -> + ?ICPACKAGE ++ "AnyHelper". + + + + +%%----------------------------------------------------------------- +%% Func: unMarshalFun/4 +%%----------------------------------------------------------------- +unMarshalFun(G, N, X, T) when element(1, T) == scoped_id -> + {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T), + BT = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)), + case BT of + "erlang.pid" -> + ".read_pid()"; + "erlang.port" -> + ".read_port()"; + "erlang.ref" -> + ".read_ref()"; + "erlang.term" -> + ".read_term()"; + {enum, Type} -> + unMarshalFun(G, N, X, Type); + _Type -> + case isBasicType(G,N,TK) of + true -> + case TK of + {'tk_string',_} -> + ".read_string()"; + + {'tk_wstring',_} -> %% WSTRING + ".read_string()"; + + 'tk_boolean' -> + ".read_boolean()"; + + 'tk_octet' -> + ".read_byte()"; + + 'tk_ushort' -> + ".read_ushort()"; + + 'tk_ulong' -> + ".read_uint()"; + + 'tk_ulonglong' -> %% ULLONG + ".read_ulong()"; + + 'tk_short' -> + ".read_short()"; + + 'tk_long' -> + ".read_int()"; + + 'tk_longlong' -> %% LLONG + ".read_long()"; + + 'tk_float' -> + ".read_float()"; + + 'tk_double' -> + ".read_double()"; + + 'tk_char' -> + ".read_char()"; + + 'tk_wchar' -> %% WCHAR + ".read_char()"; + + _ -> + %% Faked the type ! + unMarshalFun(G, N, X, {list_to_atom(tk2type(G,N,X,TK)), -1}) + end; + false -> + ".unmarshal()" + end + end; + +unMarshalFun(_G, _N, _X, S) when is_list(S) -> + ".unmarshal()"; + +unMarshalFun(_G, _N, _X, T) when is_record(T, string) -> + ".read_string()"; + +unMarshalFun(_G, _N, _X, T) when is_record(T, wstring) -> %% WSTRING + ".read_string()"; + +unMarshalFun(_G, _N, _X, T) when is_record(T, struct) -> + ".unmarshal((" ++ ?ERLANGPACKAGE ++ "OtpErlangTuple)"; + +unMarshalFun(_G, _N, _X, T) when is_record(T, union) -> + ".unmarshal((" ++ ?ERLANGPACKAGE ++ "OtpErlangTuple)"; + +unMarshalFun(_G, _N, _X, T) when is_record(T, sequence) -> + ".unmarshal((" ++ ?ERLANGPACKAGE ++ "OtpErlanglist)"; + +unMarshalFun(_G, _N, _X, T) when is_record(T, enum) -> + ".unmarshal((" ++ ?ERLANGPACKAGE ++ "OtpErlangAtom)"; + +unMarshalFun(_G, _N, _X, {boolean, _}) -> + ".read_boolean()"; + +unMarshalFun(_G, _N, _X, {octet, _}) -> + ".read_byte()"; + +unMarshalFun(_G, _N, _X, {void, _}) -> + ""; + +unMarshalFun(_G, _N, _X, {unsigned, U}) -> + case U of + {short,_} -> + ".read_ushort()"; + {long,_} -> + ".read_uint()"; + {'long long',_} -> + ".read_ulong()" + end; + +unMarshalFun(_G, _N, _X, {short, _}) -> + ".read_short()"; +unMarshalFun(_G, _N, _X, {long, _}) -> + ".read_int()"; +unMarshalFun(_G, _N, _X, {'long long', _}) -> + ".read_long()"; +unMarshalFun(_G, _N, _X, {float, _}) -> + ".read_float()"; +unMarshalFun(_G, _N, _X, {double, _}) -> + ".read_double()"; +unMarshalFun(_G, _N, _X, {char, _}) -> + ".read_char()"; +unMarshalFun(_G, _N, _X, {wchar, _}) -> %% WCHAR + ".read_char()". + + + + + +%%----------------------------------------------------------------- +%% Func: getFullType/4 - /3 +%% +%% Note : Similar to the getType/3 with the major difference +%% thet on arrays and sequences it will also declare +%% their sizes. Used for "new" declarations +%% +%%----------------------------------------------------------------- + + +getFullType(G, N, X, T) when is_record(X, typedef) andalso is_record(T, array) -> + FullDim = + tk2FullType(G,N,X,ic_forms:get_tk(X)) ++ + getFullDim(G,N,T#array.size), + fixArrayDims(FullDim); + +getFullType(G, N, X, T) when is_record(X, member) andalso is_record(T, array) -> + FullDim = + getFullType(G, N, ic_forms:get_type(X)) ++ + getFullDim(G,N,T#array.size), + fixArrayDims(FullDim); + +getFullType(G, N, X, T) when is_record(X, case_dcl) andalso is_record(T, array) -> + FullDim = + getFullType(G, N, ic_forms:get_type(X)) ++ + getFullDim(G,N,T#array.size), + fixArrayDims(FullDim); + +getFullType(G, N, _X, T) -> + getFullType(G, N, T). + + + +getFullType(G, N, T) when is_record(T, scoped_id) -> + {FullScopedName, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, T), + case TK of + {tk_array,_,_} -> + tk2FullType(G,N,T,TK); + {tk_sequence,_,_} -> + tk2FullType(G,N,T,TK); + _ -> + case isBasicType(G,N,TK) of + true -> + tk2FullType(G,N,T,TK); + false -> + %% Other types + ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)) + end + end; + +getFullType(G, N, T) when is_record(T, sequence) -> + fixSeqDims(getType(G,N,T),"_length"); + +getFullType(G, N, T) -> + getType(G, N, T). + + + +%% In order to make a legal declaration +%% of an assignable array, the dimensions +%% of empty array sequences are swifted to +%% the end of the type +fixArrayDims(Cs) -> + fixArrayDims(Cs,[],[]). + +fixArrayDims([],Fulls,Emptys) -> + lists:reverse(Fulls) ++ Emptys; +fixArrayDims([91,93|Rest],Fulls,Emptys) -> + fixArrayDims(Rest,Fulls,[91,93|Emptys]); +fixArrayDims([C|Rest],Fulls,Emptys) -> + fixArrayDims(Rest,[C|Fulls],Emptys). + + +%% In order to make a legal declaration +%% of an assignable array, the dimensions +%% of empty array of sequences are swifted +%% to the end of the type +fixSeqDims(Cs,Length) -> + fixSeqDims(Cs,Length,[]). + +fixSeqDims([],_Length,Found) -> + lists:reverse(Found); +fixSeqDims([91,93|Rest],Length,Found) when is_list(Length) -> + lists:reverse([93|lists:reverse(Length)] ++ + [91|Found]) ++ Rest; +fixSeqDims([C|Rest],Length,Found) -> + fixSeqDims(Rest,Length,[C|Found]). + + + +%%----------------------------------------------------------------- +%% Func: inlinedTypes/2 +%%----------------------------------------------------------------- +inlinedTypes(PkgName, Type) when is_record(Type, struct) -> + "_" ++ PkgName ++ "."; +inlinedTypes(PkgName, Type) when is_record(Type, union) -> + "_" ++ PkgName ++ "."; +inlinedTypes(PkgName, Type) when is_record(Type, enum) -> + "_" ++ PkgName ++ "."; +inlinedTypes(_, _) -> + "". + +%%----------------------------------------------------------------- +%% Func: marshalFun/4 +%%----------------------------------------------------------------- +marshalFun(G, N, X, Type) -> + case isBasicType(G, N, Type) of + true -> + ".write_" ++ getMarshalType(G, N, X, Type); + _ -> + getMarshalType(G, N, X, Type) ++ ".marshal" + end. + + +%%----------------------------------------------------------------- +%% Func: isBasicType/3 +%%----------------------------------------------------------------- +isBasicType(G, N, S) when element(1, S) == scoped_id -> + {_, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + isBasicType(ictype:fetchType(TK)); + +isBasicType(G, N, X) when is_record(X, member) -> + if is_record(hd(element(3,X)), array) -> + false; + true -> + isBasicType(G, N, element(2,X)) + end; + +isBasicType(_G, _N, {unsigned, {long, _}} ) -> + true; + +isBasicType(_G, _N, {unsigned, {short, _}} ) -> + true; + +isBasicType(_G, _N, {unsigned, {'long long', _}} ) -> + true; + +isBasicType(_G, _N, {'long long', _} ) -> + true; + +isBasicType(_G, _N, {Type, _} ) -> + isBasicType(Type); + +isBasicType(_G, _N, Type) -> + isBasicType(Type). + + +%%----------------------------------------------------------------- +%% Func: isBasicType/1 +%%----------------------------------------------------------------- + +isBasicType( Type ) -> + lists:member(Type, + [tk_short,short, + tk_long,long, + tk_longlong,longlong, %% LLONG + tk_ushort,ushort, + tk_ulong,ulong, + tk_ulonglong,ulonglong, %% ULLONG + tk_float,float, + tk_double,double, + tk_boolean,boolean, + tk_char,char, + tk_wchar,wchar, %% WCHAR + tk_octet,octet, + tk_wstring,wstring, %% WSTRING + tk_string,string]). + +%% returns true if the Type is a java elementary type +isJavaElementaryType( Type ) -> + lists:member(Type, + [byte, char, wchar, boolean, + int, short, long, 'long long', float, double]). + +%%----------------------------------------------------------------- +%% Func: isIntegerType/3 +%%----------------------------------------------------------------- +isIntegerType(G, N, S) when element(1, S) == scoped_id -> + {_, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + isIntegerType(ictype:fetchType(TK)); +isIntegerType(_G, _N, {unsigned, {long, _}} ) -> + true; +isIntegerType(_G, _N, {unsigned, {short, _}} ) -> + true; +isIntegerType(_G, _N, {unsigned, {'long long', _}} ) -> + true; +isIntegerType(_G, _N, {'long long', _} ) -> + true; +isIntegerType(_G, _N, {Type, _} ) -> + isIntegerType(Type); +isIntegerType(_G, _N, Type) -> + isIntegerType(Type). + +%%----------------------------------------------------------------- +%% Func: isIntegerType/1 +%%----------------------------------------------------------------- + +isIntegerType( Type ) -> + lists:member(Type, + [tk_short,short, + tk_long,long, + tk_longlong,longlong, %% LLONG + tk_ushort,ushort, + tk_ulong,ulong, + tk_ulonglong,ulonglong, %% ULLONG + tk_char,char, + tk_wchar,wchar, %% WCHAR + tk_octet,octet]). + + + +%%----------------------------------------------------------------- +%% Func: isTerm/3 +%%----------------------------------------------------------------- +isTermType(G, N, T) -> + case getType(G,N,T) of + "com.ericsson.otp.ic.Term" -> + true; + _ -> + false + end. + + + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- + + +%% Changes the typecode to the +%% corresponding "basic" type +tk2type(_G,_N,_X,{'tk_struct', _IFRId, "port", _ElementList}) -> + ?ICPACKAGE ++ "Port"; +tk2type(_G,_N,_X,{'tk_struct', _IFRId, "pid", _ElementList}) -> + ?ICPACKAGE ++ "Pid"; +tk2type(_G,_N,_X,{'tk_struct', _IFRId, "ref", _ElementList}) -> + ?ICPACKAGE ++ "Ref"; +tk2type(_G,_N,_X,{'tk_struct', _IFRId, "term", _ElementList}) -> + ?ICPACKAGE ++ "Term"; +tk2type(_G,_N,_X,{'tk_string', _}) -> + "java.lang.String"; +tk2type(_G,_N,_X,{'tk_wstring', _}) -> %% WSTRING + "java.lang.String"; +tk2type(G,N,X,{'tk_array', ElemTC, Dim}) -> + tkarr2decl(G,N,X,{'tk_array', ElemTC, Dim}); +tk2type(G,N,X,{'tk_sequence', ElemTC, MaxLsextractength}) -> + tkseq2decl(G,N,X,{'tk_sequence', ElemTC, MaxLsextractength}); +tk2type(G,N,_X,{'tk_struct', IFRId, Name, _ElementList}) -> + ScopedId= + lists:reverse(string:tokens(lists:nth(2,string:tokens(IFRId,":")),"/")), + + case ic_forms:clean_up_scope([Name|N]) of + ScopedId -> + %% Right path, use N instead + ic_util:to_dot(G,[Name|N]); + _ -> + %% Ugly work arround + ic_util:to_dot(G,ScopedId) + end; +tk2type(G,N,_X,{'tk_union', IFRId, Name, _, _, _ElementList}) -> + ScopedId= + lists:reverse(string:tokens(lists:nth(2,string:tokens(IFRId,":")),"/")), + + case ic_forms:clean_up_scope([Name|N]) of + ScopedId -> + %% Right path, use N instead + ic_util:to_dot(G,[Name|N]); + _ -> + %% Ugly work arround + ic_util:to_dot(G,ScopedId) + end; +tk2type(_G,_N,_X,{'tk_enum', _Id, Name, _ElementList}) -> + Name; +tk2type(_G,_N,_X,tk_void) -> + "void"; +tk2type(_G,_N,_X,tk_long) -> + "int"; +tk2type(_G,_N,_X,tk_longlong) -> %% LLONG + "long"; +tk2type(_G,_N,_X,tk_short) -> + "short"; +tk2type(_G,_N,_X,tk_ulong) -> + "int"; +tk2type(_G,_N,_X,tk_ulonglong) -> %% ULLONG + "long"; +tk2type(_G,_N,_X,tk_ushort) -> + "short"; +tk2type(_G,_N,_X,tk_float) -> + "float"; +tk2type(_G,_N,_X,tk_double) -> + "double"; +tk2type(_G,_N,_X,tk_boolean) -> + "boolean"; +tk2type(_G,_N,_X,tk_char) -> + "char"; +tk2type(_G,_N,_X,tk_wchar) -> %% WCHAR + "char"; +tk2type(_G,_N,_X,tk_octet) -> + "byte"; +tk2type(_G,_N,_X,tk_string) -> + "java.lang.String"; +tk2type(_G,_N,_X,tk_wstring) -> %% WSTRING + "java.lang.String"; +tk2type(_G,_N,_X,tk_any) -> + ?ICPACKAGE ++ "Any"; +tk2type(_G,_N,_X,tk_term) -> %% Term + ?ICPACKAGE ++ "Term". + +%% Changes the sequence typecode to the +%% corresponding "basic" structure +tkseq2decl(G,N,X,TKSeq) -> + tkseq2decl2(G,N,X,TKSeq,[],[]). + +tkseq2decl2(G,N,X,{tk_sequence,E,D},[],Ds) -> + tkseq2decl2(G,N,X,E,[],[D|Ds]); +tkseq2decl2(G,N,X,TkEl,[],Ds) -> + ElName = tk2type(G,N,X,TkEl), + ElName ++ getdim(Ds). + +%% Changes the array typecode to the +%% corresponding "basic" structure +tkarr2decl(G,N,X,TKArr) -> + tkarr2decl2(G,N,X,TKArr,[],[]). + +tkarr2decl2(G,N,X,{tk_array,E,D},[],Ds) -> + tkarr2decl2(G,N,X,E,[],[D|Ds]); +tkarr2decl2(G,N,X,TkEl,[],Ds) -> + ElName = tk2type(G,N,X,TkEl), + ElName ++ getdim(Ds). + +getdim([]) -> + ""; +getdim([_D|Ds]) -> + getdim(Ds) ++ "[]". + + + +%% Changes the typecode to the corresponding "basic" type +%% used for variable declarations where arrays and sequences +%% are declared with there full dimensions +tk2FullType(G,N,X,{'tk_array', ElemTC, Dim}) -> + tkarr2FullDecl(G,N,X,{'tk_array', ElemTC, Dim}); +tk2FullType(G,N,X,{'tk_sequence', ElemTC, MaxLsextractength}) -> + tkseq2FullDecl(G,N,X,{'tk_sequence', ElemTC, MaxLsextractength}); +tk2FullType(G,N,X,TK) -> + tk2type(G,N,X,TK). + + +%% Changes the sequence typecode to the +%% corresponding "basic" structure here +%% arrays and sequences are declared with +%% their full dimensions +tkseq2FullDecl(G,N,X,TKSeq) -> + tkseq2FullDecl2(G,N,X,TKSeq,[],[]). + +tkseq2FullDecl2(G,N,X,{tk_sequence,E,D},[],Ds) -> + tkseq2FullDecl2(G,N,X,E,[],[D|Ds]); +tkseq2FullDecl2(G,N,X,TkEl,[],Ds) -> + ElName = tk2FullType(G,N,X,TkEl), + ElName ++ getdim(Ds). + +%% Changes the array typecode to the +%% corresponding "basic" structure +tkarr2FullDecl(G,N,X,TKArr) -> + tkarr2FullDecl2(G,N,X,TKArr,[],[]). + +tkarr2FullDecl2(G,N,X,{tk_array,E,D},[],Ds) -> + tkarr2FullDecl2(G,N,X,E,[],[D|Ds]); +tkarr2FullDecl2(G,N,X,TkEl,[],Ds) -> + ElName = tk2FullType(G,N,X,TkEl), + ElName ++ getFullDim(G,N,Ds). + +getFullDim(_G,_N,[]) -> + ""; +getFullDim(G,N,[D|Ds]) when is_record(D,scoped_id) -> + {FSN, _, _, _} = ic_symtab:get_full_scoped_name(G, N, D), + "[" ++ ic_util:to_dot(G,FSN) ++ "]" ++ getFullDim(G,N,Ds); +getFullDim(G,N,[D|Ds]) when is_integer(D) -> + "[" ++ integer_to_list(D) ++ "]" ++ getFullDim(G,N,Ds); +getFullDim(G,N,[D|Ds]) when is_tuple(D) -> + "[" ++ ic_util:eval_java(G,N,D) ++ "]" ++ getFullDim(G,N,Ds). + + + +%% Constructs an array empty dimension string +%% used for array variable declaration +arrayEmptyDim(X) -> + arrayEmptyDim2(X#array.size). + +arrayEmptyDim2([_D]) -> + "[]"; +arrayEmptyDim2([_D |Ds]) -> + "[]" ++ arrayEmptyDim2(Ds). + + + diff --git a/lib/ic/src/ic_jbe.erl b/lib/ic/src/ic_jbe.erl new file mode 100644 index 0000000..81798d0 --- /dev/null +++ b/lib/ic/src/ic_jbe.erl @@ -0,0 +1,1487 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + + +-module(ic_jbe). + + +-export([do_gen/3, gen/3, emit_type_function/4]). + + + +-include("icforms.hrl"). +-include("ic.hrl"). +-include("ic_debug.hrl"). +-include_lib("stdlib/include/erl_compile.hrl"). + + + +%%------------------------------------------------------------ +%% +%% Entry point +%% +%%------------------------------------------------------------ + +do_gen(G, _File, Form) -> + gen(G, [], Form). + + +%%------------------------------------------------------------ +%% +%% Generate the client side C stubs. +%% +%% Each module is generated to a separate file. +%% +%% Each function needs to generate a function head and +%% a body. IDL parameters must be converted into C parameters. +%% +%%------------------------------------------------------------ + +gen(G, N, [X|Xs]) when is_record(X, preproc) -> + NewG = handle_preproc(G, N, X#preproc.cat, X), + gen(NewG, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, module) -> + gen_module(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, interface) -> + gen_interface(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, const) -> + ic_constant_java:gen(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, op) -> + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, attr) -> + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, except) -> + gen_exception(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, enum) -> + ic_enum_java:gen(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, struct) -> + ic_struct_java:gen(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, union) -> + ic_union_java:gen(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, typedef) -> + gen_typedef(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, member) -> + %%?PRINTDEBUG2("gen member: ~p\n",[ic_forms:get_type(X)]), + gen_member(G, N, X), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, case_dcl) -> + %%?PRINTDEBUG2("gen case decl: ~p\n",[ic_forms:get_type(X)]), + gen(G, N, [ic_forms:get_type(X)]), + gen(G, N, Xs); + +gen(G, N, [_|Xs]) -> + gen(G, N, Xs); + +gen(_G, _N, []) -> + ok. + + +%%%-------------------------------------------- +%%% +%%% Just generates the directory to host +%%% the module files +%%% +%%%-------------------------------------------- + +gen_module(G, N, X) -> + case ic_genobj:do_gen(G) of + + true -> %% Generate & register + N1 = [ic_forms:get_id2(X) | N], + %% Create directory + ic_file:createJavaDirectory(G, N1), + gen(G, N1, ic_forms:get_body(X)); + + false -> %% Register only + N1 = [ic_forms:get_id2(X) | N], + reg(G, N1, ic_forms:get_body(X)) + end. + +reg(G, N, [X|_Xs]) when is_record(X, module) -> + reg(G, [ic_forms:get_id2(X) | N], ic_forms:get_body(X)); + +reg(G, N, [X|_Xs]) when is_record(X, interface) -> + reg(G, [ic_forms:get_id2(X) | N], ic_forms:get_body(X)); + +reg(G, N, [X|Xs]) when is_record(X, typedef) -> + Name = ic_util:to_dot(G,[ic_forms:get_java_id(X) | N]), + case X#typedef.type of + {scoped_id,_,_,_} -> + {FullScopedName, _, _, _} = + ic_symtab:get_full_scoped_name(G, N, X#typedef.type), + Type = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)), + ic_code:insert_typedef(G, Name, Type); + _ -> + ok + end, + reg(G, N, Xs); + +reg(G, N, [_|Xs]) -> + reg(G, N, Xs); + +reg(_G, _N, []) -> + ok. + + + + +%%%---------------------------------------------- +%%% +%%% Generates the interface code +%%% +%%%---------------------------------------------- + +gen_interface(G, N, X) -> + case ic_genobj:do_gen(G) of + true -> + G1 = ic_file:javaInterfaceFilePush(G, N, X), + + %% Generate Interface file + InterfaceFd = ic_genobj:interfacefiled(G1), + emit_interface(G1, N, X, InterfaceFd), + + %% Generate Helper file + HelperFd = ic_genobj:helperfiled(G1), + emit_helper(G1, N, X, HelperFd), + + %% Generate Holder file + HolderFd = ic_genobj:holderfiled(G1), + emit_holder(G1, N, X, HolderFd), + + %% Generate Stub file + StubFd = ic_genobj:stubfiled(G1), + emit_stub(G1,N,X,StubFd), %<--------------------------------------------------- 1 + + %% Generate Skeleton file + SkelFd = ic_genobj:skelfiled(G1), + emit_skel(G1, N, X, SkelFd), + + ic_file:javaInterfaceFilePop(G1); + false -> + ok + end. + + + + +%%%-------------------------------------------- +%%% +%%% Typedef redirection +%%% +%%%-------------------------------------------- + +gen_typedef(G, N, X) -> + Name = ic_util:to_dot(G,[ic_forms:get_java_id(X) | N]), + case X#typedef.type of + {scoped_id,_,_,_} -> + {FullScopedName, _, _, _} = + ic_symtab:get_full_scoped_name(G, N, X#typedef.type), + Type = ic_code:get_basetype(G, ic_util:to_dot(G,FullScopedName)), + ic_code:insert_typedef(G, Name, Type); + _ -> + ok + end, + gen_typedef_1(G, N, X, ic_forms:get_body(X)). + +gen_typedef_1(G, N, X, Type) when is_record(Type, sequence) -> + ic_sequence_java:gen(G, N, Type, ic_forms:get_java_id(X)); +gen_typedef_1(G, N, X, Type) when is_record(Type, array) -> + ic_array_java:gen(G, N, X, Type); +gen_typedef_1(G, N, X, _Type) -> + gen_typedef_2(G, N, X, X#typedef.id), + ok. + +gen_typedef_2(G, N, X, Type) when is_record(Type, array) -> + gen_typedef_1(G, N, X, Type); +gen_typedef_2(G, N, X, Type) when is_list(Type) -> + case Type of + [] -> + ok; + _ -> + gen_typedef_2(G, N, X, hd(Type)), + gen_typedef_2(G, N, X, tl(Type)) + end; +%gen_typedef_2(G, N, X, Type) -> %% Generating Helpers for typedef +% %% Stoped due to compatibility problems +% %% with erl_genserv backend +% case ic_java_type:isBasicType(G,N,X#typedef.type) of +% true -> +% ok; +% false -> +% case ic_forms:get_type_code(G,N,X#typedef.type) of +% {'tk_struct', _, _, _} -> +% ic_struct_java:gen(G, N, X); +% {'tk_sequence',_,_} -> +% ic_sequence_java:gen(G, N, X, ic_forms:get_java_id(X)), +% ok; +% _ -> +% ok +% end +% end; +gen_typedef_2(_G, _N, _X, _Type) -> + ok. + + + +%%%-------------------------------------------- +%%% +%%% Member redirection +%%% +%%%-------------------------------------------- + +gen_member(G, N, X) -> + gen_member_1(G, N, X, [X#member.type]), + gen_member_2(G, N, X, X#member.id). + + +gen_member_1(_G, _N, _X, []) -> + ok; + +gen_member_1(G, N, X, [T|Ts]) when is_record(T, sequence) -> + ic_sequence_java:gen(G, N, T, ic_forms:get_java_id(X)), + gen_member_1(G, N, X, Ts); + +gen_member_1(G, N, X, [T|Ts]) -> + gen(G,N,[T]), + gen_member_1(G,N,X,Ts). + + +gen_member_2(_G, _N, _X, []) -> + ok; + +gen_member_2(G, N, X, [T|Ts]) when is_record(T, array) -> %% BUG ! + ic_array_java:gen(G, N, X, T), + gen_member_2(G, N, X, Ts); + +gen_member_2(G, N, X, [_T|Ts]) -> + gen_member_2(G, N, X, Ts). + + + +gen_exception(_G, N, X) -> + io:format("Warning : Exceptions not supported for java mapping, ~p ignored\n", + [ic_util:to_colon([ic_forms:get_java_id(X)|N])]), + ok. + + + +%%%----------------------------------------------------- +%%% +%%% Interface file generation +%%% +%%%----------------------------------------------------- + +emit_interface(G, N, X, Fd) -> + Interface = ic_forms:get_java_id(X), %% Java Interface Name + IFCName = ic_forms:get_id2(X), %% Internal Interface Name + + ic_codegen:emit(Fd, "public interface ~s {\n\n",[Interface]), + Body = ic_forms:get_body(X), + + %% Generate type declarations inside interface + gen(G, [IFCName |N], Body), + + lists:foreach(fun({_Name, Body1}) -> + emit_interface_prototypes(G, [IFCName|N], Body1, Fd) end, + [{x, Body} | X#interface.inherit_body]), + + ic_codegen:emit(Fd, "}\n\n"). + + +emit_interface_prototypes(G, N, [X |Xs], Fd) when is_record(X, op) -> + + {_, ArgNames, TypeList} = extract_info(G, N, X), + {R, ParameterTypes, _} = TypeList, + + OpName = ic_forms:get_java_id(X), + RT = ic_java_type:getParamType(G,N,R,ret), + PL = ic_util:mk_list(gen_par_list(G, N, X, ParameterTypes,ArgNames)), + + ic_codegen:emit(Fd, "/*\n"), + ic_codegen:emit(Fd, " * Operation ~p interface functions \n", [ic_util:to_colon([OpName|N])]), + ic_codegen:emit(Fd, " */\n\n"), + + ic_codegen:emit(Fd, "~s ~s(~s)\n",[RT, OpName, PL]), + ic_codegen:emit(Fd, " throws java.lang.Exception;\n\n\n"), + + emit_interface_prototypes(G, N, Xs, Fd); +emit_interface_prototypes(G, N, [X |Xs], Fd) when is_record(X, attr) -> + ic_attribute_java:emit_attribute_prototype(G, N, X, Fd), + emit_interface_prototypes(G, N, Xs, Fd); +emit_interface_prototypes(G, N, [_X|Xs], Fd) -> + emit_interface_prototypes(G, N, Xs, Fd); +emit_interface_prototypes(_G, _N, [], _Fd) -> ok. + + + + +%%%----------------------------------------------------- +%%% +%%% Holder file generation +%%% +%%%----------------------------------------------------- + +emit_holder(_G, N, X, Fd) -> + InterfaceName = ic_forms:get_java_id(X), + FullInterfaceName = ic_util:to_dot([InterfaceName|N]), + + ic_codegen:emit(Fd, "public final class ~sHolder {\n\n",[InterfaceName]), + + ic_codegen:emit(Fd, " // Instance variable\n"), + ic_codegen:emit(Fd, " public ~s value;\n\n",[FullInterfaceName]), + + ic_codegen:emit(Fd, " // Constructors\n"), + ic_codegen:emit(Fd, " public ~sHolder() {\n",[InterfaceName]), + ic_codegen:emit(Fd, " this(null);\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public ~sHolder(~s _arg) {\n",[InterfaceName, FullInterfaceName]), + ic_codegen:emit(Fd, " value = _arg;\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public void _marshal() {\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public void _unmarshal() {\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, "}\n\n"). + + + + +%%%----------------------------------------------------- +%%% +%%% Helper file generation +%%% +%%%----------------------------------------------------- +emit_helper(G, N, X, Fd) -> + InterfaceName = ic_forms:get_java_id(X), + FullInterfaceName = ic_util:to_dot([InterfaceName|N]), + + ic_codegen:emit(Fd, "public final class ~sHelper {\n\n",[InterfaceName]), + + ic_codegen:emit(Fd, " // Constructor\n"), + ic_codegen:emit(Fd, " public ~sHelper() {\n",[InterfaceName]), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static void _marshal() {\n"), + ic_codegen:emit(Fd, " // Writing the object to the message\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static ~s _unmarshal() {\n",[FullInterfaceName]), + ic_codegen:emit(Fd, " // Reading the object from the message\n"), + ic_codegen:emit(Fd, " return null;\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static java.lang.String id() {\n"), + ic_codegen:emit(Fd, " return ~p;\n",[ictk:get_IR_ID(G, N, X)]), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, "}\n\n"). + + + + +%%%----------------------------------------------------- +%%% +%%% Stub file generation +%%% +%%%----------------------------------------------------- + +emit_stub(G, N, X, Fd) -> + InterfaceName = ic_forms:get_java_id(X), %% Java Interface Name + IFCName = ic_forms:get_id2(X), %% Internal Interface Name + + FullInterfaceName = ic_util:to_dot([InterfaceName|N]), + Body = ic_forms:get_body(X), + + ic_codegen:emit(Fd, "public class _~sStub implements ~s {\n\n", + [InterfaceName,FullInterfaceName]), + + ic_codegen:emit(Fd, " // Client data\n"), + ic_codegen:emit(Fd, " public ~sEnvironment _env;\n\n",[?ICPACKAGE]), + + ic_codegen:emit(Fd, " // Constructors\n"), + ic_codegen:emit(Fd, " public _~sStub(~sOtpSelf _self,\n",[InterfaceName,?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " ~sOtpPeer _peer,\n",[?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " java.lang.Object _server) throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " _env =\n"), + ic_codegen:emit(Fd, " new ~sEnvironment(_self, _peer, _server);\n",[?ICPACKAGE]), + ic_codegen:emit(Fd, " _env.connect();\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public _~sStub(java.lang.String _selfN,\n",[InterfaceName]), + ic_codegen:emit(Fd, " java.lang.String _peerN,\n"), + ic_codegen:emit(Fd, " java.lang.String _cookie,\n"), + ic_codegen:emit(Fd, " java.lang.Object _server) throws java.lang.Exception {\n\n"), + ic_codegen:emit(Fd, " _env =\n"), + ic_codegen:emit(Fd, " new ~sEnvironment(_selfN, _peerN, _cookie, _server);\n",[?ICPACKAGE]), + ic_codegen:emit(Fd, " _env.connect();\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public _~sStub(~sOtpConnection _connection,\n",[InterfaceName, ?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " java.lang.Object _server) throws java.lang.Exception {\n\n"), + ic_codegen:emit(Fd, " _env =\n"), + ic_codegen:emit(Fd, " new ~sEnvironment(_connection, _server);\n",[?ICPACKAGE]), + ic_codegen:emit(Fd, " _env.connect();\n"), + ic_codegen:emit(Fd, " }\n\n"), + + emit_message_reference_extraction(Fd), + + emit_servers_object_access(Fd), + + emit_client_connection_close(Fd), + + emit_client_connection_reconnect(Fd), + + emit_client_destroy(Fd), + + lists:foreach(fun({_Name, Body1}) -> + emit_op_implementation(G, [IFCName|N], Body1, Fd) end, + [{x, Body} | X#interface.inherit_body]), + + ic_codegen:emit(Fd, "}\n\n"). + + +emit_op_implementation(G, N, [X |Xs], Fd) when is_record(X, op) -> + + WireOpName = ic_forms:get_id2(X), + OpName = ic_forms:get_java_id(WireOpName), + {_, ArgNames, TypeList} = extract_info(G, N, X), + {R, ParamTypes, _} = TypeList, + + RT = ic_java_type:getParamType(G,N,R,ret), + PL = ic_util:mk_list(gen_par_list(G, N, X, ParamTypes, ArgNames)), + CMCPL = ic_util:mk_list(gen_client_marshal_call_par_list(ArgNames)), + + ic_codegen:emit(Fd, " // Operation ~p implementation\n", [ic_util:to_colon([WireOpName|N])]), + ic_codegen:emit(Fd, " public ~s ~s(~s)\n", [RT, OpName, PL]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + %% Function marshal call + ic_codegen:emit(Fd, " // Calling the marshal function\n"), + + case CMCPL of + "" -> + ic_codegen:emit(Fd, " _~s_marshal(_env);\n\n",[OpName]); + _ -> + ic_codegen:emit(Fd, " _~s_marshal(_env, ~s);\n\n",[OpName, CMCPL]) + end, + + %% Sending call + ic_codegen:emit(Fd, " // Message send\n"), + ic_codegen:emit(Fd, " _env.send();\n\n"), + + case ic_forms:is_oneway(X) of + true -> + ok; + false -> + %% Receiving return values + ic_codegen:emit(Fd, " // Message receive\n"), + ic_codegen:emit(Fd, " _env.receive();\n\n"), + + %% Function unmarshal call + case RT of + "void" -> + case ic_util:mk_list(gen_client_unmarshal_call_par_list(ArgNames)) of + "" -> + ic_codegen:emit(Fd, " // Calling the unmarshal function\n"), + ic_codegen:emit(Fd, " _~s_unmarshal(_env);\n", + [OpName]); + UMCPL -> + ic_codegen:emit(Fd, " // Calling the unmarshal function\n"), + ic_codegen:emit(Fd, " _~s_unmarshal(_env, ~s);\n", + [OpName,UMCPL]) + end; + _ -> + ic_codegen:emit(Fd, " // Calling the unmarshal function\n"), + case ic_util:mk_list(gen_client_unmarshal_call_par_list(ArgNames)) of + "" -> + ic_codegen:emit(Fd, " return _~s_unmarshal(_env);\n", + [OpName]); + UMCPL -> + ic_codegen:emit(Fd, " return _~s_unmarshal(_env, ~s);\n", + [OpName,UMCPL]) + end + end + end, + ic_codegen:emit(Fd, " }\n\n"), + + %% Marshalling + emit_op_marshal(G, N, X, Fd), + + %% UnMarshalling + emit_op_unmarshal(G, N, X, Fd), + ic_codegen:emit(Fd, "\n"), + + emit_op_implementation(G, N, Xs, Fd); +emit_op_implementation(G, N, [X |Xs], Fd) when is_record(X, attr) -> + ic_attribute_java:emit_attribute_stub_code(G, N, X, Fd), + emit_op_implementation(G, N, Xs, Fd); +emit_op_implementation(G, N, [_X|Xs], Fd) -> + emit_op_implementation(G, N, Xs, Fd); +emit_op_implementation(_G, _N, [], _Fd) -> ok. + + + + + +%%--------------------------------------- +%% +%% Marshal operation generation +%% +%%--------------------------------------- + +emit_op_marshal(G, N, X, Fd) -> + WireOpName = ic_forms:get_id2(X), + OpName = ic_forms:get_java_id(WireOpName), + {_, ArgNames, TypeList} = extract_info(G, N, X), + {_R, ParamTypes, _} = TypeList, + + PL = ic_util:mk_list(gen_marshal_par_list(G, N, X, ParamTypes, ArgNames)), + + ic_codegen:emit(Fd, " // Marshal operation for ~p\n", [OpName]), + case PL of + "" -> + ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env)\n", + [OpName, ?ICPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"); + _ -> + ic_codegen:emit(Fd, " public static void _~s_marshal(~sEnvironment __env, ~s)\n", + [OpName, ?ICPACKAGE, PL]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n") + end, + %% Message encoding + emit_op_encode(G, N, X, OpName, WireOpName, ParamTypes, ArgNames, Fd), + + ic_codegen:emit(Fd, " }\n\n"). + + +emit_op_encode(G, N, X, _OpN, WOpN, ParamTypes, ArgNames, Fd) -> + + OpCallName = case ic_options:get_opt(G, scoped_op_calls) of + true -> + ic_util:to_undersc([WOpN|N]); + false -> + WOpN + end, + + SendParamNr = count_client_send(ArgNames), + + ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n\n", + [?ERLANGPACKAGE]), + + case ic_forms:is_oneway(X) of + true -> + %% Initiating call tuple + ic_codegen:emit(Fd, " // Message header assembly\n"), + ic_codegen:emit(Fd, " __os.reset();\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __os.write_atom(\"$gen_cast\");\n\n"); + false -> + %% Initiating call tuple + ic_codegen:emit(Fd, " // Message header assembly\n"), + ic_codegen:emit(Fd, " __os.reset();\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(3);\n"), + ic_codegen:emit(Fd, " __os.write_atom(\"$gen_call\");\n\n"), + + %% Initiating call identity tuple + ic_codegen:emit(Fd, " // Message identity part creation\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __env.write_client_pid();\n"), + ic_codegen:emit(Fd, " __env.write_client_ref();\n\n") + end, + + %% Operation part initializations + case SendParamNr > 0 of + true -> + ic_codegen:emit(Fd, " // Operation attribute creation\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(~p);\n", [SendParamNr+1]), + ic_codegen:emit(Fd, " __os.write_atom(~p);\n", [OpCallName]), + emit_op_encode_loop(G, N, X, ParamTypes, ArgNames, 1, Fd); + false -> %% No in/inout paramaters + ic_codegen:emit(Fd, " __os.write_atom(~p);\n", [OpCallName]) + end. + + + +emit_op_encode_loop(_,_,_,_,[],_,_Fd) -> + ok; +emit_op_encode_loop(G, N, X, [_Type|Types],[{out, _Arg}|Args], Counter, Fd) -> + emit_op_encode_loop(G, N, X, Types, Args, Counter, Fd); +emit_op_encode_loop(G, N, X, [Type|Types], [{inout, Arg}|Args], Counter, Fd) -> + case ic_java_type:isBasicType(G, N, Type) of + true -> + ic_codegen:emit(Fd, " __os~s(~s.value);\n", + [ic_java_type:marshalFun(G, N, X, Type),Arg]); + false -> + ic_codegen:emit(Fd, " ~s(__os, ~s.value);\n", + [ic_java_type:marshalFun(G, N, X, Type),Arg]) + end, + emit_op_encode_loop(G, N, X, Types, Args, Counter+1, Fd); +emit_op_encode_loop(G, N, X, [Type|Types], [{in, Arg}|Args], Counter, Fd) -> + case ic_java_type:isBasicType(G, N, Type) of + true -> + ic_codegen:emit(Fd, " __os~s(~s);\n", + [ic_java_type:marshalFun(G, N, X, Type),Arg]); + false -> + ic_codegen:emit(Fd, " ~s(__os, ~s);\n", + [ic_java_type:marshalFun(G, N, X, Type),Arg]) + end, + emit_op_encode_loop(G, N, X, Types, Args, Counter+1, Fd). + + + + + + +%%------------------------------------- +%% +%% UnMarshal operation generation +%% +%%------------------------------------- + +emit_op_unmarshal(G, N, X, Fd) -> + case ic_forms:is_oneway(X) of + true -> + ok; + false -> + OpName = ic_forms:get_java_id(X), + {_, ArgNames, TypeList} = extract_info(G, N, X), + {R, ParamTypes, _} = TypeList, + + RT = ic_java_type:getParamType(G,N,R,ret), + PL = ic_util:mk_list(gen_unmarshal_par_list(G, N, X, ParamTypes, ArgNames)), + + case PL of + "" -> + case RT of + "void" -> + ic_codegen:emit(Fd, " // Unmarshal operation for ~p\n", [OpName]), + ic_codegen:emit(Fd, " public static void _~s_unmarshal(~sEnvironment __env)\n", + [OpName, ?ICPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + ic_codegen:emit(Fd, " __env.getIs().read_atom();\n"), + ic_codegen:emit(Fd, " }\n\n"); + _ -> + ic_codegen:emit(Fd, " // Unmarshal operation for ~p\n", [OpName]), + ic_codegen:emit(Fd, " public static ~s _~s_unmarshal(~sEnvironment __env)\n", + [RT, OpName, ?ICPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " // Get input stream\n"), + ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n", + [?ERLANGPACKAGE]), + + emit_op_decode(G, N, X, R, RT, ParamTypes, ArgNames, Fd), + ic_codegen:emit(Fd, " }\n\n") + end; + _ -> + ic_codegen:emit(Fd, " // Unmarshal operation for ~p\n", [OpName]), + ic_codegen:emit(Fd, " public static ~s _~s_unmarshal(~sEnvironment __env, ~s)\n", + [RT, OpName, ?ICPACKAGE, PL]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " // Get input stream\n"), + ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n\n", + [?ERLANGPACKAGE]), + + emit_op_decode(G, N, X, R, RT, ParamTypes, ArgNames, Fd), + ic_codegen:emit(Fd, " }\n\n") + end + end. + + +emit_op_decode(G, N, X, R, RT, ParamTypes, ArgNames, Fd) -> + ReceiveNr = count_client_receive(ArgNames), + + case RT of + "void" -> + case ReceiveNr > 0 of + true -> + ic_codegen:emit(Fd, " // Extracting output values\n"), + ic_codegen:emit(Fd, " __is.read_tuple_head();\n"), + ic_codegen:emit(Fd, " __is.read_atom();\n"), + emit_op_decode_loop(G, N, X, ParamTypes, ArgNames, 1, Fd); + false -> + ic_codegen:emit(Fd, " __is.read_atom();\n") + end; + _ -> + case ReceiveNr > 0 of + true -> + ic_codegen:emit(Fd, " // Extracting return/output values\n"), + ic_codegen:emit(Fd, " __is.read_tuple_head();\n"), + case ic_java_type:isBasicType(G,N,R) of + true -> + ic_codegen:emit(Fd, " ~s _result = __is~s;\n", + [RT,ic_java_type:unMarshalFun(G, N, X, R)]); + false -> + ic_codegen:emit(Fd, " ~s _result = ~s.unmarshal(__is);\n", + [RT, ic_java_type:getUnmarshalType(G,N,X,R)]) + end, + emit_op_decode_loop(G, N, X, ParamTypes, ArgNames, 1, Fd), + + ic_codegen:nl(Fd), + ic_codegen:emit(Fd, " return _result;\n"); + false -> + ic_codegen:emit(Fd, " // Extracting return value\n"), + case ic_java_type:isBasicType(G,N,R) of + true -> + ic_codegen:emit(Fd, " return __is~s;\n", + [ic_java_type:unMarshalFun(G, N, X, R)]); + false -> + ic_codegen:emit(Fd, " return ~s.unmarshal(__is);\n", + [ic_java_type:getUnmarshalType(G,N,X,R)]) + end + end + end. + +emit_op_decode_loop(_,_,_,_,[],_,_Fd) -> + ok; +emit_op_decode_loop(G, N, X, [_Type|Types], [{in, _Arg}|Args], Counter, Fd) -> + emit_op_decode_loop(G, N, X, Types, Args, Counter, Fd); +emit_op_decode_loop(G, N, X, [Type|Types], [{_, Arg}|Args], Counter, Fd) -> + case ic_java_type:isBasicType(G,N,Type) of + true -> + ic_codegen:emit(Fd, " ~s.value = __is~s;\n", + [Arg, + ic_java_type:unMarshalFun(G, N, X, Type)]); + false -> + ic_codegen:emit(Fd, " ~s.value = ~s.unmarshal(__is);\n", + [Arg, + ic_java_type:getUnmarshalType(G, N, X, Type)]) + end, + emit_op_decode_loop(G, N, X, Types, Args, Counter+1, Fd). + + + +emit_message_reference_extraction(Fd) -> + ic_codegen:emit(Fd, " // Returns call reference\n"), + ic_codegen:emit(Fd, " public ~sOtpErlangRef __getRef()\n", + [?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n"), + ic_codegen:emit(Fd, " return _env.received_ref();\n"), + ic_codegen:emit(Fd, " }\n\n"). + +emit_servers_object_access(Fd) -> + ic_codegen:emit(Fd, " // Returns the server\n"), + ic_codegen:emit(Fd, " public java.lang.Object __server() {\n"), + ic_codegen:emit(Fd, " return _env.server();\n"), + ic_codegen:emit(Fd, " }\n\n"). + +emit_client_connection_close(Fd) -> + ic_codegen:emit(Fd, " // Closes connection\n"), + ic_codegen:emit(Fd, " public void __disconnect() {\n"), + ic_codegen:emit(Fd, " _env.disconnect();\n"), + ic_codegen:emit(Fd, " }\n\n"). + +emit_client_connection_reconnect(Fd) -> + ic_codegen:emit(Fd, " // Reconnects client\n"), + ic_codegen:emit(Fd, " public void __reconnect()\n"), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n"), + ic_codegen:emit(Fd, " _env.reconnect();\n"), + ic_codegen:emit(Fd, " }\n\n"). + +emit_client_destroy(Fd) -> + ic_codegen:emit(Fd, " // Destroy server\n"), + ic_codegen:emit(Fd, " public void __stop()\n"), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n"), + ic_codegen:emit(Fd, " _env.client_stop_server();\n"), + ic_codegen:emit(Fd, " }\n\n"). + + + +%%%---------------------------------------------------- +%%% +%%% Generates the server code +%%% +%%%---------------------------------------------------- + +emit_skel(G, N, X, Fd) -> + InterfaceName = ic_forms:get_java_id(X), + FullInterfaceName = ic_util:to_dot([InterfaceName|N]), + + ic_codegen:emit(Fd, "public abstract class _~sImplBase implements ~s {\n\n", + [InterfaceName,FullInterfaceName]), + + ic_codegen:emit(Fd, " // Server data\n"), + ic_codegen:emit(Fd, " protected ~sEnvironment _env = null;\n\n",[?ICPACKAGE]), + + ic_codegen:emit(Fd, " // Constructors\n"), + ic_codegen:emit(Fd, " public _~sImplBase() {\n",[InterfaceName]), + ic_codegen:emit(Fd, " }\n\n"), + + emit_caller_pid(G, N, X, Fd), + + %% Emit operation dictionary + emit_dictionary(G, N, X, Fd), + + %% Emit server switch + emit_server_switch(G, N, X, Fd), + + ic_codegen:emit(Fd, "}\n"). + + +emit_server_switch(G, N, X, Fd) -> + + IFCName = ic_forms:get_id2(X), %% Internal Interface Name + Body = ic_forms:get_body(X), + Counter = 0, + + ic_codegen:emit(Fd, " // Operation invokation\n"), + ic_codegen:emit(Fd, " public ~sOtpOutputStream invoke(~sOtpInputStream _in)\n", + [?ERLANGPACKAGE,?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " // Create a new environment if needed\n"), + ic_codegen:emit(Fd, " if (_env == null)\n"), + ic_codegen:emit(Fd, " _env = new com.ericsson.otp.ic.Environment();\n\n"), + + ic_codegen:emit(Fd, " // Unmarshal head\n"), + ic_codegen:emit(Fd, " _env.uHead(_in);\n\n"), + + ic_codegen:emit(Fd, " // Switch over operation\n"), + ic_codegen:emit(Fd, " return __switch(_env);\n"), + + ic_codegen:emit(Fd, " }\n\n"), + + + ic_codegen:emit(Fd, " // Operation switch\n"), + ic_codegen:emit(Fd, " public ~sOtpOutputStream __switch(~sEnvironment __env)\n", [?ERLANGPACKAGE,?ICPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " // Setup streams and operation label\n"), + ic_codegen:emit(Fd, " ~sOtpOutputStream __os = __env.getOs();\n",[?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " __os.reset();\n"), + ic_codegen:emit(Fd, " int __label = __env.uLabel(__operations);\n\n"), + + ic_codegen:emit(Fd, " // Switch over operation\n"), + ic_codegen:emit(Fd, " switch(__label) {\n\n"), + + OpNr = emit_server_op_switch_loop(G, + [IFCName|N], + [{x, Body} | X#interface.inherit_body], + Counter, + Fd), + + ic_codegen:emit(Fd, " case ~p: { // Standard stop operation\n\n",[OpNr]), + ic_codegen:emit(Fd, " __env.server_stop_server();\n\n"), + ic_codegen:emit(Fd, " } break;\n\n"), + + ic_codegen:emit(Fd, " default: // It will never come down here \n"), + ic_codegen:emit(Fd, " throw new java.lang.Exception(\"BAD OPERATION\");\n\n", []), + + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " if(__os.count() > 0)\n"), + ic_codegen:emit(Fd, " return __os;\n\n"), + + ic_codegen:emit(Fd, " return null;\n"), + ic_codegen:emit(Fd, " }\n\n"). + + + +emit_server_op_switch_loop(_G, _N, [], C, _Fd) -> + C; +emit_server_op_switch_loop(G, N, [{_,X}|Xs], C, Fd) -> + C1 = emit_server_op_switch(G, N, X, C, Fd), + emit_server_op_switch_loop(G, N, Xs, C1, Fd). + + +emit_server_op_switch(G, N, [X|Xs], C, Fd) when is_record(X, op) -> + + OpName = ic_forms:get_java_id(X), + + ic_codegen:emit(Fd, " case ~p: { // Operation ~s\n\n",[C,ic_util:to_dot([OpName|N])]), + + emit_invoke(G, N, X, Fd), + + ic_codegen:emit(Fd, " } break;\n\n"), + + emit_server_op_switch(G, N, Xs, C+1, Fd); +emit_server_op_switch(G, N, [X |Xs], C, Fd) when is_record(X, attr) -> + C1 = ic_attribute_java:emit_attribute_switch_case(G,N,X,Fd,C), + emit_server_op_switch(G, N, Xs, C1, Fd); +emit_server_op_switch(G, N, [_X|Xs], C, Fd) -> + emit_server_op_switch(G, N, Xs, C, Fd); +emit_server_op_switch(_G, _N, [], C, _Fd) -> + C. + + +emit_caller_pid(_G, _N, _X, Fd) -> + ic_codegen:emit(Fd, " // Extracts caller identity\n"), + ic_codegen:emit(Fd, " public ~sOtpErlangPid __getCallerPid() {\n", [?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " return _env.getScaller();\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public ~sOtpErlangPid __getCallerPid(~sEnvironment __env) {\n", + [?ERLANGPACKAGE, ?ICPACKAGE]), + ic_codegen:emit(Fd, " return __env.getScaller();\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public boolean __isStopped() {\n"), + ic_codegen:emit(Fd, " return _env.isStopped();\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public boolean __isStopped(~sEnvironment __env) {\n", + [?ICPACKAGE]), + ic_codegen:emit(Fd, " return __env.isStopped();\n"), + ic_codegen:emit(Fd, " }\n\n"). + + + +%% Creates an operation dictionary +emit_dictionary(G, N, X, Fd) -> + + Counter = 0, + Body = ic_forms:get_body(X), + + ic_codegen:emit(Fd, " // Operation dictionary\n"), + ic_codegen:emit(Fd, " private static java.util.Dictionary __operations = new java.util.Hashtable();\n"), + ic_codegen:emit(Fd, " static {\n"), + + emit_dictionary_loop(G, + [ic_forms:get_id2(X)|N], + [{x, Body} | X#interface.inherit_body], + Counter, + Fd), + + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " // Operation dictionary access\n"), + ic_codegen:emit(Fd, " public static java.util.Dictionary __operations() {\n"), + ic_codegen:emit(Fd, " return __operations;\n"), + ic_codegen:emit(Fd, " }\n\n"). + + + + +emit_dictionary_loop(_G, _N, [], C, Fd) -> + ic_codegen:emit(Fd, " __operations.put(~p, new java.lang.Integer(~p));\n", + ["stop",C]); +emit_dictionary_loop(G, N, [{_,X}|Xs], C, Fd) -> + C1 = emit_dictionary(G, N, X, C, Fd), + emit_dictionary_loop(G, N, Xs, C1, Fd). + + +emit_dictionary(G, N, [X|Xs], C, Fd) when is_record(X, op) -> + + OpName = case ic_options:get_opt(G, scoped_op_calls) of + true -> + ic_util:to_undersc([ic_forms:get_id2(X)|N]); + false -> + ic_forms:get_id2(X) + end, + + ic_codegen:emit(Fd, " __operations.put(~p, new java.lang.Integer(~p));\n", + [OpName,C]), + emit_dictionary(G, N, Xs, C+1, Fd); + +emit_dictionary(G, N, [X |Xs], C, Fd) when is_record(X, attr) -> + C1 = ic_attribute_java:emit_atrribute_on_dictionary(G, N, X, Fd, C), + emit_dictionary(G, N, Xs, C1, Fd); + +emit_dictionary(G, N, [_X|Xs], C, Fd) -> + emit_dictionary(G, N, Xs, C, Fd); + +emit_dictionary(_G, _N, [], C, _Fd) -> + C. + + + +emit_invoke(G, N, X, Fd) -> + + {_, ArgNames, TypeList} = extract_info(G, N, X), + {R, ParamTypes, _} = TypeList, + OpName = ic_forms:get_java_id(X), + RT = ic_java_type:getParamType(G,N,R,ret), + PL = ic_util:mk_list(gen_cb_arg_list(ArgNames)), + OutParamNr = count_server_send(ArgNames), + + case count_server_receive(ArgNames) of + 0 -> + ok; + _C -> + ic_codegen:emit(Fd, " // Preparing input\n"), + ic_codegen:emit(Fd, " ~sOtpInputStream __is = __env.getIs();\n", + [?ERLANGPACKAGE]), + emit_server_unmarshal_loop(G, N, X, ParamTypes, ArgNames, 1, Fd) + end, + + ic_codegen:emit(Fd, " // Calling implementation function\n"), + case RT of + "void" -> + ic_codegen:emit(Fd, " this.~s(~s);\n\n", + [OpName,PL]); + _ -> + ic_codegen:emit(Fd, " ~s _result = this.~s(~s);\n\n", + [RT, OpName, PL]) + end, + + case ic_forms:is_oneway(X) of + true -> + ok; + false -> + ic_codegen:emit(Fd, " // Marshaling output\n"), + ic_codegen:emit(Fd, " ~sOtpErlangRef __ref = __env.getSref();\n",[?ERLANGPACKAGE]), + + case RT of + "void" -> + case OutParamNr > 0 of + true -> + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.ids(),__ref.creation()); // Call reference\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(~p);\n",[OutParamNr+1]), + ic_codegen:emit(Fd, " __os.write_atom(\"ok\");\n"), + emit_server_marshal_loop(G, N, X, ParamTypes,ArgNames,1,Fd); + false -> + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.ids(),__ref.creation()); // Call reference\n"), + ic_codegen:emit(Fd, " __os.write_atom(\"ok\");\n\n") + end; + _ -> + case OutParamNr > 0 of + true -> + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.ids(),__ref.creation()); // Call reference\n"), + ic_codegen:emit(Fd, " __os.write_tuple_head(~p);\n",[OutParamNr+1]), + + case ic_java_type:isBasicType(G,N,R) of + true -> + ic_codegen:emit(Fd, " __os~s(_result); // Return value\n", + [ic_java_type:marshalFun(G,N,X,R)]); + false -> + ic_codegen:emit(Fd, " ~s(__os,_result); // Return value\n", + [ic_java_type:marshalFun(G,N,X,R)]) + end, + emit_server_marshal_loop(G, N, X, ParamTypes,ArgNames,1,Fd); + false -> + ic_codegen:emit(Fd, " __os.write_tuple_head(2);\n"), + ic_codegen:emit(Fd, " __os.write_ref(__ref.node(),__ref.ids(),__ref.creation()); // Call reference\n"), + + case ic_java_type:isBasicType(G,N,R) of + true -> + ic_codegen:emit(Fd, " __os~s(_result); // Return value\n\n", + [ic_java_type:marshalFun(G,N,X,R)]); + false -> + ic_codegen:emit(Fd, " ~s(__os,_result); // Return value\n\n", + [ic_java_type:marshalFun(G,N,X,R)]) + end + end + end, + ic_codegen:nl(Fd) + end. + + +emit_server_unmarshal_loop(_,_,_,_,[],_,Fd) -> + ic_codegen:nl(Fd); +emit_server_unmarshal_loop(G, N, X, [Type|Types], [{in, Arg}|Args], Counter, Fd) -> + case ic_java_type:isBasicType(G,N,Type) of + true -> + ic_codegen:emit(Fd, " ~s ~s = __is~s; // In value\n", + [ic_java_type:getType(G,N,Type), + Arg, + ic_java_type:unMarshalFun(G,N,X,Type)]); + false -> + ic_codegen:emit(Fd, " ~s ~s = ~s.unmarshal(__is); // In value\n", + [ic_java_type:getType(G,N,Type), + Arg, + ic_java_type:getUnmarshalType(G,N,X,Type)]) + end, + emit_server_unmarshal_loop(G, N, X, Types, Args, Counter+1, Fd); +emit_server_unmarshal_loop(G, N, X, [Type|Types],[{inout, Arg}|Args], Counter, Fd) -> + Holder = ic_java_type:getHolderType(G,N,Type), + case ic_java_type:isBasicType(G,N,Type) of + true -> +% OtpEncVar = ic_java_type:getUnmarshalType(G,N,X,Type), + ic_codegen:emit(Fd, " ~s _~s = __is~s;\n", + [ic_java_type:getType(G,N,Type), + Arg, + ic_java_type:unMarshalFun(G,N,X,Type)]), + ic_codegen:emit(Fd, " ~s ~s = new ~s(_~s); // InOut value\n", + [Holder, + Arg, + Holder, + Arg]); + false -> + ic_codegen:emit(Fd, " ~s ~s = new ~s(); // InOut value\n", + [Holder, + Arg, + Holder]), + ic_codegen:emit(Fd, " ~s._unmarshal(__is);\n", + [Arg]) + end, + emit_server_unmarshal_loop(G, N, X, Types, Args, Counter+1, Fd); +emit_server_unmarshal_loop(G, N, X, [Type|Types],[{out, Arg}|Args], Counter, Fd) -> + Holder = ic_java_type:getHolderType(G,N,Type), + ic_codegen:emit(Fd, " ~s ~s = new ~s(); // Out value\n", [Holder, Arg, Holder]), + emit_server_unmarshal_loop(G, N, X, Types, Args, Counter, Fd). + + +emit_server_marshal_loop(_,_,_,_,[],_,_Fd) -> + ok; +emit_server_marshal_loop(G, N, X, [_Type|Types],[{in, _Arg}|Args], Counter, Fd) -> + emit_server_marshal_loop(G, N, X, Types, Args, Counter, Fd); +emit_server_marshal_loop(G, N, X, [Type|Types],[{_, Arg}|Args], Counter, Fd) -> +% Holder = ic_java_type:getHolderType(G,N,Type), + case ic_java_type:isBasicType(G,N,Type) of + true -> + ic_codegen:emit(Fd, " __os~s(~s.value); // Out/InOut value\n", + [ic_java_type:marshalFun(G,N,X,Type),Arg]); + false -> + ic_codegen:emit(Fd, " ~s._marshal(__os); // Out/InOut value\n", + [Arg]) + end, + emit_server_marshal_loop(G, N, X, Types, Args, Counter+1, Fd). + + + + + +%%%---------------------------------------------------- +%%% +%%% Utilities +%%% +%%%---------------------------------------------------- + +extract_info(_G, N, X) when is_record(X, op) -> + Name = ic_util:to_undersc([ic_forms:get_id2(X) | N]), + Args = X#op.params, + ArgNames = mk_c_vars(Args), + TypeList = {ic_forms:get_type(X), + lists:map(fun(Y) -> ic_forms:get_type(Y) end, Args), + [] + }, + {Name, ArgNames, TypeList}; +extract_info(_G, N, X) -> + Name = ic_util:to_undersc([ic_forms:get_id2(X) | N]), + {Name, [], []}. + +%% Input is a list of parameters (in parse form) and output is a list +%% of parameter attribute and variable names. +mk_c_vars(Params) -> + lists:map(fun(P) -> {A, _} = P#param.inout, + {A, ic_forms:get_id(P#param.id)} + end, + Params). + +%% +handle_preproc(G, _N, line_nr, X) -> + Id = ic_forms:get_java_id(X), + Flags = X#preproc.aux, + case Flags of + [] -> ic_genobj:push_file(G, Id); + _ -> + lists:foldr(fun({_, _, "1"}, Gprim) -> ic_genobj:push_file(Gprim, Id); + ({_, _, "2"}, Gprim) -> ic_genobj:pop_file(Gprim, Id); + ({_, _, "3"}, Gprim) -> ic_genobj:sys_file(Gprim, Id) end, + G, Flags) + end; +handle_preproc(G, _N, _Other, _X) -> + G. + + +%% +gen_par_list(_, _, _, [], []) -> + []; +gen_par_list(G, N, X, [Type |Types], [{Attr, Arg}|Args]) -> + JType = ic_java_type:getParamType(G, N, Type, Attr), + [JType ++ " " ++ Arg | + gen_par_list(G, N, X, Types, Args)]. + + +gen_marshal_par_list(_, _, _, [], []) -> + []; +gen_marshal_par_list(G, N, X, [_Type |Types], [{out, _Arg}|Args]) -> + gen_marshal_par_list(G, N, X, Types, Args); +gen_marshal_par_list(G, N, X, [Type |Types], [{Attr, Arg}|Args]) -> + JType = ic_java_type:getParamType(G, N, Type, Attr), + [JType ++ " " ++ Arg | + gen_marshal_par_list(G, N, X, Types, Args)]. + + +gen_unmarshal_par_list(_, _, _, [], []) -> + []; +gen_unmarshal_par_list(G, N, X, [_Type |Types], [{in, _Arg}|Args]) -> + gen_unmarshal_par_list(G, N, X, Types, Args); +gen_unmarshal_par_list(G, N, X, [Type |Types], [{Attr, Arg}|Args]) -> + JType = ic_java_type:getParamType(G, N, Type, Attr), + [JType ++ " " ++ Arg | + gen_unmarshal_par_list(G, N, X, Types, Args)]. + + +%% +gen_client_marshal_call_par_list([]) -> + []; +gen_client_marshal_call_par_list([{out, _Arg}|Args]) -> + gen_client_marshal_call_par_list(Args); +gen_client_marshal_call_par_list([{_Attr, Arg}|Args]) -> + [Arg | gen_client_marshal_call_par_list(Args)]. + + +gen_client_unmarshal_call_par_list([]) -> + []; +gen_client_unmarshal_call_par_list([{in, _Arg}|Args]) -> + gen_client_unmarshal_call_par_list(Args); +gen_client_unmarshal_call_par_list([{_Attr, Arg}|Args]) -> + [Arg | gen_client_unmarshal_call_par_list(Args)]. + + + +count_client_receive(ArgNames) -> + count_client_receive(ArgNames,0). + +count_client_receive([],C) -> + C; +count_client_receive([{in, _Arg}|Args],C) -> + count_client_receive(Args,C); +count_client_receive([_|Args],C) -> + count_client_receive(Args,C+1). + + + +count_client_send(ArgNames) -> + count_client_send(ArgNames,0). + +count_client_send([],C) -> + C; +count_client_send([{out, _Arg}|Args],C) -> + count_client_send(Args,C); +count_client_send([_|Args],C) -> + count_client_send(Args,C+1). + + +gen_cb_arg_list([]) -> + []; +gen_cb_arg_list([{_Attr, Arg}|Args]) -> + [Arg | gen_cb_arg_list(Args)]. + + +count_server_receive(ArgNames) -> + count_server_receive(ArgNames,0). + +count_server_receive([],C) -> + C; +count_server_receive([_|Args],C) -> + count_server_receive(Args,C+1). + + +count_server_send(ArgNames) -> + count_server_send(ArgNames,0). + +count_server_send([],C) -> + C; +count_server_send([{in, _Arg}|Args],C) -> + count_server_send(Args,C); +count_server_send([_|Args],C) -> + count_server_send(Args,C+1). + + + + + +%%%------------------------------------------------------- + + +emit_type_function(G, N, X, Fd) -> + + TC = ic_forms:get_type_code(G, N, X), + + %%io:format("X = ~p\nTC = ~p\n",[X,TC]), + + ic_codegen:emit(Fd, " private static ~sTypeCode _tc;\n",[?ICPACKAGE]), + ic_codegen:emit(Fd, " synchronized public static ~sTypeCode type() {\n\n",[?ICPACKAGE]), + + ic_codegen:emit(Fd, " if (_tc != null)\n"), + ic_codegen:emit(Fd, " return _tc;\n\n"), + + emit_type_function(TC, 0, Fd), + + ic_codegen:emit(Fd, "\n _tc = _tc0;\n"), + + ic_codegen:emit(Fd, "\n return _tc0;\n"), + ic_codegen:emit(Fd, " }\n\n"). + + + +emit_type_function({tk_struct, ID, Name, ML}, C, Fd) -> %% struct + ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]), + ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_struct);\n", [C,?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.id(~p);\n", [C,ID]), + ic_codegen:emit(Fd, " _tc~p.name(~p);\n", [C,Name]), + ic_codegen:emit(Fd, " _tc~p.member_count(~p);\n", [C,length(ML)]), + emit_struct_members(ML, C, C+1, 0, Fd); + +emit_type_function({tk_enum, ID, Name, MNames}, C, Fd) -> %% enum + ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]), + ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_enum);\n", [C,?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.id(~p);\n", [C,ID]), + ic_codegen:emit(Fd, " _tc~p.name(~p);\n", [C,Name]), + ic_codegen:emit(Fd, " _tc~p.member_count(~p);\n", [C,length(MNames)]), + emit_enum_members(MNames, C, 0, Fd), + C+1; + +emit_type_function({tk_array, ET, L}, C, Fd) -> %% array + ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]), + ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_array);\n", [C,?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.id(id());\n",[C]), + ic_codegen:emit(Fd, " _tc~p.length(~p);\n", [C,L]), + C1 = C+1, + C2 = emit_type_function(ET, C1, Fd), + ic_codegen:emit(Fd, " _tc~p.content_type(_tc~p);\n", [C,C1]), + C2; + +emit_type_function({tk_sequence, ET, L}, C, Fd) -> %% sequence + ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]), + ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_sequence);\n", [C,?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.id(id());\n",[C]), + ic_codegen:emit(Fd, " _tc~p.length(~p);\n", [C,L]), + C1 = C+1, + C2 = emit_type_function(ET, C1, Fd), + ic_codegen:emit(Fd, " _tc~p.content_type(_tc~p);\n", [C,C1]), + C2; + +emit_type_function({tk_string, L}, C, Fd) -> %% string + ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]), + ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_string);\n", [C,?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.length(~p);\n", [C,L]), + C+1; + +emit_type_function({tk_union, ID, Name, DT, DI, LL}, C, Fd) -> %% union + + ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]), + ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_union);\n", [C,?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.id(~p);\n", [C,ID]), + ic_codegen:emit(Fd, " _tc~p.name(~p);\n", [C,Name]), + + C1 = C+1, + C2 = emit_type_function(DT, C1, Fd), + + ic_codegen:emit(Fd, " _tc~p.discriminator_type(_tc~p);\n", [C,C1]), + ic_codegen:emit(Fd, " _tc~p.default_index(~p);\n", [C,DI]), + ic_codegen:emit(Fd, " _tc~p.member_count(~p);\n", [C,length(LL)]), + + emit_union_labels(LL, C, DT, C2, 0, Fd); + +emit_type_function(tk_term, C, Fd) -> %% term, must change it to tk_any + ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]), + ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.tk_any);\n", [C,?ICPACKAGE]), + C+1; + +emit_type_function(TC, C, Fd) -> %% other + ic_codegen:emit(Fd, " ~sTypeCode _tc~p =\n",[?ICPACKAGE,C]), + ic_codegen:emit(Fd, " new ~sTypeCode();\n", [?ICPACKAGE]), + ic_codegen:emit(Fd, " _tc~p.kind(~sTCKind.~p);\n", [C,?ICPACKAGE,TC]), + C+1. + + + +emit_struct_members([], _, TCtr, _, _Fd) -> + TCtr; +emit_struct_members([{Name,MT}|Rest], BTCtr, TCtr, I, Fd) -> + ic_codegen:emit(Fd, " _tc~p.member_name(~p,~p);\n", [BTCtr,I,Name]), + TCtr2 = emit_type_function(MT, TCtr, Fd), + ic_codegen:emit(Fd, " _tc~p.member_type(~p,_tc~p);\n", [BTCtr,I,TCtr]), + emit_struct_members(Rest, BTCtr, TCtr2, I+1, Fd). + +emit_enum_members([], _, _, _Fd) -> + ok; +emit_enum_members([Name|Names], BTCtr, I, Fd) -> + ic_codegen:emit(Fd, " _tc~p.member_name(~p,~p);\n", [BTCtr,I,Name]), + emit_enum_members(Names, BTCtr, I+1, Fd). + + +emit_union_labels([], _, _, TCtr, _, _) -> + TCtr; +emit_union_labels([{L, LN, LT}|Rest], BTCtr, DT, TCtr, I, Fd) -> + ic_codegen:emit(Fd, " ~sAny _any~p =\n",[?ICPACKAGE,TCtr]), + ic_codegen:emit(Fd, " new ~sAny();\n", [?ICPACKAGE]), + TCtr1 = TCtr+1, + TCtr2 = emit_type_function(LT, TCtr1,Fd), + ic_codegen:emit(Fd, " _any~p.type(_tc~p);\n",[TCtr,TCtr1]), + + case L of + default -> + ic_codegen:emit(Fd, " _any~p.insert_atom(\"default\");\n", [TCtr]); + _ -> + case DT of + tk_boolean -> + ic_codegen:emit(Fd, " _any~p.insert_boolean(~p);\n",[TCtr,L]); + tk_char -> + Default = if is_integer(L) -> + [L]; + true -> + L + end, + ic_codegen:emit(Fd, " _any~p.insert_char('~s');\n",[TCtr,Default]); + tk_ushort -> + ic_codegen:emit(Fd, " _any~p.insert_ushort(~p);\n",[TCtr,L]); + tk_ulong -> + ic_codegen:emit(Fd, " _any~p.insert_ulong(~p);\n",[TCtr,L]); + tk_short -> + ic_codegen:emit(Fd, " _any~p.insert_short(~p);\n",[TCtr,L]); + tk_long -> + ic_codegen:emit(Fd, " _any~p.insert_long(~p);\n",[TCtr,L]); + _ -> + ic_codegen:emit(Fd, " _any~p.insert_string(~p);\n", [TCtr,L]) + end + end, + ic_codegen:emit(Fd, " _tc~p.member_label(~p,_any~p);\n", [BTCtr,I,TCtr]), + ic_codegen:emit(Fd, " _tc~p.member_name(~p,~p);\n", [BTCtr,I,LN]), + TCtr3 = emit_type_function(LT, TCtr2, Fd), + ic_codegen:emit(Fd, " _tc~p.member_type(~p,_tc~p);\n", [BTCtr,I,TCtr2]), + emit_union_labels(Rest, BTCtr, DT, TCtr3, I+1, Fd). + + + + + + + + diff --git a/lib/ic/src/ic_noc.erl b/lib/ic/src/ic_noc.erl new file mode 100644 index 0000000..d43d550 --- /dev/null +++ b/lib/ic/src/ic_noc.erl @@ -0,0 +1,1113 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_noc). + + +-export([do_gen/3]). +%%------------------------------------------------------------ +%% +%% Internal stuff +%% +%%------------------------------------------------------------ + +-export([unfold/1, mk_attr_func_names/2]). + + +-import(ic_util, [mk_name/2, mk_var/1, mk_oe_name/2, to_atom/1, to_list/1]). +-import(ic_forms, [get_id/1, get_id2/1, get_body/1, is_oneway/1]). +-import(ic_codegen, [emit/2, emit/3, nl/1]). +-import(ic_options, [get_opt/2]). + + +-import(lists, [foreach/2, foldr/3, map/2]). + + +-include("icforms.hrl"). +-include("ic.hrl"). + + + + +%%------------------------------------------------------------ +%% +%% Generate the client side Erlang stubs. +%% +%% Each module is generated to a separate file. +%% +%% Export declarations for all interface functions must be +%% generated. Each function then needs to generate a function head and +%% a body. IDL parameters must be converted into Erlang parameters +%% (variables, capitalised) and a type signature list must be +%% generated (for later encode/decode). +%% +%%------------------------------------------------------------ + + +do_gen(G, File, Form) -> + G2 = ic_file:filename_push(G, [], mk_oe_name(G, + ic_file:remove_ext(to_list(File))), + erlang), + gen_head(G2, [], Form), + exportDependency(G2), + %% Loop through form and adds inheritence data + ic_pragma:preproc(G2, [], Form), + gen(G2, [], Form), + genDependency(G2), + ic_file:filename_pop(G2, erlang), + ok. + + +gen(G, N, [X|Xs]) when is_record(X, preproc) -> + NewG = ic:handle_preproc(G, N, X#preproc.cat, X), + gen(NewG, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, module) -> + CD = ic_code:codeDirective(G,X), + G2 = ic_file:filename_push(G, N, X, CD), + N2 = [get_id2(X) | N], + gen_head(G2, N2, X), + gen(G2, N2, get_body(X)), + G3 = ic_file:filename_pop(G2, CD), + gen(G3, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, interface) -> + G2 = ic_file:filename_push(G, N, X, erlang), + N2 = [get_id2(X) | N], + gen_head(G2, N2, X), + gen(G2, N2, get_body(X)), + foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end, + X#interface.inherit_body), + gen_serv(G2, N, X), + G3 = ic_file:filename_pop(G2, erlang), + gen(G3, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, const) -> +% N2 = [get_id2(X) | N], + emit_constant_func(G, X#const.id, X#const.val), + gen(G, N, Xs); %% N2 or N? + +gen(G, N, [X|Xs]) when is_record(X, op) -> + {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), + + case getNocType(G,X,N) of + transparent -> + emit_transparent_func(G, N, X, Name, ArgNames, TypeList, OutArgs); + multiple -> + mark_not_transparent(G,N), + emit_transparent_func(G, N, X, Name, ArgNames, TypeList, OutArgs); + _XTuple -> + mark_not_transparent(G,N), + emit_stub_func(G, N, X, Name, ArgNames, TypeList, OutArgs) + end, + + gen(G, N, Xs); + + +gen(G, N, [X|Xs]) when is_record(X, attr) -> + emit_attr(G, N, X, fun emit_stub_func/7), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, except) -> + icstruct:except_gen(G, N, X, erlang), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) -> + case may_contain_structs(X) of + true -> icstruct:struct_gen(G, N, X, erlang); + false -> ok + end, + gen(G, N, Xs); + +gen(_G, _N, []) -> ok. + + +may_contain_structs(X) when is_record(X, typedef) -> true; +may_contain_structs(X) when is_record(X, struct) -> true; +may_contain_structs(X) when is_record(X, union) -> true; +may_contain_structs(_X) -> false. + + + +%%-------------------------------------------------------------------- +%% +%% Generate the server side (handle_call and handle_cast) +%% + +gen_serv(G, N, X) -> + case ic_genobj:is_stubfile_open(G) of + true -> + emit_serv_std(G, N, X), + N2 = [get_id2(X) | N], + gen_calls(G, N2, get_body(X)), + lists:foreach(fun({_Name, Body}) -> + gen_calls(G, N2, Body) end, + X#interface.inherit_body), + get_if_gen(G, N2, X), + gen_end_of_call(G, N, X), % Note N instead of N2 + + gen_casts(G, N2, get_body(X)), + lists:foreach(fun({_Name, Body}) -> + gen_casts(G, N2, Body) end, + X#interface.inherit_body), + gen_end_of_cast(G, N, X), % Note N instead of N2 + emit_skel_footer(G, N, X); % Note N instead of N2 + false -> + ok + end. + +gen_calls(G, N, [X|Xs]) when is_record(X, op) -> + case is_oneway(X) of + false -> + {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), + emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs), + gen_calls(G, N, Xs); + true -> + gen_calls(G, N, Xs) + end; + +gen_calls(G, N, [X|Xs]) when is_record(X, attr) -> + emit_attr(G, N, X, fun emit_skel_func/7), + gen_calls(G, N, Xs); + +gen_calls(G, N, [_X|Xs]) -> gen_calls(G, N, Xs); +gen_calls(_G, _N, []) -> ok. + +gen_casts(G, N, [X|Xs]) when is_record(X, op) -> + case is_oneway(X) of + true -> + {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), + emit_skel_func(G, N, X, Name, ArgNames, TypeList, OutArgs), + gen_casts(G, N, Xs); + false -> + gen_casts(G, N, Xs) + end; + +gen_casts(G, N, [_X|Xs]) -> gen_casts(G, N, Xs); +gen_casts(_G, _N, []) -> ok. + +emit_attr(G, N, X, F) -> + XX = #id_of{type=X}, + {GetType, SetType} = mk_attr_func_types(N, X), + lists:foreach(fun(Id) -> + X2 = XX#id_of{id=Id}, + {Get, Set} = mk_attr_func_names(N, get_id(Id)), + F(G, N, X2, Get, [], GetType, []), + case X#attr.readonly of + {readonly, _} -> ok; + _ -> + F(G, N, X2, Set, [mk_name(G, "Value")], + SetType, []) + end end, ic_forms:get_idlist(X)). + + +extract_info(G, _N, X) when is_record(X, op) -> + Name = get_id2(X), + InArgs = ic:filter_params([in,inout], X#op.params), + OutArgs = ic:filter_params([out,inout], X#op.params), + ArgNames = mk_erl_vars(G, InArgs), + TypeList = {ic_forms:get_tk(X), + map(fun(Y) -> ic_forms:get_tk(Y) end, InArgs), + map(fun(Y) -> ic_forms:get_tk(Y) end, OutArgs) + }, + {Name, ArgNames, TypeList, OutArgs}. + + + + +emit_serv_std(G, N, X) -> + Fd = ic_genobj:stubfiled(G), + case transparent(G) of + true -> + true; + _XTupleORMultiple -> + Impl = getImplMod(G,X,[get_id2(X)|N]), + TypeID = ictk:get_IR_ID(G, N, X), + + nl(Fd), nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Server implementation."]), + nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Function for fetching the interface type ID."]), + nl(Fd), + emit(Fd, "typeID() ->\n"), + emit(Fd, " \"~s\".\n", [TypeID]), + nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Server creation functions."]), + nl(Fd), + emit(Fd, "oe_create() ->\n"), + emit(Fd, " start([], []).\n", []), + nl(Fd), + emit(Fd, "oe_create_link() ->\n"), + emit(Fd, " start_link([], []).\n", []), + nl(Fd), + emit(Fd, "oe_create(Env) ->\n"), + emit(Fd, " start(Env, []).\n", []), + nl(Fd), + emit(Fd, "oe_create_link(Env) ->\n"), + emit(Fd, " start_link(Env, []).\n", []), + nl(Fd), + emit(Fd, "oe_create(Env, RegName) ->\n"), + emit(Fd, " start(RegName, Env, []).\n", []), + nl(Fd), + emit(Fd, "oe_create_link(Env, RegName) ->\n"), + emit(Fd, " start_link(RegName, Env, []).\n", []), + nl(Fd), + ic_codegen:mcomment(Fd, ["Start functions."]), + nl(Fd), + emit(Fd, "start(Env, Opt) ->\n"), + emit(Fd, " gen_server:start(?MODULE, Env, Opt).\n"), + nl(Fd), + emit(Fd, "start_link(Env, Opt) ->\n"), + emit(Fd, " gen_server:start_link(?MODULE, Env, Opt).\n"), + nl(Fd), + emit(Fd, "start(RegName, Env, Opt) ->\n"), + emit(Fd, " gen_server:start(RegName, ?MODULE, Env, Opt).\n"), + nl(Fd), + emit(Fd, "start_link(RegName, Env, Opt) ->\n"), + emit(Fd, " gen_server:start_link(RegName, ?MODULE, Env, Opt).\n"), + nl(Fd), + ic_codegen:comment(Fd, "Call to implementation init"), + emit(Fd, "init(Env) ->\n"), + emit(Fd, " ~p:~p(Env).\n", [Impl, init]), + nl(Fd), + emit(Fd, "terminate(Reason, State) ->\n"), + emit(Fd, " ~p:~p(Reason, State).\n", + [Impl, terminate]), + nl(Fd), nl(Fd) + end, + Fd. + + + + +gen_end_of_call(G, _N, _X) -> + case transparent(G) of + true -> + true; + _XTuple -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + ic_codegen:mcomment_light(Fd, ["Standard gen_server call handle"]), + emit(Fd, "handle_call(stop, From, State) ->\n"), + emit(Fd, " {stop, normal, ok, State}"), + case get_opt(G, serv_last_call) of + exception -> + emit(Fd, ";\n"), + nl(Fd), + emit(Fd, "handle_call(Req, From, State) ->\n"), + emit(Fd, " {reply, ~p, State}.\n",[getCallErr()]); + exit -> + emit(Fd, ".\n"), + nl(Fd), + nl(Fd) + end + end, + ok. + + +gen_end_of_cast(G, _N, _X) -> + case transparent(G) of + true -> + true; + _XTuple -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + ic_codegen:mcomment_light(Fd, ["Standard gen_server cast handle"]), + emit(Fd, "handle_cast(stop, State) ->\n"), + emit(Fd, " {stop, normal, State}"), + case get_opt(G, serv_last_call) of + exception -> + emit(Fd, ";\n"), + nl(Fd), + emit(Fd, "handle_cast(Req, State) ->\n"), + emit(Fd, " {reply, ~p, State}.\n",[getCastErr()]); + exit -> + emit(Fd, ".\n"), + nl(Fd), nl(Fd) + end + end, + ok. + + +emit_skel_footer(G, N, X) -> + case transparent(G) of + true -> + true; + _XTuple -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + ic_codegen:mcomment_light(Fd, ["Standard gen_server handles"]), + emit(Fd, "handle_info(X, State) ->\n"), + case use_impl_handle_info(G, N, X) of + true -> + emit(Fd, " ~p:handle_info(X, State).\n\n", + [list_to_atom(ic_genobj:impl(G))]); + false -> + emit(Fd, " {reply, ~p, State}.\n\n",[getInfoErr()]) + end + end, + ok. + + +use_impl_handle_info(G, N, X) -> + FullName = ic_util:to_colon([get_id2(X) | N]), + case {get_opt(G, {handle_info, true}), get_opt(G, {handle_info, FullName})} of + {_, force_false} -> false; + {false, false} -> false; + _ -> true + end. + + +use_timeout(G, N, _X) -> + FullName = ic_util:to_colon(N), + case {get_opt(G, {timeout, true}), get_opt(G, {timeout, FullName})} of + {_, force_false} -> false; + {false, false} -> false; + _ -> true + end. + + +get_if_name(G) -> mk_oe_name(G, "get_interface"). + + +%% Generates the get_interface function (for Lars) +get_if_gen(G, N, X) -> + case transparent(G) of + true -> + ok; + _XTuple -> + case ic_genobj:is_stubfile_open(G) of + true -> + IFC_TKS = tk_interface_data(G,N,X), + Fd = ic_genobj:stubfiled(G), + Name = to_atom(get_if_name(G)), + + ic_codegen:mcomment_light(Fd, + [io_lib:format("Standard Operation: ~p", + [Name])]), + + emit(Fd, "handle_call({~s, ~p, []}, From, State) ->~n", + [mk_name(G, "Ref"), Name]), + + emit(Fd, " {reply, ~p, State};~n", [IFC_TKS]), + nl(Fd), + ok; + + false -> ok + end + end. + + +get_if(G,N,[X|Rest]) when is_record(X, op) -> + R = ic_forms:get_tk(X), + IN = lists:map(fun(P) -> ic_forms:get_tk(P) end, + ic:filter_params([in, inout], X#op.params)), + OUT = lists:map(fun(P) -> ic_forms:get_tk(P) end, + ic:filter_params([out, inout], X#op.params)), + case print_tk(G,N,X) of + true -> + [{get_id2(X), {R, IN, OUT}} | get_if(G,N,Rest)]; + false -> + get_if(G,N,Rest) + end; + +get_if(G,N,[X|Rest]) when is_record(X, attr) -> %% Attributes not handled so far <<<<<<<<<<<<<<<<<<<<<<<< + {GetT, SetT} = mk_attr_func_types([], X), + AList = lists:map(fun(Id) -> + {Get, Set} = mk_attr_func_names([], get_id(Id)), + case X#attr.readonly of + {readonly, _} -> + {Get, GetT}; + _ -> + [{Set, SetT}, {Get, GetT}] + end end, ic_forms:get_idlist(X)), + lists:flatten(AList) ++ get_if(G,N,Rest); + +get_if(G,N,[_X|Rest]) -> get_if(G,N,Rest); +get_if(_,_,[]) -> []. + + + + +%%------------------------------------------------------------ +%% +%% Export stuff +%% +%% Gathering of all names that should be exported from a stub +%% file. +%% + + +gen_head_special(G, N, X) when is_record(X, interface) -> + Fd = ic_genobj:stubfiled(G), + NocType = getNocType(G,X,N), + + foreach(fun({Name, Body}) -> + ic_codegen:comment(Fd, "Exports from ~p", + [ic_util:to_colon(Name)]), + ic_codegen:export(Fd, exp_top(G, N, Body, NocType, [])), + nl(Fd) + end, X#interface.inherit_body), + + case transparent(G) of + true -> + nl(Fd), nl(Fd); + _XTuple -> + ic_codegen:comment(Fd, "Type identification function"), + ic_codegen:export(Fd, [{typeID, 0}]), + nl(Fd), + ic_codegen:comment(Fd, "Used to start server"), + ic_codegen:export(Fd, [{start, 2},{start_link, 3}]), + ic_codegen:export(Fd, [{oe_create, 0}, {oe_create_link, 0}, {oe_create, 1}, + {oe_create_link, 1},{oe_create, 2}, {oe_create_link, 2}]), + nl(Fd), + ic_codegen:comment(Fd, "gen server export stuff"), + emit(Fd, "-behaviour(gen_server).\n"), + ic_codegen:export(Fd, [{init, 1}, {terminate, 2}, {handle_call, 3}, + {handle_cast, 2}, {handle_info, 2}]), + nl(Fd), nl(Fd), + ic_codegen:mcomment(Fd, ["Object interface functions."]), + nl(Fd), nl(Fd), nl(Fd) + end, + Fd; + + +gen_head_special(_G, _N, _X) -> ok. + + + +%% Shall generate all export declarations +gen_head(G, N, X) -> + case ic_genobj:is_stubfile_open(G) of + true -> + F = ic_genobj:stubfiled(G), + ic_codegen:comment(F, "Interface functions"), + ic_codegen:export(F, exp_top(G, N, X, getNocType(G,X,N), [])), + nl(F), + gen_head_special(G, N, X); + false -> ok + end. + +exp_top(_G, _N, X, _NT, Acc) when element(1, X) == preproc -> + Acc; +exp_top(G, N, L, NT, Acc) when is_list(L) -> + exp_list(G, N, L, NT, Acc); +exp_top(G, N, M, NT, Acc) when is_record(M, module) -> + exp_list(G, N, get_body(M), NT, Acc); +exp_top(G, N, I, NT, Acc) when is_record(I, interface) -> + exp_list(G, N, get_body(I), NT, Acc); +exp_top(G, N, X, NT, Acc) -> + exp3(G, N, X, NT, Acc). + +exp3(_G, _N, C, _NT, Acc) when is_record(C, const) -> + [{get_id(C#const.id), 0} | Acc]; + +exp3(G, N, Op, NocType, Acc) when is_record(Op, op) -> + FuncName = get_id(Op#op.id), + + TA = case use_timeout(G,N,Op) of + true -> + 1; + false -> + 0 + end, + + case NocType of + transparent -> + Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, + [{FuncName, Arity} | Acc]; + multiple -> + case getModType(G, Op, N) of + dt -> + Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, + [{FuncName, Arity} | Acc]; + do -> + Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, + [{FuncName, Arity} | Acc]; + spt -> + Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, + [{FuncName, Arity} | Acc]; + spo -> + Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, + [{FuncName, Arity} | Acc] + end; + _ -> + Arity = length(ic:filter_params([in, inout], Op#op.params)) + TA + 1, + [{FuncName, Arity} | Acc] + end; +exp3(_G, _N, A, _NT, Acc) when is_record(A, attr) -> + lists:foldr(fun(Id, Acc2) -> + {Get, Set} = mk_attr_func_names([], get_id(Id)), + case A#attr.readonly of + {readonly, _} -> [{Get, 1} | Acc2]; + _ -> [{Get, 1}, {Set, 2} | Acc2] + end end, Acc, ic_forms:get_idlist(A)); + +exp3(_G, _N, _X, _NT, Acc) -> Acc. + +exp_list(G, N, L, NT, OrigAcc) -> + lists:foldr(fun(X, Acc) -> exp3(G, N, X, NT, Acc) end, OrigAcc, L). + + + + +%%------------------------------------------------------------ +%% +%% Emit stuff +%% +%% Low level generation primitives +%% + +emit_stub_func(G, N, X, Name, ArgNames, TypeList, _OutArgs) -> + case ic_genobj:is_stubfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:stubfiled(G), + StubName = list_to_atom(Name), + This = mk_name(G, "Ref"), + XTuple = getNocType(G,X,N), + CallOrCast = + case is_oneway(X) of + true -> ?CAST; + _ -> ?CALL + end, + + %% Type expand operation on comments + ic_code:type_expand_op(G,N,X,Fd), + + case use_timeout(G,N,X) of + true -> + Timeout = mk_name(G,"Timeout"), + emit(Fd, "~p(~s) ->\n", + [StubName, mk_list([This, Timeout| ArgNames])]), + emit(Fd, " ~p:~s(~s, ~s, ?MODULE, ~p, ~p, [~s], ~p).\n\n", + [getImplMod(G,X,N), + CallOrCast, + This, + Timeout, + XTuple, + StubName, + mk_list(ArgNames), + tk_operation_data(G, N, X, TypeList)]); + false -> + emit(Fd, "~p(~s) ->\n", + [StubName, mk_list([This | ArgNames])]), + + emit(Fd, " ~p:~s(~s, ~p, ?MODULE, ~p, [~s], ~p).\n\n", + [getImplMod(G,X,N), + CallOrCast, + This, + XTuple, + StubName, + mk_list(ArgNames), + tk_operation_data(G, N, X, TypeList)]) + end + end. + + +emit_transparent_func(G, N, X, Name, ArgNames, _TypeList, _OutArgs) -> + case ic_genobj:is_stubfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:stubfiled(G), + OpName = list_to_atom(Name), + + ArgList = case use_timeout(G,N,X) of + true -> + mk_list([mk_name(G,"Ref"),mk_name(G,"Timeout")|ArgNames]); + false -> + mk_list([mk_name(G,"Ref")|ArgNames]) + end, + + %% Type expand operation on comments + ic_code:type_expand_op(G,N,X,Fd), + + emit(Fd, "~p(~s) ->\n", [OpName,ArgList]), + emit(Fd, " ~p:~s(~s).\n\n", [getImplMod(G,X,N), OpName, ArgList]) + end. + + + + + + +emit_skel_func(G, N, X, OpName, ArgNames, _TypeList, _OutArgs) -> + case getNocType(G,X,N) of + transparent -> + true; + multiple -> + true; + XTuple -> + case ic_genobj:is_stubfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:stubfiled(G), + Name = list_to_atom(OpName), + This = mk_name(G, "Ref"), + From = mk_name(G, "From"), + State = mk_name(G, "State"), + + %% Type expand handle operation on comments + ic_code:type_expand_handle_op(G,N,X,Fd), + + case is_oneway(X) of + true -> + emit(Fd, "handle_cast({~s, ~p, OE_Module, ~p, [~s]}, ~s) ->\n", + [This, XTuple, Name, mk_list(ArgNames), State]), + emit(Fd, " ~p:handle_cast({~s, ~p, OE_Module, ~p, [~s]}, ~s);\n\n", + [getImplMod(G,X,N), This, XTuple, Name, mk_list(ArgNames), State]); + false -> + emit(Fd, "handle_call({~s, ~p, OE_Module, ~p, [~s]}, ~s, ~s) ->\n", + [This, XTuple, Name, mk_list(ArgNames), From, State]), + emit(Fd, " ~p:handle_call({~s, ~p, OE_Module, ~p, [~s]}, ~s, ~s);\n\n", + [getImplMod(G,X,N), This, XTuple, Name, mk_list(ArgNames), From, State]) + end + end + end. + + + +emit_constant_func(G, Id, Val) -> + case ic_genobj:is_stubfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:stubfiled(G), + N = list_to_atom(get_id(Id)), + emit_const_comment(G, Fd, Id, N), + emit(Fd, "~p() -> ~p.\n\n", [N, Val]) + end. + + +emit_const_comment(_G, F, _X, Name) -> + ic_codegen:mcomment_light(F, + [io_lib:format("Constant: ~p", [Name])]). + +%%------------------------------------------------------------ +%% +%% Utilities +%% +%% Convenient little go-get functions +%% +%%------------------------------------------------------------ + +%% The automaticly generated get and set operation names for an +%% attribute. +mk_attr_func_names(_Scope, Name) -> + {"_get_" ++ Name, "_set_" ++ Name}. + +%% Returns TK of the Get and Set attribute functions. +mk_attr_func_types(_N, X) -> + TK = ic_forms:get_tk(X), + {{TK, [], []}, {tk_void, [TK], []}}. + + + +%%------------------------------------------------------------ +%% +%% Generation utilities and common stuff +%% +%% Convenient stuff for generation +%% +%%------------------------------------------------------------ + + +%% Input is a list of parameters (in parse form) and output is a list +%% of capitalised variable names. mk_var is in icgen +mk_erl_vars(_G, Params) -> + map(fun(P) -> mk_var(get_id(P#param.id)) end, Params). + + +%% mk_list produces a nice comma separated string of variable names +mk_list([]) -> []; +mk_list([Arg | Args]) -> + Arg ++ mk_list2(Args). +mk_list2([Arg | Args]) -> + ", " ++ Arg ++ mk_list2(Args); +mk_list2([]) -> []. + + +%%------------------------------------------------------------ +%% +%% Parser utilities +%% +%% Called from the yecc parser. Expands the identifier list of an +%% attribute so that the attribute generator never has to handle +%% lists. +%% +%%------------------------------------------------------------ + + +%% Unfold identifier lists or nested lists. Note that many records +%% contain an entry named id that is a list before unfold and a single +%% id afterwards. +unfold(L) when is_list(L) -> + lists:flatten(map(fun(X) -> unfold2(X) end, L)); +unfold(X) -> unfold2(X). + +unfold2(A) when is_record(A, attr) -> + map(fun(Id) -> A#attr{id=Id} end, A#attr.id); +unfold2(M) when is_record(M, member) -> + map(fun(Id) -> M#member{id=Id} end, M#member.id); +unfold2(M) when is_record(M, case_dcl) -> + map(fun(Id) -> M#case_dcl{label=Id} end, M#case_dcl.label); +unfold2(T) when is_record(T, typedef) -> + map(fun(Id) -> T#typedef{id=Id} end, T#typedef.id ). + + + + + + +%% Export code produce for dependency function +exportDependency(G) -> + Fd = ic_genobj:stubfiled(G), + ic_codegen:export(Fd, [{oe_dependency, 0}]), + nl(Fd). + +%% Code produce for dependency function +genDependency(G) -> + Fd = ic_genobj:stubfiled(G), + nl(Fd),nl(Fd), + ic_codegen:comment(Fd, "Idl file dependency list function"), + emit(Fd, "oe_dependency() ->\n", []), + emit(Fd, " ~p.\n\n", [ic_pragma:get_dependencies(G)]). + + + + + +%%%%%% + + +getImplMod(G,X,Scope) -> %% to_atom(ic_genobj:impl(G)) | ChoicedModuleName + + %% Get actual pragma appliance scope + SpecScope = getActualScope(G,X,Scope), + + %% The "broker" option is passed + %% only by pragmas, seek for module. + case ic_pragma:getBrokerData(G,X,SpecScope) of + {Module,_Type} -> + Module; + _List -> + element(1,ic_pragma:defaultBrokerData(G)) + end. + + +getNocType(G,X,Scope) when is_record(X, interface) -> %% default | specified + OpList = getAllOperationScopes(G,Scope), + getNocType2(G,X,OpList); +getNocType(G,X,Scope) -> %% transparent | {extraarg1,....,extraargN} + getNocType3(G,X,Scope). + +getNocType2(G,X,List) -> + getNocType2(G,X,List,[]). + +getNocType2(_,_,[],Found) -> + selectTypeFromList(Found); +getNocType2(G,X,[OpScope|OpScopes],Found) -> + getNocType2(G,X,OpScopes,[getNocType3(G,X,OpScope)|Found]). + +getNocType3(G,X,Scope) -> %% transparent | {extraarg1,....,extraargN} + + %% Get actual pragma appliance scope + SpecScope = getActualScope(G,X,Scope), + + %% The "broker" option is passed + %% only by pragmas, seek for type. + case ic_pragma:getBrokerData(G,X,SpecScope) of + {_Module,Type} -> + Type; + List -> + selectTypeFromList(List) %%transparent/multiple + end. + + +getModType(G,X,Scope) -> %% default | specified + + %% Get actual pragma appliance scope + SpecScope = getActualScope(G,X,Scope), + + %% The "broker" option is passed + %% only by pragmas, seek for brokerdata. + case ic_pragma:getBrokerData(G,X,SpecScope) of + {Module,Type} -> + case Module == ic_genobj:impl(G) of + true -> + case Type of + transparent -> + dt; %% default + transparent + _ -> + do %% default + opaque + end; + false -> + case Type of + transparent -> + spt; %% specified + transparent + _ -> + spo %% specified + opaque + end + end; + _List -> + dt + end. + + + +%%%% +%% +%% Returns a list of ALL operation full +%% scoped names local and inherited +%% from other interfaces +%% + +getAllOperationScopes(G,Scope) -> + getOperationScopes(G,Scope) ++ + getInhOperationScopes(G,Scope). + + +getOperationScopes(G,Scope) -> + getOpScopes(G, + Scope, + ets:match(ic_genobj:pragmatab(G),{op,'$0',Scope,'_','_'}), + []). + +getOpScopes(_,_,[],OpScopes) -> + OpScopes; +getOpScopes(G,Scope,[[Name]|Names],Found) -> + getOpScopes(G,Scope,Names,[[Name|Scope]|Found]). + + +getInhOperationScopes(G,Scope) -> + getInhOpScopes1(G, + Scope, + ets:match(ic_genobj:pragmatab(G),{inherits,Scope,'$1'}), + []). + +getInhOpScopes1(G,_Scope,[],OpScopes) -> + getInhOpScopes2(G,OpScopes); +getInhOpScopes1(G,Scope,[[SC]|SCs],Found) -> + getInhOpScopes1(G,Scope,SCs,[SC|Found]). + + +getInhOpScopes2(G,Scopes) -> + getInhOpScopes2(G,Scopes,[]). + +getInhOpScopes2(_G,[],Found) -> + Found; +getInhOpScopes2(G,[SC|SCs],Found) -> + getOperationScopes(G,SC) ++ getInhOpScopes2(G,SCs,Found). + +%% +%% +%%%% + + + +%%%% +%% +%% +%% Seek the actual operation scope : +%% +%% * if the operation is inherited, get the real scope for it +%% +%% * if the operation has a specific pragma, apply the real +%% scope, otherwise return the including scope +%% +getActualScope(G, X, Scope) when is_record(X, op) -> + OpScope = getRealOpScope(G,X,Scope), + case ets:match(ic_genobj:pragmatab(G),{codeopt_specific,OpScope}) of + [[]] -> + OpScope; + _ -> + Scope + end; +getActualScope(_G, _X, N) -> + N. + +%% +%% Just seek and return the scope for the operation +%% where it were originaly defined +%% +getRealOpScope(G,X,N) when is_record(X, op) -> + Ptab = ic_genobj:pragmatab(G), + Id = get_id2(X), + + case ets:match(Ptab,{op,Id,N,'_','_'}) of + [[]] -> + [Id|N]; + _ -> + getRealOpScope(G, Ptab, X, N, Id, ets:match(Ptab,{inherits,N,'$1'})) + end; +getRealOpScope(_G,_X,N) -> + N. + +getRealOpScope(_G, _S, _X, N, Id, []) -> + [Id|N]; +getRealOpScope(G, S, X, N, Id, [[OS]|OSs]) -> + case ets:match(S,{op,Id,OS,'_','_'}) of + [[]] -> + [Id|OS]; + _ -> + getRealOpScope(G, S, X, N, Id, OSs) + end. + +selectTypeFromList([]) -> + transparent; +selectTypeFromList([{_,transparent}|Rest]) -> + selectTypeFromList(Rest); +selectTypeFromList([transparent|Rest]) -> + selectTypeFromList(Rest); +selectTypeFromList([_|_Rest]) -> + multiple. + + + +getCallErr() -> + {'ERROR' ,"Bad Operation -- handle call"}. + +getCastErr() -> + {'ERROR' ,"Bad Operation -- handle cast"}. + +getInfoErr() -> + {'ERROR' ,"Bad Operation -- handle info"}. + + + + + + +%% +%% Type code access utilities +%% + +tk_operation_data(G, N, X, TL) -> + case print_tk(G,N,X) of + true -> + TL; + false -> + no_tk + end. + +tk_interface_data(G, N, X) -> + InfoList = + foldr(fun({_Name, Body}, Acc) -> + get_if(G,N,Body)++Acc end, + get_if(G,N,get_body(X)), + X#interface.inherit_body), + case InfoList of + [] -> + no_tk; %%%%%%%% Should be changed to [] <<<<<<<<<<<<<<<<<<<<<<<<<<< Warning ! + _ -> + InfoList + end. + + +print_tk(G, N, X) when is_record(X, op)-> %% operation + case getNocType(G,X,N) of + transparent -> + false; + multiple -> + false; + _XTuple -> %%check if there are any USETK pragmas + operation_usetk(G,N,X) + end; +print_tk(_G, _N, _X) -> %% error + false. + + +operation_usetk(G,N,X) -> + PTab = ic_genobj:pragmatab(G), + OTab = ic_genobj:optiontab(G), + OpName = get_id2(X), +% SID = ic_util:to_colon(N), + Res = case use_tk(OTab,[N]) of + {ok,N} -> + true; + false -> + %% Look if there is an operation with that name + %% which can be found in an included file. + case ets:match(PTab,{file_data_included,'_','_',op,'$3',OpName,'_','_','_'}) of + [] -> + false; + ScopeList -> + case use_tk(OTab,ScopeList) of + %% There is an operation with that name, + %% look if it is inherited by interface "N" + {ok,FoundScope} -> + ic_pragma:is_inherited_by(FoundScope,N,PTab); + false -> + false + end + end + end, + Res. + + +use_tk(_,[]) -> + false; +use_tk(OTab,[[Scope]|Scopes]) -> + SID = ic_util:to_colon(Scope), + case ets:match(OTab,{{option,{use_tk,SID}},true}) of + [] -> + case ets:match(OTab,{{option,{use_tk,"::"++SID}},true}) of + [] -> + use_tk(OTab,Scopes); + _ -> + {ok,Scope} + end; + _ -> + {ok,Scope} + end; +use_tk(OTab,[Scope|Scopes]) -> + SID = ic_util:to_colon(Scope), + case ets:match(OTab,{{option,{use_tk,SID}},true}) of + [] -> + case ets:match(OTab,{{option,{use_tk,"::"++SID}},true}) of + [] -> + use_tk(OTab,Scopes); + _ -> + {ok,Scope} + end; + _ -> + {ok,Scope} + end. + + + + + +mark_not_transparent(G,N) -> + + %% Mark that there are multiple + %% functions in interface + S = ic_genobj:pragmatab(G), + ets:insert(S,{no_transparent,N}). + + +transparent(G) -> + + S = ic_genobj:pragmatab(G), + case ets:match_object(S,{no_transparent,'$0'}) of + [] -> + true; + _ -> + false + end. + diff --git a/lib/ic/src/ic_options.erl b/lib/ic/src/ic_options.erl new file mode 100644 index 0000000..8d17fc1 --- /dev/null +++ b/lib/ic/src/ic_options.erl @@ -0,0 +1,363 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_options). + +-include_lib("ic/src/ic.hrl"). +-include_lib("kernel/include/file.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([defaultBe/0, float_to_version/1, get_opt/2, add_opt/3, + read_cfg/2, which_opts/1, allowed_opt/2]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%-------------------------------------------------------------------- +%% +%% Option handling +%% +%% Valid options are: (those with * is NotYetImpl) +%% +%% pedantic - makes the compiler really nitty-gritty about its input +%% +%% Wall - those warning options that we feel an IDL programmer should +%% care about. Not as picky as pedantic +%% +%% warn_multi_mod - warn if several modules are declared in the same +%% IDL file +%% +%% warn_nested_mod - warn if there are nested modules. This is not a +%% problem but it breakes the rule that modules are put into one file +%% each. +%% +%% warn_name_shadow - warn if identifiers are shadow through inherited +%% interfaces. Default is true. +%% +%% warn_quoted_atom - warn if atoms needs quote, this makes Erlang +%% code less nice but is certainly no error. +%% +%% nowarn - suppress all warning messages. Will still output warnings +%% if silent2 option is used +%% +%% always_outargs - force object server implementation return the +%% tuple {RetVal, OutArgs, NewState} even if there are no OutArgs. If +%% this option is not set then such an operation implementation is +%% assumed to return {RetVal, NewState} +%% +%% use_proc_dict - use the process dictionary in the client +%% stubs. This means that client stubs return RetVal instead of {ok, +%% RetVal, OutArgs} and that corba:get_outargs() returns OutArgs. The +%% out arguments are stored with the key '$corba_outargs'. +%% +%% module_group - use the top module as file name for both skeletons +%% and stubs. Default value is false which means that each interface +%% is put in a separate file. +%% +%% skel_module_group - group all interfaces in a module in one +%% skeleton file as opposed to one skeleton file for each +%% interface. Defaults to false. +%% +%% stub_module_group - group all interface stubs from a module in one +%% stub file as opposed to one stub file for each interface. Default +%% is false. +%% +%% *help - prints a small summary of the compiler usage +%% +%% silent - suppresses all messages from the compiler +%% +%% silent2 - suppresses all messages from the compiler and returns all +%% warnings or errors as lists. Returns {ok, WarnList} or {error, +%% WarnList, ErrList} +%% +%% *noexec - runs the compiler but does not open files or write to +%% files. +%% +%% {serv, } - sets the name of the implementation skeleton +%% file. This defaults to ModName_skel. +%% +%% {impl, } - sets the name of the interface server +%% implementation module name. This defaults to InterfaceName_impl +%% +%% {outdir, Dir} - use Dir as the directory to put all generated +%% files. +%% +%% {servdir, Dir} - put all generated skel files in the directory Dir. +%% +%% {stubdir, Dir} - put all generated stub files in the directory Dir. +%% +%% {this, InterfaceOrOpName} - puts the OE_THIS parameter into the +%% impl. call. This option can be used both on whole interfaces an on +%% distinct operations. Fullscoped names must be used (as in {this, +%% "M1::I1::Op"}). The option can be given in 3 ways: {this, Name} +%% means this will be added to all matching Name or as {{this, Name}, +%% true} or this can explicitly be asked to be left out as in {{this, +%% Name}, false} which enables OE_THIS to be passed to all ops of an +%% interface except those set by the false flag. +%% +%% cfgfile - sets the name of the config file that is read at +%% startup. The order of the different ways to set options is: default +%% setting, configuration file, options given when generator is +%% called. Default name for this file is .ic_config +%% +%% serv_last_call - tells what the last handle_call clause should +%% do. It can have the values exception, which makes the last clause +%% return a CORBA exception and exit which does not generate a last clause +%% (which will make the server crash on an unknown call) +%% +%% +%% -- UNDOCUMENTED -- +%% +%% debug - prints debug information +%% +%% tokens - prints the tokens from the tokenizer and then exit +%% +%% form - prints the form from the parser and then exit +%% +%% tform - form returned from type check +%% +%% time - if true then time is measured during compilation +%% +%% +%%-------------------------------------------------------------------- +allowed_opt(default_opts, _V) -> true; +allowed_opt(debug, V) -> is_bool(V); +allowed_opt(tokens, V) -> is_bool(V); +allowed_opt(form, V) -> is_bool(V); +allowed_opt(tform, V) -> is_bool(V); +allowed_opt(time, V) -> is_bool(V); +allowed_opt(maxerrs, V) -> is_intorinfinity(V); +allowed_opt(maxwarns, V) -> is_intorinfinity(V); +allowed_opt(nowarn, V) -> is_bool(V); +allowed_opt(show_opts, V) -> is_bool(V); + +allowed_opt(help, V) -> is_bool(V); +allowed_opt('Wall', V) -> is_bool(V); +allowed_opt(warn_multi_mod, V) -> is_bool(V); +allowed_opt(warn_quoted_atom, V) -> is_bool(V); +allowed_opt(warn_nested_mod, V) -> is_bool(V); +allowed_opt(warn_name_shadow, V) -> is_bool(V); +allowed_opt(module_group, V) -> is_bool(V); +allowed_opt(skel_module_group, V) -> is_bool(V); +allowed_opt(stub_module_group, V) -> is_bool(V); +allowed_opt(always_outargs, V) -> is_bool(V); +allowed_opt(pedantic, V) -> is_bool(V); +%%allowed_opt(gen_serv, V) -> is_bool(V); +%%allowed_opt(gen_stub, V) -> is_bool(V); +allowed_opt(gen_hrl, V) -> is_bool(V); +allowed_opt(serv_last_call, exception) -> true; +allowed_opt(serv_last_call, exit) -> true; +allowed_opt(silent, V) -> is_bool(V); +allowed_opt(silent2, V) -> is_bool(V); +allowed_opt({serv, _}, _V) -> true; +allowed_opt({impl, _}, _V) -> true; +allowed_opt(outdir, _V) -> true; +allowed_opt(servdir, _V) -> true; +allowed_opt(stubdir, _V) -> true; +allowed_opt(cfgfile, _V) -> true; +allowed_opt(use_preproc, V) -> is_bool(V); +allowed_opt(preproc_cmd, _V) -> true; +allowed_opt(preproc_flags, _V) -> true; +allowed_opt(this, _V) -> true; +allowed_opt({this, _}, V) -> is_bool(V); +allowed_opt(from, _V) -> true; +allowed_opt({from, _}, V) -> is_bool(V); +allowed_opt(handle_info, _V) -> true; +allowed_opt({handle_info, _}, V) -> is_bool(V); +allowed_opt(timeout, _V) -> true; +allowed_opt({timeout, _}, V) -> is_bool(V); +allowed_opt(c_timeout, {V1, V2}) -> is_int(V1) and is_int(V2); +allowed_opt(c_timeout, V) -> is_int(V); +allowed_opt(c_report, V) -> is_bool(V); +allowed_opt(scoped_op_calls, V) -> is_bool(V); +% Compatibility option (semantic check limitation) +allowed_opt(scl, V) -> is_bool(V); +% Added switches for non corba generation +allowed_opt(flags, V) -> is_int(V); +allowed_opt(be, erl_corba) -> true; +allowed_opt(be, erl_template) -> true; +allowed_opt(be, erl_genserv) -> true; +allowed_opt(be, c_genserv) -> true; +allowed_opt(be, erl_plain) -> true; +allowed_opt(be, c_server) -> true; +allowed_opt(be, c_client) -> true; +allowed_opt(be, java) -> true; +% Noc backend +allowed_opt(be, noc) -> true; +allowed_opt({broker,_},{_,transparent}) -> true; +allowed_opt({broker,_},{_,Term}) -> is_term(Term); +allowed_opt({use_tk,_},V) -> is_bool(V); +% +% Multiple be +allowed_opt(multiple_be, _List) -> true; +% +allowed_opt(precond, {_M, _F}) -> true; +allowed_opt({precond, _}, {_M, _F}) -> true; +allowed_opt(postcond, {_M, _F}) -> true; +allowed_opt({postcond, _}, {_M, _F}) -> true; +allowed_opt(no_codechange, V) -> is_bool(V); +allowed_opt(user_protocol, _V) -> true; +allowed_opt(light_ifr, V) -> is_bool(V); +allowed_opt(_, _) -> false. + + +-define(DEFAULTCFGFILE, ".ic_config"). + +which_opts(G) -> + ets:match(G#genobj.options, {{option, '$1'}, '$2'}). + +add_opt(G, KList, Val) when is_list(KList) -> + lists:foreach(fun({K, V}) -> add_opt(G, K, V); + (K) -> add_opt(G, K, Val) end, + KList); + +add_opt(G, servdir, V) -> + do_add_opt(G, servdir, assure_directory(G, ic_util:to_list(V))); +add_opt(G, stubdir, V) -> + do_add_opt(G, stubdir, assure_directory(G, ic_util:to_list(V))); +add_opt(G, K, V) -> + do_add_opt(G, K, V). + + +assure_directory(_G, Dir) -> + Dirs = filename:split(Dir), + check_dirs(Dirs, [], filename:pathtype(Dir)). + +check_dirs([X | Xs], SoFar, Type) -> + New = if SoFar == [], Type /= absolute -> + X; + true -> + filename:join(SoFar, X) + end, + assert_dir(New), + check_dirs(Xs, New, Type); +check_dirs([], SoFar, _Type) -> + SoFar. + +assert_dir(D) -> + case file:read_file_info(D) of + {ok, X} when X#file_info.type == directory -> ok; + _ -> case file:make_dir(D) of + ok -> ok; + _ -> exit({could_not_create, D}) + end + end. + +do_add_opt(G, handle_info, V) -> + ?insert(G#genobj.options, {option, {handle_info, V}}, true); +do_add_opt(G, {handle_info, V}, false) -> + ?insert(G#genobj.options, {option, {handle_info, V}}, force_false); +do_add_opt(G, timeout, V) -> + ?insert(G#genobj.options, {option, {timeout, V}}, true); +do_add_opt(G, {timeout, V}, false) -> + ?insert(G#genobj.options, {option, {timeout, V}}, force_false); +do_add_opt(G, this, V) -> + ?insert(G#genobj.options, {option, {this, V}}, true); +do_add_opt(G, {this, V}, false) -> + ?insert(G#genobj.options, {option, {this, V}}, force_false); +do_add_opt(G, from, V) -> + ?insert(G#genobj.options, {option, {from, V}}, true); +do_add_opt(G, {from, V}, false) -> + ?insert(G#genobj.options, {option, {from, V}}, force_false); +do_add_opt(G, scoped_op_calls, V) when V /= true, V /= false -> + ?insert(G#genobj.options, {option, {scoped_op_calls, V}}, false); +do_add_opt(G, K, V) -> + case allowed_opt(K, V) of + true -> + case expand_opt(K) of + L when is_list(L) -> + add_opt(G, L, V); + _ -> + %%io:format("Add opt: ~p ~p~n", [K, V]), + ?insert(G#genobj.options, {option, K}, V) + end; + _ -> + ic_error:warn(G, {illegal_opt, K}) + end. + +get_opt(G, K) -> + case ets:lookup(G#genobj.options, {option, K}) of + [] -> false; + [{{_, K}, V}] -> V + end. + +expand_opt(pedantic) -> [warn_multi_mod, warn_quoted_atom, always_outargs]; +expand_opt(module_group) -> [skel_module_group, stub_module_group]; +expand_opt('Wall') -> [warn_multi_mod, warn_nested_mod, warn_name_shadow]; +expand_opt(outdir) -> [servdir, stubdir]; +expand_opt(default_opts) -> + ['Wall', gen_hrl, {serv_last_call, exception}, + {outdir, []}, use_preproc, {preproc_cmd, "erl"}, + {preproc_flags, ""}, {maxerrs, 10}, {maxwarns, infinity}]; +%% gcc preproc command {preproc_cmd, "gcc -x c++ -E"} +expand_opt(Opt) -> Opt. + + +%% Use this if user not provide +%% a backend. +defaultBe() -> erl_corba. + + +%% +%% Read any config file +read_cfg(G, Opts) -> + Name = case lists:keysearch(cfgfile, 1, Opts) of + {value, {_, N}} -> ic_util:to_list(N); + _ -> ?DEFAULTCFGFILE + end, + case file:consult(Name) of + {ok, OptList} -> + add_opt(G, OptList, true); + _X when Name == ?DEFAULTCFGFILE -> ok; +%% {error, X} -> +%% ic_error:warn(G, {cfg_open, X, Name}); + X -> ic_error:warn(G, {cfg_open, X, Name}) + end. + + +float_to_version({_,_,Str}) -> Str. + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- +is_bool(true) -> true; +is_bool(false) -> true; +is_bool(_) -> false. + +is_int(V) when is_integer(V) -> true; +is_int(_) -> false. + +is_intorinfinity(X) when is_integer(X) -> true; +is_intorinfinity(infinity) -> true; +is_intorinfinity(_X) -> false. + + +is_term(Term) when is_tuple(Term) -> true; +is_term(_NoTerm) -> false. + diff --git a/lib/ic/src/ic_plainbe.erl b/lib/ic/src/ic_plainbe.erl new file mode 100644 index 0000000..7b3e3dc --- /dev/null +++ b/lib/ic/src/ic_plainbe.erl @@ -0,0 +1,355 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_plainbe). + + +-export([do_gen/3]). +%%------------------------------------------------------------ +%% +%% Internal stuff +%% +%%------------------------------------------------------------ + +-import(ic_util, [mk_var/1, mk_oe_name/2, to_atom/1, to_list/1]). +-import(ic_forms, [get_id/1, get_id2/1, get_body/1]). +-import(ic_codegen, [emit/3, nl/1]). + +-import(lists, [foreach/2, map/2]). + +-include("icforms.hrl"). +-include("ic.hrl"). + +%%------------------------------------------------------------ +%% +%% Generate the client side Erlang stubs. +%% +%% Each module is generated to a separate file. +%% +%% Export declarations for all interface functions must be +%% generated. Each function then needs to generate a function head and +%% a body. IDL parameters must be converted into Erlang parameters +%% (variables, capitalised) and a type signature list must be +%% generated (for later encode/decode). +%% +%%------------------------------------------------------------ + + +do_gen(G, File, Form) -> + G2 = ic_file:filename_push(G, [], mk_oe_name(G, + ic_file:remove_ext(to_list(File))), + erlang), + gen_head(G2, [], Form), + exportDependency(G2), + gen(G2, [], Form), + genDependency(G2), + ic_file:filename_pop(G2, erlang), + ok. + + +gen(G, N, [X|Xs]) when is_record(X, preproc) -> + NewG = ic:handle_preproc(G, N, X#preproc.cat, X), + gen(NewG, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, module) -> + CD = ic_code:codeDirective(G,X), + G2 = ic_file:filename_push(G, N, X, CD), + N2 = [get_id2(X) | N], + gen_head(G2, N2, X), + gen(G2, N2, get_body(X)), + G3 = ic_file:filename_pop(G2, CD), + gen(G3, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, interface) -> + %% Add inheritence data to pragmatab + ic_pragma:add_inh_data(G,N,X), + G2 = ic_file:filename_push(G, N, X, erlang), + N2 = [get_id2(X) | N], + gen_head(G2, N2, X), + gen(G2, N2, get_body(X)), + foreach(fun({_Name, Body}) -> gen(G2, N2, Body) end, + X#interface.inherit_body), + G3 = ic_file:filename_pop(G2, erlang), + gen(G3, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, const) -> +% N2 = [get_id2(X) | N], + emit_constant_func(G, X#const.id, X#const.val), + gen(G, N, Xs); %% N or N2? + +gen(G, N, [X|Xs]) when is_record(X, op) -> + {Name, ArgNames, TypeList, OutArgs} = extract_info(G, N, X), + emit_func(G, N, X, Name, ArgNames, TypeList, OutArgs), + gen(G, N, Xs); + + +gen(G, N, [X|Xs]) when is_record(X, attr) -> + emit_attr(G, N, X, fun emit_func/7), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) when is_record(X, except) -> + icstruct:except_gen(G, N, X, erlang), + gen(G, N, Xs); + +gen(G, N, [X|Xs]) -> + case may_contain_structs(X) of + true -> icstruct:struct_gen(G, N, X, erlang); + false -> ok + end, + gen(G, N, Xs); + +gen(_G, _N, []) -> ok. + + +may_contain_structs(X) when is_record(X, typedef) -> true; +may_contain_structs(X) when is_record(X, struct) -> true; +may_contain_structs(X) when is_record(X, union) -> true; +may_contain_structs(_X) -> false. + + +%%------------------------------------------------------------ +%% +%% Export stuff +%% +%% Gathering of all names that should be exported from a stub +%% file. +%% + + +gen_head_special(G, N, X) when is_record(X, interface) -> + Fd = ic_genobj:stubfiled(G), + + foreach(fun({Name, Body}) -> + ic_codegen:comment(Fd, "Exports from ~p", + [ic_util:to_colon(Name)]), + ic_codegen:export(Fd, exp_top(G, N, Body, [])), + nl(Fd) + end, X#interface.inherit_body), + Fd; +gen_head_special(_G, _N, _X) -> ok. + + + +%% Shall generate all export declarations +gen_head(G, N, X) -> + case ic_genobj:is_stubfile_open(G) of + true -> + F = ic_genobj:stubfiled(G), + ic_codegen:comment(F, "Interface functions"), + ic_codegen:export(F, exp_top(G, N, X, [])), + nl(F), + gen_head_special(G, N, X); + false -> ok + end. + +exp_top(_G, _N, X, Acc) when element(1, X) == preproc -> + Acc; +exp_top(G, N, L, Acc) when is_list(L) -> + exp_list(G, N, L, Acc); +exp_top(G, N, M, Acc) when is_record(M, module) -> + exp_list(G, N, get_body(M), Acc); +exp_top(G, N, I, Acc) when is_record(I, interface) -> + exp_list(G, N, get_body(I), Acc); +exp_top(G, N, X, Acc) -> + exp3(G, N, X, Acc). + +exp3(_G, _N, C, Acc) when is_record(C, const) -> + [{get_id(C#const.id), 0} | Acc]; + +exp3(_G, _N, Op, Acc) when is_record(Op, op) -> + FuncName = get_id(Op#op.id), + Arity = length(ic:filter_params([in, inout], Op#op.params)), + [{FuncName, Arity} | Acc]; + +exp3(_G, _N, A, Acc) when is_record(A, attr) -> + lists:foldr(fun(Id, Acc2) -> + {Get, Set} = mk_attr_func_names([], get_id(Id)), + case A#attr.readonly of + {readonly, _} -> [{Get, 1} | Acc2]; + _ -> [{Get, 1}, {Set, 2} | Acc2] + end end, Acc, ic_forms:get_idlist(A)); + +exp3(_G, _N, _X, Acc) -> Acc. + +exp_list(G, N, L, OrigAcc) -> + lists:foldr(fun(X, Acc) -> exp3(G, N, X, Acc) end, OrigAcc, L). + + + + +%%------------------------------------------------------------ +%% +%% Emit stuff +%% +%% Low level generation primitives +%% + + +emit_func(G, _N, X, Name, ArgNames, _TypeList, OutArgs) -> + case ic_genobj:is_stubfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:stubfiled(G), + OpName = list_to_atom(Name), + ArgList = mk_list(ArgNames), + emit_op_comment(G, Fd, X, OpName, ArgNames, OutArgs), + emit(Fd, "~p(~s) ->\n", [OpName,ArgList]), + emit(Fd, " ~p:~p(~s).\n\n", [to_atom(ic_genobj:impl(G)), OpName, ArgList]) + end. + +emit_attr(G, N, X, F) -> + XX = #id_of{type=X}, + {GetType, SetType} = mk_attr_func_types(N, X), + lists:foreach(fun(Id) -> + X2 = XX#id_of{id=Id}, + {Get, Set} = mk_attr_func_names(N, get_id(Id)), + F(G, N, X2, Get, [], GetType, []), + case X#attr.readonly of + {readonly, _} -> ok; + _ -> + F(G, N, X2, Set, [ic_util:mk_name(G, "Value")], + SetType, []) + end end, ic_forms:get_idlist(X)). + +emit_constant_func(G, Id, Val) -> + case ic_genobj:is_stubfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:stubfiled(G), + N = list_to_atom(get_id(Id)), + emit_const_comment(G, Fd, Id, N), + emit(Fd, "~p() -> ~p.\n\n", [N, Val]) + end. + + +emit_const_comment(_G, F, _X, Name) -> + ic_codegen:mcomment_light(F, + [io_lib:format("Constant: ~p", [Name])]). + + +emit_op_comment(G, F, X, Name, InP, OutP) -> + ic_codegen:mcomment_light(F, + [io_lib:format("~s: ~p", [get_title(X), Name]), + "", + get_returns(G, X, InP, OutP) | + get_raises(X)]). + +get_title(X) when is_record(X, attr) -> "Attribute Operation"; +get_title(_X) -> "Operation". + +get_raises(X) when is_record(X, op) -> + if X#op.raises == [] -> []; + true -> + [" Raises: " ++ + mk_list(lists:map(fun(E) -> ic_util:to_colon(E) end, X#op.raises))] + end; +get_raises(_X) -> []. + +get_returns(_G, _X, _InP, []) -> + " Returns: RetVal"; +get_returns(G, _X, _InP, OutP) -> + " Returns: "++mk_list(["RetVal" | mk_erl_vars(G, OutP)]). + + + + +%%------------------------------------------------------------ +%% +%% Utilities +%% +%% Convenient little go-get functions +%% +%%------------------------------------------------------------ + +%% The automaticly generated get and set operation names for an +%% attribute. +mk_attr_func_names(_Scope, Name) -> + {"_get_" ++ Name, "_set_" ++ Name}. + +%% Returns TK of the Get and Set attribute functions. +mk_attr_func_types(_N, X) -> + TK = ic_forms:get_tk(X), + {{TK, [], []}, {tk_void, [TK], []}}. + + + +%%------------------------------------------------------------ +%% +%% Generation utilities and common stuff +%% +%% Convenient stuff for generation +%% +%%------------------------------------------------------------ + + +%% Input is a list of parameters (in parse form) and output is a list +%% of capitalised variable names. mk_var is in icgen +mk_erl_vars(_G, Params) -> + map(fun(P) -> mk_var(get_id(P#param.id)) end, Params). + + +%% mk_list produces a nice comma separated string of variable names +mk_list([]) -> []; +mk_list([Arg | Args]) -> + Arg ++ mk_list2(Args). +mk_list2([Arg | Args]) -> + ", " ++ Arg ++ mk_list2(Args); +mk_list2([]) -> []. + + +%%------------------------------------------------------------ +%% +%% Parser utilities +%% +%% Called from the yecc parser. Expands the identifier list of an +%% attribute so that the attribute generator never has to handle +%% lists. +%% +%%------------------------------------------------------------ + + + + +%% Export code produce for dependency function +exportDependency(G) -> + Fd = ic_genobj:stubfiled(G), + ic_codegen:export(Fd, [{oe_dependency, 0}]), + nl(Fd). + +%% Code produce for dependency function +genDependency(G) -> + Fd = ic_genobj:stubfiled(G), + nl(Fd),nl(Fd), + ic_codegen:comment(Fd, "Idl file dependency list function"), + emit(Fd, "oe_dependency() ->\n", []), + emit(Fd, " ~p.\n\n", [ic_pragma:get_dependencies(G)]). + + + + +extract_info(G, _N, X) when is_record(X, op) -> + Name = get_id2(X), + InArgs = ic:filter_params([in,inout], X#op.params), + OutArgs = ic:filter_params([out,inout], X#op.params), + ArgNames = mk_erl_vars(G, InArgs), + TypeList = {ic_forms:get_tk(X), + map(fun(Y) -> ic_forms:get_tk(Y) end, InArgs), + map(fun(Y) -> ic_forms:get_tk(Y) end, OutArgs) + }, + {Name, ArgNames, TypeList, OutArgs}. diff --git a/lib/ic/src/ic_pp.erl b/lib/ic/src/ic_pp.erl new file mode 100644 index 0000000..db06118 --- /dev/null +++ b/lib/ic/src/ic_pp.erl @@ -0,0 +1,2139 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_pp). + +-export([run/2]). + +-define(is_number(X), X >= $0, X =< $9). +-define(is_upper(X), X >= $A, X =< $Z). +-define(is_lower(X), X >= $a, X =< $z). +-define(is_underline(X), X == $_). +-define(is_tab(X), X == 9). +-define(is_space(X), X == 32). +-define(tab, 9). +-define(space, 32). + + +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== +%% Preprocessor +%% +%% This preprocessor is equivalent to the gcc-preprocessor. It takes a file name and +%% a list of preprocessor flags as an input and returns a processed text file. +%% +%% The processing is done in two phases. +%% In the first phase the input file is tokenised into a list where all comments are +%% replaced by a space and all "backslash-newline" sequences are removed. +%% +%% In the second phase all macros are expanded. + +%% %% %% NOTE: #if, #else, and #elif are not yet implemented. +%% Only '#if 0' is implemented to be possible to keep old code as a comment for +%% future refence by putting '#if 0' before it and '#endif' after it. +%% +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== + + +%%====================================================================================== +%% Variables which are used throughout the program: +%% ------------------------------------------------ +%% +%% Command A preprocessor command +%% Current Temporary variable used when tokenising the file +%% Defs The currently valid macro definitions +%% Err The current list of errors = [{file, line number, error text}, ...] +%% File The tokenised file (or what remains of it when expanding the macros) +%% Flags The preprocessor flags +%% FN or FileName Tbe name of the current file +%% IfCou Used for ifdef/ifndef/endif values: check_all | {endif, Endif, IfLine} +%% Endif = number of matching endif's yet to be found +%% Ifline = the line number for the the first found ifdef/ifndef +%% IncDir Directories to be searched for included files +%% IncFile Stack of included files +%% IncLine The line numer of an include +%% L The current line number +%% Name Name of a macro +%% Nl Number of encountered newlines +%% No_of_para Numer of parameters of the currently expanded macro +%% Out The result of the second step +%% Parameters The parameters of the currently expanded macro +%% PrevFile The name of the "parent" file which includes the currently expanded file +%% Rem Remaining of the file currently being expanded +%% Removed The tokens removed, used when removing tokens to the end of a line +%% Result The current result of something +%% SelfRef List of variables which shoud not be expanded at the rescan to avoid +%% endless loops due to self referencing +%% Str Temporary string +%% Text A variable used for string handling, e.g at error handling +%% Tokens Temoprary list when tokenising +%% War The current list of warnings = [{file, line number, warning text}, ...] +%% X Temporary variable used when the value is not important +%% Y Temporary variable used when the value is not important +%% +%%====================================================================================== + + + + +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== +%% The main entry for the preprocessor +%% +%% +%% Output {ok, Out, War} | {error, Err} +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== +run(FileName, Flags) when is_atom(FileName) -> + run(atom_to_list(FileName), Flags); + +run(FileName, Flags) -> + IncDir = include_dir(Flags), + + case catch file:read_file(FileName) of + {ok, Bin} -> + FileList = binary_to_list(Bin), + run(FileList, FileName, IncDir, Flags); + {error, _} -> + Text = "No such file or directory", + {error, [FileName ++ ": " ++ Text]} + end. + + +run(FileList, FileName, IncDir, Flags) -> + %%---------------------------------------------------------- + %% Run the first phase, i.e tokenise the file + %%---------------------------------------------------------- + File = tokenise(FileList, FileName), + + %%---------------------------------------------------------- + %% Run the second phase, i.e expand macros + %%---------------------------------------------------------- + {Out, Err, War, _Defs, IfCou} = expand(File, FileName, IncDir, Flags), + + %%---------------------------------------------------------- + %% Check if all #if #ifdef #ifndef have a matching #endif + %%---------------------------------------------------------- + IfError = case IfCou of + {endif, Endif, IfLine} when Endif > 0 -> + [{FileName, IfLine, "unterminated `#if' conditional"}]; + _ -> + [] + end, + + Err2 = Err++IfError, + + case Err2 of + [] -> + {ok, lists:flatten(lists:reverse(Out)), lists:reverse(War)}; + _ -> + {error, lists:reverse(Err2)} + end. + +%%====================================================================================== +%% The entry for all included files +%% +%% +%% Output {Out, Defs, Err, War} +%%====================================================================================== +run_include(FileName, FileList, _Out, Defs, Err, War, IncLine, IncFile, IncDir) -> + + %%---------------------------------------------------------- + %% Run the first phase, i.e tokenise the file + %%---------------------------------------------------------- + [PrevFile | _T] = IncFile, + {File, FileInfoStart, FileInfoEnd} = + tokenise(FileList, FileName, IncLine, PrevFile), + + %%---------------------------------------------------------- + %% Run the second phase, i.e expand macros + %%---------------------------------------------------------- + + %% Try first pass without file info start/end + {OutT, ErrT, WarT, DefsT, IfCouT} = + expand(File, Defs, Err, War, [FileName|IncFile], IncDir), + + {Out2, Err2, War2, Defs2, IfCou2} = + case only_nls(OutT) of + true -> %% The file is defined before + {["\n"], ErrT, WarT, DefsT, IfCouT}; + false -> %% The file is not defined before, try second pass + expand([FileInfoStart|File]++FileInfoEnd, Defs, Err, War, [FileName|IncFile], IncDir) + end, + + %%---------------------------------------------------------- + %% Check if all #if #ifdef #ifndef have a matching #endif + %%---------------------------------------------------------- + IfError = case IfCou2 of + {endif, Endif, IfLine} when Endif > 0 -> + [{FileName, IfLine, "unterminated `#if' conditional"}]; + _ -> + [] + end, + + {Out2, Defs2, Err2++IfError, War2}. + + + +%% Return true if there is no data +%% other than new lines +only_nls([]) -> + true; +only_nls(["\n"|Rem]) -> + only_nls(Rem); +only_nls(["\r","\n"|Rem]) -> + only_nls(Rem); +only_nls([_|_Rem]) -> + false. + + + + + + + + + + +%%=================================================================================== +%%=================================================================================== +%%=================================================================================== +%% Tokenise the file +%% +%% +%% Output: File +%% +%% Description: +%% The input file is tokenised into a list where all comments are replaced +%% by a space and all "backslash-newline" sequences are removed. +%% +%% A file information is added at start and end of an included file to set the +%% current file name and line number. +%% +%% +%% A token consists of: +%% -------------------- +%% +%% {char, Char} special characters like ()[]{},!%& etc +%% {command,Command} a macro command +%% {expanded,Str} an expanded variable, used to prevent infinite loops +%% at self reference +%% {file_info,FI} start and end information of a file +%% FI is a string of the following format: +%% "# Line FileName Int" were Int is +%% 1 if start of an included file, +%% 2 when returning to "parent" file +%% {nl, L} newline +%% {number,Num) variable, a string starting with a number +%% {self_ref,Var} to allow reference to a variable again, used when expanding +%% self refering macros +%% space a space +%% space_exp a space, special notation to prevent not wanted concatination +%% {string, Str} a (tail of a) string constant +%% {string_part, Str} a head of a string constant defined on several consecutive lines +%% {sys_head, Str} (tail of) the file name of included system file +%% {sys_head_part , Str} the file name of included system file +%% {var,Var} variable, a string starting with minuscular or capital letter or +%% an underline +%% +%% Note, comments are not removed within a character or string constant +%% or inside an include-definition where the file name is delimited with < > +%%=================================================================================== +%%=================================================================================== +%%=================================================================================== + +tokenise(File, FileName) -> + {Result, _L} = token(File, 2, [], not_set, 0), + FI_start = lists:reverse(lists:flatten(io_lib:format("# 1 ~p~n",[FileName]))), + FileInfoStart = {file_info, FI_start}, + [FileInfoStart | Result]. + +tokenise(File, FileName, IncLine, PrevFile) -> + {Result, _L} = token(File, 2, [], not_set, 0), + FI_start = lists:reverse(lists:flatten(io_lib:format("# 1 ~p 1~n",[FileName]))), + FileInfoStart = {file_info, FI_start}, + FI_end = lists:reverse(lists:flatten(io_lib:format("# ~p ~p 2~n~n",[IncLine-1,PrevFile]))), + FileInfoEnd = [{file_info, FI_end}], + {Result, FileInfoStart, FileInfoEnd}. +% [FileInfoStart | Result] ++ FileInfoEnd. + + +%%=================================================================================== +%% token(InputFile, L, Result, Gen) +%% Gen information of the first token on the line, default = not_set +%% +%% Output: File +%%=================================================================================== + +%%================================================================== +%% Normal line +%%================================================================== +%%--------------------------------------- +%% All file tokenised +%%--------------------------------------- +token([], L, [{nl,NL}|Result], _Gen, _BsNl) when L == NL+1-> + {lists:reverse([{nl,NL}|Result]), L}; +token([], L, Result, _Gen, _BsNl) -> + {lists:reverse([{nl,L-1}|Result]), L}; + +%%--------------------------------------- +%% String +%%--------------------------------------- +token(File, L, Result, string, BsNl) -> + case token_string(File, []) of + {Rem, Str, nl} -> + Result1 = [{nl, L}, {string,Str} | Result], + token(Rem, L+1, Result1, string, BsNl); + {Rem, Str} -> + token(Rem, L, [{string,Str}|Result], not_set, BsNl) + end; + +token([$"|File], L, Result, Gen, BsNl) -> + case token_string(File, []) of + {Rem, Str, nl} -> + Result1 = [{nl, L}, {string_part,Str} | Result], + token(Rem, L+1, Result1, string, BsNl); + {Rem, Str} -> + token(Rem, L, [{string,Str}|Result], Gen, BsNl) + end; + +%%--------------------------------------- +%% Include with < > +%%--------------------------------------- +token(File, L, Result, include, BsNl) -> + case token_include(File, []) of + {Rem, Str, nl} -> + Result1 = [{nl, L}, {sys_head,Str} | Result], + token(Rem, L+1, Result1, include, BsNl); + {Rem, Str} -> + token(Rem, L, [{sys_head,Str}|Result], not_set, BsNl) + end; + +token([$<|File], L, [space,{command,"include"}|Result], Gen, BsNl) -> + case token_include(File, []) of + {Rem, Str, nl} -> + Result1 = [{nl, L}, {sys_head_part,Str}, space, {command,"include"} |Result], + token(Rem, L+1,Result1, include, BsNl); + {Rem, Str} -> + Result1 = [{sys_head,Str}, space, {command,"include"} |Result], + token(Rem, L, Result1, Gen, BsNl) + end; +token([$<|File], L, [{command,"include"}|Result], Gen, BsNl) -> + case token_include(File, []) of + {Rem, Str, nl} -> + Result1 = [{nl, L}, {sys_head_part,Str}, space, {command,"include"} |Result], + token(Rem, L+1,Result1, include, BsNl); + {Rem, Str} -> + Result1 = [{sys_head,Str}, space, {command,"include"} |Result], + token(Rem, L, Result1, Gen, BsNl) + end; + + + + +%%--------------------------------------- +%% CR (just remove these) +%%--------------------------------------- +token([$\r|File], L, Result, Gen, BsNl) -> +% Bs = lists:duplicate(BsNl+1,{nl,L}), + token(File, L, Result, Gen, BsNl); %% Bs or BsNl? + +%%--------------------------------------- +%% Newline +%%--------------------------------------- +token([$\n|File], L, Result, _Gen, BsNl) -> + Bs = lists:duplicate(BsNl+1,{nl,L}), + token(File, L+1, Bs++Result, not_set, 0); + +token([$\\,$\n|File], L, Result, Gen, BsNl) -> + token(File, L, Result, Gen, BsNl+1); + +%%--------------------------------------- +%% Comments +%%--------------------------------------- +token([$/,$/|File], L, Result, not_set, BsNl) -> + Rem = skip_to_nl(File), + token(Rem, L+1,[{nl, L} | Result], not_set, BsNl); +token([$/,$/|File], L, Result, _Gen, BsNl) -> + Rem = skip_to_nl(File), + token(Rem, L+1,[{nl, L} | Result], not_set, BsNl); + +token([$/,$*|File], L, Result, not_set, BsNl) -> + case token_comment(File) of + {Rem, nl} -> + token(Rem, L+1, [{nl, L} | Result], not_set, BsNl); + Rem -> + token(Rem, L, Result, not_set, BsNl) + end; +token([$/,$*|File], L, Result, Gen, BsNl) -> + case token_comment(File) of + {Rem, nl} -> + token(Rem, L+1, [{nl, L}, space | Result], not_set, BsNl); + Rem -> + token(Rem, L, [space|Result], Gen, BsNl) + end; + +%%--------------------------------------- +%% Variable +%%--------------------------------------- +token([X|File], L, Result, Gen, BsNl) when ?is_upper(X) -> + GenNew = case Gen of not_set -> var; _ -> Gen end, + {Rem, Var} = tok_var(File, [X]), + token(Rem, L, [{var,Var}|Result], GenNew, BsNl); +token([X|File], L, Result, Gen, BsNl) when ?is_lower(X) -> + GenNew = case Gen of not_set -> var; _ -> Gen end, + {Rem, Var} = tok_var(File, [X]), + token(Rem, L, [{var,Var}|Result], GenNew, BsNl); +token([X|File], L, Result, Gen, BsNl) when ?is_underline(X) -> + GenNew = case Gen of not_set -> var; _ -> Gen end, + {Rem, Var} = tok_var(File, [X]), + token(Rem, L, [{var,Var}|Result], GenNew, BsNl); + +%%--------------------------------------- +%% Number +%%--------------------------------------- +token([X|File], L, Result, Gen, BsNl) when ?is_number(X) -> + GenNew = case Gen of not_set -> number; _ -> Gen end, + {Rem, Tokens} = tok_number(File, [X]), + token(Rem, L, [{number,Tokens}|Result], GenNew, BsNl); + +%%--------------------------------------- +%% Space +%%--------------------------------------- +token([X|File], L, [Y|Result], Gen, BsNl) when ?is_space(X) -> + case Y of + space -> + Rem = remove_leading_spaces(File), + token(Rem, L, [Y|Result], Gen, BsNl); + {nl,_,_} -> + Rem = remove_leading_spaces(File), + token(Rem, L, Result, Gen, BsNl); + _ -> + Rem = remove_leading_spaces(File), + token(Rem, L, [space, Y |Result], Gen, BsNl) + end; + +token([X|File], L, [Y|Result], Gen, BsNl) when ?is_tab(X) -> + case Y of + space -> + Rem = remove_leading_spaces(File), + token(Rem, L, [Y|Result], Gen, BsNl); + {nl,_,_} -> + Rem = remove_leading_spaces(File), + token(Rem, L, Result, Gen, BsNl); + _ -> + Rem = remove_leading_spaces(File), + token(Rem, L, [space, Y |Result], Gen, BsNl) + end; + +%%--------------------------------------- +%% Command +%%--------------------------------------- +token([$#|File], L, Result, not_set, BsNl) -> + {Rem, Command} = token_pp_com(File), + case catch list_to_integer(Command) of + {'EXIT', _} -> + token(Rem, L, [{command,Command}|Result], not_set, BsNl); + _Int -> + Result1 = [{number,Command}, {command,"line"}| Result], + token(Rem, L, Result1, not_set, BsNl) + end; + +%%--------------------------------------- +%% Char +%%--------------------------------------- +token([X|File], L, Result, Gen, BsNl) -> + GenNew = case Gen of not_set -> char; _ -> Gen end, + token(File, L, [{char,X}|Result], GenNew, BsNl). + + +%%================================================================== +%% Scan to the end of a token +%%================================================================== +%%--------------------------------------- +%% Number +%%--------------------------------------- +tok_number([], Str) -> + {[], lists:reverse(Str)}; +tok_number([X|File], Str) when ?is_upper(X) -> + tok_number(File, [X|Str]); +tok_number([X|File], Str) when ?is_lower(X) -> + tok_number(File, [X|Str]); +tok_number([X|File], Str) when ?is_underline(X) -> + tok_number(File, [X|Str]); +tok_number([X|File], Str) when ?is_number(X) -> + tok_number(File, [X|Str]); +tok_number(File, Str) -> + {File, lists:reverse(Str)}. + + +%%--------------------------------------- +%% Variable +%%--------------------------------------- +tok_var([], Str) -> + {[], lists:reverse(Str)}; +tok_var([X|File], Str) when ?is_upper(X) -> + tok_var(File, [X|Str]); +tok_var([X|File], Str) when ?is_lower(X) -> + tok_var(File, [X|Str]); +tok_var([X|File], Str) when ?is_underline(X) -> + tok_var(File, [X|Str]); +tok_var([X|File], Str) when ?is_number(X) -> + tok_var(File, [X|Str]); +tok_var(File, Str) -> + {File, lists:reverse(Str)}. + + +%%--------------------------------------- +%% Preprocessor command +%%--------------------------------------- +token_pp_com([X|File]) when ?is_upper(X) -> + tok_var(File, [X]); +token_pp_com([X|File]) when ?is_lower(X) -> + tok_var(File, [X]); +token_pp_com([X|File]) when ?is_underline(X) -> + tok_var(File, [X]); +token_pp_com([X|File]) when ?is_number(X) -> + tok_var(File, [X]); +token_pp_com(File) -> + Rem = remove_leading_spaces(File), + {Rem, "null"}. + + + +%%--------------------------------------- +%% Comment +%%--------------------------------------- +token_comment([]) -> + []; +token_comment([$*,$/|File]) -> + File; +token_comment([$\n|File]) -> + {[$/,$*|File], nl}; +token_comment([$\r,$\n|File]) -> + {[$/,$*|File], nl}; +token_comment([$\\,$\n|File]) -> + {[$/,$*|File], nl}; +%token_comment([$\\,$\n|File]) -> +% token_comment(File); +token_comment([_|File]) -> + token_comment(File). + + +%%--------------------------------------- +%% String +%%--------------------------------------- +token_string([], Str) -> + {[], lists:reverse(Str)}; +token_string([$"|File], Str) -> + {File, lists:reverse(Str)}; +token_string([$\n|File], Str) -> + {File, lists:reverse(Str), nl}; +token_string([$\r,$\n|File], Str) -> + {File, lists:reverse(Str), nl}; +token_string([$\\,$\n|File], Str) -> + token_string(File, Str); +token_string([X|File], Str) -> + token_string(File, [X|Str]). + + +%%--------------------------------------- +%% Include +%%--------------------------------------- +token_include([], Str) -> + {[], lists:reverse(Str)}; +token_include([$>|File], Str) -> + {File, lists:reverse(Str)}; +token_include([$\n|File], Str) -> + {File, lists:reverse(Str), nl}; +token_include([$\r,$\n|File], Str) -> + {File, lists:reverse(Str), nl}; +token_include([$\\,$\n|File], Str) -> + token_include(File, Str); +token_include([X|File], Str) -> + token_include(File, [X|Str]). + + + + +%%=================================================================================== +%% detokenise a list of tokens, until next newline +%% +%% Output: a string +%%=================================================================================== +detokenise(Tokens) -> + detokenise(Tokens, []). + +detokenise([], Result) -> + lists:flatten(Result); +detokenise([space], Result) -> + lists:flatten(Result); +detokenise([space_exp], Result) -> + lists:flatten(Result); +detokenise([space|Rem], Result) -> + detokenise(Rem, Result++[?space]); +detokenise([space_exp|Rem], Result) -> + detokenise(Rem, Result++[?space]); +detokenise([nl|Rem], Result) -> + detokenise(Rem, Result++[$\n]); +detokenise([{_, String}|Rem], Result) -> + detokenise(Rem, Result++[String]). + + +detokenise_pragma(Tokens) -> + detokenise_pragma(Tokens, []). + +detokenise_pragma([], Result) -> + lists:flatten(Result); +detokenise_pragma([space], Result) -> + lists:flatten(Result); +detokenise_pragma([space|Rem], Result) -> + detokenise_pragma(Rem, Result++[?space]); +detokenise_pragma([nl|Rem], Result) -> + detokenise_pragma(Rem, Result++[$\n]); +detokenise_pragma([{string, String}|Rem], Result) -> + detokenise_pragma(Rem, Result++[$"|String]++[$"]); +detokenise_pragma([{_, String}|Rem], Result) -> + detokenise_pragma(Rem, Result++[String]). + + + + + + + +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== +%% Expand macros. +%% +%% +%% Output: A text file +%% +%% Description: Expands all macros. All macro definitions are logged in a list 'Defs' +%% and all found errors and warnings are logged in a list 'Err' and 'War', +%% respectively. +%% +%% When a macro name is found in a source line it is expanded according +%% to the current 'Defs'-list. The macro must agree both to the name +%% and number of parameters, otherwise an error is reported. +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== + + +expand(List, FileName, IncDir, Flags) -> + %% Get all definitions from preprocessor commnads + %% and merge them on top of the file collected. + CLDefs = get_cmd_line_defs(Flags), + expand(List, [], [], CLDefs, [FileName], IncDir, check_all, [], [], 1, FileName). + +expand(List, Defs, Err, War, [FileName|IncFile], IncDir) -> + expand(List, [], [], Defs, [FileName|IncFile], IncDir, check_all, Err, War, 1, FileName). + + +%%======================================================= +%% Main loop for the expansion +%%======================================================= +expand([], Out, _SelfRef, Defs, _IncFile, _IncDir, IfCou, Err, War, _L, _FN) -> +% io:format("~n ===============~n"), +% io:format(" definitions ~p~n",[lists:reverse(Defs)]), +% io:format(" found warnings ~p~n",[lists:reverse(War)]), +% io:format(" found errors ~p~n",[lists:reverse(Err)]), +% io:format(" ===============~n~n~n"), + {Out, Err, War, Defs, IfCou}; + +expand([{file_info, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + expand(Rem, Str++Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +%%--------------------------------------- +%% Searching for endif, +%% i.e skip all source lines until matching +%% end if is encountered +%%--------------------------------------- +expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) + when Command == "ifdef" -> + {_Removed, Rem2, _Nl} = read_to_nl(Rem), + IfCou2 = {endif, Endif+1, IfLine}, + expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err, War, L, FN); + + +expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) + when Command == "ifndef" -> + {_Removed, Rem2, _Nl} = read_to_nl(Rem), + IfCou2 = {endif, Endif+1, IfLine}, + expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err, War, L, FN); + + +expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) + when Command == "if" -> + case pp_command(Command, Rem, Defs, IncDir, Err, War, L, FN) of + {{'if', true}, Rem2, Err2, War2, Nl} -> + IfCou2 = {endif, Endif+1, IfLine}, + expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN); +%% {{'if', false}, Rem2, Err2, War2, Nl} -> Not implemented yet + {{'if', error}, Rem2, Err2, War2, Nl} -> + IfCou2 = {endif, Endif, IfLine}, + expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN) + end; + +expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) + when Command == "endif" -> + {_Removed, Rem2, Nl} = read_to_nl(Rem), + case Endif of + 1 -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN); + _ -> + IfCou2 = {endif, Endif-1, IfLine}, + expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err, War, L+Nl, FN) + end; + + +expand([{command,_Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) -> + {_Removed, Rem2, _Nl} = read_to_nl(Rem), + IfCou2 = {endif, Endif, IfLine}, + expand(Rem2, Out, SelfRef, Defs, IncFile, IncDir, IfCou2, Err, War, L, FN); + +%% Solves a bug when spaces in front of hashmark ! +expand([space | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) -> + expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN); + +expand([{nl,_Nl} | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) -> + expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN); + + +expand([_X | Rem], Out, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN) -> + {_Removed, Rem2, Nl} = read_to_nl(Rem), + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, {endif, Endif, IfLine}, Err, War, L, FN); + + + + + +%%--------------------------------------- +%% Check all tokens +%%--------------------------------------- +expand([{nl, _N} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + expand(Rem, [$\n | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L+1, FN); + +expand([space | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + expand(Rem, [?space | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([space_exp | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + expand(Rem, [?space | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{command,Command} | Rem], Out, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L, FN) -> + case pp_command(Command, Rem, Defs, IncDir, Err, War, L, FN) of + {define, Rem2, Defs2, Err2, War2, Nl} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs2, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN); + + {undef, Rem2, Defs2, Err2, War2, Nl} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs2, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN); + + {{include, ok}, FileName, FileCont, Rem2, Nl, Err2, War2} -> + {Out3, Defs3, Err3, War3} = + run_include(FileName, FileCont, Out, Defs, Err2, War2, L+Nl, IncFile, IncDir), + Nls = [], + Out4 = Out3++Nls++Out, + expand(Rem2, Out4, SelfRef, Defs3, IncFile, IncDir, check_all, Err3, War3, L+Nl, FN); + + {{include, error}, Rem2, Nl, Err2, War2} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN); + + {{ifdef, true}, Rem2, Err2, War2, Nl} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + IfCou2 = {endif, 1, L}, + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN); + {{ifdef, false}, Rem2, Err2, War2, Nl} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN); + + {{ifndef, true}, Rem2, Err2, War2, Nl} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + IfCou2 = {endif, 1, L}, + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN); + {{ifndef, false}, Rem2, Err2, War2, Nl} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN); + + {endif, Rem2, Err2, War2, Nl} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN); + + {{'if', true}, Rem2, Err2, War2, Nl} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + IfCou2 = {endif, 1, L}, + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, IfCou2, Err2, War2, L+Nl, FN); +%% {{'if', false}, Removed, Rem2, Nl} -> Not implemented at present + {{'if', error}, Rem2, Err2, War2, Nl} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err2, War2, L+Nl, FN); + + {'else', {_Removed, Rem2, Nl}} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + Err2 = {FN, L, "`else' command is not implemented at present"}, + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN); + + {'elif', {_Removed, Rem2, Nl}} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + Err2 = {FN, L, "`elif' command is not implemented at present"}, + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN); + + {warning, {WarningText, Rem2, Nl}} -> + [FileName|_More] = IncFile, + War2 = {FileName, L, "warning: #warning "++detokenise(WarningText)}, + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, [War2|War], L+Nl, FN); + + {error, {ErrorText, Rem2, Nl}} -> + [FileName|_More] = IncFile, + Err2 = {FileName, L, detokenise(ErrorText)}, + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN); + + {{line, ok}, {_Removed, Rem2, Nl}, L2, FN2, LineText} -> + Out2 = lists:duplicate(Nl,$\n)++LineText++Out, + [_X|IF] = IncFile, + IncFile2 = [FN2|IF], + expand(Rem2, Out2, SelfRef, Defs, IncFile2, IncDir, check_all, Err, War, L2, FN2); + {{line, error}, {_Removed, Rem2, Nl}, Err2} -> + Out2 = [lists:duplicate(Nl,$\n)|Out], + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN); + + hash_mark -> + expand(Rem, Out, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L, FN); + + {pragma, Rem2, Nl, Text} -> + Out2 = lists:duplicate(Nl,$\n)++Text++Out, + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN); + + {ident, Rem2, Nl, Text} -> + Out2 = lists:duplicate(Nl,$\n)++Text++Out, + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN); + + {not_recognised, {Removed, Rem2, Nl}} -> + Text = lists:reverse([$#|Command]), + RemovedS = lists:reverse([?space|detokenise(Removed)]), + Out2 = [$\n|RemovedS]++Text++Out, + case Command of + [X|_T] when ?is_upper(X) -> + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN); + [X|_T] when ?is_lower(X) -> + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN); + [X|_T] when ?is_underline(X) -> + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, Err, War, L+Nl, FN); + _ -> + Err2 = {FN, L, "invalid preprocessing directive name"}, + expand(Rem2, Out2, SelfRef, Defs, IncFile, IncDir, check_all, [Err2|Err], War, L+Nl, FN) + end; + + Else -> +% io:format(" %%%%Else%%%%%% ~p~n",[Else]), + exit(Else) + end; + + +expand([{var, "__LINE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + LL = io_lib:format("~p",[L]), + expand(Rem, [LL | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{var, "__FILE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + expand(Rem, [$",FN,$" | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{var, "__DATE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + {{Y,M,D},{_H,_Mi,_S}} = calendar:universal_time(), + Date = io_lib:format("\"~s ~p ~p\"",[month(M),D,Y]), + expand(Rem, [Date | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{var, "__TIME__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + {{_Y,_M,_D},{H,Mi,S}} = calendar:universal_time(), + HS = if H < 10 -> "0"++integer_to_list(H); + true -> integer_to_list(H) + end, + MiS = if Mi < 10 -> "0"++integer_to_list(Mi); + true -> integer_to_list(Mi) + end, + SS = if S < 10 -> "0"++integer_to_list(S); + true -> integer_to_list(S) + end, + Time = io_lib:format("\"~s:~s:~s\"",[HS,MiS,SS]), + expand(Rem, [Time | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{var, "__INCLUDE_LEVEL__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + IL = io_lib:format("~p",[length(IncFile)-1]), + expand(Rem, [IL | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{var, "__BASE_FILE__"}|Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + [BF|_T] = lists:reverse(IncFile), + expand(Rem, [$",BF,$" | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{var, Var} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + {Out2, Err2, War2, Rem2, SelfRef2} = + source_line(Var, Rem, SelfRef, Defs, Err, War, L, FN), + expand(Rem2, [Out2 | Out], SelfRef2, Defs, IncFile, IncDir, IfCou, Err2, War2, L, FN); + +expand([{char, Char} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + expand(Rem, [Char | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{number, Number} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + expand(Rem, [Number | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{expanded, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + expand(Rem, [Str | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{self_ref, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + SelfRef2 = lists:delete(Str,SelfRef), + expand(Rem, Out, SelfRef2, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{string, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + expand(Rem, [$", Str, $" | Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN); + +expand([{string_part, Str} | Rem], Out, SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L, FN) -> + {Str2, Rem2, Nl} = expand_string_part([$"|Str], Rem), + expand(Rem2, [Str2| Out], SelfRef, Defs, IncFile, IncDir, IfCou, Err, War, L+Nl, FN). + + + + + + + + +%%======================================================================== +%% Expand a line starting as a partial string +%%======================================================================== +expand_string_part(Str, File) -> + expand_string_part(File, Str, 0). + +expand_string_part([{string, Str_part} | Rem], Str, Nl) -> + {Str++Str_part++[$"], Rem, Nl}; +expand_string_part([space | Rem], Str, Nl) -> + expand_string_part(Rem, Str, Nl); +expand_string_part([nl| Rem], Str, Nl) -> + expand_string_part(Rem, Str++[$\n], Nl); +expand_string_part([{string_part, Str_part} | Rem], Str, Nl) -> + expand_string_part(Rem, Str++Str_part, Nl). + + + + + +%%======================================================================== +%% Parse and integrate command line macro directives +%% At this momment, only -D and -U are supported (gcc like) +%%======================================================================== + + +%% Collect all command line macro definitions +get_cmd_line_defs(Flags) -> + Adjusted = parse_cmd_line(Flags,[]), + + {_Out, _Err, _War, Defs, _IfCou} = + expand(tokenise(Adjusted,""), + [], + [], + [], + [], + [], + check_all, + [], + [], + 1, + ""), + Defs. + +%% Parse command line macros +parse_cmd_line([],Found) -> + lists:flatten(lists:reverse(Found)); + +parse_cmd_line([45,68|Rest],Found) -> + {Collected,RestCmds} = collect_define(Rest,[]), + parse_cmd_line(RestCmds,[Collected|Found]); + +parse_cmd_line([45,85|Rest],Found) -> + {Collected,RestCmds} = collect_undefine(Rest,[]), + parse_cmd_line(RestCmds,[Collected|Found]); + +parse_cmd_line([_|Rest],Found) -> + parse_cmd_line(Rest,Found). + + +%% Collect defines and translate them +%% into a text format +collect_define([],Found) -> + { "#define "++lists:reverse(Found)++"\n", [] }; +collect_define([32|Rest],Found) -> + { "#define "++lists:reverse(Found)++"\n", Rest }; +collect_define([61|Rest],[]) -> + { "", Rest }; +collect_define([61|Rest],Found) -> + collect_define(Rest,[32|Found]); +collect_define([C|Rest],Found) -> + collect_define(Rest,[C|Found]). + + +%% Collect undefines and translate them +%% into a text format +collect_undefine([],Found) -> + { "#undef "++lists:reverse(Found)++"\n", [] }; +collect_undefine([32|Rest],Found) -> + { "#undef "++lists:reverse(Found)++"\n", Rest }; +collect_undefine([C|Rest],Found) -> + collect_undefine(Rest,[C|Found]). + + + + + + + + + + + + +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== +%% Read a preprocessor command +%% +%% +%% Output: Depending of the command, typically = {Command, Rem, Err, War, Nl} +%% +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== + +pp_command(Command, [space|File], Defs, IncDir, Err, War, L, FN) -> + pp_command(Command, File, Defs, IncDir, Err, War, L, FN); + +pp_command(Command, File, Defs, IncDir, Err, War, L, FN) -> + + case Command of + %%---------------------------------------- + %% #define + %%---------------------------------------- + "define" -> + case define(File, Err, War, L, FN) of + {error, Rem, Err2, War2, Nl} -> + {define, Rem, Defs, Err2, War2, Nl}; + {warning, Rem, Name, No_of_para, Parameters, Macro, Err2, War2, Nl} -> + case is_define_ok(Name, No_of_para, Parameters, Macro, Defs) of + {yes, Defs2} -> + {define, Rem, Defs2, Err2, War2, Nl}; + {no, Defs2} -> + Text = lists:flatten(io_lib:format("`~s' redefined",[Name])), + {define, Rem, Defs2, Err2, [{FN, L, Text}|War2], Nl}; + {error, Text, Defs2} -> + {define, Rem, Defs2, [{FN, L, Text}|Err2], War2, Nl} + end; + {ok, Rem, Name, No_of_para, Parameters, Macro, Err2, War2, Nl} -> + case is_define_ok(Name, No_of_para, Parameters, Macro, Defs) of + {yes, Defs2} -> + {define, Rem, Defs2, Err2, War2, Nl}; + {no, Defs2} -> + Text = lists:flatten(io_lib:format("`~s' redefined",[Name])), + {define, Rem, Defs2, Err2, [{FN, L, Text}|War2], Nl}; + {error, Text, Defs2} -> + {define, Rem, Defs2, [{FN, L, Text}|Err2], War2, Nl} + end + end; + + %%---------------------------------------- + %% #undef + %%---------------------------------------- + "undef" -> + case undef(File, Err, War, L, FN) of + {error, Rem, Err2, War2, Nl} -> + {undef, Rem, Defs, Err2, War2, Nl}; + {ok, Rem, Name, Err2, War2, Nl} -> + Defs2 = lists:keydelete(Name, 1, Defs), + {undef, Rem, Defs2, Err2, War2, Nl} + end; + + %%---------------------------------------- + %% #include + %%---------------------------------------- + "include" -> + case include(File, IncDir) of + {error, Rem, Nl, Err2} -> + {{include, error}, Rem, Nl, [{FN, L, Err2}|Err], War}; + {error, Rem, Nl, Err2, NameNl} -> + {{include, error}, Rem, Nl, [{FN, L+ NameNl, Err2}|Err], War}; + {ok, FileName, FileCont, Rem, Nl} -> + {{include, ok}, FileName, FileCont, Rem, Nl, Err, War} + end; + + %%---------------------------------------- + %% #ifdef + %%---------------------------------------- + "ifdef" -> + case define(File, Err, War, L, FN) of + {error, Rem, Err2, War2, Nl} -> + {{ifdef, false}, Rem, Defs, Err2, War2, Nl}; + {warning, Rem, Name, No_of_para, _Parameters, _Macro, Err2, War2, Nl} -> + case is_defined_before(Name, No_of_para, Defs) of + yes -> + {{ifdef, false}, Rem, Err2, War2, Nl}; + no -> + {{ifdef, true}, Rem, Err2, War2, Nl} + end; + {ok, Rem, Name, No_of_para, _Parameters, _Macro, Err2, War2, Nl} -> + case is_defined_before(Name, No_of_para, Defs) of + yes -> + {{ifdef, false}, Rem, Err2, War2, Nl}; + no -> + {{ifdef, true}, Rem, Err2, War2, Nl} + end + end; + + + + %%---------------------------------------- + %% #ifndef + %%---------------------------------------- + "ifndef" -> + case define(File, Err, War, L, FN) of + {error, Rem, Err2, War2, Nl} -> + {{ifndef, false}, Rem, Defs, Err2, War2, Nl}; + {warning, Rem, Name, No_of_para, _Parameters, _Macro, Err2, War2, Nl} -> + case is_defined_before(Name, No_of_para, Defs) of + yes -> + {{ifndef, true}, Rem, Err2, War2, Nl}; + no -> + {{ifndef, false}, Rem, Err2, War2, Nl} + end; + {ok, Rem, Name, No_of_para, _Parameters, _Macro, Err2, War2, Nl} -> + case is_defined_before(Name, No_of_para, Defs) of + yes -> + {{ifndef, true}, Rem, Err2, War2, Nl}; + no -> + {{ifndef, false}, Rem, Err2, War2, Nl} + end + end; + + + %%---------------------------------------- + %% #endif + %%---------------------------------------- + "endif" -> + {Removed, Rem, Nl} = read_to_nl(File), + case Removed of + [] -> + {endif, Rem, Err, War, 1}; + _ -> + Text = "ignoring the tail of the line", + {ok, Rem, Err, [{FN, L, Text}|War], Nl} + end; + + + %%---------------------------------------- + %% #if + %%---------------------------------------- + "if" -> + case if_zero(File, Err, War, L, FN) of + {error, Rem2, _Removed, Nl} -> + Err2 = {FN, L, "only '#if 0' is implemented at present"}, + {{'if', error}, Rem2, [Err2 | Err], War, Nl}; + {ok, Rem2, 0, _Removed, Nl} -> + {{'if', true}, Rem2, Err, War, Nl}; + {ok, Rem2, _Num, _Removed, Nl} -> + Err2 = {FN, L, "only '#if 0' is implemented at present"}, + {{'if', error}, Rem2, [Err2 | Err], War, Nl} + end; + + %%---------------------------------------- + %% #else + %%---------------------------------------- + "else" -> + {'else', read_to_nl(File)}; + + %%---------------------------------------- + %% #elif + %%---------------------------------------- + "elif" -> + {'elif', read_to_nl(File)}; + + %%---------------------------------------- + %% #pragma + %%---------------------------------------- + "pragma" -> + {Removed, Rem, Nl} = read_to_nl(File), + {pragma, Rem, Nl, lists:reverse("#pragma " ++ detokenise_pragma(Removed))}; + + %%---------------------------------------- + %% #ident + %%---------------------------------------- + "ident" -> + {Removed, Rem, Nl} = read_to_nl(File), + {ident, Rem, Nl, lists:reverse("#ident " ++ detokenise_pragma(Removed))}; + + %%---------------------------------------- + %% #warning + %%---------------------------------------- + "warning" -> + {warning, read_to_nl(File)}; + + %%---------------------------------------- + %% #error + %%---------------------------------------- + "error" -> + {error, read_to_nl(File)}; + + %%---------------------------------------- + %% #line + %%---------------------------------------- + "line" -> + line(File, L, FN); + + %%---------------------------------------- + %% # + %%---------------------------------------- + "null" -> + hash_mark; + + %%---------------------------------------- + %% not recognised preprocessor commands + %%---------------------------------------- + _Else -> + {not_recognised, read_to_nl(File)} + end. + + + + +%%=============================================================== +%%=============================================================== +%%=============================================================== +%% if +%% +%% Only #if 0 is implemented at the time to be able to use if +%% to comment some code parts. +%%=============================================================== +%%=============================================================== +%%=============================================================== + +if_zero(File, _Err, _War, _L, _FN) -> + case if_zero(File) of + {ok, Remain, Num, Removed, Nl} -> + case catch list_to_integer(Num) of + {'EXIT', _} -> + {Removed2, Rem2, Nl2} = read_to_nl(File), + {error, Rem2, Removed2, Nl2}; + Int -> + {ok, Remain, Int, Removed, Nl} + end; + E -> + E + end. + +if_zero([{number,Num}]) -> + {ok, [], Num, [], 0}; +if_zero([{number,Num}, space]) -> + {ok, [], Num, [], 0}; +if_zero([{number,Num} | Rem]) -> + {Removed, Rem2, Nl} = read_to_nl(Rem), + {ok, Rem2, Num, Removed, Nl}; +%if_zero([{number,Num}, {nl,_X} | Rem]) -> +% {ok, Rem, Num, [], 1}; +if_zero(Rem) -> + {Removed, Rem2, Nl} = read_to_nl(Rem), + {error, Rem2, Removed, Nl}. + + + +%%=============================================================== +%%=============================================================== +%%=============================================================== +%% Define macro +%% +%% Check the syntax of the macro, extract the parameters if any. +%% If valid macro it is added to the Defs-list. +%% If a macro is redefined, a warning will be given, the latest +%% definition is always the valid one. +%%=============================================================== +%%=============================================================== +%%=============================================================== + +define(File, Err, War, L, FN) -> + case define_name(File) of + {ok, Rem, Name, No_of_para, Parameters, Macro, Nl} -> + {ok, Rem, Name, No_of_para, Parameters, Macro, Err, War, Nl}; + {{warning,no_space}, Rem, Name, No_of_para, Parameters, Macro, Nl} -> + Text = lists:flatten(io_lib:format("missing white space after `#define ~s'",[Name])), + {warning, Rem, Name, No_of_para, Parameters, Macro, Err, [{FN, L, Text}|War], Nl}; + {error, invalid_name, Nl} -> + Text = "invalid macro name", + {_Removed, Rem, Nl2} = read_to_nl(File), + {error, Rem, [{FN, L, Text}|Err], War, Nl+Nl2}; + {error, invalid_name, Name, Nl} -> + Text = lists:flatten(io_lib:format("invalid macro name `~s'",[Name])), + {_Removed, Rem, Nl2} = read_to_nl(File), + {error, Rem, [{FN, L, Text}|Err], War, Nl+Nl2}; + {error, illegal_arg} -> + {Removed, Rem, Nl} = read_to_nl(File), + RemovedS = detokenise(Removed), + Text = lists:flatten(io_lib:format("Invalid argument list ~s",[RemovedS])), + {error, Rem, [{FN, L, Text}|Err], War, Nl} + end. + + + +%%=========================================================== +%% Check if valid macro +%%=========================================================== +define_name([]) -> + {warning, no_macro}; +define_name([space]) -> + {warning, no_macro}; +%% Macro with parameters +define_name([{var,Name},{char,$(}|Rem]) -> + case read_para([{char,$(}|Rem]) of + {ok, Rem2, Para, NoOfPara} -> + {Removed, Rem3, _Nl} = read_to_nl(Rem2), + {ok, Rem3, Name, NoOfPara, Para, Removed, 1}; + Error -> + Error + end; +%% Macro without parameters +define_name([{var,Name}]) -> + {ok, [], Name, 0, [], [], 0}; +define_name([{var,Name}, space | Rem]) -> + {Removed, Rem2, Nl} = read_to_nl(Rem), + {ok, Rem2, Name, 0, [], Removed, Nl}; +define_name([{var,Name}, {nl,_X} | Rem]) -> + {ok, Rem, Name, 0, [], [], 1}; +define_name([{var,Name} | Rem]) -> + {Removed, Rem2, Nl} = read_to_nl(Rem), + {{warning,no_space}, Rem2, Name, 0, [], Removed, Nl}; +%% Invalid macro name +define_name([{number, Name} | _Rem]) -> + {error, invalid_name, Name, 0}; +define_name(_Rem) -> + {error, invalid_name, 0}. + + + + + + + +%%=============================================================== +%%=============================================================== +%%=============================================================== +%% Undefine macro +%% +%% If it is a valid undef command the macro name will be deleted +%% from the Defs-list +%%=============================================================== +%%=============================================================== +%%=============================================================== + +undef(File, Err, War, L, FN) -> + case undef(File) of + {ok, Rem, Name, Nl} -> + {ok, Rem, Name, Err, War, Nl}; + {warning, Rem, Name, Nl} -> + Text = "ignoring the tail of the line", + {ok, Rem, Name, Err, [{FN, L, Text}|War], Nl}; + {error, invalid_name} -> + Text = "invalid macro name", + {_Removed, Rem, Nl} = read_to_nl(File), + {error, Rem, [{FN, L, Text}|Err], War, Nl}; + {error, invalid_name, Name} -> + Text = lists:flatten(io_lib:format("invalid macro name `~s'",[Name])), + {_Removed, Rem, Nl} = read_to_nl(File), + {error, Rem, [{FN, L, Text}|Err], War, Nl} + end. + +%%------------------------------------------------- +%% Check if valid macro name +%%------------------------------------------------- +undef([]) -> + {error, invalid_name, []}; +%% Valid name +undef([{var,Name}]) -> + {ok, [], Name, 0}; +undef([{var,Name}, {nl,_X} | Rem]) -> + {ok, Rem, Name, 1}; +undef([{var,Name}, space, {nl,_X} | Rem]) -> + {ok, Rem, Name, 1}; +undef([{var,Name} | Rem]) -> + {_Removed, Rem2, Nl} = read_to_nl(Rem), + {warning, Rem2, Name, Nl}; +%% Invalid macro name +undef([{number, Name} | _Rem]) -> + {error, invalid_name, Name}; +undef(_Rem) -> + {error, invalid_name}. + + + + + + +%%=============================================================== +%%=============================================================== +%%=============================================================== +%% Include macro +%% +%% Read the included file +%%=============================================================== +%%=============================================================== +%%=============================================================== + +include(File, IncDir) -> + case include2(File) of + {ok, FileName, Rem, Nl, FileType} -> + %% The error handling is lite strange just to make it compatible to gcc + case {read_inc_file(FileName, IncDir), Nl, FileType} of + {{ok, FileList, FileNamePath}, _, _} -> + {ok, FileNamePath, FileList, Rem, Nl}; + {{error, Text}, _, own_file} -> + NameNl = count_nl(FileName,0), + Error = lists:flatten(io_lib:format("~s: ~s",[FileName,Text])), + {error, Rem, Nl, Error, NameNl}; + {{error, Text}, 1, sys_file} -> + NameNl = count_nl(FileName,0), + Error = lists:flatten(io_lib:format("~s: ~s",[FileName,Text])), + {error, Rem, Nl, Error, NameNl}; + {{error, _Text}, _, sys_file} -> + {error, Rem, Nl, "`#include' expects \"FILENAME\" or "} + end; + + {error, {_Removed, Rem, Nl}} -> + {error, Rem, Nl, "`#include' expects \"FILENAME\" or "} + end. + +count_nl([],Nl) -> + Nl; +count_nl([$\n|T],Nl) -> + count_nl(T,Nl+1); +count_nl([_H|T],Nl) -> + count_nl(T,Nl). + +%%================================================= +%% Extract the file name from the token list +%%================================================= +include2([space|Rem]) -> + include2(Rem); + +include2([{string, FileName}]) -> + {ok, FileName, [], 1, own_file}; +include2([{string, FileName}, space]) -> + {ok, FileName, [], 1, own_file}; +include2([{string, FileName}, {nl, _X} | Rem]) -> + {ok, FileName, Rem, 1, own_file}; +include2([{string, FileName}, space, {nl, _X} | Rem]) -> + {ok, FileName, Rem, 1, own_file}; +include2([{string, _FileName}, _No_nl | Rem]) -> + {error, read_to_nl(Rem)}; +include2([{string_part, File_part}, {nl, _X} | Rem]) -> + case include_read_string_file_name(File_part++[$\n], Rem, 1) of + {ok, FileName, Rem2, Nl} -> + {ok, FileName, Rem2, Nl, own_file}; + error -> + {error, read_to_nl([{string_part,File_part} | Rem])} + end; +include2([{sys_head, FileName}]) -> + {ok, FileName, [], 1, sys_file}; +include2([{sys_head, FileName}, space]) -> + {ok, FileName, [], 1, sys_file}; +include2([{sys_head, FileName}, {nl, _X} | Rem]) -> + {ok, FileName, Rem, 1, sys_file}; +include2([{sys_head, FileName}, space, {nl, _X} | Rem]) -> + {ok, FileName, Rem, 1, sys_file}; +include2([{sys_head, _FileName}, _No_nl | Rem]) -> + {error, read_to_nl(Rem)}; +include2([{sys_head_part ,File_part}, {nl, _X} | Rem]) -> + case include_read_sys_file_name(File_part++[$\n], Rem, 1) of + {ok, FileName, Rem2, Nl} -> + {ok, FileName, Rem2, Nl, sys_file}; + error -> + {error, read_to_nl([{sys_head_part, File_part} | Rem])} + end; +include2(Rem) -> + {error, read_to_nl(Rem)}. + + + +%%------------------------------------------------- +%% File name framed by " " +%%------------------------------------------------- +include_read_string_file_name(File, [{string, File_part}, {nl,_X} | Rem], Nl) -> + {ok, File++File_part, Rem, Nl+1}; +include_read_string_file_name(File, [{string_part, File_part}, {nl,_X} | Rem], Nl) -> + include_read_string_file_name(File++File_part++[$\n], Rem, Nl+1); +include_read_string_file_name(_File, _X, _Nl) -> + error. + +%%------------------------------------------------- +%% File name framed by < > +%%------------------------------------------------- +include_read_sys_file_name(File, [{sys_head, File_part}, {nl,_X} | Rem], Nl) -> + {ok, File++File_part, Rem, Nl+1}; +include_read_sys_file_name(File, [{sys_head_part, File_part}, {nl,_X} | Rem], Nl) -> + include_read_sys_file_name(File++File_part++[$\n], Rem, Nl+1); +include_read_sys_file_name(_File, _X, _Nl) -> + error. + + + + + + + +%%=============================================================== +%%=============================================================== +%%=============================================================== +%% Line macro +%% +%% The line macro may redefine both the current line number and +%% the current file name: #line ' new_line_nr' 'new_file_name' +%%=============================================================== +%%=============================================================== +%%=============================================================== + +line(File, L, FN) -> + line(File, L, FN, not_defined, not_defined). + + + +line([], L, FN, _Line, _File) -> + {{line, error}, {[],[],0}, {FN,L,"invalid format `#line' directive"}}; + +line([space|Rem], L, FN, Line, File) -> + line(Rem, L, FN, Line, File); + +%%------------------------------ +%% Line number expected +%%------------------------------ +line([{number,Number}|Rem], L, FN, not_defined, File) -> + case catch list_to_integer(Number) of + {'EXIT', _} -> + {{line, error}, read_to_nl(Rem), {FN,L,"invalid format `#line' directive"}}; + Int -> + line(Rem, L, FN, Int, File) + end; +line(Rem, L, FN, not_defined, _File) -> + {{line, error}, read_to_nl(Rem), {FN,L,"invalid format `#line' directive"}}; + +%%------------------------------ +%% File name or newline expected +%%------------------------------ +line([{nl, _NL}|Rem], _L, FN, Line, not_defined) -> + {{line, ok}, {[],Rem,1}, Line, FN, io_lib:format("~n~p ~p #",[FN, Line-1])}; +line([{string,NewFN}|Rem], _L, _FN, Line, not_defined) -> + {{line, ok}, read_to_nl(Rem), Line, NewFN, io_lib:format("~n~p ~p #",[NewFN, Line-1])}; +line(Rem, L, FN, _Line, _File) -> + {{line, error}, read_to_nl(Rem), {FN,L,"invalid format `#line' directive"}}. + + + + +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== +%% Source line +%% +%% +%% Output: {Str, Err, War, Rem, SelfRef} +%% +%% Description: The input source line is searched for macros. If a macro is found it +%% is expanded. The result of an expansion is rescanned for more macros. +%% To prevent infinite loops if the macro is self referring +%% an extra token is put into the Rem list. The variable SelfRef +%% contains all the macros which are inhibited to be expanded. +%% A special specae token is also inserted to prevent not wanted +%% concatinations if one of the variables to be concatinated is expanded. +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== + +source_line(Str, Rem, SelfRef, Defs, Err, War, L, FN) -> + {Rem2, Para, No_of_para} = case read_para(Rem) of + {ok, RemT, ParaT, No_of_paraT} -> + {RemT, ParaT, No_of_paraT}; + {error, illegal_arg} -> + {[], [], 0} + end, + + + %%------------------------------------------------- + %% Check if a valid macro + %%------------------------------------------------- + case lists:keysearch(Str, 1, Defs) of + %% a macro without parameters + {value, {Str, 0, _MacroPara, Macro}} -> + case lists:member(Str, SelfRef) of + true -> + {[Str], Err, War, Rem, SelfRef}; + false -> + ExpandedRes2 = sl_mark_expanded(Macro, Str), + {[], Err, War, ExpandedRes2 ++ [{self_ref,Str}|Rem], [Str|SelfRef]} + end; + + %% a macro with parameters + {value, {Str, N, _MacroPara, Macro}} when N == No_of_para -> + case lists:member(Str, SelfRef) of + true -> + {[Str], Err, War, Rem, SelfRef}; + false -> + ExpandedRes = sl_macro_expand(Macro, Para, Defs), + ExpandedRes2 = sl_mark_expanded(ExpandedRes, Str), + {[], Err, War, ExpandedRes2 ++ [{self_ref,Str}|Rem2], [Str|SelfRef]} + end; + + %% a variable, because it doesn't have any parameters + {value, {Str, _N, _MacroPara, _Macro}} when No_of_para == 0 -> + {Str, Err, War, Rem, SelfRef}; + + %% illegal no of parameters + {value, {Str, N, _MacroPara, _Macro}} when No_of_para < N -> + Text = io_lib:format(" macro `~s' used with just ~p arg",[Str,No_of_para]), + Err2 = {FN, L, lists:flatten(Text)}, + {Str, [Err2|Err], War, Rem, SelfRef}; + {value, {Str, _N, _MacroPara, _Macro}} -> + Text = io_lib:format(" macro `~s' used with too many (~p) args",[Str,No_of_para]), + Err2 = {FN, L, lists:flatten(Text)}, + {Str, [Err2|Err], War, Rem, SelfRef}; + + %% no macro + false -> + {Str, Err, War, Rem, SelfRef} + end. + + + + + +%%================================================= +%% Expand a macro +%%================================================= +sl_macro_expand(Macro, Para, Defs) -> + sl_macro_expand(Macro, Para, Defs, []). + + +%%................... +%% End +%%................... +sl_macro_expand([], _Para, _Defs, Res) -> + lists:reverse(Res); + +%%................... +%% Concatination +%%................... +%% para ## para +sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, Res) -> + Exp = sl_para_para({para, N},{para, M}, Para), + sl_macro_expand(Exp++T, Para, Defs, [space |Res]); +%% para## para +sl_macro_expand([{para, N}, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, Res) -> + Exp = sl_para_para({para, N},{para, M}, Para), + sl_macro_expand(Exp++T, Para, Defs, [space |Res]); +%% para ##para +sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, Res) -> + Exp = sl_para_para({para, N},{para, M}, Para), + sl_macro_expand(Exp++T, Para, Defs, [space |Res]); +%% para##para +sl_macro_expand([{para, N}, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, Res) -> + Exp = sl_para_para({para, N},{para, M}, Para), + sl_macro_expand(Exp++T, Para, Defs, [space |Res]); + +%% para ## var +sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, space, {var, Var}|T], Para, Defs, Res) -> + Exp = sl_para_var({para, N}, {var, Var}, Para), + sl_macro_expand(Exp++T, Para, Defs, [space |Res]); +%% para## var +sl_macro_expand([{para, N}, {char,$#}, {char,$#}, space, {var, Var} | T], Para, Defs, Res) -> + [{var, VarN}] = lists:nth(N,Para), + sl_macro_expand(T, Para, Defs, [{expanded,Var},{expanded,VarN}, space |Res]); +%% para ##var +sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, {var, Var} | T], Para, Defs, Res) -> + [{var, VarN}] = lists:nth(N,Para), + sl_macro_expand(T, Para, Defs, [{expanded,Var},{expanded,VarN}, space |Res]); +%% para##var +sl_macro_expand([{para, N}, {char,$#}, {char,$#}, {var, Var} | T], Para, Defs, Res) -> + [{var, VarN}] = lists:nth(N,Para), + sl_macro_expand(T, Para, Defs, [{expanded,Var},{expanded,VarN}, space |Res]); + +%% var ## para +sl_macro_expand([{var, Var}, space, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, Res) -> + Exp = sl_var_para({var, Var},{para, M}, Para), + sl_macro_expand(Exp++T, Para, Defs, [space |Res]); +%% var## para +sl_macro_expand([{var, Var}, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, Res) -> + Exp = sl_var_para({var, Var},{para, M}, Para), + sl_macro_expand(Exp++T, Para, Defs, [space |Res]); +%% var ##para +sl_macro_expand([{var, Var}, space, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, Res) -> + Exp = sl_var_para({var, Var},{para, M}, Para), + sl_macro_expand(Exp++T, Para, Defs, [space |Res]); +%% var##para +sl_macro_expand([{var, Var}, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, Res) -> + Exp = sl_var_para({var, Var},{para, M}, Para), + sl_macro_expand(Exp++T, Para, Defs, [space |Res]); + +%% expanded ## para +sl_macro_expand([space, {char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, [{expanded, Var}|Res]) -> + [{var, VarM}] = lists:nth(M,Para), + sl_macro_expand(T, Para, Defs, [{expanded,VarM},{expanded,Var} |Res]); +%% expanded## para +sl_macro_expand([{char,$#}, {char,$#}, space, {para,M} | T], Para, Defs, [{expanded, Var}|Res]) -> + [{var, VarM}] = lists:nth(M,Para), + sl_macro_expand(T, Para, Defs, [{expanded,VarM},{expanded,Var} |Res]); +%% expanded ##para +sl_macro_expand([space, {char,$#}, {char,$#}, {para,M} | T], Para, Defs, [{expanded, Var}|Res]) -> + [{var, VarM}] = lists:nth(M,Para), + sl_macro_expand(T, Para, Defs, [{expanded,VarM},{expanded,Var} |Res]); +%% expanded##para +sl_macro_expand([{char,$#}, {char,$#}, {para,M} | T], Para, Defs, [{expanded, Var}|Res]) -> + [{var, VarM}] = lists:nth(M,Para), + sl_macro_expand(T, Para, Defs, [{expanded,VarM},{expanded,Var} |Res]); + +%% para ## ? +sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, space, X | T], Para, Defs, Res) -> + Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []), + sl_macro_expand([X, space|T], Para, Defs, lists:flatten([Reexp, space|Res])); +%% para## ? +sl_macro_expand([{para, N}, {char,$#}, {char,$#}, space, X | T], Para, Defs, Res) -> + Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []), + sl_macro_expand([X, space|T], Para, Defs, lists:flatten([Reexp, space|Res])); +%% para ##? +sl_macro_expand([{para, N}, space, {char,$#}, {char,$#}, X | T], Para, Defs, Res) -> + Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []), + sl_macro_expand([X, space|T], Para, Defs, lists:flatten([Reexp, space|Res])); +%% para##? +sl_macro_expand([{para, N}, {char,$#}, {char,$#}, X | T], Para, Defs, Res) -> + Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []), + sl_macro_expand([X, space|T], Para, Defs, lists:flatten([Reexp, space|Res])); + +sl_macro_expand([{char,$#}, {char,$#}, space |T], Para, Defs, [space|Res]) -> + sl_macro_expand(T, Para, Defs, Res); +sl_macro_expand([{char,$#}, {char,$#} |T], Para, Defs, [space|Res]) -> + sl_macro_expand(T, Para, Defs, Res); +sl_macro_expand([{char,$#}, {char,$#}, space |T], Para, Defs, Res) -> + sl_macro_expand(T, Para, Defs, Res); +sl_macro_expand([{char,$#}, {char,$#} |T], Para, Defs, Res) -> + sl_macro_expand(T, Para, Defs, Res); + +%%................... +%% Stringification +%%................... +sl_macro_expand([{char,$#}, {para, N}|T], Para, Defs, Res) -> + Nth = lists:nth(N,Para), + Tokens = detokenise(Nth), + sl_macro_expand(T, Para, Defs, [{string,Tokens}|Res]); +sl_macro_expand([{char,$#}, space, {para, N}|T], Para, Defs, Res) -> + Nth = lists:nth(N,Para), + Tokens = detokenise(Nth), + sl_macro_expand(T, Para, Defs, [{string,Tokens}|Res]); + +%%................... +%% A parameter +%%................... +sl_macro_expand([{para, N}|T], Para, Defs, Res) -> + Reexp = sl_macro_reexpand(lists:nth(N,Para), Defs, []), + sl_macro_expand(T, Para, Defs, lists:flatten([Reexp|Res])); + +%%................... +%% No parameter +%%................... +sl_macro_expand([H|T], Para, Defs, Res) -> + sl_macro_expand(T, Para, Defs, [H|Res]). + + + +%%------------------------------------------------- +%% Expand parameters +%%------------------------------------------------- +sl_para_para({para, N}, {para, M}, Para) -> + case sl_para_1st(lists:nth(N,Para)) of + {ok, Para1st} -> + Para1st ++ sl_para_2nd(lists:nth(M,Para)); + {exp, Para1st} -> + Para1st ++ sl_para_2nd(lists:nth(M,Para)) ++ [space_exp]; + {space, Para1st} -> + Para1st ++ [space_exp | sl_para_2nd(lists:nth(M,Para))] + end. + + +sl_var_para(Var, {para, M}, Para) -> + [Var|sl_para_2nd(lists:nth(M,Para))]. + + +sl_para_var({para, N}, Var, Para) -> + case sl_para_1st(lists:nth(N,Para)) of + {ok, Para1st} -> + Para1st ++ [Var]; + {exp, Para1st} -> + Para1st ++ [Var | space_exp]; + {space, Para1st} -> + Para1st ++ [space_exp | Var] + end. + + +sl_para_1st([{var, Var}]) -> + {ok,[{expanded,Var}]}; +sl_para_1st([{var, Var}, space]) -> + {ok,[{expanded,Var}]}; +sl_para_1st([{var, Var}, space_exp]) -> + {exp, [{expanded,Var}]}; +sl_para_1st(L) -> + {space, L}. + +sl_para_2nd([{var, Var}]) -> + [{expanded,Var}]; +sl_para_2nd([{var, Var}, space_exp]) -> + [{expanded,Var}]; +sl_para_2nd([space, {var, Var}]) -> + [{expanded,Var}]; +sl_para_2nd([space_exp, {var, Var}]) -> + [{expanded,Var}]; +sl_para_2nd(L) -> + L++[space]. + + + +%%------------------------------------------------- +%% Check if the expansion is a valid macro, +%% do not reexpand if concatination +%%------------------------------------------------- +sl_macro_reexpand([], _Defs, Result) -> + Result; +sl_macro_reexpand([{var,Var}|Rem], Defs, Result) -> + case lists:keysearch(Var, 1, Defs) of + {value, {Var, 0, _MacroPara, Macro}} -> + Rem2 = case Rem of + [space | RemT] -> + [space_exp | RemT]; + _ -> + [space_exp | Rem] + end, + sl_macro_reexpand(Macro++Rem2, Defs, Result); + _ -> + sl_macro_reexpand(Rem, Defs, [{var,Var}|Result]) + end; +sl_macro_reexpand([H|Rem], Defs, Result) -> + sl_macro_reexpand(Rem, Defs, [H|Result]). + + + +%%------------------------------------------------- +%% Self referring macros are marked not be reexpanded +%%------------------------------------------------- +sl_mark_expanded(QQ, Str) -> + sl_mark_expanded(QQ, Str, []). + +sl_mark_expanded([], _Str, Res) -> + lists:reverse(Res); +sl_mark_expanded([H|T], Str, Res) -> + case H of + {_,Str} -> + sl_mark_expanded(T, Str, [{expanded, Str}|Res]); + _ -> + sl_mark_expanded(T, Str, [H|Res]) + end. + + + + + + + + + +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== +%% Misceleaneous functions +%%====================================================================================== +%%====================================================================================== +%%====================================================================================== + + +%%=============================================================== +%% Check the Flags for include directories +%%=============================================================== +include_dir(Flags) when is_list(Flags)-> + include_dir(Flags,[]); +include_dir(_Flags) -> + []. + +include_dir(Flags,IncDir) -> + case string:str(Flags,"-I") of + 0 -> + lists:reverse(IncDir); + X -> + Rem2 = string:sub_string(Flags, X+2), + Rem = string:strip(Rem2, left), + Y = string:str(Rem," "), + case string:str(Rem," ") of + 0 -> + lists:reverse([string:sub_string(Rem, Y+1)|IncDir]); + Y -> + include_dir(string:sub_string(Rem, Y+1), + [string:sub_string(Rem,1,Y-1)|IncDir]) + end + end. + + + +%%=============================================================== +%% Read a included file. Try current dir first then the IncDir list +%%=============================================================== + +read_inc_file(FileName, IncDir) -> + case catch file:read_file(FileName) of + {ok, Bin} -> + FileList = binary_to_list(Bin), + {ok, FileList, FileName}; + {error, _} -> + read_inc_file2(FileName, IncDir) + end. + +read_inc_file2(_FileName, []) -> + {error, "No such file or directory"}; +read_inc_file2(FileName, [D|Rem]) -> + Dir = case lists:last(D) of + $/ -> + D; + _ -> + D++"/" + end, + + case catch file:read_file(Dir++FileName) of + {ok, Bin} -> + FileList = binary_to_list(Bin), + {ok, FileList, Dir++FileName}; + {error, _} -> + read_inc_file2(FileName, Rem) + end. + + + + +%%=============================================================== +%% Read parameters of a macro or a variable in a source line +%%=============================================================== +read_para([{char,$(} | Rem]) -> + read_para(Rem, 1, [], [], 1); +read_para([space,{char,$(} | Rem]) -> + read_para(Rem, 1, [], [], 1); +read_para(_Rem) -> + {ok, [], [], 0}. + + +%% Abrupt end of the list +read_para([], _NoOfParen, _Current, _Para, _NoOfPara) -> + {error, illegal_arg}; +%% All parameters checked +read_para([{char,$)}|Rem], 1, [], Para, NoOfPara) -> + {ok, Rem, lists:reverse(Para), NoOfPara}; +read_para([{char,$)}|Rem], 1, Current, Para, NoOfPara) -> + {ok, Rem, lists:reverse([Current|Para]), NoOfPara}; + +%% Continue reading +read_para([{char,$)}|Rem], NoOfParen, Current, Para, NoOfPara) -> + read_para(Rem, NoOfParen-1, Current++[{char,$)}], Para, NoOfPara); +read_para([{char,$(}|Rem], NoOfParen, Current, Para, NoOfPara) -> + read_para(Rem, NoOfParen+1, Current++[{char,$(}], Para, NoOfPara); +read_para([{char,$,}|Rem], NoOfParen, Current, Para, NoOfPara) when NoOfParen == 1 -> + read_para(Rem, NoOfParen, [], [Current|Para], NoOfPara+1); +read_para([space|Rem], NoOfParen, [], Para, NoOfPara) -> + read_para(Rem, NoOfParen, [], Para, NoOfPara); +read_para([X|Rem], NoOfParen, Current, Para, NoOfPara) -> + read_para(Rem, NoOfParen, Current++[X], Para, NoOfPara). + + + + + + +%%=================================================================================== +%% check if a macro is already defined +%%=================================================================================== +is_define_ok(Name, No_of_para, Parameters, Macro, Defs) -> + + case lists:keysearch(Name, 1, Defs) of + {value, {Name, No_of_para, _MacroPara, Macro}} -> + {yes, Defs}; + {value, _} -> + Defs2 = lists:keydelete(Name, 1, Defs), + NewMacro = is_define_ok_check_para(Parameters, Macro, []), + case is_stringify_ok(NewMacro) of + yes -> + {no, [{Name, No_of_para, Parameters, NewMacro}|Defs2]}; + no -> + ErrorText = "`#' operator is not followed by a macro argument name", + {error, ErrorText, [{Name, No_of_para, Parameters, NewMacro}|Defs2]} + end; + false -> + NewMacro = is_define_ok_check_para(Parameters, Macro, []), + case is_stringify_ok(NewMacro) of + yes -> + {yes, [{Name, No_of_para, Parameters, NewMacro}|Defs]}; + no -> + ErrorText = "`#' operator is not followed by a macro argument name", + {error, ErrorText, [{Name, No_of_para, Parameters, NewMacro}|Defs]} + end + end. + +is_define_ok_check_para(_Para, [], Result) -> + lists:reverse(Result); + +is_define_ok_check_para(Para, [H|T], Result) -> + case define_arg_para_number(1, Para, H) of + no_para -> + is_define_ok_check_para(Para, T, [H|Result]); + N -> + is_define_ok_check_para(Para, T, [{para,N}|Result]) + end. + +define_arg_para_number(_N, [], _Current) -> + no_para; +define_arg_para_number(N, [H|_Para], Current) when H == [Current] -> + N; +define_arg_para_number(N, [_H|Para], Current) -> + define_arg_para_number(N+1, Para, Current). + + +is_stringify_ok([]) -> + yes; +is_stringify_ok([{char,$#},{char,$#}|T]) -> + is_stringify_ok(T); +is_stringify_ok([{char,$#},space,{para,_X}|T]) -> + is_stringify_ok(T); +is_stringify_ok([{char,$#},{para,_X}|T]) -> + is_stringify_ok(T); +is_stringify_ok([{char,$#},space,{var,_X}|T]) -> + is_stringify_ok(T); +is_stringify_ok([{char,$#},{var,_X}|T]) -> + is_stringify_ok(T); +is_stringify_ok([{char,$#},space,{nl,_X}|_T]) -> + no; +is_stringify_ok([{char,$#},{nl,_X}|_T]) -> + no; +is_stringify_ok([{char,$#}|_T]) -> + no; +is_stringify_ok([_H|T]) -> + is_stringify_ok(T). + +%%=================================================================================== +%% check if a macro is already defined +%%=================================================================================== +is_defined_before(Name, No_of_para, Defs) -> + case lists:keysearch(Name, 1, Defs) of + {value, {Name, No_of_para, _MacroPara, _Macro}} -> + yes; + {value, _} -> + no; + false -> + no + end. + + + + +%%=================================================================================== +%% read_to_nl(File) +%%=================================================================================== +read_to_nl([space|Rem]) -> + read_to_nl(Rem, [], 1); +read_to_nl(Rem) -> + read_to_nl(Rem, [], 1). + +read_to_nl([], Result, Nl) -> + {lists:reverse(Result), [], Nl}; +read_to_nl([{nl, _N}|Rem], [{string_part,String} | Result], Nl) -> + read_to_nl(Rem, [nl, {string_part,String}|Result], Nl+1); +read_to_nl([{nl, _N}|Rem], [{sys_head_part,String} | Result], Nl) -> + read_to_nl(Rem, [nl, {sys_head_part,String}|Result], Nl+1); +read_to_nl([{nl, _N}|Rem], Result, Nl) -> + {lists:reverse(Result), Rem, Nl}; +read_to_nl([space|Rem], Result, Nl) -> + read_to_nl(Rem, [space|Result], Nl); +read_to_nl([{X,String}|Rem], Result, Nl) -> + read_to_nl(Rem, [{X,String}|Result], Nl). + + + + +%%=========================================================== +%% Read characters until next newline +%%=========================================================== +%read_to_nl2(Str) -> read_to_nl2([],Str). + +%read_to_nl2(Line, []) -> {Line,[]}; +%read_to_nl2(Line, [$\n|Str]) -> {Line, Str}; +%read_to_nl2(Line, [X|Str]) -> read_to_nl2([X|Line], Str). + + + + +%%=========================================================== +%% Remove leading spaces from a list +%%=========================================================== +remove_leading_spaces([?space|List]) -> + remove_leading_spaces(List); +remove_leading_spaces([?tab|List]) -> + remove_leading_spaces(List); +remove_leading_spaces(List) -> + List. + + + + +%%=========================================================== +%% Skip characters until next newline +%%=========================================================== +skip_to_nl([]) -> []; +skip_to_nl([$\n | Str]) -> Str; +skip_to_nl([$\\,$\n | Str]) -> [$/,$/|Str]; +skip_to_nl([_|Str]) -> skip_to_nl(Str). + + + + +month(1) -> "Jan"; +month(2) -> "Feb"; +month(3) -> "Mar"; +month(4) -> "Apr"; +month(5) -> "May"; +month(6) -> "Jun"; +month(7) -> "Jul"; +month(8) -> "Aug"; +month(9) -> "Sep"; +month(10) -> "Oct"; +month(11) -> "Nov"; +month(12) -> "Dec". + + + + diff --git a/lib/ic/src/ic_pragma.erl b/lib/ic/src/ic_pragma.erl new file mode 100644 index 0000000..9165e3b --- /dev/null +++ b/lib/ic/src/ic_pragma.erl @@ -0,0 +1,1957 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ic_pragma). + + +-export([pragma_reg/2,pragma_cover/3]). +-export([pragma_prefix/3,pragma_version/3,pragma_id/3]). +-export([mk_alias/3,get_alias/2,scope2id/2,id2scope/2,mk_scope/1]). +-export([mk_ref/3,get_incl_refs/1,get_local_refs/1]). +-export([get_dependencies/1, add_inh_data/3, preproc/3]). +-export([getBrokerData/3,defaultBrokerData/1,list_to_term/1]). +-export([get_local_c_headers/2,get_included_c_headers/1,is_inherited_by/3]). +-export([no_doubles/1,fetchRandomLocalType/1,fetchLocalOperationNames/2]). +-export([is_local/2]). + +%% Debug +-export([print_tab/1,slashify/1,is_short/1]). + +-import(lists,[suffix/2,delete/2,reverse/1,keysearch/3,member/2,last/1,flatten/1]). +-import(string,[tokens/2]). +-import(ets,[insert/2,lookup/2]). + +-import(ic_forms, [get_id2/1, get_body/1, get_line/1]). +-import(ic_util, [to_atom/1]). +-import(ic_genobj, [idlfile/1]). +-import(ic_options, [get_opt/2]). + +-include("icforms.hrl"). +-include("ic.hrl"). + + + + +%% Initialization of the pragma table and +%% start of pragma registration. +%% NOTE : this pragma registration is build +%% as a separate stage under compilation. +%% If it is to be optimised, it should be +%% embodied in one of other compiling stages. +pragma_reg(G,X) -> + S = ic_genobj:pragmatab(G), + init_idlfile(G,S), + init_pragma_status(S), + registerOptions(G,S), + pragma_reg_all(G, S, [], X), + denote_specific_code_opts(G), %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case get_pragma_compilation_status(S) of + true -> + %% Remove ugly pragmas from form + PragmaCleanForm = cleanup(X), + {ok,PragmaCleanForm}; + false -> + ErrorNr = get_pragma_error_nr(S), + %% Just print the number of errors found + case ErrorNr > 1 of + true -> + io:format("There were ~p errors found on file ~p~n", + [ErrorNr,get_idlfile(S)]), + error; + false -> + io:format("There were ~p error found on file ~p~n", + [ErrorNr,get_idlfile(S)]), + error + end + end. + + + +registerOptions(G,S) -> + OptList = ets:tab2list(ic_genobj:optiontab(G)), + registerOptions(G,S,OptList). + + +registerOptions(_G,_S,[]) -> + true; +registerOptions(G,S,[{{option,{broker,Scope}},{Mod,Type}}|Rest]) -> + insert(S, + {codeopt, + reverse(tokens(Scope,":")), + {broker,{Mod,Type}}, + -1, + nil, + nil}), + registerOptions(G,S,Rest); +registerOptions(G,S,[_|Rest]) -> + registerOptions(G,S,Rest). + + +%% Decide if to apply pragmas +%% by checking backend switch +applyPragmasInBe(G) -> + case get_opt(G, be) of + erl_plain -> + false; + _ -> + true + end. + + +%% Decide if the code option directive +%% is allowed to change backend +applyCodeOpt(G) -> + case get_opt(G, be) of + erl_corba -> %% Does not support codeopt + false; + erl_plain -> %% Does not support codeopt + false; + c_native -> %% Does not support codeopt + false; + _ -> + true + end. + + + +%% This removes all pragma records from the form. +%% When debugged, it can be enbodied in pragma_reg_all. +cleanup([],C) -> C; +cleanup([X|Xs],CSF) -> + cleanup(Xs, CSF++cleanup(X)). + +cleanup(X) when is_list(X) -> cleanup(X,[]); +cleanup(X) when is_record(X, preproc) -> [X]; +cleanup(X) when is_record(X, pragma) -> []; +cleanup(X) when is_record(X, op) -> % Clean inside operation parameters + [ X#op{params = cleanup(X#op.params,[])}]; + +cleanup(X) when is_record(X, module) -> % Clean inside module body + [ X#module{body = cleanup(X#module.body,[])}]; + +cleanup(X) when is_record(X, interface) -> % Clean inside interface body + [ X#interface{body = cleanup(X#interface.body,[])}]; + +cleanup(X) when is_record(X, except) -> % Clean inside exception body + [ X#except{body = cleanup(X#except.body,[])}]; + +cleanup(X) when is_record(X, struct) -> % Clean inside struct body + [ X#struct{body = cleanup(X#struct.body,[])}]; + +cleanup(X) when is_record(X, case_dcl) -> % Clean inside union body + [ X#case_dcl{label = cleanup(X#case_dcl.label,[])}]; + +cleanup(X) when is_record(X, union) -> % Clean inside union body + [ X#union{body = cleanup(X#union.body,[])}]; + +cleanup(X) when is_record(X, enum) -> % Clean inside enum body + [ X#enum{body = cleanup(X#enum.body,[])}]; + +cleanup(X) -> [X]. + + + + +%% pragma_reg_all is top level registration for pragmas +pragma_reg_all(_G, _S, _N, []) -> ok; +pragma_reg_all(G, S, N, [X|Xs]) -> + pragma_reg(G, S, N, X), + pragma_reg_all(G, S, N, Xs). + + +%% pragma_reg is top level registration for pragmas +pragma_reg(G, S, N, X) when is_list(X) -> pragma_reg_list(G, S, N, X); +pragma_reg(_G, S, _N, X) when element(1, X) == preproc -> + case X#preproc.aux of + [{_, _, "1"}] -> + IncludeEntryLNr = get_line(X#preproc.id), + IncludeFileName = element(3,element(3,X)), + insert(S,{includes,get_idlfile(S),IncludeFileName,IncludeEntryLNr}); + _Other -> + ok + end, + set_idlfile(S,element(3,element(3,X))); +pragma_reg(G, S, N, X) when element(1, X) == pragma -> + case applyPragmasInBe(G) of + + %% Pragmas are allowed to be + %% applied in this this backend. + true -> + + File = get_idlfile(S), % The current file or an included one. + Type = case idlfile(G) of % Local/Included flag + File -> + local; + _ -> + included + end, + + %% Register pragmas into pragmatab. + case X of + {pragma,{_,LineNr,"prefix"}, _To, _Apply} -> + insert(S,{prefix,X,LineNr,N,File,Type}); + + {pragma,{_,_,"ID"},_,_} -> + pragma_reg_ID(G, S, N, X); + + {pragma,{_,_,"version"},_,_} -> + pragma_reg_version(G, S, N, X ); + + {pragma,{_,_,"CODEOPT"},_,_} -> + pragma_reg_codeOpt(G,S,N,X); + + {pragma,{_,LineNr,BadPragma}, _To, _Apply} -> + io:format("Warning : on file ~p :~n",[get_idlfile(S)]), + io:format(" Unknown pragma directive ~p on line ~p, ignored.~n", + [BadPragma,LineNr]) + end; + + %% Pragmas are not to be applied in + %% this backend, ignore all pragmas. + false -> + true + end, + ok; + +pragma_reg(G, S, N, X) when is_record(X, module) -> + mk_ref(G,[get_id2(X) | N],mod_ref), + mk_file_data(G,X,N,module), + pragma_reg_all(G, S, [get_id2(X) | N], get_body(X)); + +pragma_reg(G, S, N, X) when is_record(X, interface) -> + mk_ref(G,[get_id2(X) | N],ifc_ref), + mk_file_data(G,X,N,interface), + pragma_reg_all(G, S, [get_id2(X) | N], get_body(X)); + +pragma_reg(G, S, N, X) when is_record(X, op) -> + %% Add operation in table + insert(S,{op, + get_id2(X), + N, + get_idlfile(S), + get_filepath(S)}), + mk_file_data(G,X,N,op), + pragma_reg_all(G, S, N, X#op.params); + +pragma_reg(G, S, N, X) when is_record(X, except) -> + mk_ref(G,[get_id2(X) | N],except_ref), + mk_file_data(G,X,N,except), + pragma_reg_all(G, S, N, X#except.body); + +pragma_reg(G, _S, N, X) when is_record(X, const) -> + mk_ref(G,[get_id2(X) | N],const_ref), + mk_file_data(G,X,N,const); + +pragma_reg(G, _S, N, X) when is_record(X, typedef) -> + XX = #id_of{type=X}, + lists:foreach(fun(Id) -> + mk_ref(G,[get_id2(Id) | N],typedef_ref), + mk_file_data(G,XX#id_of{id=Id},N,typedef) + end, + ic_forms:get_idlist(X)); + +pragma_reg(G, S, N, X) when is_record(X, enum) -> + mk_ref(G,[get_id2(X) | N],enum_ref), + mk_file_data(G,X,N,enum), + pragma_reg_all(G, S, N, X#enum.body); + +pragma_reg(G, S, N, X) when is_record(X, union) -> + mk_ref(G,[get_id2(X) | N],union_ref), + mk_file_data(G,X,N,union), + pragma_reg_all(G, S, N, X#union.body); + +pragma_reg(G, S, N, X) when is_record(X, struct) -> + mk_ref(G,[get_id2(X) | N],struct_ref), + mk_file_data(G,X,N,struct), + pragma_reg_all(G, S, N, X#struct.body); + +pragma_reg(G, _S, N, X) when is_record(X, attr) -> + XX = #id_of{type=X}, + lists:foreach(fun(Id) -> + mk_ref(G,[get_id2(Id) | N],attr_ref), + mk_file_data(G,XX#id_of{id=Id},N,attr) + end, + ic_forms:get_idlist(X)); + +pragma_reg(_G, _S, _N, _X) -> ok. + + + + +pragma_reg_list(_G, _S, _N, []) -> ok; +pragma_reg_list(G, S, N, List ) -> + CurrentFileName = get_idlfile(S), + pragma_reg_list(G, S, N, CurrentFileName, List). + +pragma_reg_list(_G, _S, _N, _CFN, []) -> ok; +pragma_reg_list(G, S, N, CFN, [X | Xs]) -> + case X of + {preproc,_,{_,_,FileName},_} -> + set_idlfile(S,FileName), + pragma_reg(G, S, N, X), + pragma_reg_list(G, S, N, FileName, Xs); + _ -> + pragma_reg(G, S, N, X), + pragma_reg_list(G, S, N, CFN, Xs) + end. + + + + + +pragma_reg_ID(G, S, N, X) -> + {pragma,{_,LineNr,"ID"}, _To, Apply} = X, + + + File = get_idlfile(S), % The current file or an included one. + Type = case idlfile(G) of % Local/Included flag + File -> + local; + _ -> + included + end, + + %% Check if ID is one of the allowed types : + %% * OMG IDL + %% * DCE UUID + %% * LOCAL + case tokens(element(3,Apply),":") of + ["IDL",_,_] -> + insert(S,{id,X,LineNr,N,File,Type}); + ["DCE",_,VSN] -> + case is_short(VSN) of + true -> + insert(S,{id,X,LineNr,N,File,Type}); + false -> + set_compilation_failure(S), + io:format("Error on file ~p :~n",[get_idlfile(S)]), + io:format(" Bad pragma ID ~p on line ~p,~n", + [element(3,Apply),LineNr]), + io:format(" the version part of ID is not a short integer.~n") + end; + ["LOCAL"|_] -> + insert(S,{id,X,LineNr,N,File,Type}); + _ -> + set_compilation_failure(S), + io:format("Error on file ~p :~n",[get_idlfile(S)]), + io:format(" Bad pragma ID ~p on line ~p.~n", + [element(3,Apply),LineNr]) + end. + + + +pragma_reg_version(G, S, N, X) -> + {pragma,{_,LineNr,"version"}, _To, Apply} = X, + + File = get_idlfile(S), % The current file or an included one. + Type = case idlfile(G) of % Local/Included flag + File -> + local; + _ -> + included + end, + + case tokens(Apply,".") of + [Major,Minor] -> + case is_short(Major) and is_short(Minor) of + true -> + insert(S,{version,X,LineNr,N,File,Type}); + false -> + set_compilation_failure(S), + io:format("Error on file ~p :~n",[get_idlfile(S)]), + io:format(" Bad pragma version ~p on line ~p,~n", + [Apply,LineNr]), + io:format(" the version is not valid.~n") + end; + _ -> + set_compilation_failure(S), + io:format("Error on file ~p :~n",[get_idlfile(S)]), + io:format(" Bad pragma version ~p on line ~p,~n", + [Apply,LineNr]), + io:format(" the version is not valid.~n") + end. + + +pragma_reg_codeOpt(G, S, _N, {pragma,{_,LineNr,"CODEOPT"},_,Apply} )-> + case applyCodeOpt(G) of + true -> + {_,_,OptionList_str} = Apply, + case list_to_term(OptionList_str) of + error -> + ic_error:error(G,{pragma_code_opt_bad_option_list,LineNr}); + OptionList -> + case lists:keysearch(be,1,OptionList) of + false -> + %% Add the terms of the option list + %% to the compiler option list + applyCodeOpts(G,S,LineNr,OptionList); + {value, {be,Type}} -> + %% If backend is set from user, + %% let the same backend be otherwize + %% set backend by codeOpt directive + case get_opt(G, be) of + false -> + %% Add the terms of the option list + %% to the compiler option list + applyCodeOpts(G,S,LineNr,OptionList); + _ -> + %% Add all the terms of the option list + %% to the compiler option list but the + %% backend option + applyCodeOpts(G, + S, + LineNr, + lists:delete({be,Type},OptionList)) + end + end + end; + false -> + true + end. + + + +applyCodeOpts(_,_,_,[]) -> + true; +applyCodeOpts(G,S,LNr,[{{broker,Scope},{M,T}}|Xs]) -> + ScopedId = reverse(tokens(Scope,":")), + case ets:match(S, + {codeopt,ScopedId, + '$1','$2','_','_'}) of + [] -> + %% Add pragma in table + insert(S, + {codeopt, + ScopedId, + {broker,{M,T}}, + LNr, + get_idlfile(S), + get_filepath(S)}), + %% Continue + applyCodeOpts(G,S,LNr,Xs); + _ -> + %% Use the code option + %% from user and continue + applyCodeOpts(G,S,LNr,Xs) + end; +applyCodeOpts(G,S,LNr,[X|Xs]) -> + case is_allowed_opt(X) of + true -> + %% Add that term of the option list + %% to the compiler option list + ic_options:add_opt(G, [X], true), + %% Continue + applyCodeOpts(G,S,LNr,Xs); + false -> + %% Print warning and continue + io:format("Warning on file ~p :~n",[get_idlfile(S)]), + io:format(" Bad option in pragma : ~p, ignored !~n",[X]), + applyCodeOpts(G,S,LNr,Xs) + end. + + +is_allowed_opt({X,Y}) -> + ic_options:allowed_opt(X,Y); +is_allowed_opt(_X) -> + false. + + + +%% Returns a tuple { PFX, VSN, ID }, that is the +%% pragma prefix, version and id coverages of +%% the scope SCOPE. This is done by use of the +%% function pragma_cover/4. +pragma_cover(G,Scope,Object) -> + pragma_cover(ic_genobj:pragmatab(G),get_id2(Object),Scope,get_line(Object)). + +%% Returns a tuple { PFX, VSN, ID }, that is the +%% pragma prefix, version and id coverages of +%% the scope SCOPE +pragma_cover(PragmaTab,Name,Scope,LineNr) -> + PFX = pragma_prefix_cover(PragmaTab,Name,Scope,LineNr), + VSN = pragma_version_cover(PragmaTab,Name,Scope,LineNr), + ID = pragma_id_cover(PragmaTab,Name,Scope,LineNr), + { PFX, VSN, ID }. + + + +%% Finds out which pragma PREFIX that affects +%% the scope Scope +pragma_prefix(G,Scope,Object) -> + pragma_prefix_cover(ic_genobj:pragmatab(G),get_id2(Object),Scope,get_line(Object)). + + +%% Finds out which pragma PREFIX that affects +%% the scope Scope +pragma_prefix_cover(PragmaTab,Name,Scope,LineNr) -> + case lookup(PragmaTab,prefix) of + [] -> + none; + PragmaPrefixList -> + FilteredPragmaPrefixList = + filter_pragma_prefix_list(PragmaTab,Name,Scope,PragmaPrefixList), + case most_local(FilteredPragmaPrefixList,Scope) of + [] -> + none; + MostLocalList -> + case dominant_prefix(MostLocalList,LineNr) of + none -> + none; + + %% Just filter empty pragma prefix + {prefix,{pragma,{_,_,_},_,{'',_,[]}},_,_,_,_} -> + none; + + DP -> + %% Return the scoped id (reversed list of + %% path elements, but remember to remove + %% '[]' that represents the top level + slashify(lists:sublist(Scope, 1, + length(Scope) - length(element(4,DP))) ++ + [ element(3,element(4,element(2,DP)))]) + end + end + end. + + +%% Returns a slashified name, [I1, M1] becomes "M1/I1" +slashify(List) -> lists:foldl(fun(X, Acc) -> X++"/"++Acc end, + hd(List), tl(List)). + + +%% Finds out which pragma VERSION that affects +%% the scope Scope +pragma_version(G,Scope,Object) -> + pragma_version_cover(ic_genobj:pragmatab(G),get_id2(Object),Scope,get_line(Object)). + +%% Finds out which pragma VERSION that affects +%% the scope Scope +pragma_version_cover(PragmaTab,Name,Scope,LineNr) -> + case lookup(PragmaTab,version) of + [] -> + default_version(); + PragmaVersionList -> + case all_actual_for_version_or_id( PragmaVersionList, Name ) of + [] -> + default_version(); + ActualVersionList -> + case most_local(ActualVersionList,Scope) of + [] -> + default_version(); + MostLocalList -> + case dominant_version(MostLocalList,LineNr) of + DV -> + element(4,element(2,DV)) + end + end + end + end. + + +default_version() -> "1.0". + + + +%% Finds out which pragma ID that affects +%% the scope Scope +pragma_id(G,Scope,Object) -> + pragma_id_cover(ic_genobj:pragmatab(G),get_id2(Object),Scope,get_line(Object)). + +%% Finds out which pragma ID that affects +%% the scope Scope +pragma_id_cover(PragmaTab,Name,Scope,LineNr) -> + case lookup(PragmaTab,id) of + [] -> + none; + PragmaIdList -> + case all_actual_for_version_or_id( PragmaIdList, Name ) of + [] -> + none; + ActualIdList -> + case most_local(ActualIdList,Scope) of + [] -> + none; + MostLocalList -> + case dominant_id(MostLocalList,LineNr) of + PI -> + element(3,element(4,element(2,PI))) + end + end + end + end. + + + + +%% Finds out which pragma VERSION ( or ID ) that +%% that affects the scope object with name NAME +all_actual_for_version_or_id(NList, Name) -> + all_actual_for_version_or_id( NList, [], Name ). + +all_actual_for_version_or_id([], Actual, _) -> + Actual; +all_actual_for_version_or_id([First|Rest], Found, Name) -> + case is_actual_for_version_or_id(First,Name) of + true -> + all_actual_for_version_or_id(Rest, [First|Found], Name); + false -> + all_actual_for_version_or_id(Rest, Found, Name) + end. + +is_actual_for_version_or_id( Current, Name ) -> + case element(3,element(3,element(2,Current))) of + Name -> + true; + OtherName -> + suffix([Name],tokens(OtherName,"::")) + end. + + + + +%% Find the most locally defind pragmas +%% to the scope SCOPE +most_local( SList, Scope ) -> + case SList of + [] -> + []; + [First|Rest] -> + case suffix( element(4,First), Scope ) of + true -> + most_local( Rest, First, Scope, [First] ); + false -> + most_local( Rest, Scope ) + end + end. + +%% Returns a list of all pragmas found in the +%% same scope. Should choose the right one by looking +%% att the position of the pragma in relation to +%% the current object..... ( For hairy cases ). +most_local( SList, Current, Scope, AllFound ) -> + case SList of + [] -> + AllFound; + [First|Rest] -> + FirstScope = element(4,First), + case suffix( FirstScope, Scope ) of + true -> + CurrentScope = element(4,Current), + case suffix( CurrentScope, FirstScope ) of + true -> + case length( CurrentScope ) == length( FirstScope ) of + true -> %% SAME SCOPE ! KEEP BOTH + most_local( Rest, Current, Scope, [First|AllFound] ); + false -> + most_local( Rest, First, Scope, [First] ) + end; + false -> + most_local( Rest, Current, Scope, AllFound ) + end; + false -> + most_local( Rest, Current, Scope, AllFound ) + end + end. + + + + +%% Find the most dominant prefix pragmas +%% located onto the SAME scope. Now +%% we look att the line number, the position +%% on the file. +dominant_prefix(SList,LineNr) -> + case SList of + [First|Rest] -> + dominant_prefix(Rest,First,LineNr) + end. + + +dominant_prefix([],{prefix,X,PLNr,N,F,T},LineNr) -> + case LineNr > PLNr of + true -> + {prefix,X,PLNr,N,F,T}; + false -> + none + end; +dominant_prefix([{prefix,FX,FPLNr,FN,F1,T1}|Rest],{prefix,CX,CPLNr,CN,F2,T2},LineNr) -> + case LineNr > FPLNr of % Check if FIRST before the object + true -> + case FPLNr > CPLNr of % Check if FIRST after CURRENT + true -> + dominant_prefix(Rest,{prefix,FX,FPLNr,FN,F1,T1},LineNr); + false -> + dominant_prefix(Rest,{prefix,CX,CPLNr,CN,F2,T2},LineNr) + end; + false -> % FIRST does not affect the object + dominant_prefix(Rest,{prefix,CX,CPLNr,CN,F2,T2},LineNr) + end. + + + + +%% Find the most dominant version pragmas +%% located onto the SAME scope. Now +%% we look att the line number, the position +%% on the file. +dominant_version(SList,LineNr) -> + case SList of + [First|Rest] -> + dominant_version(Rest,First,LineNr) + end. + + +dominant_version([],Current,_) -> Current; +dominant_version([{version,FX,FPLNr,FN,F1,T1}|Rest],{version,CX,CPLNr,CN,F2,T2},LineNr) -> + case FPLNr > CPLNr of % Check if FIRST after CURRENT + true -> + dominant_version(Rest,{prefix,FX,FPLNr,FN,F1,T1},LineNr); + false -> + dominant_version(Rest,{prefix,CX,CPLNr,CN,F2,T2},LineNr) + end. + + + + +%% Find the most dominant id pragmas +%% located onto the SAME scope. Now +%% we look att the line number, the position +%% on the file. +dominant_id(SList,LineNr) -> + case SList of + [First|Rest] -> + dominant_id(Rest,First,LineNr) + end. + + +dominant_id([],Current,_) -> Current; +dominant_id([{id,FX,FPLNr,FN,F1,T1}|Rest],{id,CX,CPLNr,CN,F2,T2},LineNr) -> + case FPLNr > CPLNr of % Check if FIRST after CURRENT + true -> + dominant_id(Rest,{id,FX,FPLNr,FN,F1,T1},LineNr); + false -> + dominant_id(Rest,{id,CX,CPLNr,CN,F2,T2},LineNr) + end. + + + + + +%% This registers a module defined inside the file or +%% an included file. A tuple that describes the module +%% is added to the table. +%% Observe that the modules registered are ONLY those +%% who are in the top level, not definedd inside others ! +mk_ref(G,Name,Type) -> + case length(Name) > 1 of + true -> %% The interface is NOT defined att top level + true; + false -> + S = ic_genobj:pragmatab(G), + File = get_idlfile(S), % The current file or an included one. + case idlfile(G) of % The current file to be compiled. + File -> + insert(S,{Type,Name,File,local}); + _ -> + insert(S,{Type,Name,File,included}) + end + end. + + +%% The same as mk_ref/3 but this registers everything with +%% all vital information available inside files. +%% Registers ESSENTIAL data for included files +mk_file_data(G,X,Scope,Type) -> + S = ic_genobj:pragmatab(G), + Name = get_id2(X), + PreprocFile = get_idlfile(S), % The current file or an included one. + CompFile = idlfile(G), % The current file compiled + Depth = length(Scope), % The depth of the scope + ScopedName = ic_util:to_undersc([Name|Scope]), + Line = ic_forms:get_line(X), + case PreprocFile of + CompFile -> + insert(S,{file_data_local,CompFile,CompFile,Type,Scope,Name,ScopedName,Depth,Line}); + PreprocFile -> + insert(S,{file_data_included,PreprocFile,CompFile,Type,Scope,Name,ScopedName,Depth,Line}) + end. + + + +%% Return a list with all the headers from +%% the local file that represent the module +%% or interface that is preciding the current +get_local_c_headers(G,X) -> + S = ic_genobj:pragmatab(G), + Local = lookup(S,file_data_local), + FoundLocal = get_local_c_headers(X,Local,Local), + no_doubles(FoundLocal). + +get_local_c_headers(X,Local,Local) -> + get_local_c_headers(X,Local,Local,[]). + +get_local_c_headers(_X,[],_All,Found) -> + Found; +get_local_c_headers(X,[{file_data_local,_PF_idl,_,module,_,_,SN,_,Line}|Hs],All,Found)-> + case ic_forms:get_line(X) > Line of + true -> + get_local_c_headers(X,Hs,All,[SN|Found]); + false -> + get_local_c_headers(X,Hs,All,Found) + end; +get_local_c_headers(X,[{file_data_local,_PF_idl,_,interface,_,_,SN,_,Line}|Hs],All,Found)-> + case ic_forms:get_line(X) > Line of + true -> + get_local_c_headers(X,Hs,All,[SN|Found]); + false -> + get_local_c_headers(X,Hs,All,Found) + end; +get_local_c_headers(X,[_|Hs],All,Found) -> + get_local_c_headers(X,Hs,All,Found). + + + +%% Return a list with all the headers from +%% the included file that represent the module +%% or interface that have to be included +get_included_c_headers(G) -> + S = ic_genobj:pragmatab(G), + Included = lookup(S,file_data_included), + FoundIncluded = get_included_c_headers(Included,Included), + no_doubles(FoundIncluded). + +get_included_c_headers(Included,Included) -> + get_included_c_headers(Included,Included,[]). + +get_included_c_headers([],_All,Found) -> + Found; +get_included_c_headers([{file_data_included,PF_idl,_CF_idl,T,_S,_N,SN,0,_}|Hs],All,Found) -> + Len = length(PF_idl), + FN = string:sub_string(PF_idl,1,Len-4), + case only_top_level(PF_idl,All) of + true -> + %% + L = string:tokens(FN,"/"), + FN2 = lists:last(L), + %% + get_included_c_headers(Hs,All,["oe_"++FN2|Found]); + false -> + case T of + module -> + case contains_interface(PF_idl,All) of + true -> + %% + L = string:tokens(FN,"/"), + FN2 = lists:last(L), + %% + get_included_c_headers(Hs,All,["oe_"++FN2|Found]); + false -> + get_included_c_headers(Hs,All,[SN|Found]) + end; + interface -> + case contains_interface(PF_idl,All) of + true -> + %% + L = string:tokens(FN,"/"), + FN2 = lists:last(L), + %% + get_included_c_headers(Hs,All,["oe_"++FN2|Found]); + false -> + get_included_c_headers(Hs,All,[SN|Found]) + end; + _ -> + get_included_c_headers(Hs,All,["oe_"++FN|Found]) + end + end; +get_included_c_headers([{file_data_included,_PF_idl,_,module,_,_,SN,_,_}|Hs],All,Found)-> + get_included_c_headers(Hs,All,[SN|Found]); +get_included_c_headers([{file_data_included,_PF_idl,_,interface,_,_,SN,_,_}|Hs],All,Found)-> + get_included_c_headers(Hs,All,[SN|Found]); +get_included_c_headers([_|Hs],All,Found) -> + get_included_c_headers(Hs,All,Found). + +%% Help functions for the above + +only_top_level(_PF_idl,[]) -> + true; +only_top_level(PF_idl,[H|Hs]) -> + case element(2,H) of + PF_idl -> + case element(8,H) > 0 of + true -> + false; + false -> + only_top_level(PF_idl,Hs) + end; + _ -> + only_top_level(PF_idl,Hs) + end. + +contains_interface(_PF_idl,[]) -> + false; +contains_interface(PF_idl,[H|Hs]) -> + case element(2,H) of + PF_idl -> + case element(4,H) of + interface -> + case element(8,H) > 0 of + true -> + true; + false -> + contains_interface(PF_idl,Hs) + end; + _ -> + contains_interface(PF_idl,Hs) + end; + _ -> + contains_interface(PF_idl,Hs) + end. + + + +%% This returns a list of everything defined in an included file. +get_incl_refs(G) -> + S = ic_genobj:pragmatab(G), + + RefList = + ets:match(S,{mod_ref,'$0','_',included}) ++ + ets:match(S,{ifc_ref,'$0','_',included}) ++ + ets:match(S,{const_ref,'$0','_',included}) ++ + ets:match(S,{typedef_ref,'$0','_',included}) ++ + ets:match(S,{except_ref,'$0','_',included}) ++ + ets:match(S,{struct_ref,'$0','_',included}) ++ + ets:match(S,{union_ref,'$0','_',included}) ++ + ets:match(S,{enum_ref,'$0','_',included}) ++ + ets:match(S,{attr_ref,'$0','_',included}), + + case RefList of + [] -> + none; + _ -> + RefList + end. + + + +%% This returns a list of everything locally defined. +get_local_refs(G) -> + S = ic_genobj:pragmatab(G), + + RefList = + ets:match(S,{mod_ref,'$0','_',local}) ++ + ets:match(S,{ifc_ref,'$0','_',local}) ++ + ets:match(S,{const_ref,'$0','_',local}) ++ + ets:match(S,{typedef_ref,'$0','_',local}) ++ + ets:match(S,{except_ref,'$0','_',local}) ++ + ets:match(S,{struct_ref,'$0','_',local}) ++ + ets:match(S,{union_ref,'$0','_',local}) ++ + ets:match(S,{enum_ref,'$0','_',local}) ++ + ets:match(S,{attr_ref,'$0','_',local}), + + case RefList of + [] -> + none; + _ -> + RefList + end. + + + + + +%% This is intented to be used for solving the identification +%% problem introduced by pragmas. It creates aliases between +%% scoped and "final" identities. +mk_alias(G,PragmaId,ScopedId) -> + %io:format("~nMaking alias -> ~p~n",[PragmaId]), + S = ic_genobj:pragmatab(G), + insert(S,{alias,ScopedId,PragmaId}). + + +%% This is used to find out if the object described with +%% the scoped id is created. If this is the case, it should +%% be registered as an alias and the identity of the object +%% is returned. Otherwize "none" is returned. +get_alias(G,ScopedId) -> + S = ic_genobj:pragmatab(G), + case ets:match(S,{alias,ScopedId,'$1'}) of + [] -> + none; + [[IfrId]] -> + %io:format("~nFound alias -> ~p~n",[IfrId]), + IfrId + end. + + + +%% Returns the alias id or constructs an id +scope2id(G,ScopedId) -> + case get_alias(G,ScopedId) of + none -> + case is_included(G,ScopedId) of + true -> %% File included + get_included_IR_ID(G,ScopedId); + false -> %% File local + NewIfrId = mk_id(ScopedId), % Create a "standard" id + mk_alias(G,NewIfrId,ScopedId), % Create an alias + NewIfrId + end; + IfrId -> + IfrId + end. + + + + +is_included(G,ScopedId) -> + S = ic_genobj:pragmatab(G), + Name = ic_util:to_undersc(ScopedId), + case ets:match(S,{file_data_included,'_','_','_','_','_',Name,'_','_'}) of + [[]] -> + true; + _ -> + false + end. + + + +get_included_IR_ID(G,ScopedId) -> + S = ic_genobj:pragmatab(G), + ScopedName = ic_util:to_undersc(ScopedId), + [[Scope,Name,LNr]] = ets:match(S,{file_data_included,'_','_','_','$3','$4',ScopedName,'_','$7'}), + {Prefix,Vsn,Id} = pragma_cover(S,Name,Scope,LNr), + case Id of + none -> + case Prefix of + none -> + IR_ID = + lists:flatten(io_lib:format("IDL:~s:~s",[ScopedName, Vsn])), + ic_pragma:mk_alias(G,IR_ID,ScopedId), + IR_ID; + _ -> + IR_ID = + lists:flatten(io_lib:format("IDL:~s:~s",[Prefix ++ "/" ++ ScopedName, Vsn])), + ic_pragma:mk_alias(G,IR_ID,ScopedId), + IR_ID + end; + _ -> + ic_pragma:mk_alias(G,Id,ScopedId), + Id + end. + + + + + +%% Returns the scope for object +id2scope(G,IfrId) -> + S = ic_genobj:pragmatab(G), + case lookup(S,alias) of + [] -> + mk_scope(IfrId); + AliasList -> + case keysearch(IfrId,3,AliasList) of + false -> + mk_scope(IfrId); + {value,{alias,ScopedId,_}} -> + ScopedId + end + end. + +%% Returns a "standard" IDL ID by getting the scope list +mk_id(ScopedId) -> + "IDL:" ++ ic_pragma:slashify(ScopedId) ++ ":" ++ default_version(). + +%% Returns the scope of an object when getting a "standard" IDL ID +mk_scope(IfrId) -> + [_,Body,_] = tokens(IfrId,":"), + reverse(tokens(Body,"/")). + + + +%% This is used to note the exact compiled file +%% under pragma creation. There are two options, the +%% main file or files included by the main file. This +%% just denotes the CURRENT file, the main file or +%% the included ones. A very usual field is the file +%% path that shows the include path of the file + +init_idlfile(G,S) -> + IdlFile = idlfile(G), + insert(S,{file,IdlFile,[]}). + +set_idlfile(S,FileName) -> + FilePath = get_filepath(S), + case FilePath of + [] -> + ets:delete(S,file), + insert(S,{file,FileName,[FileName|FilePath]}); + _ -> + case hd(FilePath) of + [] -> + ets:delete(S,file), + insert(S,{file,FileName,[FileName|FilePath]}); + _ -> + case tl(FilePath) of + [] -> + ets:delete(S,file), + insert(S,{file,FileName,[FileName|FilePath]}); + _ -> + case hd(tl(FilePath)) of + [] -> + ets:delete(S,file), + insert(S,{file,FileName,[FileName|FilePath]}); + FileName -> + ets:delete(S,file), + insert(S,{dependency,FilePath}), % Add dependency branch + insert(S,{file,FileName,tl(FilePath)}); + _ -> + ets:delete(S,file), + insert(S,{file,FileName,[FileName|FilePath]}) + end + end + end + end. + +get_idlfile(S) -> + [FT] = lookup(S,file), + element(2,FT). + +get_filepath(S) -> + [FT] = lookup(S,file), + element(3,FT). + + +%% This returns a list of file names +%% that direct or indirect the current +%% compiled file is depended on. +get_dependencies(G) -> + S = ic_genobj:pragmatab(G), + case lookup(S,dependency) of + [] -> + []; + Dependencies -> + {get_idlfile(S),get_dependencies(Dependencies,[])} + end. + +get_dependencies([],Dependencies) -> + no_doubles(Dependencies); +get_dependencies([{dependency,Path}|Tail],Current) -> + get_dependencies(Tail,[hd(Path)|Current]). + + +no_doubles(List) -> + no_doubles(List,[]). + +no_doubles([],NoDoubles) -> + NoDoubles; +no_doubles([X|Xs],Current) -> + case member(X,Xs) of + true -> + no_doubles(Xs,Current); + false -> + no_doubles(Xs,[X|Current]) + end. + + + + +%% Pragma compilation status initialization +init_pragma_status(S) -> + insert(S,{status,true,0}). + +%% Pragma compilation status set to failure +%% and count up the number of errors +set_compilation_failure(S) -> + [{status,_,ErrorNr}] = lookup(S,status), + ets:delete(S,status), + insert(S,{status,false,ErrorNr+1}). + +%% Pragma compilation status set to lookup +get_pragma_compilation_status(S) -> + [Status] = lookup(S,status), + element(2,Status). + +%% Pragma error number +get_pragma_error_nr(S) -> + [Status] = lookup(S,status), + element(3,Status). + + +%% Short check +is_short(N_str) when is_list(N_str) -> + case is_short_decimal_str(N_str) of + true -> + true; + false -> + false + end; +is_short(N) when is_integer(N)-> + (N < 65535) and (N > -65536); +is_short(_) -> false. + + +%% Check if the string is a +%% list of characters representing +%% a short. Avoid crash !. +is_short_decimal_str(N_str) -> + case is_decimal_str(N_str) of + true -> + N = list_to_integer(N_str), + (N < 65535) and (N > -65536); + false -> + false + end. + +%% Check if the string is a +%% list of characters representing +%% decimals. +is_decimal_str([]) -> + true; +is_decimal_str([First|Rest]) -> + case is_decimal_char(First) of + true -> + is_decimal_str(Rest); + false -> + false + end. + +%% True if D is a character +%% representing a decimal (0-9). +is_decimal_char(D) -> + case (48= + true; + false -> + false + end. + + +%% Prints out all the table +print_tab(G) -> + io:format("~nPragmaTab = ~p~n",[ets:tab2list(ic_genobj:pragmatab(G))]). + + +list_to_term(List) -> + case catch erl_scan:string(List) of + {ok, Tokens, _} -> + case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of + {ok,Term} -> + Term; + _ -> + error + end; + _ -> + error + end. + + + +%% Cleanup all other code options for a specified scope +%% in the same file, but the most dominant. +cleanup_codeOptions(G,S,ScopedId) -> + case ets:match(S,{codeopt,ScopedId,'$1','$2',idlfile(G),'$4'}) of + [] -> + %% No codeOpt directive is placed inside the + %% currently compiled file. Try to find other + %% directives located in included files. + true; + List -> + %% A codeOpt directive is placed inside the + %% currently compiled file. This dominates + %% all other directives. + CodeOption = best_positioned_codeOpt(List), + %% Remove code options that do not affect + %% the code production (redundant) + remove_redundant_codeOpt(S,[ScopedId|CodeOption]) + end. + + +%% Best positioned is the codeopt located +%% "highest" on the SAME file, the one with +%% lowest line number. +best_positioned_codeOpt([X|Xs]) -> + best_positioned_codeOpt(Xs,X). + +best_positioned_codeOpt([],Found) -> + Found; +best_positioned_codeOpt([X|Xs],Current) -> + case hd(tl(X)) > hd(tl(Current)) of + true -> + best_positioned_codeOpt(Xs,Current); + false -> + best_positioned_codeOpt(Xs,X) + end. + + +remove_redundant_codeOpt(S,[ScopedId,CodeOption,LNr,FilePath]) -> + ets:match_delete(S,{codeopt,ScopedId,'$1','$2','$3','$4'}), + ets:insert(S,{codeopt,ScopedId,CodeOption,LNr,last(FilePath),FilePath}). + + + + +add_inh_data(G,InclScope,X) -> + S = ic_genobj:pragmatab(G), + case X#interface.inherit of + [] -> + true; + [InhBody] -> + Scope = [get_id2(X)|InclScope], + insert(S,{inherits,Scope,InhBody}); + InhList -> + add_inh_data(G, S, InclScope, X, InhList) + end. + +add_inh_data(_,_,_,_,[]) -> + true; +add_inh_data(G, S, InclScope, X, [InhBody|InhBodies]) -> + Scope = [get_id2(X)|InclScope], + insert(S, {inherits,Scope,InhBody}), + add_inh_data(G, S, InclScope, X, InhBodies). + + +%% Returns a default broker data +defaultBrokerData(G) -> + {to_atom(ic_genobj:impl(G)),transparent}. + + +%% Loops through the form and sdds inheritence data +preproc(G, N, [X|Xs]) when is_record(X, interface) -> + %% Add inheritence data to pragmatab + ic_pragma:add_inh_data(G,N,X), + N2 = [get_id2(X) | N], + preproc(G, N2, get_body(X)), + lists:foreach(fun({_Name, Body}) -> preproc(G, N2, Body) end, + X#interface.inherit_body), + preproc(G, N, Xs); + +preproc(G,N,[X|Xs]) when is_record(X, module) -> + N2 = [get_id2(X) | N], + preproc(G, N2, get_body(X)), + preproc(G,N,Xs); + +preproc(G,N,[_X|Xs]) -> + preproc(G,N,Xs); + +preproc(_G, _N, []) -> + ok. + + +%% Returns a tuple / list of tuples { Mod, Type } +%% Does not check overridence because it is the +%% top scope for the module to be produced and +%% cannot be overriden. +getBrokerData(G,X,Scope) -> + S = ic_genobj:pragmatab(G), + cleanup_codeOptions(G,S,Scope), + + %% Check if it is an operation denoted + case isOperation(S,Scope) of + %% Yes, check options + true -> + %% Look if there is a specific code option on top file + case hasSpecificCodeoptionOnTopFile(S,ic_genobj:idlfile(G),Scope) of + true -> + %% Yes, let it work + getBrokerData(G,S,X,Scope,[Scope],[]); + false -> + %% No, try to see if there is codeoption on top file + case hasNonSpecificCodeoptionOnTopFile(S,ic_genobj:idlfile(G)) of + true -> + %% Yes, override every other specific code option + [_H|T] = Scope, + getBrokerData(G,S,X,Scope,[T],[]); + false -> + %% No, let inherited specific code options work + getBrokerData(G,S,X,Scope,[Scope],[]) + end + end; + %% No, continue + false -> + getBrokerData(G,S,X,Scope,[Scope],[]) + end. + +%% Returns a tuple / list of tuples { Mod, Type } +%% Inside loop, uses overridence. +getBrokerData(G,X,RS,Scope,CSF) -> + S = ic_genobj:pragmatab(G), + cleanup_codeOptions(G,S,Scope), + OvScope = overridedFrom(S,RS,Scope), + getBrokerData(G,S,X,RS,[OvScope],[OvScope|CSF]). + + + +getBrokerData(G,S,X,RS,[[[First]|Rest]],CSF) when is_integer(First) -> + Scope = [[First]|Rest], + case ets:match(S,{codeopt,Scope,'$1','_','_','_'}) of + [] -> + case ets:match(S,{inherits,Scope,'$1'}) of + [] -> %% No inheritence, no pragma codeopt + defaultBrokerData(G); %% Default + [InhScope] -> + getBrokerData(G,S,X,RS,InhScope,CSF); + InhList -> + getBrokerDataInh(G,S,X,RS,Scope,CSF,InhList) + end; + [[{broker,{Module,Type}}]] -> %% A branch only, with pragma codeopt + {Module,Type}; + List -> %% Multiple branches with pragma codeopt + flatten(List) + end; + +getBrokerData(G,S,X,RS,[[[First]|Rest]],CSF) -> + getBrokerDataLoop(G,S,X,RS,[[First]|Rest],CSF); + +getBrokerData(G,S,X,RS,[Scope],CSF) -> + %io:format(" 1"), + case ets:match(S,{codeopt,Scope,'$1','_','_','_'}) of + [] -> + %io:format(" 2"), + case ets:match(S,{inherits,Scope,'$1'}) of + [] -> %% No inheritence, no pragma codeopt + %io:format(" 5"), + defaultBrokerData(G); %% Default + [InhScope] -> + %io:format(" 6"), + getBrokerData(G,S,X,RS,InhScope,CSF); + InhList -> + %io:format(" 7"), + getBrokerDataInh(G,S,X,RS,Scope,CSF,InhList) + end; + [[{broker,{Module,Type}}]] -> %% A branch only, with pragma codeopt + %io:format(" 3"), + {Module,Type}; + List -> %% Multiple branches with pragma codeopt + %io:format(" 4"), + flatten(List) + end. + + +%% Special treatment when X is an operation +getBrokerDataInh(G,S,X,RS,Scope,CSF,InhList) when is_record(X,op)-> + %io:format(" 8"), + case ets:match(S,{op,get_id2(X),'$1','_','_'}) of + [] -> + %io:format(" 10"), + CleanList = remove_inherited(S,InhList), + getBrokerDataLoop(G,S,X,RS,CleanList,CSF); + + [[Scope]] -> + %io:format(" 11"), + CleanList = remove_inherited(S,InhList), + getBrokerDataLoop(G,S,X,RS,CleanList,CSF); + + [[OpScope]] -> + %io:format(" 12"), + case member([OpScope],InhList) of + true -> + %io:format(" 14"), + %% No inherited scopes + getBrokerData(G,X,RS,OpScope,CSF); + false -> + %io:format(" 15"), + %% Inherited scopes + CleanList = remove_inherited(S,InhList), + getBrokerDataLoop(G,S,X,RS,CleanList,CSF) + end; + + ListOfOpScopes -> + %io:format(" 13"), + case get_inherited(S,Scope,ListOfOpScopes) of + [[OpScope]] -> + case member([OpScope],InhList) of + true -> + getBrokerData(G,X,RS,OpScope,CSF); + false -> + CleanList = remove_inherited(S,InhList), + getBrokerDataLoop(G,S,X,RS,CleanList,CSF) + end; + _ -> + CleanList = remove_inherited(S,InhList), + getBrokerDataLoop(G,S,X,RS,CleanList,CSF) + end + end; +%% Just add InhList after removing all inherited +getBrokerDataInh(G,S,X,RS,_Scope,CSF,InhList) -> + %io:format(" 9"), + CleanList = remove_inherited(S,InhList), + getBrokerDataLoop(G,S,X,RS,CleanList,CSF). + + + + +%% Loops over a list of scopes +getBrokerDataLoop(G,S,X,RS,List,CSF) -> + getBrokerDataLoop(G,S,X,RS,List,[],CSF). + +getBrokerDataLoop(G,_,_X,_RS,[],BrokerDataList,_CSF) -> + case no_doubles(BrokerDataList) of + [BrokerData] -> %% No pragma codeopt / Multiple branches with pragma codeopt + BrokerData; + List -> + DefaultBD = defaultBrokerData(G), + case member(DefaultBD,List) of + true -> + %% Remove default, choose codeoption + NewList = delete(DefaultBD,List), + case NewList of + [BData] -> %% A branch only, with pragma codeopt + BData; + _Other -> %% Multiple branches with pragma codeopt + %%io:format("Multiple branches ~p~n",[Other]), + NewList + end; + false -> %% Multiple branches with pragma codeopt + flatten(List) + end + end; + +getBrokerDataLoop(G,S,X,RS,[[Scope]|Scopes],_Found,CSF) when is_integer(Scope) -> + getBrokerData(G,S,X,RS,[[Scope]|Scopes],CSF); + +getBrokerDataLoop(G,S,X,RS,[[Scope]|Scopes],Found,CSF) -> + %% Start from the beginning, check for overridings + case member(overridedFrom(S,RS,Scope),CSF) of %% Avoid infinite loops + true -> + getBrokerDataLoop(G,S,X,RS,Scopes,Found,CSF); + false -> + BrokerData = getBrokerData(G,X,RS,Scope,CSF), + getBrokerDataLoop(G,S,X,RS,Scopes,[BrokerData|Found],[Scope|CSF]) + end. + + + + +%%%-------------------------------------- +%%% Finds out the overrider of a scope +%%%-------------------------------------- +overridedFrom(S,RS,Scope) -> + overridedFrom(S,RS,Scope,Scope). + +overridedFrom(S,RS,Last,Scope) -> + case ets:match(S,{inherits,'$0',Scope}) of + [] -> + %% No inheritence, no pragma codeopt, + %% choose the last scope. + Last; + + [[RS]] -> + %% Garbage, unused interface with pragma + %% code option ! Danger ! + Last; + + [[InhScope]] -> + case ets:match(S,{codeopt,InhScope,'$1','_','_','_'}) of + [] -> + %% InhScope has no code options, keep Last. + overridedFrom(S,RS,Scope,InhScope); + _ -> + %% InhScope has code option, Last = InhScope. + overridedFrom(S,RS,InhScope,InhScope) + end; + List -> + %% Several inherit from Scope, choose the one feeseble, + %% the one DIRECTLY inherited by Scope and not through + %% other interface. + case remove_inheriters(S,RS,List) of + [] -> + Scope; + Removed -> + Removed + end + end. + +%%%------------------------------------------------------ +%%% Removes all the scopes that inherit from others +%%%------------------------------------------------------ +remove_inheriters(S,RS,InheriterList) -> + DominantList = + dominantList(S,InheriterList), + ReducedInhList = + [X || X <- InheriterList, + member(X,DominantList)], + + case ReducedInhList of + [] -> + []; + [_OneOnly] -> + ReducedInhList; + _Other -> + EtsList = ets:tab2list(S), + CleanList = + [X || X <- EtsList, element(1,X) == inherits], +% CodeOptList = +% [X || X <- EtsList, element(1,X) == codeopt], + NoInheriters =remove_inheriters2(S,ReducedInhList,CleanList), + + [ [X] || [X] <- NoInheriters, + inherits(RS,X,CleanList)] + end. + +remove_inheriters2(_,[A],_) -> + [A]; +remove_inheriters2(_S,[A,B],EtsList) -> + case remove_inh(A,B,[A,B],EtsList) of + [[X]] -> + X; + List -> + List + end; +remove_inheriters2(S,[A,B|Rest],EtsList) -> + case remove_inh(A,B,[A,B|Rest],EtsList) of + [A,B|Rest] -> + [A,B|Rest]; + NewList -> + remove_inheriters2(S,NewList,EtsList) + end. + +remove_inh([X],[Y],List,EtsList) -> + case inherits(X,Y,EtsList) of + true -> + delete([X],List); + false -> + case inherits(Y,X,EtsList) of + true -> + delete([Y],List); + false -> + List + end + end. + + + +%%%---------------------------------------------- +%%% Should remove all scope links that inherit +%%% from others in the list +%%%---------------------------------------------- +remove_inherited(S,InheriterList) -> + EtsList = ets:tab2list(S), + CleanList = + [X || X <- EtsList, element(1,X) == inherits], + remove_inherited(S,InheriterList,CleanList). + + +remove_inherited(_S,[A,B],EtsList) -> + case remove_inhed(A,B,[A,B],EtsList) of + [[X]] -> + [[X]]; + List -> + List + end; +remove_inherited(S,[A,B|Rest],EtsList) -> + case remove_inhed(A,B,[A,B|Rest],EtsList) of + [A,B|Rest] -> + [A,B|Rest]; + NewList -> + remove_inherited(S,NewList,EtsList) + end. + + +remove_inhed([X],[Y],List,EtsList) -> + case inherits(X,Y,EtsList) of + true -> + delete([Y],List); + false -> + case inherits(Y,X,EtsList) of + true -> + delete([X],List); + false -> + List + end + end. + + + + + + + +%%%---------------------------------------------- +%%% Should return all scope links that is +%% are inherited from scope in the list +%%%---------------------------------------------- +get_inherited(S,Scope,OpScopeList) -> + EtsList = ets:tab2list(S), + [[element(3,X)] || X <- EtsList, + element(1,X) == inherits, + element(2,X) == Scope, + member([element(3,X)],OpScopeList)]. + + + + + + + +%%%--------------------------------------------------- +%%% Returns a the list of scopes that have codeoption +%%% from a list of scopes +%%%--------------------------------------------------- +dominantList(S,IL) -> + dominantList(S,IL,[]). + +dominantList(_S,[],Found) -> + Found; +dominantList(S,[[X]|Xs],Found) -> + case ets:match(S,{codeopt,X,'$1','_','_','_'}) of + [] -> + dominantList(S,Xs,Found); + _ -> + dominantList(S,Xs,[[X]|Found]) + end. + + + + +%%%--------------------------------------------------- +%%% Returns true if X direct or indirect inherits Y +%%%--------------------------------------------------- +inherits(X,Y,EtsList) -> + case member({inherits,X,Y},EtsList) of + true -> + %% Direct inherited + true; + false -> + %% Indirectly inherited + AllInh = [ B || {inherits,A,B} <- EtsList, A == X ], + inherits(X,Y,AllInh,EtsList) + end. + +inherits(_X,_Y,[],_EtsList) -> + false; +inherits(X,Y,[Z|Zs],EtsList) -> + case inherits2(X,Y,Z,EtsList) of + true -> + true; + false -> + inherits(X,Y,Zs,EtsList) + end. + +inherits2(_X,Y,Z,EtsList) -> + case member({inherits,Z,Y},EtsList) of + true -> + true; + false -> + inherits(Z,Y,EtsList) + end. + + + +%% +%% is_inherited_by/3 +%% +%% Returns : +%% +%% true if the first parameter is +%% inherited by the second one +%% +%% false otherwise +%% +is_inherited_by(Interface1,Interface2,PragmaTab) -> + FullList = ets:tab2list(PragmaTab), + InheritsList = + [X || X <- FullList, element(1,X) == inherits], + inherits(Interface2,Interface1,InheritsList). + + + + +%% Filters all pragma prefix from list not in same file +%% the object + +filter_pragma_prefix_list(PragmaTab, Name, Scope, List) -> + IdlFile = scoped_names_idl_file(PragmaTab, Name, Scope), + filter_pragma_prefix_list2(PragmaTab,IdlFile,List,[]). + + +filter_pragma_prefix_list2(_,_,[],Found) -> + Found; +filter_pragma_prefix_list2(PT, IdlFile, [PP|PPs], Found) -> + case PP of + {prefix,_,_,_,IdlFile,_} -> %% Same file as the Object, keep + filter_pragma_prefix_list2(PT, IdlFile, PPs, [PP|Found]); + + _Other -> %% NOT in same file as the Object, throw away + filter_pragma_prefix_list2(PT, IdlFile, PPs, Found) + end. + +scoped_names_idl_file(PragmaTab, Name, Scope) -> + case ets:match(PragmaTab,{'_','$0','_','$2',Scope,Name,'_','_','_'}) of + [[IdlFile, _Type]] -> %% Usual case + IdlFile; + [[_File,module]|_Files] -> %% Multiple modules, get LOCAL file + case ets:match(PragmaTab,{file_data_local,'$0','_',module,Scope,Name,'_','_','_'}) of + [[LocalIdlFile]] -> + LocalIdlFile; + _ -> %% Should NEVER occur + error + end; + + _ -> + error %% Should NEVER occur + end. + + + + + + +%%------------------------------------------------- +%% +%% Register specific pragma code options +%% +%% If there is an operation with that +%% scope, denote this as {codeopt_specific,Scope} +%% +%%------------------------------------------------- +denote_specific_code_opts(G) -> + case ic_options:get_opt(G, be) of + noc -> + S = ic_genobj:pragmatab(G), + COList = ets:match(S,{codeopt,'$0','_','_','_','_'}), + OPList = ets:match(S,{op,'$0','$1','_','_'}), + denote_specific_code_opts(S,COList,OPList); + _ -> + ok + end. + +denote_specific_code_opts(_,_,[]) -> + ok; +denote_specific_code_opts(S,COList,[[OpN,OpS]|OPSs]) -> + case lists:member([[OpN|OpS]],COList) of + true -> + insert(S, {codeopt_specific,[OpN|OpS]}); + false -> + ok + end, + denote_specific_code_opts(S,COList,OPSs). + + + +%%--------------------------------------------- +%% +%% Returns true/false if it denotes an operation +%% +%%--------------------------------------------- +isOperation(_S,[]) -> + false; +isOperation(_S,[_]) -> + false; +isOperation(S,[H|T]) -> + case ets:match(S,{op,H,T,'$2','$3'}) of + [] -> + false; + _ -> + true + end. + + +hasSpecificCodeoptionOnTopFile(S,File,Scope) -> + case ets:match(S,{codeopt,Scope,'_','$2',File,[File]}) of + [] -> + false; + _ -> + true + end. + + +hasNonSpecificCodeoptionOnTopFile(S,File) -> + case ets:match(S,{codeopt,'_','_','$2',File,[File]}) of + [] -> + false; + _ -> + true + end. + + + +%%--------------------------------------------- +%% +%% Returns {ok,IfrId}/error when searching a random local type +%% +%%--------------------------------------------- + + +fetchRandomLocalType(G) -> + + S = ic_genobj:pragmatab(G), + + case ets:match(S,{file_data_local,'_','_','$2','$3','$4','_','_','_'}) of + [] -> + false; + + List -> + fetchRandomLocalType(S,List) + end. + + +fetchRandomLocalType(_,[]) -> + false; +fetchRandomLocalType(S,[[module|_]|Tail]) -> + fetchRandomLocalType(S,Tail); +fetchRandomLocalType(S,[[_,Scope,Name]|Tail]) -> + case ets:match(S,{alias,[Name|Scope],'$1'}) of + [] -> + fetchRandomLocalType(S,Tail); + [[IfrId]] -> + {ok,IfrId} + end. + + + +%%--------------------------------------------- +%% +%% Returns A list of local operation mapping +%% for a given scope +%% +%%--------------------------------------------- + + +fetchLocalOperationNames(G,I) -> + S = ic_genobj:pragmatab(G), + case ets:match(S,{file_data_local,'_','_',op,I,'$4','_','_','_'}) of + [] -> + []; + List -> + fetchLocalOperationNames2(List,[]) + end. + +fetchLocalOperationNames2([],Found) -> + lists:reverse(Found); +fetchLocalOperationNames2([[Name]|Names],Found) -> + fetchLocalOperationNames2(Names,[Name|Found]). + + + +%%------------------------------------------------ +%% +%% Returns a true if this scoped id is a local +%% one, false otherwise +%% +%%------------------------------------------------ +is_local(G,ScopedId) -> + S = ic_genobj:pragmatab(G), + Name = ic_util:to_undersc(ScopedId), + case ets:match(S,{file_data_local,'_','_','_',tl(ScopedId),'_',Name,'_','_'}) of + [[]] -> + true; + _ -> + false + end. diff --git a/lib/ic/src/ic_sequence_java.erl b/lib/ic/src/ic_sequence_java.erl new file mode 100644 index 0000000..b57652f --- /dev/null +++ b/lib/ic/src/ic_sequence_java.erl @@ -0,0 +1,239 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_sequence_java). + + +-include("icforms.hrl"). +-include("ic.hrl"). +-include("ic_debug.hrl"). +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([gen/4]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: gen/4 +%%----------------------------------------------------------------- +gen(G, N, X, SequenceName) when is_record(X, sequence) -> + emit_holder_class(G, N, X, SequenceName), + emit_helper_class(G, N, X, SequenceName); +gen(_G, _N, _X, _SequenceName) -> + ok. + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- + + +%%----------------------------------------------------------------- +%% Func: emit_holder_class/4 +%%----------------------------------------------------------------- +emit_holder_class(G, N, X, SequenceName) -> + SName = string:concat(SequenceName, "Holder"), + {Fd, _}= ic_file:open_java_file(G, N, SName), + + SequenceType = ic_java_type:getType(G, N, X), + + ic_codegen:emit(Fd, ["final public class ",SequenceName,"Holder {\n" + " // instance variables\n" + " public ",SequenceType," value;\n\n" + " // constructors\n" + " public ",SequenceName,"Holder() {}\n" + " public ",SequenceName,"Holder(",SequenceType," initial) {\n" + " value = initial;\n" + " }\n\n" + + " // methods\n" + + " public void _marshal(",?ERLANGPACKAGE,"OtpOutputStream out) throws java.lang.Exception{\n" + " ",SequenceName,"Helper.marshal(out, value);\n" + " }\n\n" + + " public void _unmarshal(",?ERLANGPACKAGE,"OtpInputStream in) throws java.lang.Exception {\n" + " value = ",SequenceName,"Helper.unmarshal(in);\n" + " }\n\n" + "}\n"]), + file:close(Fd). + + + +emit_helper_class(G, N, X, SequenceName) -> + SName = string:concat(SequenceName, "Helper"), + {Fd, _}= ic_file:open_java_file(G, N, SName), + + SequenceType = ic_java_type:getType(G, N, X), + ElementType = ic_forms:get_type(X), + + ic_codegen:emit(Fd, ["public class ",SequenceName,"Helper {\n" + + " // constructors\n" + " private ",SequenceName,"Helper() {}\n\n" + + " // methods\n" + " public static void marshal(",?ERLANGPACKAGE,"OtpOutputStream _out, ",SequenceType," _value) \n" + " throws java.lang.Exception {\n\n"]), + + emit_sequence_marshal_function(G, N, X, Fd, SequenceName, ElementType), + + ic_codegen:emit(Fd, [" }\n\n" + + " public static ",SequenceType," unmarshal(",?ERLANGPACKAGE,"OtpInputStream _in) \n" + " throws java.lang.Exception {\n\n"]), + + emit_sequence_unmarshal_function(G, N, X, Fd, SequenceName, ElementType), + + ic_codegen:emit(Fd, [" }\n\n" + + " public static String id() {\n" + " return \"",ic_pragma:scope2id(G, [SequenceName | N]),"\";\n" + " }\n\n" + + " public static String name() {\n" + " return \"",SequenceName,"\";\n" + " }\n\n"]), + + ic_jbe:emit_type_function(G, N, X, Fd), + + ic_codegen:emit(Fd, [" public static void insert(",?ICPACKAGE,"Any _any, ",SequenceType," _this)\n" + " throws java.lang.Exception {\n\n" + + " ",?ERLANGPACKAGE,"OtpOutputStream _os = \n" + " new ",?ERLANGPACKAGE,"OtpOutputStream();\n\n" + + " _any.type(type());\n" + " marshal(_os, _this);\n" + " _any.insert_Streamable(_os);\n" + " }\n\n" + + " public static ",SequenceType," extract(",?ICPACKAGE,"Any _any)\n" + " throws java.lang.Exception {\n\n" + + " return unmarshal(_any.extract_Streamable());\n" + " }\n\n" + + + %% In corba mapping there is also a _type function here. + "}\n\n"]), + file:close(Fd). + + +%%----------------------------------------------------------------- +%% Func: emit_sequence_marshal_function/6 +%%----------------------------------------------------------------- +emit_sequence_marshal_function(G, N, X, Fd, _SequenceName, ElementType) -> + ic_codegen:emit(Fd, [" int _length = _value.length;\n\n" + + " _out.write_list_head(_length);\n\n" + + " if (_length > 0) {\n" + " for(int _tmp = 0; _tmp < _length; _tmp++)\n"]), + + case ic_java_type:isBasicType(G, N, ElementType) of + true -> + ic_codegen:emit(Fd, [" _out",ic_java_type:marshalFun(G, N, X, ElementType),"(_value[_tmp]);\n\n"]); + false -> + ic_codegen:emit(Fd, [" ",ic_java_type:marshalFun(G, N, X, ElementType),"(_out, _value[_tmp]);\n\n"]) + end, + + ic_codegen:emit(Fd, [" _out.write_nil();\n" + " }\n\n"]). + + + + +%%----------------------------------------------------------------- +%% Func: emit_sequence_unmarshal_function/6 +%%----------------------------------------------------------------- +emit_sequence_unmarshal_function(G, N, X, Fd, _SequenceName, ElementType) -> + + SequenceElementType = ic_java_type:getType(G, N, ElementType), + + ic_codegen:emit(Fd, [" int _tag,_length;\n" + " ",SequenceElementType," _sequence[];\n" + " _tag = _in.peek();\n\n"]), + + case ic_java_type:isIntegerType(G, N, ElementType) of + true -> + ic_codegen:emit(Fd, [" switch(_tag) {\n" + " case ",?ERLANGPACKAGE,"OtpExternal.stringTag:\n" + " byte _compressed[] = (_in.read_string()).getBytes();\n" + " _length = _compressed.length;\n" + " _sequence = new ",ic_java_type:getFullType(G,N,X),";\n\n" + + " for(int _tmp = 0; _tmp < _length; _tmp++)\n" + " _sequence[_tmp] = (",ic_java_type:getType(G, N, ElementType),")(_compressed[_tmp] & 0xff);\n\n" + + " break;\n" + " default:\n" + " _length = _in.read_list_head();\n" + " _sequence = new ",ic_java_type:getFullType(G,N,X),";\n\n" + + " if(_length > 0) {\n" + " for(int _tmp = 0; _tmp < _length; _tmp++)\n" + " _sequence[_tmp] = _in",ic_java_type:unMarshalFun(G, N, X, ElementType),";\n\n" + + " _in.read_nil();\n" + " }\n" + " }\n"]); + false -> + ic_codegen:emit(Fd, [" _length = _in.read_list_head();\n" + " _sequence = new ",ic_java_type:getFullType(G,N,X),";\n\n" + + " if(_length > 0) {\n" + " for(int _tmp = 0; _tmp < _length; _tmp++)\n"]), + case ic_java_type:isBasicType(G, N, ElementType) of + true -> + ic_codegen:emit(Fd, [" _sequence[_tmp] = _in",ic_java_type:unMarshalFun(G, N, X, ElementType),";\n\n"]); + _ -> + ic_codegen:emit(Fd, [" _sequence[_tmp] = ",ic_java_type:getUnmarshalType(G, N, X, ElementType),".unmarshal(_in);\n\n"]) + end, + + ic_codegen:emit(Fd, [" _in.read_nil();\n" + " }\n\n"]) + end, + + ic_codegen:emit(Fd, " return _sequence;\n"). + + + + +%%--------------------------------------------------- +%% Utilities +%%--------------------------------------------------- + + + + + + + + + diff --git a/lib/ic/src/ic_struct_java.erl b/lib/ic/src/ic_struct_java.erl new file mode 100644 index 0000000..e577fd6 --- /dev/null +++ b/lib/ic/src/ic_struct_java.erl @@ -0,0 +1,314 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_struct_java). + +-include("icforms.hrl"). +-include("ic.hrl"). +-include("ic_debug.hrl"). +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([gen/3]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- +gen(G, N, X) when is_record(X, struct) -> + StructName = ic_forms:get_java_id(X), + WireStructName = ic_forms:get_id2(X), + emit_struct_class(G, N, X, StructName), + emit_holder_class(G, N, X, StructName), + emit_helper_class(G, N, X, StructName, WireStructName), + N2 = [StructName ++ "Package" |N], + ic_jbe:gen(G, N2, ic_forms:get_body(X)); +gen(_G, _N, _X) -> + ok. + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: emit_struct_class/4 +%%----------------------------------------------------------------- +emit_struct_class(G, N, X, StructName) -> + {Fd, _}= ic_file:open_java_file(G, N, StructName), + + MList = struct_member_list(G, N, X), + ArgList = gen_parameter_list(G, [ StructName ++ "Package" |N], X, MList), + + ic_codegen:emit(Fd, ["final public class ",StructName," {\n" + " // instance variables\n"]), + + emit_struct_members_declarations(G, [StructName ++ "Package" |N], + X, Fd, MList), + + ic_codegen:emit(Fd, ["\n // constructors\n" + " public ",StructName,"() {}\n\n" + + " public ",StructName,"(",ArgList,") {\n"]), + + emit_struct_members_initialisation(G, N, X, Fd, MList), + + ic_codegen:emit(Fd, [" }\n\n" + + "}\n\n"]), + file:close(Fd). + + +%%----------------------------------------------------------------- +%% Func: emit_holder_class/4 +%%----------------------------------------------------------------- +emit_holder_class(G, N, _X, StructName) -> + SName = string:concat(StructName, "Holder"), + {Fd, _}= ic_file:open_java_file(G, N, SName), + + ic_codegen:emit(Fd, ["final public class ",StructName,"Holder {\n" + + " // instance variables\n" + " public ",StructName," value;\n\n" + + " // constructors\n" + " public ",StructName,"Holder() {}\n\n" + + " public ",StructName,"Holder(",StructName," initial) {\n" + " value = initial;\n" + " }\n\n" + + " // methods\n"]), + + ic_codegen:emit(Fd, [" public void _marshal(",?ERLANGPACKAGE,"OtpOutputStream out) throws java.lang.Exception {\n" + " ",StructName,"Helper.marshal(out, value);\n" + " }\n\n" + + " public void _unmarshal(",?ERLANGPACKAGE,"OtpInputStream in) throws java.lang.Exception {\n" + " value = ",StructName,"Helper.unmarshal(in);\n" + " }\n" + + "}\n\n"]), + file:close(Fd). + +%%----------------------------------------------------------------- +%% Func: emit_helper_class/5 +%%----------------------------------------------------------------- +emit_helper_class(G, N, X, StructName, WireStructName) -> + SName = string:concat(StructName, "Helper"), + {Fd, _}= ic_file:open_java_file(G, N, SName), + + ic_codegen:emit(Fd, ["public class ",StructName,"Helper {\n" + + " // constructors\n" + " private ",StructName,"Helper() {}\n\n" + + " // methods\n"]), + + MList = struct_member_list(G, N, X), + + ic_codegen:emit(Fd, [" public static void marshal(",?ERLANGPACKAGE,"OtpOutputStream _out, ",StructName," _value)\n" + " throws java.lang.Exception {\n\n"]), + + emit_struct_marshal_function(G, N, X, Fd, StructName, WireStructName, MList), + + ic_codegen:emit(Fd, [" }\n\n" + + " public static ",StructName," unmarshal(",?ERLANGPACKAGE,"OtpInputStream _in)\n" + " throws java.lang.Exception {\n\n"]), + + emit_struct_unmarshal_function(G, N, X, Fd, StructName, WireStructName, MList), + + ic_codegen:emit(Fd, [" }\n\n" + + " public static String id() {\n" + " return \"",ictk:get_IR_ID(G, N, X),"\";\n" + " }\n\n" + + " public static String name() {\n" + " return \"",StructName,"\";\n" + " }\n\n"]), + + ic_jbe:emit_type_function(G, N, X, Fd), + + ic_codegen:emit(Fd, [" public static void insert(",?ICPACKAGE,"Any _any, ",StructName," _this)\n" + " throws java.lang.Exception {\n\n" + + " ",?ERLANGPACKAGE,"OtpOutputStream _os = \n" + " new ",?ERLANGPACKAGE,"OtpOutputStream();\n\n" + + " _any.type(type());\n" + " marshal(_os, _this);\n" + " _any.insert_Streamable(_os);\n" + " }\n\n" + + " public static ",StructName," extract(",?ICPACKAGE,"Any _any)\n" + " throws java.lang.Exception {\n\n" + + " return unmarshal(_any.extract_Streamable());\n" + " }\n\n" + + + %% In corba mapping there is also a _type function here. + "}\n"]), + file:close(Fd). + + +%%----------------------------------------------------------------- +%% Func: emit_struct_members_declarations/ +%%----------------------------------------------------------------- +emit_struct_members_declarations(_, _, _, _, []) -> + ok; +emit_struct_members_declarations(G, N, X, Fd, [{Member, _Type, Id} | MList]) -> + ic_codegen:emit(Fd, [" public ",ic_java_type:getType(G, N, Member)," ",Id,";\n"]), + emit_struct_members_declarations(G, N, X, Fd, MList). + + + +%%----------------------------------------------------------------- +%% Func: emit_struct_members_initialisation/5 +%%----------------------------------------------------------------- +emit_struct_members_initialisation(_, _, _, _, []) -> + ok; +emit_struct_members_initialisation(G, N, X, Fd, [{_Member, _Type, Id} | MList]) -> + ic_codegen:emit(Fd, [" ",Id," = _",Id,";\n"]), + emit_struct_members_initialisation(G, N, X, Fd, MList). + + + + +%%----------------------------------------------------------------- +%% Func: emit_struct_marshal_function/7 +%%----------------------------------------------------------------- +emit_struct_marshal_function(G, N, X, Fd, StructName, WireStructName, MList) -> + + ic_codegen:emit(Fd, [" _out.write_tuple_head(",integer_to_list(length(MList) + 1),");\n" + " _out.write_atom(\"",ic_util:to_undersc([WireStructName|N]),"\");\n\n"]), + + emit_struct_marshal_function_loop(G, [StructName ++ "Package" |N], + X, Fd, MList, 1). + +%%----------------------------------------------------------------- +%% Func: emit_struct_marshal_function_loop/6 +%%----------------------------------------------------------------- +emit_struct_marshal_function_loop(_, _, _, Fd, [], _) -> + ic_codegen:nl(Fd); +emit_struct_marshal_function_loop(G, N, X, Fd, [{Member, Type, Id} |MList], Num) -> + + case ic_java_type:isBasicType(G, N, Member) of + true -> + ic_codegen:emit(Fd, [" _out",ic_java_type:marshalFun(G, N, Member, Type),"(_value.",Id,");\n"]); + _ -> + if (element(1,hd(element(3,Member))) == array) -> + ic_codegen:emit(Fd, + [" ", + ic_util:to_dot(G,[ic_forms:get_id2(Member)|N]), + "Helper.marshal(_out, _value.",Id,");\n"]); + true -> + ic_codegen:emit(Fd, [" ", + ic_java_type:marshalFun(G, N, Member, Type), + "(_out, _value.",Id,");\n"]) + end + end, + + emit_struct_marshal_function_loop(G, N, X, Fd, MList, Num+1). + + + + +%%----------------------------------------------------------------- +%% Func: emit_struct_unmarshal_function/7 +%%----------------------------------------------------------------- +emit_struct_unmarshal_function(G, N, X, Fd, StructName, WireStructName, MList) -> + + ic_codegen:emit(Fd, [" _in.read_tuple_head();\n\n" + + " if ((_in.read_atom()).compareTo(\"", + ic_util:to_undersc([WireStructName|N]), + "\") != 0)\n" + " throw new java.lang.Exception(\"\");\n\n" + + " ",StructName," _value = new ",StructName,"();\n"]), + + emit_struct_unmarshal_function_loop(G, [StructName ++ "Package"|N], + X, Fd, MList, 1), + + ic_codegen:emit(Fd, " return _value;\n"). + +%%----------------------------------------------------------------- +%% Func: emit_union_unmarshal_function_loop/6 +%%----------------------------------------------------------------- +emit_struct_unmarshal_function_loop(_, _, _, Fd, [], _) -> + ic_codegen:nl(Fd); +emit_struct_unmarshal_function_loop(G, N, X, Fd, [{Member, Type, Id} |MList], Num) -> + + case ic_java_type:isBasicType(G, N, Member) of + true -> + ic_codegen:emit(Fd, [" _value.",Id," = _in",ic_java_type:unMarshalFun(G, N, Member, Type),";\n"]); + _ -> + if (element(1,hd(element(3,Member))) == array) -> + ic_codegen:emit(Fd, + [" _value.",Id," = ",ic_util:to_dot(G,[ic_forms:get_id2(Member)|N]),"Helper.unmarshal(_in);\n"]); + true -> + ic_codegen:emit(Fd, + [" _value.",Id," = ",ic_java_type:getUnmarshalType(G, N, Member, Type),".unmarshal(_in);\n"]) + end + end, + + emit_struct_unmarshal_function_loop(G, N, X, Fd, MList, Num +1). + + + +%%----------------------------------------------------------------- +%% Func: gen_parameter_list/4 +%%----------------------------------------------------------------- +gen_parameter_list(G, N, _X, [{Member, _Type, Id}]) -> + ic_java_type:getType(G,N,Member) ++ + " _" ++ + ic_util:to_list(Id); +gen_parameter_list(G, N, X, [{Member, _Type, Id} | MList]) -> + ic_java_type:getType(G,N,Member) ++ + " _" ++ + ic_util:to_list(Id) ++ + ", " ++ + gen_parameter_list(G, N, X, MList). + + +%%----------------------------------------------------------------- +%% Func: struct_member_list/3 +%%----------------------------------------------------------------- +struct_member_list(_G, _N, X) -> + M = lists:map( + fun(Member) -> + lists:map( + fun(Id) -> + Type = ic_forms:get_type(Member), + { Member, Type, ic_forms:get_java_id(Id)} + end, + ic_forms:get_idlist(Member)) + end, + ic_forms:get_body(X)), + lists:flatten(M). + + + diff --git a/lib/ic/src/ic_symtab.erl b/lib/ic/src/ic_symtab.erl new file mode 100644 index 0000000..889c75e --- /dev/null +++ b/lib/ic/src/ic_symtab.erl @@ -0,0 +1,232 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_symtab). + + +-include_lib("ic/src/ic.hrl"). +-include_lib("ic/src/icforms.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([new/0, store/3, retrieve/2, soft_retrieve/2, intf_resolv/3]). +-export([get_full_scoped_name/3, scoped_id_new_global/1, scoped_id_new/1]). +-export([scoped_id_strip/1,symtab_add_faked_included_types/1]). +-export([scoped_id_is_global/1, scoped_id_add/2]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + + +%%-------------------------------------------------------------------- +%% +%% Symbol table routines +%% +%% Symbol tables handles mappings Id -> Value, where Id is an +%% ordinary Id from the parser (or a string) and value is an +%% arbitrary term. +%% +%%-------------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: new/0 (used to be symtab_new) +%%----------------------------------------------------------------- +new() -> + ets:new(symtab, [set, public]). + +%%----------------------------------------------------------------- +%% Func: store/3 (used to be symtab_store) +%%----------------------------------------------------------------- +store(G, N, X) -> + Name = [ic_forms:get_id2(X) | N], + %%io:format("Adding id: ~p~n", [N]), + case soft_retrieve(G, Name) of + {error, _} -> + ets:insert(G#genobj.symtab, {Name, X}); + {ok, Y} when is_record(Y, forward) -> + ets:insert(G#genobj.symtab, {Name, X}); + {ok, _Y} -> + ic_error:error(G, {multiply_defined, X}) + end. + + +%%----------------------------------------------------------------- +%% Func: retrieve/2 (used to be symtab_retrieve) +%% +%% Makes a lookup in the symbol table for Id. Will throw +%% not_found if it fails. +%%----------------------------------------------------------------- +retrieve(G, Id) -> + case ets:lookup(G#genobj.symtab, Id) of + [{_, Val}] -> Val; + [] -> ic_error:error(G, {symtab_not_found, Id}) + end. + + +%%----------------------------------------------------------------- +%% Func: soft_retrieve/2 (used to be symtab_soft_retrieve) +%% +%% Same as retrieve but will use tagged return values. +%% +%%----------------------------------------------------------------- +soft_retrieve(G, Id) -> + case ets:lookup(G#genobj.symtab, Id) of + [{_, Val}] -> {ok, Val}; + [] -> {error, {symtab_not_found, Id}} + end. + + +%%----------------------------------------------------------------- +%% Func: intf_resolv/3 and resolv2/3 +%% (used to be symtab_intf_resolv and symtab_intf_resolv2) +%% +%% Tries to resolv the interface identifier reference. The id can +%% be either a scoped name or an standard identifier. The +%% function returns a global reference to the id. +%% +%% Will throw not_found if the id really cannot be found. Will +%% throw illegal_forward if any forward references are founf in +%% the inheritance list. +%% +%%----------------------------------------------------------------- +intf_resolv(G, Scope, Id) -> + case scoped_id_is_global(Id) of + true -> + retrieve(G, Id), + Id; + false -> + intf_resolv2(G, Scope, Id) + end. + +intf_resolv2(G, Scope, Id) -> + N = scoped_id_add(Scope, Id), + case soft_retrieve(G, scoped_id_strip(N)) of + {ok, F} when is_record(F, forward) -> + ic_error:error(G, {illegal_forward, Id}), []; + {ok, _Val} -> + scoped_id_mk_global(N); + _ -> + case scoped_id_is_top(Scope) of + false -> + intf_resolv2(G, scoped_id_up_one(Scope), Id); + true -> + ic_error:error(G, {symtab_not_found, Id}), [] + end + end. + + + +%%-------------------------------------------------------------------- +%% +%% Scoped id routines +%% +%% A scoped id is an id written as M::Id in IDL. Scoped ids are +%% implemented as lists of id in reverse order, so M1::F1 becomes +%% [F1, M1]. +%% +%%-------------------------------------------------------------------- + +get_full_scoped_name(G, N, S) when element(1, S) == scoped_id -> + ictype:scoped_lookup(G, ic_genobj:tktab(G), N, S). + +scoped_id_new_global(Id) -> + X=scoped_id_new(Id), X#scoped_id{type=global}. + +scoped_id_new(Id) -> + #scoped_id{line=ic_forms:get_line(Id), id=[ic_forms:get_id(Id)]}. + +%% Adds one more id to the list of ids +scoped_id_add(S1, S2) when is_record(S2, scoped_id) -> + S1#scoped_id{id=S2#scoped_id.id ++ S1#scoped_id.id, + line=S2#scoped_id.line}; +scoped_id_add(S, Id) -> + S#scoped_id{id=[ic_forms:get_id(Id) | S#scoped_id.id], line=ic_forms:get_line(Id)}. + + +scoped_id_mk_global(S) -> S#scoped_id{type=global}. + +scoped_id_is_global(S) when is_record(S, scoped_id), S#scoped_id.type==global -> + true; +scoped_id_is_global(_) -> false. + +%% Top level scope (i.e no more cd ..) +scoped_id_is_top(S) when S#scoped_id.id==[] -> true; +scoped_id_is_top(_) -> false. + + +scoped_id_up_one(S) -> S#scoped_id{id=tl(S#scoped_id.id)}. % cd .. in scope +%%scoped_id_get_def(S) -> hd(S#scoped_id.id). % Last added id +scoped_id_strip(S) -> S#scoped_id.id. % Strips all junk + + + + +% Add CORBA:: that as if they +% were defined in an included file. +% This is only supported in the case +% of Corba backend +symtab_add_faked_included_types(G) -> + case ic_options:get_opt(G, be) of + false -> + %% Add TypeCode as if it were defiend in included file + ets:insert(G#genobj.symtab, {["CORBA"], + {interface,{'',0,"TypeCode"}, + [], + [], + [], + {tk_objref, + "IDL:omg.org/CORBA/TypeCode:1.0", + "TypeCode"}}}); + erl_corba -> + %% Add TypeCode as if it were defiend in included file + ets:insert(G#genobj.symtab, {["CORBA"], + {interface,{'',0,"TypeCode"}, + [], + [], + [], + {tk_objref, + "IDL:omg.org/CORBA/TypeCode:1.0", + "TypeCode"}}}); + erl_template -> + %% Add TypeCode as if it were defiend in included file + ets:insert(G#genobj.symtab, {["CORBA"], + {interface,{'',0,"TypeCode"}, + [], + [], + [], + {tk_objref, + "IDL:omg.org/CORBA/TypeCode:1.0", + "TypeCode"}}}); + _ -> + ok + end. + + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- diff --git a/lib/ic/src/ic_union_java.erl b/lib/ic/src/ic_union_java.erl new file mode 100644 index 0000000..4be93f3 --- /dev/null +++ b/lib/ic/src/ic_union_java.erl @@ -0,0 +1,754 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + + +-module(ic_union_java). + +-include("icforms.hrl"). +-include("ic.hrl"). +-include("ic_debug.hrl"). +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([gen/3]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: gen/3 +%%----------------------------------------------------------------- +gen(G, N, X) when is_record(X, union) -> + + %% Create a TK value if not existed + %% Should be integrated in fetchTk + %% instead + NewX = case ic_forms:get_tk(X) of + undefined -> + S = ic_genobj:tktab(G), + Tk = ictype:tk(G, S, N, X), + #union{ id = X#union.id, + type = X#union.type, + body = X#union.body, + tk = Tk }; + _Tk -> + X + end, + + UnionName = ic_forms:get_java_id(NewX), + WiredUnionName = ic_forms:get_id2(NewX), + N2 = [UnionName ++ "Package"|N], + %%?PRINTDEBUG2("Recursive call over type ~p", + %% [[ic_forms:get_type(NewX)]]), + ic_jbe:gen(G, N, [ic_forms:get_type(NewX)]), + %%?PRINTDEBUG2("Recursive call over body: ~p", + %% [ic_forms:get_body(NewX)]), + ic_jbe:gen(G, N2, ic_forms:get_body(NewX)), + + emit_union_class(G, N, NewX, UnionName), + emit_holder_class(G, N, NewX, UnionName), + emit_helper_class(G, N, NewX, UnionName, WiredUnionName); +gen(_G, _N, _X) -> + ok. + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Func: emit_union_class/4 +%%----------------------------------------------------------------- +emit_union_class(G, N, X, UnionName) -> + {Fd, _} = ic_file:open_java_file(G, N, UnionName), + + DiscrType = ic_java_type:getType(G, [UnionName ++ "Package"|N], + ic_forms:get_type(X)), + + MList = union_member_list(G, N, X, DiscrType), + + ic_codegen:emit(Fd, "final public class ~s {\n",[UnionName]), + + ic_codegen:emit(Fd, " // instance variables\n", []), + ic_codegen:emit(Fd, " private boolean _initialized;\n", []), + ic_codegen:emit(Fd, " private ~s _discriminator;\n", [DiscrType]), + ic_codegen:emit(Fd, " private java.lang.Object _value;\n", []), + + {tk_union,_, _,DiscrTk, _, _} = ic_forms:get_tk(X), + + DV = get_default_val(G, [UnionName |N], DiscrType, DiscrTk, MList), + + case DV of + none -> %% all values in case + ok; + _ -> + ic_codegen:emit(Fd, " private ~s _default = ~s;\n", + [DiscrType, DV]) + end, + + ic_codegen:nl(Fd), + ic_codegen:emit(Fd, " // constructors\n", []), + + ic_codegen:emit(Fd, " public ~s() {\n", [UnionName]), + ic_codegen:emit(Fd, " _initialized = false;\n", []), + ic_codegen:emit(Fd, " _value = null;\n", []), + ic_codegen:emit(Fd, " }\n", []), + ic_codegen:nl(Fd), + + ic_codegen:emit(Fd, " // discriminator access\n", []), + + ic_codegen:emit(Fd, " public ~s discriminator() " + "throws java.lang.Exception {\n", [DiscrType]), + ic_codegen:emit(Fd, " if (!_initialized) {\n", []), + ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n",[]), + ic_codegen:emit(Fd, " }\n", []), + ic_codegen:emit(Fd, " return _discriminator;\n", []), + ic_codegen:emit(Fd, " }\n", []), + ic_codegen:nl(Fd), + + emit_union_members_functions(G, [UnionName ++ "Package"|N], X, + Fd, UnionName, DiscrType, MList, MList), + ic_codegen:nl(Fd), + + ic_codegen:emit(Fd, "}\n", []), + file:close(Fd). + +%%----------------------------------------------------------------- +%% Func: emit_holder_class/4 +%%----------------------------------------------------------------- +emit_holder_class(G, N, _X, UnionName) -> + UName = string:concat(UnionName, "Holder"), + {Fd, _} = ic_file:open_java_file(G, N, UName), + + ic_codegen:emit(Fd, "final public class ~sHolder {\n",[UnionName]), + + ic_codegen:emit(Fd, " // instance variables\n"), + ic_codegen:emit(Fd, " public ~s value;\n", [UnionName]), + ic_codegen:nl(Fd), + + ic_codegen:emit(Fd, " // constructors\n"), + ic_codegen:emit(Fd, " public ~sHolder() {}\n", [UnionName]), + ic_codegen:emit(Fd, " public ~sHolder(~s initial) {\n", + [UnionName, UnionName]), + ic_codegen:emit(Fd, " value = initial;\n"), + ic_codegen:emit(Fd, " }\n"), + ic_codegen:nl(Fd), + + ic_codegen:emit(Fd, " // methods\n"), + + ic_codegen:emit(Fd, " public void _marshal(~sOtpOutputStream out) throws java.lang.Exception {\n", + [?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " ~sHelper.marshal(out, value);\n", [UnionName]), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public void _unmarshal(~sOtpInputStream in) throws java.lang.Exception {\n", + [?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " value = ~sHelper.unmarshal(in);\n", [UnionName]), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, "}\n"), + file:close(Fd). + + +%%----------------------------------------------------------------- +%% Func: emit_helper_class/4 +%%----------------------------------------------------------------- +emit_helper_class(G, N, X, UnionName, WiredUnionName) -> + UName = string:concat(UnionName, "Helper"), + {Fd, _} = ic_file:open_java_file(G, N, UName), + + DiscrType = ic_java_type:getType(G, [ UnionName ++ "Package" |N], + ic_forms:get_type(X)), + + ic_codegen:emit(Fd, "public class ~sHelper {\n",[UnionName]), + + ic_codegen:emit(Fd, " // constructors\n", []), + ic_codegen:emit(Fd, " private ~sHelper() {}\n", [UnionName]), + ic_codegen:nl(Fd), + + ic_codegen:emit(Fd, " // methods\n", []), + MList = union_member_list(G, N, X, DiscrType), + + ic_codegen:emit(Fd, " public static void marshal(~sOtpOutputStream _out, ~s _value)\n", + [?ERLANGPACKAGE, UnionName]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + emit_union_marshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static ~s unmarshal(~sOtpInputStream _in)\n", + [UnionName, ?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + emit_union_unmarshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static String id() {\n"), + ic_codegen:emit(Fd, " return ~p;\n",[ictk:get_IR_ID(G, N, X)]), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static String name() {\n"), + ic_codegen:emit(Fd, " return ~p;\n",[UnionName]), + ic_codegen:emit(Fd, " }\n\n"), + + ic_jbe:emit_type_function(G, N, X, Fd), + + + ic_codegen:emit(Fd, " public static void insert(~sAny _any, ~s _this)\n", + [?ICPACKAGE,UnionName]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " ~sOtpOutputStream _os = \n",[?ERLANGPACKAGE]), + ic_codegen:emit(Fd, " new ~sOtpOutputStream();\n\n",[?ERLANGPACKAGE]), + + ic_codegen:emit(Fd, " _any.type(type());\n"), + ic_codegen:emit(Fd, " marshal(_os, _this);\n"), + ic_codegen:emit(Fd, " _any.insert_Streamable(_os);\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static ~s extract(~sAny _any)\n", + [UnionName,?ICPACKAGE]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n\n"), + + ic_codegen:emit(Fd, " return unmarshal(_any.extract_Streamable());\n"), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " public static int discriminatorAsInt(~s _discriminator)\n", + [DiscrType]), + ic_codegen:emit(Fd, " throws java.lang.Exception {\n"), + emit_discriminator_as_int(G, N, ic_forms:get_type(X), Fd), + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, "}\n"), + file:close(Fd). + +%%----------------------------------------------------------------- +%% Func: emit_union_members_functions/7 +%%----------------------------------------------------------------- +emit_union_members_functions(_, _, _, _, _, _, [], _) -> + ok; +emit_union_members_functions(G, N, X, Fd, UnionName, DiscrType, + [{Label, Case, TypeDef, Id, Ls} | MList], MListTot) -> + + CaseId = Case#case_dcl.id, %% Maybe Array + CaseType = Case#case_dcl.type, %% Maybe Sequence + + Type = if element(1,CaseId) == array -> + ic_java_type:getType(G, N, TypeDef) ++ + ic_java_type:getdim(CaseId#array.size); + true -> + ic_java_type:getType(G, N, TypeDef) + end, + + HolderType = + if element(1,CaseId) == array -> + ic_java_type:getHolderType(G, N, CaseId); + true -> + if element(1,CaseType) == sequence -> + ic_util:to_dot(G,[Id|N]) ++"Holder"; + true -> + ic_java_type:getHolderType(G, N, TypeDef) + end + end, + + %% + %% Set method + %% + ic_codegen:emit(Fd, " // ~s access and set functions\n",[Id]), + ic_codegen:emit(Fd, " public void ~s(~s value) " + "throws java.lang.Exception {\n", + [Id, Type]), + ic_codegen:emit(Fd, " _initialized = true;\n", []), + case Label of + "default" -> + ic_codegen:emit(Fd, " _discriminator = (~s) _default;\n", + [DiscrType]); + _ -> + case ic_java_type:isBasicType(G, N, ic_forms:get_type(X)) of + true -> + ic_codegen:emit(Fd, " _discriminator = (~s) " + "~s;\n", + [DiscrType, Label]); + _ -> + ic_codegen:emit(Fd, " _discriminator = (~s) " + "~s.~s;\n", + [DiscrType, DiscrType, Label]) + end + end, + ic_codegen:emit(Fd, " _value = new ~s(value);\n", + [HolderType]), + ic_codegen:emit(Fd, " }\n", []), + + %% + %% Check this entry has more than one label and the generate an extra set method. + %% + case Ls of + [] -> + ok; + _ -> + ic_codegen:emit(Fd, " public void ~s(~s discriminator, ~s value) " + "throws java.lang.Exception {\n", + [Id, DiscrType, Type]), + ic_codegen:emit(Fd, " _initialized = true;\n", []), + ic_codegen:emit(Fd, " _discriminator = (~s) discriminator;\n", + [DiscrType]), + ic_codegen:emit(Fd, " _value = new ~s(value);\n", + [HolderType]), + ic_codegen:emit(Fd, " }\n", []) + end, + + %% + %% Get method + %% + ic_codegen:emit(Fd, " public ~s ~s() throws java.lang.Exception {\n", + [Type, Id]), + ic_codegen:emit(Fd, " if (!_initialized) {\n", []), + ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n",[]), + ic_codegen:emit(Fd, " }\n", []), + ic_codegen:emit(Fd, " switch (~sHelper.discriminatorAsInt" + "(discriminator())) {\n", + [UnionName]), + if + Label == "default" -> + ic_codegen:emit(Fd, " default:\n", []), + ic_codegen:emit(Fd, " break;\n", []), + emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType, + MListTot), + ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n", []); + true -> + ic_codegen:emit(Fd, " case ~s:\n", + [get_case_as_int(G, N, ic_forms:get_type(X), + DiscrType, Label)]), + ic_codegen:emit(Fd, " break;\n", []), + ic_codegen:emit(Fd, " default:\n", []), + ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n", []) + end, + ic_codegen:emit(Fd, " }\n", []), + + ic_codegen:emit(Fd, " return ((~s) _value).value;\n", + [HolderType]), + ic_codegen:emit(Fd, " }\n", []), + ic_codegen:nl(Fd), + emit_union_members_functions(G, N, X, Fd, UnionName, DiscrType, MList, + MListTot). + + +%%----------------------------------------------------------------- +%% Func: emit_default_access_fun_switch_cases/6 +%%----------------------------------------------------------------- +emit_default_access_fun_switch_cases(_G, _N, _X, _Fd, _DiscrType, []) -> + ok; +emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType, + [{"default", _, _, _, _} |MList]) -> + emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType, MList); +emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType, + [{Label, _Case, _TypeDef, _Id, _} | MList]) -> + ic_codegen:emit(Fd, " case ~s:\n", + [get_case_as_int(G, N, ic_forms:get_type(X), + DiscrType, Label)]), + emit_default_access_fun_switch_cases(G, N, X, Fd, DiscrType, MList). + + + +%%----------------------------------------------------------------- +%% Func: emit_union_unmarshal_function/5 +%%----------------------------------------------------------------- +emit_union_unmarshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList) -> + DiscrTypeForm = ic_forms:get_type(X), + DiscrType = ic_java_type:getType(G, [UnionName ++ "Package"|N], + DiscrTypeForm), + + ic_codegen:emit(Fd, " _in.read_tuple_head();\n\n"), + + ic_codegen:emit(Fd, " if ((_in.read_atom()).compareTo(~p) != 0)\n", + [ic_util:to_undersc([WiredUnionName|N])]), + ic_codegen:emit(Fd, " throw new java.lang.Exception(\"\");\n\n",[]), + + ic_codegen:emit(Fd, " ~s _value = new ~s();\n", [UnionName, UnionName]), + + %% Decode discriminator + case ic_java_type:isBasicType(G, N, DiscrTypeForm) of + true -> + ic_codegen:emit(Fd, " ~s _discriminator = _in~s;\n\n", + [DiscrType, + ic_java_type:unMarshalFun(G, N, X, DiscrTypeForm)]); + _ -> + ic_codegen:emit(Fd, " ~s _discriminator = ~s.unmarshal(_in);\n\n", + [DiscrType,ic_java_type:getUnmarshalType(G, N, X, DiscrTypeForm)]) + end, + + ic_codegen:emit(Fd, " switch (~sHelper.discriminatorAsInt(_discriminator)) {\n", + [UnionName]), + + emit_union_unmarshal_function_loop(G, [UnionName ++ "Package"|N], X, + Fd, DiscrType, MList), + + ic_codegen:emit(Fd, " }\n\n"), + + ic_codegen:emit(Fd, " return _value;\n"). + +%%----------------------------------------------------------------- +%% Func: emit_union_unmarshal_function_loop/6 +%%----------------------------------------------------------------- +emit_union_unmarshal_function_loop(_, _, _, _, _, []) -> + ok; +emit_union_unmarshal_function_loop(G, N, X, Fd, DiscrType, + [{Label, Case, Type, Id, Ls} |MList]) -> + case Label of + "default" -> + ic_codegen:emit(Fd, " default:\n"); + _ -> + ic_codegen:emit(Fd, " case ~s:\n", + [get_case_as_int(G, N, ic_forms:get_type(X), + DiscrType, Label)]) + end, + + gen_multiple_cases(G, N, X, Fd, DiscrType, Ls), + + CaseId = Case#case_dcl.id, %% Maybe Array + CaseType = Case#case_dcl.type, %% Maybe Sequence + + case element(1,CaseId) of + array -> + ic_codegen:emit(Fd, " _value.~s(~s.unmarshal(_in));\n", + [Id, + ic_java_type:getUnmarshalType(G, N, Case, CaseId)]); + + _ -> + case element(1, CaseType) of + sequence -> + ic_codegen:emit(Fd, " _value.~s(~s.unmarshal(_in));\n", + [Id, + ic_java_type:getUnmarshalType(G, N, Case, CaseType)]); + _ -> + case ic_java_type:isBasicType(G, N, CaseType) of + true -> + ic_codegen:emit(Fd, " _value.~s(_in~s);\n", + [Id, + ic_java_type:unMarshalFun(G, N, X, Type)]); + false -> + ic_codegen:emit(Fd, " _value.~s(~s.unmarshal(_in));\n", + [Id, + ic_java_type:getUnmarshalType(G, N, X, Type)]) + end + end + end, + + ic_codegen:emit(Fd, " break;\n", []), + emit_union_unmarshal_function_loop(G, N, X, Fd, DiscrType, MList). + + + + + +%%----------------------------------------------------------------- +%% Func: emit_union_marshal_function/6 +%%----------------------------------------------------------------- +emit_union_marshal_function(G, N, X, Fd, UnionName, WiredUnionName, MList) -> + + DiscrTypeForm = ic_forms:get_type(X), + DiscrType = ic_java_type:getType(G, [UnionName ++ "Package" |N], + DiscrTypeForm), + + ic_codegen:emit(Fd, " _out.write_tuple_head(3);\n"), + ic_codegen:emit(Fd, " _out.write_atom(~p);\n", + [ic_util:to_undersc([WiredUnionName|N])]), + + case ic_java_type:isBasicType(G, N, DiscrTypeForm) of + true -> + ic_codegen:emit(Fd, " _out~s(_value.discriminator());\n\n", + [ic_java_type:marshalFun(G, N, X, DiscrTypeForm)]); + false -> + ic_codegen:emit(Fd, " ~s(_out, _value.discriminator());\n\n", + [ic_java_type:marshalFun(G, N, X, DiscrTypeForm)]) + end, + + ic_codegen:emit(Fd, " switch(~sHelper.discriminatorAsInt(_value.discriminator())) {\n", + [UnionName]), + + emit_union_marshal_function_loop(G, + [ UnionName ++ "Package"|N], + X, + Fd, + DiscrType, + MList), + + ic_codegen:emit(Fd, " }\n\n", []). + + +%%----------------------------------------------------------------- +%% Func: emit_union_marshal_function_loop/ +%%----------------------------------------------------------------- +emit_union_marshal_function_loop(_, _, _, _, _, []) -> + ok; +emit_union_marshal_function_loop(G, N, X, Fd, DiscrType, + [{Label, Case, Type, Id, Ls} |MList]) -> + case Label of + "default" -> + ic_codegen:emit(Fd, " default:\n", + []); + _ -> + ic_codegen:emit(Fd, " case ~s:\n", + [get_case_as_int(G, N, ic_forms:get_type(X), + DiscrType, Label)]) + end, + + gen_multiple_cases(G, N, X, Fd, DiscrType, Ls), + + + CaseId = Case#case_dcl.id, %% Maybe Array + CaseType = Case#case_dcl.type, %% Maybe Sequence + + case element(1,CaseId) of + array -> + ic_codegen:emit(Fd, " ~s(_out, _value.~s());\n", + [ic_java_type:marshalFun(G, N, Case, CaseId), + Id]); + _ -> + case element(1, CaseType) of + sequence -> + ic_codegen:emit(Fd, " ~s.marshal(_out, _value.~s());\n", + [ic_util:to_dot(G,[Id|N]) ++ "Helper", + Id]); + _ -> + case ic_java_type:isBasicType(G, N, CaseType) of + true -> + ic_codegen:emit(Fd, " _out~s(_value.~s());\n", + [ic_java_type:marshalFun(G, N, X, Type), + Id]); + false -> + ic_codegen:emit(Fd, " ~s(_out, _value.~s());\n", + [ic_java_type:marshalFun(G, N, X, Type), + Id]) + end + end + end, + + ic_codegen:emit(Fd, " break;\n", []), + emit_union_marshal_function_loop(G, N, X, Fd, DiscrType, MList). + + + +gen_multiple_cases(_G, _N, _X, _Fd, _DiscrType, []) -> + ok; +gen_multiple_cases(G, N, X, Fd, DiscrType, [Label |Ls]) -> + ic_codegen:emit(Fd, " case ~s:\n", + [get_case_as_int(G, N, ic_forms:get_type(X), + DiscrType, getLabel(DiscrType, Label))]), + gen_multiple_cases(G, N, X, Fd, DiscrType, Ls). + + +%%----------------------------------------------------------------- +%% Func: union_member_list/3 +%%----------------------------------------------------------------- +union_member_list(G, N, X, DiscrType) -> + M = lists:map( + fun(Case) -> + {Label, LabelList} = case check_default(ic_forms:get_idlist(Case)) of + {{default, C}, List} -> + {{default, C}, List}; + {L, []} -> + {L, []}; + {_, [L |Ls]} -> + {L, Ls} + end, + + CName = ic_forms:get_java_id(Case), + CId = Case#case_dcl.id, + CType = Case#case_dcl.type, + + if element(1,CId) == array -> + N2 = [ic_forms:get_id2(X) ++ "Package" |N], + ic_array_java:gen(G, N2, Case, CId); + true -> + if element(1,Case#case_dcl.type) == sequence -> + N2 = [ic_forms:get_id2(X) ++ "Package" |N], + ic_sequence_java:gen(G, N2, CType, CName); + true -> + ok + end + end, + + {getLabel(DiscrType, Label), + Case, + ic_forms:get_type(Case), + CName, + LabelList} + end, + ic_forms:get_body(X)), + lists:flatten(M). + +check_default([]) -> + {false, []}; +check_default([{default, X} |Ls]) -> + {{default, X}, Ls}; +check_default([L]) -> + {false, [L]}; +check_default([L |Ls]) -> + {X, Y} = check_default(Ls), + {X, [L | Y]}. + +getLabel(_, {'', _, N}) -> + N; +getLabel(_, {'', _, N}) -> + "'" ++ N ++ "'"; +getLabel(_, {'', _, N}) -> + "'" ++ N ++ "'"; +getLabel(_, {'TRUE',_}) -> + "true"; +getLabel(_, {'FALSE',_}) -> + "true"; +getLabel(_, {default, _}) -> + "default"; +getLabel(_DiscrType, X) -> %%DiscrType ++ "." ++ + ic_util:to_dot(ic_forms:get_id(X)). + +get_default_val(G, N, _, tk_short, MList) -> + integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList)); +get_default_val(G, N, _, tk_long, MList) -> + integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList)); +get_default_val(G, N, _, tk_ushort, MList) -> + integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList)); +get_default_val(G, N, _, tk_ulong, MList) -> + integer_default_val(G, N, 1, lists:map(fun({V, _, _, _, _}) -> V end, MList)); +get_default_val(G, N, _, tk_char, MList) -> + char_default_val(G, N, $a, lists:map(fun({V, _, _, _, _}) -> V end, MList)); +get_default_val(G, N, _, tk_boolean, MList) -> + boolean_default_val(G, N, lists:map(fun({V, _, _, _, _}) -> V end, MList)); +get_default_val(G, N, DiscrType, {tk_enum, _, _, Values}, MList) -> + enum_default_val(G, N, DiscrType, Values, MList). + +integer_default_val(G, N, Num, MList) -> + Num2 = integer_to_list(Num), + case lists:member(Num2, MList) of + true -> + integer_default_val(G, N, Num + 1, MList); + false -> + Num2 + end. + +char_default_val(G, N, CharNum, MList) -> + Str = "'", + CharNum2 = Str ++ [CharNum | Str], + case lists:member(CharNum2, MList) of + true -> + char_default_val(G, N, CharNum + 1, MList); + false -> + CharNum2 + end. + +boolean_default_val(G, N, MList) -> + if + length(MList) > 2 -> + ic_error:error(G, {plain_error_string, + lists:flatten( + io_lib:format("Default value found while all values have label on ~s", + [ic_util:to_colon(N)]))}), + none; + true -> + case MList of + ["true"] -> + "false"; + ["false"] -> + "true"; + ["default","true"] -> + "false"; + ["true","default"] -> + "false"; + ["default","false"] -> + "true"; + ["false","default"] -> + "true"; + _ -> + none + end + end. + + + + +enum_default_val(G, N, DiscrType, Values, Mlist) -> + + VLen = length(Values), + MLen = length(Mlist), + + case MLen > VLen of + true -> + ic_error:error(G, {plain_error_string, + lists:flatten( + io_lib:format("Default value found while all values have label on ~s", + [ic_util:to_colon(N)]))}), + none; + false -> + enum_default_val_loop(G, N, DiscrType, Values, Mlist) + end. + +enum_default_val_loop(_G, _N, _, [], []) -> + none; +enum_default_val_loop(_G, _N, DiscrType, [Value| _], []) -> + DiscrType ++ "." ++ Value; +enum_default_val_loop(G, N, DiscrType, Values, [Case | MList]) when is_tuple(Case) -> + NewValues = lists:delete(element(1,Case), Values), + enum_default_val_loop(G, N, DiscrType, NewValues, MList). + + + +emit_discriminator_as_int(G, N, T, Fd) -> + case ictype:isBoolean(G,N,T) of + true -> + ic_codegen:emit(Fd, " if(_discriminator)\n", []), + ic_codegen:emit(Fd, " return 1;\n", []), + ic_codegen:emit(Fd, " else\n", []), + ic_codegen:emit(Fd, " return 0;\n", []); + false -> + case ictype:isEnum(G, N, T) of + true -> + ic_codegen:emit(Fd, " return _discriminator.value();\n", + []); + false -> + ic_codegen:emit(Fd, " return _discriminator;\n", []) + end + end. + + +get_case_as_int(G, N, T, DiscrJavaTypeName, Label) -> + case ictype:isBoolean(G,N,T) of + true -> + case Label of + "true" -> + "1"; + "false" -> + "0" + end; + false -> + case ictype:isEnum(G, N, T) of + true -> + DiscrJavaTypeName ++ "._" ++ Label; + false -> + "(" ++ DiscrJavaTypeName ++ ") " ++ Label + end + end. + + + diff --git a/lib/ic/src/ic_util.erl b/lib/ic/src/ic_util.erl new file mode 100644 index 0000000..1a6acb2 --- /dev/null +++ b/lib/ic/src/ic_util.erl @@ -0,0 +1,313 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(ic_util). + + +-include("icforms.hrl"). +-include("ic.hrl"). +-include("ic_debug.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- + +-export([mk_align/1, mk_list/1, join/2, chain/2, mk_name/2, + mk_OE_name/2, mk_oe_name/2, mk_var/1]). + +-export([to_atom/1, to_colon/1, to_list/1, to_undersc/1, to_dot/1, + to_dot/2]). +-export([to_uppercase/1, adjustScopeToJava/2, eval_java/3, eval_c/3]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +%% mk_list produces a nice comma separated string of variable names +mk_list([]) -> []; +mk_list([Arg | Args]) -> + Arg ++ mk_list2(Args). +mk_list2([Arg | Args]) -> + ", " ++ Arg ++ mk_list2(Args); +mk_list2([]) -> []. + +%% Produce a list of items separated by S. +join([E1, E2| Es], S) -> + [E1, S| join([E2| Es], S)]; +join([E], _) -> + [E]; +join([], _) -> + []. + +%% Produce a list of items, each terminated by T. +chain([E| Es], T) -> + [E, T| chain(Es, T)]; +chain([], _) -> + []. + + +%% Shall convert a string to a Erlang variable name (Capitalise) +mk_var( [N | Str] ) when N >= $a, N =< $z -> + [ N+$A-$a | Str ]; +mk_var( [N | Str] ) when N >= $A, N =< $Z -> [N | Str]. + +%% Shall produce a "public" name for name. When we introduce new +%% identifiers in the mapping that must not collide with those from +%% the IDL spec. +%% +%% NOTE: Change name of IFR ID in system exceptions in corba.hrl when +%% prefix is changed here. +%% +mk_name(_Gen, Name) -> lists:flatten(["OE_" | Name]). +mk_OE_name(_Gen, Name) -> lists:flatten(["OE_" | Name]). +mk_oe_name(_Gen, Name) -> lists:flatten(["oe_" | Name]). + +mk_align(String) -> + io_lib:format("OE_ALIGN(~s)",[String]). + +to_atom(A) when is_atom(A) -> A; +to_atom(L) when is_list(L) -> list_to_atom(L). + +to_list(A) when is_list(A) -> A; +to_list(L) when is_atom(L) -> atom_to_list(L); +to_list(X) when is_integer(X) -> integer_to_list(X). + + + +%% Produce a colon (or under score) separated string repr of the name +%% X +%% +to_colon(X) when element(1, X) == scoped_id -> + to_colon2(ic_symtab:scoped_id_strip(X)); +to_colon(L) -> to_colon2(L). + +to_colon2([X]) -> X; +to_colon2([X | Xs]) -> to_colon2(Xs) ++ "::" ++ X; +to_colon2([]) -> "". + + +to_undersc(X) when element(1, X) == scoped_id -> + to_undersc2(ic_symtab:scoped_id_strip(X)); +to_undersc(L) -> to_undersc2(L). + +to_undersc2([X]) -> X; +to_undersc2([X | Xs]) -> to_undersc2(Xs) ++ "_" ++ X; +to_undersc2([]) -> "". + + +%% Z is a single name +to_uppercase(Z) -> + lists:map(fun(X) when X>=$a, X=<$z -> X-$a+$A; + (X) -> X end, Z). + + +%% +to_dot(X) when element(1, X) == scoped_id -> + to_dotLoop(ic_symtab:scoped_id_strip(X)); +to_dot(L) -> to_dotLoop(L). + +to_dotLoop([X]) -> ic_forms:get_java_id(X); +to_dotLoop([X | Xs]) -> to_dotLoop(Xs) ++ "." ++ ic_forms:get_java_id(X); +to_dotLoop([]) -> "". + + + +%% +to_dot(G,X) when element(1, X) == scoped_id -> + S = ic_genobj:pragmatab(G), + ScopedId = ic_symtab:scoped_id_strip(X), + case isConstScopedId(S, ScopedId) of %% Costants are left as is + true -> + to_dotLoop(ScopedId) ++ addDotValue(S, ScopedId); + false -> + to_dotLoop(S,ScopedId) + end; +to_dot(G,ScopedId) -> + S = ic_genobj:pragmatab(G), + case isConstScopedId(S, ScopedId) of %% Costants are left as is + true -> + to_dotLoop(ScopedId) ++ addDotValue(S, ScopedId); + false -> + to_dotLoop(S,ScopedId) + end. + +addDotValue(S, [_C | Ss]) -> + case isInterfaceScopedId(S, Ss) of + true -> + ""; + false -> + ".value" + end. + +to_dotLoop(S,[X]) -> + case isInterfaceScopedId(S, [X]) of + true -> + ic_forms:get_java_id(X) ++ "Package"; + false -> + ic_forms:get_java_id(X) + end; +to_dotLoop(S,[X | Xs]) -> + case isInterfaceScopedId(S, [X | Xs]) of + true -> + to_dotLoop(S,Xs) ++ "." ++ ic_forms:get_java_id(X) ++ "Package"; + false -> + to_dotLoop(S,Xs) ++ "." ++ ic_forms:get_java_id(X) + end; +to_dotLoop(_S,[]) -> "". + +isInterfaceScopedId(_S,[]) -> + false; +isInterfaceScopedId(S,[X|Xs]) -> + case ets:match(S,{file_data_local,'_','_',interface,Xs,X,'_','_','_'}) of + [] -> + case ets:match(S,{file_data_included,'_','_',interface,Xs,X,'_','_','_'}) of + [] -> + false; + _ -> + true + end; + _ -> + true + end. + +isConstScopedId(_S,[]) -> + false; +isConstScopedId(S,[X|Xs]) -> + case ets:match(S,{file_data_local,'_','_',const,Xs,X,'_','_','_'}) of + [] -> + case ets:match(S,{file_data_included,'_','_',const,Xs,X,'_','_','_'}) of + [] -> + false; + _ -> + true + end; + _ -> + true + end. + + + +%% +adjustScopeToJava(G,X) when element(1, X) == scoped_id -> + S = ic_genobj:pragmatab(G), + ScopedId = ic_symtab:scoped_id_strip(X), + case isConstScopedId(S, ScopedId) of %% Costants are left as is + true -> + ic_forms:get_java_id(ScopedId); + false -> + adjustScopeToJavaLoop(S,ScopedId) + end; +adjustScopeToJava(G,ScopedId) -> + S = ic_genobj:pragmatab(G), + case isConstScopedId(S, ScopedId) of %% Costants are left as is + true -> + ic_forms:get_java_id(ScopedId); + false -> + adjustScopeToJavaLoop(S,ScopedId) + end. + + + +adjustScopeToJavaLoop(_S,[]) -> + []; +adjustScopeToJavaLoop(S,[X | Xs]) -> + case isInterfaceScopedId(S, [X | Xs]) of + true -> + [ic_forms:get_java_id(X) ++ "Package" | adjustScopeToJavaLoop(S,Xs)]; + false -> + [ic_forms:get_java_id(X) | adjustScopeToJavaLoop(S,Xs)] + end. + + +%% +%% Expression evaluator for java +%% +%% Well, this is not an evaluator, it just +%% prints the hole operation, sorry. +%% +eval_java(G,N,Arg) when is_record(Arg, scoped_id) -> + {FSN, _, _, _} = + ic_symtab:get_full_scoped_name(G, N, Arg), + ic_util:to_dot(G,FSN); +eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_java(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_java(G,N,{Op,Arg1,Arg2}) -> + "(" ++ eval_java(G,N,Arg1) ++ + ic_forms:get_java_id(Op) ++ + eval_java(G,N,Arg2) ++ ")". + + + +%% +%% Expression evaluator for c +%% +%% Well, this is not an evaluator, it just +%% prints the hole operation, sorry. +%% +eval_c(G,N,Arg) when is_record(Arg, scoped_id) -> + {FSN, _, _, _} = + ic_symtab:get_full_scoped_name(G, N, Arg), + ic_util:to_undersc(FSN); +eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_c(_G,_N,Arg) when is_tuple(Arg) andalso element(1,Arg) == '' -> + element(3,Arg); +eval_c(G,N,{Op,Arg1,Arg2}) -> + "(" ++ eval_c(G,N,Arg1) ++ + atom_to_list(Op) ++ + eval_c(G,N,Arg2) ++ ")". + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- + + + + + + diff --git a/lib/ic/src/icenum.erl b/lib/ic/src/icenum.erl new file mode 100644 index 0000000..0af200e --- /dev/null +++ b/lib/ic/src/icenum.erl @@ -0,0 +1,205 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: icenum.erl +%% +%% +%%----------------------------------------------------------------- +%% +%% Code generation for enum's. +%%----------------------------------------------------------------- +-module(icenum). + +-import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]). + +-include("icforms.hrl"). +-include("ic.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([enum_gen/4]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +enum_gen(G, N, X, c) when is_record(X, enum) -> + emit_c_enum(G, N, X); +enum_gen(_G, _N, _X, _L) -> + ok. + + +emit_c_enum(G, N, X) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + EnumName = [ic_forms:get_id2(X) | N], + + case ic_pragma:is_local(G,EnumName) of + true -> + + Fd = ic_genobj:hrlfiled(G), + EnumNameStr = ic_util:to_undersc(EnumName), + ic_code:insert_typedef(G, EnumNameStr, {enum, EnumNameStr}), + {tk_enum,_,_,EList} = ic_forms:get_tk(X), + emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(EnumNameStr)]), + emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(EnumNameStr)]), + ic_codegen:mcomment_light(Fd, + [io_lib:format("Enum definition: ~s", + [EnumNameStr])], + c), + emit(Fd, "typedef CORBA_enum {", []), + emit_c_enum_values(G, N, Fd, EList), + emit(Fd, "} ~s ;\n\n", [EnumNameStr]), + create_c_enum_file(G, N, EnumNameStr, EList), + emit(Fd, "\n#endif\n\n"); + + false -> %% Do not generate included types att all. + ok + end; + + false -> + ok + end. + + +emit_c_enum_values(_G, N, Fd, [E]) -> + emit(Fd, "~s", [ic_util:to_undersc([E| N])]); +emit_c_enum_values(G, N, Fd, [E |Es]) -> + emit(Fd, "~s, ", [ic_util:to_undersc([E| N])]), + emit_c_enum_values(G, N, Fd, Es). + + +open_c_coding_file(G, Name) -> + SName = string:concat(ic_util:mk_oe_name(G, "code_"), Name), + FName = + ic_file:join(ic_options:get_opt(G, stubdir),ic_file:add_dot_c(SName)), + case file:open(FName, [write]) of + {ok, Fd} -> + {Fd, SName}; + Other -> + exit(Other) + end. + + +create_c_enum_file(G, N, Name, Elist) -> + + {Fd , SName} = open_c_coding_file(G, Name), + HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header + HrlFName = filename:basename(ic_genobj:include_file(G)), + ic_codegen:emit_stub_head(G, Fd, SName, c), + emit(Fd, "#include \"~s\"\n\n",[HrlFName]), + + %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Fd = ic_genobj:stubfiled(G), %% Write on stubfile + %% HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header + %% HrlFName = filename:basename(ic_genobj:include_file(G)), + %% emit(Fd, "#include \"~s\"\n\n",[HrlFName]), + %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + emit(Fd, "char* ~s[~p] = {\n", [ic_util:mk_oe_name(G, Name), + length(Elist)]), + emit_c_enum_array_values(Fd, Elist), + emit(Fd, "};\n\n",[]), + emit_sizecount(G, N, Fd, HFd, Name, Elist), + emit_encode(G, N, Fd, HFd, Name, Elist), + emit_decode(G, N, Fd, HFd, Name, Elist), + file:close(Fd). + +emit_c_enum_array_values(Fd, [E]) -> + emit(Fd, " ~p\n", [E]); +emit_c_enum_array_values(Fd, [E |Es]) -> + emit(Fd, " ~p,\n", [E]), + emit_c_enum_array_values(Fd, Es). + + +emit_sizecount(G, _N, Fd, HFd, Name, _Elist) -> + + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, int*, int*);\n", + [ic_util:mk_oe_name(G, "sizecalc_"), Name]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, int* oe_size_count_index, int* oe_size)\n" + "{\n", + [ic_util:mk_oe_name(G, "sizecalc_"), Name]), + emit(Fd, " int oe_error_code = 0;\n\n",[]), + + AlignName = lists:concat(["*oe_size + sizeof(",Name,")"]), + emit(Fd, " *oe_size = ~s;\n\n",[ic_util:mk_align(AlignName)]), + + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " return 0;\n\n",[]), + emit(Fd, "}\n\n",[]). + + +emit_encode(G, _N, Fd, HFd, Name, _Elist) -> + + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s);\n", + [ic_util:mk_oe_name(G, "encode_"), Name, Name]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s oe_rec) {\n", + [ic_util:mk_oe_name(G, "encode_"), Name, Name]), + emit(Fd, " int oe_error_code = 0;\n\n",[]), + + emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, ~s[oe_rec])) < 0) {\n", + [ic_util:mk_oe_name(G, Name)]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " return 0;\n\n",[]), + emit(Fd, "}\n\n",[]). + +emit_decode(G, _N, Fd, HFd, Name, Elist) -> + + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, int*, ~s *);\n", + [ic_util:mk_oe_name(G, "decode_"), Name, Name]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, int* oe_outindex, " + "~s *oe_out) {\n\n", + [ic_util:mk_oe_name(G, "decode_"), Name, Name]), + emit(Fd, " int oe_error_code = 0;\n",[]), + emit(Fd, " int oe_i;\n",[]), + emit(Fd, " char oe_atom[256];\n\n",[]), + + AlignName = lists:concat(["*oe_outindex + sizeof(",Name,")"]), + emit(Fd, " *oe_outindex = ~s;\n\n",[ic_util:mk_align(AlignName)]), + + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_atom)) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + + Len = length(Elist), + emit(Fd, " for(oe_i = 0; oe_i < ~p && strcmp(oe_atom, ~s[oe_i]); oe_i++);\n", + [Len, ic_util:mk_oe_name(G, Name)]), + emit(Fd, " *oe_out = oe_i;\n\n", []), + + emit(Fd, " if (oe_i == ~p) {\n",[Len]), + emit_c_enc_rpt(Fd, " ", "decode atom failure", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " return 0;\n",[]), + emit(Fd, "}\n\n",[]). + + + + + diff --git a/lib/ic/src/iceval.erl b/lib/ic/src/iceval.erl new file mode 100644 index 0000000..81093dc --- /dev/null +++ b/lib/ic/src/iceval.erl @@ -0,0 +1,555 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(iceval). + +-include("icforms.hrl"). + +-export([eval_const/5, eval_e/5]). + +-export([check_tk/3, get_val/1, mk_val/1]). + +-define(get_max(__X, __Y), if __X > __Y -> __X; true -> __Y end). +-define(get_min(__X, __Y), if __X > __Y -> __Y; true -> __X end). + +-define(BASE, 100000000000000000000000000000000). +-define(FIXED_MAX, 9999999999999999999999999999999). + +%% Called fr: ictype 99, 522, 533 +%% Fixed constants can be declared as: +%% (1) const fixed pi = 3.14D; or +%% (2) typedef fixed<3,2> f32; +%% const f32 pi = 3.14D; +%% Hence, if fixed is declared as (1) we must handle it especially. +eval_const(G, S, N, tk_fixed, Expr) -> + case catch eval_e(G, S, N, tk_fixed, Expr) of + T when element(1, T) == error -> 0; + V when is_record(V, fixed) -> + {ok, {tk_fixed, V#fixed.digits, V#fixed.scale}, V}; + V -> + ic_error:error(G, {bad_tk_match, Expr, tk_fixed, get_val(V)}) + end; +eval_const(G, S, N, TK, Expr) -> + case catch eval_e(G, S, N, TK, Expr) of + T when element(1, T) == error -> 0; + V -> + case check_tk(G, TK, V) of + true -> ok; + false -> + ic_error:error(G, {bad_tk_match, Expr, TK, get_val(V)}) + end, + get_val(V) + end. + + +check_op(G, S, N, Tk, Types, Op, E1, E2) -> + V1 = eval_e(G, S, N, Tk, E1), + V2 = eval_e(G, S, N, Tk, E2), + check_types(G, Op, E1, Types, V1), + check_types(G, Op, E2, Types, V2), + case check_comb(V1, V2) of + true -> + {V1, V2}; + false -> + Err = {bad_type_combination, E1, get_val(V1), get_val(V2)}, + ic_error:error(G, Err), + throw({error, Err}) + end. + +check_op(G, S, N, Tk, Types, Op, E1) -> + V1 = eval_e(G, S, N, Tk, E1), + check_types(G, Op, E1, Types, V1), + V1. + +%% Match the declared type TK against the factual value of an constant +%% +check_tk(_G, _Any, default) -> true; % Default case in union +check_tk(_G, positive_int, V) when is_integer(V) andalso V >= 0 -> true; +check_tk(_G, tk_long, V) when is_integer(V) -> true; +check_tk(_G, tk_longlong, V) when is_integer(V) -> true; %% LLON_G +check_tk(_G, tk_short, V) when is_integer(V) -> true; +check_tk(_G, tk_ushort, V) when is_integer(V) andalso V >= 0 -> true; +check_tk(_G, tk_ulong, V) when is_integer(V) andalso V >= 0 -> true; +check_tk(_G, tk_ulonglong, V) when is_integer(V) andalso V >= 0 -> true; %% ULLON_G +check_tk(_G, tk_float, V) when is_float(V) -> true; +check_tk(_G, tk_double, V) when is_float(V) -> true; +check_tk(_G, tk_boolean, V) -> is_bool(V); +check_tk(_G, tk_char, {char, _V}) -> true; +check_tk(_G, tk_wchar, {wchar, _V}) -> true; %% WCHAR +check_tk(_G, {tk_string, _Len}, {string, _V}) -> true; +check_tk(_G, {tk_wstring, _Len}, {wstring, _V}) -> true; %% WSTRING +check_tk(_G, {tk_fixed, Digits, Scale}, {fixed, Digits, Scale, _V}) -> true; +check_tk(_G, tk_octet, V) when is_integer(V) -> true; +%%check_tk(_G, tk_null, V) when integer(V) -> true; +%%check_tk(_G, tk_void, V) when integer(V) -> true; +%%check_tk(_G, tk_any, V) when integer(V) -> true; +%%check_tk(_G, {tk_objref, "", "Object"}, V) when integer(V) -> true. +check_tk(_G, {tk_enum, _, _, Body}, {enum_id, Id}) -> + until(fun(X) when X == Id -> true; + (_X) -> + false + end, Body); +check_tk(_G, _TK, _V) -> + false. + +get_val({string, X}) -> X; +get_val({wstring, X}) -> X; %% WCHAR +get_val({char, X}) -> X; +get_val({wchar, X}) -> X; %% WSTRING +get_val({enum_id, X}) -> X; +get_val(X) -> X. + +check_types(G, Op, Expr, TypeList, V) -> + case until(fun(int) when is_integer(V) -> true; + (float) when is_float(V) -> true; + (bool) when V==true -> true; + (bool) when V==false -> true; + (fixed) when is_record(V, fixed) -> true; + (_) -> false end, + TypeList) of + true -> true; + false -> + Err = {bad_type, Expr, Op, TypeList, V}, + ic_error:error(G, Err), + throw({error, Err}) + end. + +%%get_op(T) when tuple(T) -> element(1, T). + +%% Should be in lists +until(F, [H|T]) -> + case F(H) of + true -> true; + false -> until(F, T) + end; +until(_F, []) -> false. + +%% Section of all the boolean operators (because Erlang ops don't like +%% boolean values. +e_or(X, Y) when is_integer(X) andalso is_integer(Y) -> X bor Y; +e_or(true, _) -> true; +e_or(_, true) -> true; +e_or(_, _) -> false. + +e_and(X, Y) when is_integer(X) andalso is_integer(Y) -> X band Y; +e_and(true, true) -> true; +e_and(_, _) -> false. + +e_xor(X, Y) when is_integer(X) andalso is_integer(Y) -> X bxor Y; +e_xor(X, X) -> false; +e_xor(_, _) -> true. + +%% Handling infix operators (+,-,*,/) for fixed type. +%% Boundries determined as fixed +e_fixed_add(#fixed{digits = D1, scale = S1, value = V1}, + #fixed{digits = D2, scale = S2, value = V2}) -> + Scale = ?get_max(S1, S2), + Digits = ?get_max((D1-S1), (D2-S2)) + Scale +1, + %% We must normalize the values before adding. Why? + %% 4.23 and 5.2 are represented as 423 and 52. To be able to get the + %% correct result we must add 4230 and 5200 == 9430. + {PV1, PV2} = normalize(S1, V1, S2, V2), + check_fixed_overflow(#fixed{digits = Digits, + scale = Scale, + value = (PV1 + PV2)}). + +%% Boundries determined as fixed +e_fixed_sub(#fixed{digits = D1, scale = S1, value = V1}, + #fixed{digits = D2, scale = S2, value = V2}) -> + Scale = ?get_max(S1, S2), + Digits = ?get_max((D1-S1), (D2-S2)) + Scale +1, + {PV1, PV2} = normalize(S1, V1, S2, V2), + check_fixed_overflow(#fixed{digits = Digits, + scale = Scale, + value = (PV1 - PV2)}). + +%% Boundries determined as fixed +e_fixed_mul(#fixed{digits = D1, scale = S1, value = V1}, + #fixed{digits = D2, scale = S2, value = V2}) -> + check_fixed_overflow(#fixed{digits = (D1+D2), + scale = (S1+S2), + value = V1*V2}). + +%% Boundries determined as fixed<(d1-s1+s2) + s inf ,s inf> +e_fixed_div(#fixed{digits = D1, scale = S1, value = V1}, + #fixed{digits = _D2, scale = S2, value = V2}) -> + {PV1, PV2} = normalize(S1, V1, S2, V2), + DigitsMin = (D1-S1+S2), + R1 = (PV1 div PV2), + R2 = (R1*?BASE + (PV1 rem PV2) * (?BASE div PV2)), + {Result2, Sinf} = delete_zeros_value(R2, 0, R1), + check_fixed_overflow(#fixed{digits = DigitsMin + Sinf, scale = Sinf, + value = Result2}). + + +%% Checks combination of argument types, basically floats and ints are +%% interchangeable, and all types are allowed with themselves. No +%% other combinations are allowed +%% +check_comb(X, Y) when is_integer(X) andalso is_integer(Y) -> true; +check_comb(X, Y) when is_float(X) andalso is_integer(Y) -> true; +check_comb(X, Y) when is_integer(X) andalso is_float(Y) -> true; +check_comb(X, Y) when is_float(X) andalso is_float(Y) -> true; +check_comb({X, _}, {X, _}) -> true; % Strings and chars are tuples +check_comb({fixed, _, _, _}, {fixed, _, _, _}) -> true; +check_comb(X, Y) -> + case {is_bool(X), is_bool(Y)} of + {true, true} -> + true; + _ -> + false + end. + +is_bool(true) -> true; +is_bool(false) -> true; +is_bool(_) -> false. + + +%%%% (15) +eval_e(G, S, N, Tk, {'or', T1, T2}) -> + {E1, E2} = check_op(G, S, N, Tk, [int, bool], 'or', T1, T2), + e_or(E1, E2); + +%%%% (16) +eval_e(G, S, N, Tk, {'xor', T1, T2}) -> + {E1, E2} = check_op(G, S, N, Tk, [int, bool], 'xor', T1, T2), + e_xor(E1, E2); + +%%%% (17) +eval_e(G, S, N, Tk, {'and', T1, T2}) -> + {E1, E2} = check_op(G, S, N, Tk, [int, bool], 'and', T1, T2), + e_and(E1, E2); + +%%%% (18) +eval_e(G, S, N, Tk, {'rshift', T1, T2}) -> + {E1, E2} = check_op(G, S, N, Tk, [int], 'rshift', T1, T2), + E1 bsr E2; +eval_e(G, S, N, Tk, {'lshift', T1, T2}) -> + {E1, E2} = check_op(G, S, N, Tk, [int], 'lshift', T1, T2), + E1 bsl E2; + +%%%% (19) +eval_e(G, S, N, Tk, {'+', T1, T2}) -> + case check_op(G, S, N, Tk, [int, float, fixed], '+', T1, T2) of + {F1, F2} when is_record(F1,fixed) andalso is_record(F2,fixed) -> + e_fixed_add(F1, F2); + {E1, E2} -> + E1 + E2 + end; +eval_e(G, S, N, Tk, {'-', T1, T2}) -> + case check_op(G, S, N, Tk, [int, float, fixed], '-', T1, T2) of + {F1, F2} when is_record(F1,fixed) andalso is_record(F2,fixed) -> + e_fixed_sub(F1, F2); + {E1, E2} -> + E1 - E2 + end; + +%%%% (20) +eval_e(G, S, N, Tk, {'*', T1, T2}) -> + case check_op(G, S, N, Tk, [int, float, fixed], '*', T1, T2) of + {F1, F2} when is_record(F1,fixed) andalso is_record(F2,fixed) -> + e_fixed_mul(F1, F2); + {E1, E2} -> + E1 * E2 + end; +eval_e(G, S, N, Tk, {'/', T1, T2}) -> + case check_op(G, S, N, Tk, [int, float, fixed], '/', T1, T2) of + {F1, F2} when is_record(F1,fixed) andalso is_record(F2,fixed) -> + e_fixed_div(F1, F2); + {E1, E2} -> + E1 / E2 + end; +eval_e(G, S, N, Tk, {'%', T1, T2}) -> + {E1, E2} = check_op(G, S, N, Tk, [int], '%', T1, T2), + E1 rem E2; + +%%%% (21) +eval_e(G, S, N, Tk, {{'-', _Line}, T}) -> + case check_op(G, S, N, Tk, [int, float, fixed], '-', T) of + F when is_record(F,fixed) -> + F#fixed{value = -(F#fixed.value)}; + Number -> + -Number + end; +eval_e(G, S, N, Tk, {{'+', _Line}, T}) -> + check_op(G, S, N, Tk, [int, float, fixed], '+', T); +eval_e(G, S, N, Tk, {{'~', Line}, T}) -> + ic_error:error(G, {unsupported_op, {'~', Line}}), + eval_e(G, S, N, Tk, T); + + +%% Ints are repr. by an Erlang integer val, floats and doubles by +%% Erlang floats, chars and strings must be tuplerized for type +%% checking. These tuples are removed just before returning from top +%% function. +%% +eval_e(_G, _S, _N, tk_fixed, {'', _Line, X}) -> + create_fixed(X); +eval_e(G, _S, _N, {tk_fixed, Digits, Scale}, {'', Line, X}) + when Digits < 32, Digits >= Scale -> + case convert_fixed(X, [], Digits, Digits-Scale) of + {error, Format, Args} -> + ic_error:error(G, {bad_fixed, Format, Args, Line}); + FixedData -> + {fixed, Digits, Scale, FixedData} + end; +eval_e(_G, _S, _N, _Tk, {'', _Line, X}) -> list_to_integer(X); +eval_e(_G, _S, _N, {tk_string,_}, {'', _Line, X}) -> {string, X}; +eval_e(_G, _S, _N, {tk_wstring,_}, {'', _Line, X}) -> {wstring, X}; %% WSTRING +eval_e(_G, _S, _N, tk_char, {'', _Line, X}) -> {char, hd(X)}; +eval_e(_G, _S, _N, tk_wchar, {'', _Line, X}) -> {wchar, hd(X)}; %% WCHAR +eval_e(_G, _S, _N, _Tk, {'TRUE', _Line}) -> true; +eval_e(_G, _S, _N, _Tk, {'FALSE', _Line}) -> false; +eval_e(_G, _S, _N, _Tk, {'', _Line, X}) -> to_float(X); +%% Some possible error conditions +eval_e(_G, _S, _N, _Tk, {'', _Line, X}) -> {char, hd(X)}; %% ERROR? +%% +eval_e(G, S, N, _Tk, X) when element(1, X) == scoped_id -> + mk_val(ictype:scoped_lookup(G, S, N, X)); +eval_e(_G, _S, _N, _Tk, {default, _}) -> default; % Default case in union +eval_e(G, _S, _N, Tk, Val) -> + ic_error:error(G, {plain_error_string, Val, + io_lib:format("value and declared type ~p differ", [Tk])}). + +%% A fixed type can be 123.45 or 123 but we represent it as integers (i.e. 12345 or 123). +convert_fixed([], Acc, 0, _) -> + list_to_integer(lists:reverse(Acc)); +convert_fixed([], _Acc, _, _) -> + {error, "Fixed type do not match the digits field", []}; +convert_fixed([$.|Rest], Acc, Digits, 0) -> + convert_fixed(Rest, Acc, Digits, -1); +convert_fixed([$.|_Rest], _Acc, _, _) -> + {error, "Fixed decimal point placed incorrectly", []}; +convert_fixed([X|Rest], Acc, Digits, Position) -> + convert_fixed(Rest, [X|Acc], Digits-1, Position-1). + + +create_fixed([$0|Rest]) -> + %% Leading zeros shall be ignored. + create_fixed(Rest); +create_fixed(Fixed) -> + create_fixed(Fixed, [], 0, 0, false). + +create_fixed([], Acc, Total, Frac, true) -> + {Fixed, N} = remove_trailing_zeros(Acc, 0), + Digits = Total-N, + Scale = Frac-N, + #fixed{digits = Digits, scale = Scale, value = list_to_integer(Fixed)}; +create_fixed([], Acc, Total, _Frac, false) -> + %% A '.' never found. Hence, must be 2000D + #fixed{digits = Total, scale = 0, value = list_to_integer(lists:reverse(Acc))}; +create_fixed([$.|Rest], Acc, Total, _, _) -> + create_fixed(Rest, Acc, Total, 0, true); +create_fixed([X|Rest], Acc, Total, Frac, FoundDot) -> + create_fixed(Rest, [X|Acc], Total+1, Frac+1, FoundDot). + +remove_trailing_zeros([$0|Rest], N) -> + remove_trailing_zeros(Rest, N+1); +remove_trailing_zeros(Fixed, N) -> + {lists:reverse(Fixed), N}. + +%% Make the newly looked up value a value that can be type checked. +mk_val({_, _, {tk_string, _}, V}) -> {string, V}; +mk_val({_, _, {tk_wstring, _}, V}) -> {wstring, V}; %% WSTRING +mk_val({_, _, tk_char, V}) -> {char, V}; +mk_val({_, _, tk_wchar, V}) -> {wchar, V}; %% WCHAR +mk_val({_, _, enum_val, V}) -> + {enum_id, ic_forms:get_id2(V)}; +mk_val(X) when element(1, X) == error -> X; +mk_val({_, _, _TK, V}) -> + V; +mk_val(V) -> V. + + + +%% Floating point numbers +%% +%% Conversion to Erlang floating points is neccessary because +%% list_to_float BIF differs from IDL floats. "1e2" ".4e2" is +%% allowed in IDL and must be translated to "1.0e2" and "0.4e2" + +to_float(X) -> + list_to_float(erlangify(X)). + +erlangify([$. | R]) -> + [$0, $. | R]; +erlangify(R) -> + look_for_dot(R). + +look_for_dot([$. | R]) -> [$. | dot_pending(R)]; +look_for_dot([$e | R]) -> [$., $0, $e | R]; +look_for_dot([$E | R]) -> [$., $0, $E | R]; +look_for_dot([X | R]) -> [X | look_for_dot(R)]. + +dot_pending([$e | R]) -> [$0, $e | R]; +dot_pending([$E | R]) -> [$0, $E | R]; +dot_pending([]) -> [$0]; +dot_pending(R) -> R. + + +%%------------------------------------------------------------------ +%%--------------- Fixed Datatype Helper Functions ------------------ +%%------------------------------------------------------------------ +%% Pretty?! No, but since we now the upper-limit this is the fastest way +%% to calculate 10^x +power(0) -> 1; +power(1) -> 10; +power(2) -> 100; +power(3) -> 1000; +power(4) -> 10000; +power(5) -> 100000; +power(6) -> 1000000; +power(7) -> 10000000; +power(8) -> 100000000; +power(9) -> 1000000000; +power(10) -> 10000000000; +power(11) -> 100000000000; +power(12) -> 1000000000000; +power(13) -> 10000000000000; +power(14) -> 100000000000000; +power(15) -> 1000000000000000; +power(16) -> 10000000000000000; +power(17) -> 100000000000000000; +power(18) -> 1000000000000000000; +power(19) -> 10000000000000000000; +power(20) -> 100000000000000000000; +power(21) -> 1000000000000000000000; +power(22) -> 10000000000000000000000; +power(23) -> 100000000000000000000000; +power(24) -> 1000000000000000000000000; +power(25) -> 10000000000000000000000000; +power(26) -> 100000000000000000000000000; +power(27) -> 1000000000000000000000000000; +power(28) -> 10000000000000000000000000000; +power(29) -> 100000000000000000000000000000; +power(30) -> 1000000000000000000000000000000; +power(31) -> 10000000000000000000000000000000; +power(_) -> 10000000000000000000000000000000. + + + +%% If the result of an operation (+, -, * or /) causes overflow we use this +%% operation. However, since these calculations are performed during compiletime, +%% shouldn't the IDL-specification be changed to not cause overflow?! But, since +%% the OMG standard allows this we must support it. +check_fixed_overflow(#fixed{digits = Digits, scale = Scale, value = Value}) -> + case count_digits(abs(Value)) of + overflow -> + {N, NewVal} = cut_overflow(0, Value), +% NewDigits = Digits - N, + if + N > Scale -> + #fixed{digits = 31, scale = 0, value = NewVal}; + true -> + NewScale = Scale - N, + {NewVal2, Removed} = delete_zeros(NewVal, NewScale), + #fixed{digits = 31, scale = NewScale-Removed, value = NewVal2} + end; + Count when Count > Digits -> + Diff = Count-Digits, + if + Diff > Scale -> + #fixed{digits = Digits, scale = 0, + value = (Value div power(Diff))}; + true -> + NewScale = Scale-Diff, + {NewVal, Removed} = delete_zeros((Value div power(Diff)), NewScale), + #fixed{digits = Digits-Removed, + scale = NewScale-Removed, + value = NewVal} + end; + Count -> + {NewVal, Removed} = delete_zeros(Value, Scale), + #fixed{digits = Count-Removed, scale = Scale-Removed, value = NewVal} + end. + +%% This function see to that the values are of the same baase. +normalize(S, V1, S, V2) -> + {V1, V2}; +normalize(S1, V1, S2, V2) when S1 > S2 -> + {V1, V2*power(S1-S2)}; +normalize(S1, V1, S2, V2) -> + {V1*power(S2-S1), V2}. + +%% If we have access to the integer part of the fixed type we use this +%% operation to remove all trailing zeros. If we know the scale, length of +%% fraction part, we can use delete_zeros as well. But, after a division +%% it's hard to know the scale and we don't need to calcluate the integer part. +delete_zeros_value(0, N, _) -> + {0, 32-N}; +delete_zeros_value(X, N, M) when X > M, (X rem 10) == 0 -> + delete_zeros_value((X div 10), N+1, M); +delete_zeros_value(X, N, _) -> + {X, 32-N}. + +%% If we know the exact scale of a fixed type we can use this operation to +%% remove all trailing zeros. +delete_zeros(0, _) -> + {0,0}; +delete_zeros(X, Max) -> + delete_zeros(X, 0, Max). +delete_zeros(X, Max, Max) -> + {X, Max}; +delete_zeros(X, N, Max) when (X rem 10) == 0 -> + delete_zeros((X div 10), N+1, Max); +delete_zeros(X, N, _) -> + {X, N}. + +cut_overflow(N, X) when X > ?FIXED_MAX -> + cut_overflow(N+1, (X div 10)); +cut_overflow(N, X) -> + {N, X}. + +%% A fast way to check the size of a fixed data type. +count_digits(X) when X > ?FIXED_MAX -> overflow; +count_digits(X) when X >= 1000000000000000000000000000000 -> 31; +count_digits(X) when X >= 100000000000000000000000000000 -> 30; +count_digits(X) when X >= 10000000000000000000000000000 -> 29; +count_digits(X) when X >= 1000000000000000000000000000 -> 28; +count_digits(X) when X >= 100000000000000000000000000 -> 27; +count_digits(X) when X >= 10000000000000000000000000 -> 26; +count_digits(X) when X >= 1000000000000000000000000 -> 25; +count_digits(X) when X >= 100000000000000000000000 -> 24; +count_digits(X) when X >= 10000000000000000000000 -> 23; +count_digits(X) when X >= 1000000000000000000000 -> 22; +count_digits(X) when X >= 100000000000000000000 -> 21; +count_digits(X) when X >= 10000000000000000000 -> 20; +count_digits(X) when X >= 1000000000000000000 -> 19; +count_digits(X) when X >= 100000000000000000 -> 18; +count_digits(X) when X >= 10000000000000000 -> 17; +count_digits(X) when X >= 1000000000000000 -> 16; +count_digits(X) when X >= 100000000000000 -> 15; +count_digits(X) when X >= 10000000000000 -> 14; +count_digits(X) when X >= 1000000000000 -> 13; +count_digits(X) when X >= 100000000000 -> 12; +count_digits(X) when X >= 10000000000 -> 11; +count_digits(X) when X >= 1000000000 -> 10; +count_digits(X) when X >= 100000000 -> 9; +count_digits(X) when X >= 10000000 -> 8; +count_digits(X) when X >= 1000000 -> 7; +count_digits(X) when X >= 100000 -> 6; +count_digits(X) when X >= 10000 -> 5; +count_digits(X) when X >= 1000 -> 4; +count_digits(X) when X >= 100 -> 3; +count_digits(X) when X >= 10 -> 2; +count_digits(_X) -> 1. + +%%------------------------------------------------------------------ +%%--------------- END Fixed Datatype Helper Functions -------------- +%%------------------------------------------------------------------ diff --git a/lib/ic/src/icforms.hrl b/lib/ic/src/icforms.hrl new file mode 100644 index 0000000..d1869e6 --- /dev/null +++ b/lib/ic/src/icforms.hrl @@ -0,0 +1,68 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%% +%% Module documentation: +%% --------------------- +%% +%% Header file for the Erlang IDL compiler. Contains all records +%% used in the parse tree +%% +%% +%%------------------------------------------------------------ + + + +%%------------------------------------------------------------ + +-record(module, {id, body}). +-record(interface, {id, inherit, body, inherit_body, tk}). +-record(forward, {id, tk}). +-record(const, {type, id, val, tk}). +-record(type_dcl, {type, tk}). +-record(typedef, {type, id, tk}). +-record(struct, {id, body, tk}). +-record(member, {type, id}). +-record(union, {id, type, body, tk}). +-record(case_dcl, {label, id, type}). +-record(enum, {id, body, tk}). +-record(enumerator, {id}). +-record(sequence, {type, length=0}). +-record(string, {length=0}). +-record(wstring, {length=0}). %% WSTRING +-record(array, {id, size}). +-record(attr, {readonly, type, id, tk}). +-record(except, {id, body, tk}). +-record(op, {oneway, type, id, params, raises, ctx, tk}). +-record(param, {inout, type, id, tk}). +-record(fixed, {digits, scale, value}). + +%% NON-STANDARD +-record(preproc, {cat, id, aux}). +-record(pragma, {type, to, apply}). + + + + + + + + + + diff --git a/lib/ic/src/icparse.yrl b/lib/ic/src/icparse.yrl new file mode 100644 index 0000000..25b0f45 --- /dev/null +++ b/lib/ic/src/icparse.yrl @@ -0,0 +1,864 @@ +%% +%% 1997-2007 +%% Ericsson AB, All Rights Reserved +%% +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson AB. +%% +%% +%%------------------------------------------------------------ +%% Yecc spec for IDL +%% +%% +%% +%% Implementation Detail: +%% OorM_ means OneORMany and is used instead of +%% the "+" BNF notation +%% ZorM_ means ZeroORMany and is used instead of +%% the "*" BNF notation +%% +%% All the reverse/1 calls are because yecc+lists naturally leads +%% to reversed lists, which then have to be reversed. Maybe fix +%% this? +%% +%% Implementation history +%% +%% The IDL language supported is not the complete IDL. We skipped +%% the multiple declarator syntax allowed (i.e. typedef long T1, +%% T2). This also applies to attributes members in structs, +%% unions and exceptions, and to case labels in unions. The cases +%% where IDL has been altered is marked with comments containing +%% NIY. +%% +%% Above is chaging. Whenever we change a clause, we put (FIXED) in +%% its comment. +%% +%%------------------------------------------------------------ + + + + + +Nonterminals + '' + '' + '' + 'OorM_' + '' + '' + '' + '' + '' + '' + '' + 'ZorM_' + 'Opt_' + '' + '' + '' + '' + '' + '' + 'ZorM_' + 'Opt_' + '' + '' + '' + '' + '' + 'OorM_' + '' + '' + '' + '' + '' + '' + '' + '' + 'ZorM_' + '' + '' + '' + 'OorM_' + '' + '' + '' + '' + 'OorM_' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + 'Opt_' + '' + '' + 'ZorM_' + '' + '' + '' + 'ZorM_' + 'ZorM_' + '' + '' + '' + '' + 'Opt_readonly' + '' + '' + '' + 'OorM_' + '' + '' + '' + '' + '' + '' + 'Opt_' + 'ZorM_' + '' + '' + '' + '' + 'ZorM_' + '' + 'OE_preproc' % NON standard + 'OE_pragma' % NON standard + 'Ugly_pragmas' % NON standard + 'ZorM_' + '' + '' + . + + +Terminals + '#' + 'in' + '[' + 'interface' + '(' + 'case' + 'union' + 'struct' + '' + '' + ')' + ']' + 'any' + 'long' + 'float' + 'out' + '*' + '^' + 'enum' + 'double' + '+' + 'context' + 'oneway' + 'sequence' + ',' + 'FALSE' + '' + '{' + 'readonly' + ':' + '-' + 'void' + ';' + 'char' + 'wchar' %% WCHAR + '|' + 'inout' + '}' + 'attribute' + '<' + 'octet' + '/' + 'TRUE' + '~' + '=' + '>' + 'switch' + 'unsigned' + 'typedef' + '>>' + 'const' + '' + '' + 'raises' + 'string' + 'wstring' + 'fixed' + 'default' + 'short' + '%' + '<<' + 'module' + 'exception' + 'boolean' + '' + '' + '' + '&' + '::' + 'Object' + . + + +Rootsymbol ''. + + +%%------------------------------------------------------------ +%% Clauses +%% + +%% Handling of pragmas. +%% Pragma prefix, id and version are not standard. + +%% pragma prefix, or codeopt +OE_pragma -> '#' '' '' + '' '' '#' + : #pragma{type='$4', to=followed, apply='$5'} . + +%% pragma id +OE_pragma -> '#' '' '' + '' '' '' '#' + : #pragma{type='$4', to='$5', apply='$6'} . + +%% pragma version +OE_pragma -> '#' '' '' + '' '' '' '#' + : #pragma{type='$4', to='$5', apply=ic_options:float_to_version('$6')} . + + + + + + + +%% Ugly pragmas +Ugly_pragmas -> '$empty' : []. +Ugly_pragmas -> 'Ugly_pragmas' 'OE_pragma' : ['$2'|'$1']. + + + +%% (0) Handling of preprocessor stuff. + +OE_preproc -> '#' '#' . + +OE_preproc -> '#' '' '' + 'ZorM_' '#' + : case '$4' of + [] -> + case '$2' of + {_,_,"1"} -> + #preproc{cat=line_nr, id='$3', aux='$4'}; + _ -> + [] + end; + _ -> + #preproc{cat=line_nr, id='$3', aux='$4'} + end. + +%% (0b) Non-standard +'ZorM_' -> '$empty' : [] . +'ZorM_' -> '' 'ZorM_' + : ['$1' | '$2'] . + +%% (1) +'' -> 'OorM_' : reverse('$1') . + + +%% Added clause +'OorM_' -> '' : ['$1'] . +'OorM_' -> 'OorM_' '' +: ['$2' | '$1'] . + + +%% (2) +'' -> '' ';' : '$1' . +'' -> '' ';' : '$1' . +'' -> '' ';' : '$1' . +'' -> '' ';' : '$1' . +'' -> '' ';' : '$1' . +'' -> 'OE_preproc' : '$1' . +'' -> 'OE_pragma' : '$1' . + + +%% (3) +'' -> 'module' '' '{' 'OorM_' '}' +: #module{ id='$2', body=reverse('$4')}. + + +%% (4) +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (5) +'' -> '' '{' '' '}' + : #interface{id=element(1, '$1'), inherit=element(2, '$1'), + body=lists:reverse('$3')} . + + +%% (6) +'' -> 'interface' '' +: #forward{id='$2'} . + + +%% (7) +'' -> 'interface' '' 'Opt_' +: {'$2', '$3'} . + + +%% (8) +'' -> 'ZorM_' : '$1' . + + +%% Added clause +'ZorM_' -> '$empty' : [] . +'ZorM_' -> 'ZorM_' '' + %% Complicated because might be a list (of type defs for instance) + : if is_list('$2') -> '$2' ++ '$1'; + true -> ['$2' | '$1'] + end . + + +%% (9) +'' -> '' ';' : '$1' . +'' -> '' ';' : '$1' . +'' -> '' ';' : '$1' . +'' -> '' ';' : '$1' . +'' -> '' ';' : '$1' . +'' -> 'OE_preproc' : '$1' . +'' -> 'OE_pragma' : '$1' . + +%% Added clause +'Opt_' -> '$empty' : []. +'Opt_' -> '' : '$1'. + +%% (10) +'' -> ':' '' 'ZorM_' + : ['$2' | reverse('$3')] . + + +%% Added clause +'ZorM_' -> '$empty' : [] . +'ZorM_' -> 'ZorM_' ',' '' + : ['$3' | '$1'] . + + +%% (11) +'' -> '' : ic_symtab:scoped_id_new('$1') . +'' -> '::' '' : ic_symtab:scoped_id_new_global('$2') . +'' -> '' '::' '' + : ic_symtab:scoped_id_add('$1', '$3') . + + +%% (12) +'' -> 'const' '' '' '=' '' + : #const{type='$2', id='$3', val='$5'} . + + +%% (13) +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (14) +'' -> '' : '$1' . + + +%% (15) +'' -> '' : '$1' . +'' -> '' '|' '' : {'or', '$1', '$3'} . + + +%% (16) +'' -> '' : '$1' . +'' -> '' '^' '' : {'xor', '$1', '$3'} . + + +%% (17) +'' -> '' : '$1' . +'' -> '' '&' '' : {'and', '$1', '$3'} . + + +%% (18) +'' -> '' : '$1' . +'' -> '' '>>' '' : {'rshift', '$1', '$3'} . +'' -> '' '<<' '' : {'lshift', '$1', '$3'} . + + +%% (19) +'' -> '' : '$1' . +'' -> '' '+' '' : {'+', '$1', '$3'} . +'' -> '' '-' '' : {'-', '$1', '$3'} . + + +%% (20) +'' -> '' : '$1' . +'' -> '' '*' '' : {'*', '$1', '$3'} . +'' -> '' '/' '' : {'/', '$1', '$3'} . +'' -> '' '%' '' : {'%', '$1', '$3'} . + + +%% (21) +'' -> '' '' : {'$1', '$2'} . +'' -> '' : '$1' . + + +%% (22) +'' -> '-' : '$1' . +'' -> '+' : '$1' . +'' -> '~' : '$1' . + + +%% (23) +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '(' '' ')' : '$2' . + + +%% (24) +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (25) +'' -> 'TRUE' : '$1' . +'' -> 'FALSE' : '$1' . + + +%% (26) +'' -> '' : '$1' . + + +%% (27) +'' -> 'typedef' '' : '$2' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . + +%% (28) NIY multiple declarators (FIXED) +'' -> '' '' + : #typedef{type='$1', id='$2'} . %%%ic:unfold(#typedef{type='$1', id='$2'}) . +%%'' -> '' '' +%% : #typedef{type='$1', id='$2'} . + +%% (29) +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (30) +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (31) +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> 'Object' : '$1' . %% NON Standard, isn't a base type + + +%% (32) +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (33) +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (34) +'' -> '' 'ZorM_' +: ['$1' | reverse('$2')] . + +%% Added clause +'ZorM_' -> '$empty' : [] . +'ZorM_' -> 'ZorM_' ',' '' +: ['$3' | '$1'] . + + +%% (35) +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (36) +'' -> '' : '$1' . + + +%% (37) +'' -> '' : '$1' . + + +%% (38) +'' -> 'float' : '$1' . +'' -> 'double' : '$1' . + + +%% (39) +'' -> '' : '$1' . +'' -> '' : {'unsigned', '$1'} . + + +%% (40) +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (41) +'' -> 'long' : '$1' . +'' -> 'long' 'long': {'long long', element(2,'$2')} . + + +%% (42) +'' -> 'short' : '$1' . + + +%% (43) +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (44) +'' -> 'unsigned' 'long' : '$2' . +'' -> 'unsigned' 'long' 'long' : {'long long', element(2,'$2')} . %% ULLONG + + +%% (45) +'' -> 'unsigned' 'short' : '$2' . + + +%% (46) +'' -> 'char' : '$1' . +'' -> 'wchar' : '$1' . %% WCHAR + + +%% (47) +'' -> 'boolean' : '$1' . + + +%% (48) +'' -> 'octet' : '$1' . + + +%% (49) +'' -> 'any' : '$1' . + +%% +'' -> 'fixed' : '$1'. + +%% (50) NIY: unfolding of struct decls (FIXED) +%%'' -> 'struct' '' '{' '' '}' +%% : #struct{id='$2', body=ic:unfold('$4')} . +'' -> 'struct' '' '{' '' '}' + : #struct{id='$2', body='$4'} . + + +%% (51) +'' -> 'OorM_' : reverse('$1') . + + +%% Added clause +%%'OorM_' -> '' : ['$1'] . +%%'OorM_' -> 'OorM_' '' +%% : ['$2' | '$1'] . + +'OorM_' -> '' : '$1' . +'OorM_' -> 'OorM_' '' + : '$2' ++ '$1' . + + + +%% (52) NIY: member multiple declarators (FIXED) +%%'' -> '' '' ';' +%% : #member{type='$1', id='$2'} . + +'' -> 'Ugly_pragmas' '' '' 'Ugly_pragmas' ';' 'Ugly_pragmas' + : '$1' ++ '$4' ++ '$6' ++ [#member{type='$2', id='$3'}] . + + +%% (53) NIY: unfolding of union cases (FIXED) +%%'' -> 'union' '' 'switch' +%% '(' '' ')' '{' '' '}' +%% : #union{id='$2', type='$5', body=ic:unfold('$8')} . +'' -> 'union' '' 'switch' + '(' '' ')' '{' '' '}' + : #union{id='$2', type='$5', body='$8'} . + + +%% (54) +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (55) +'' -> 'OorM_' : reverse(lists:flatten('$1')) . + +%%'' -> 'OorM_' : '$1' . + + +%% Added clause +'OorM_' -> '' : ['$1'] . +'OorM_' -> 'OorM_' '' : ['$2' | '$1'] . + + +%% (56) NIY thing: multiple case labels (FIXED) +%%'' -> 'OorM_' '' ';' +%% : '$2'#case_dcl{label=reverse('$1')} . + +'' -> + 'Ugly_pragmas' 'OorM_' + 'Ugly_pragmas' '' + 'Ugly_pragmas' ';' 'Ugly_pragmas' + : '$1' ++ '$3' ++ '$5' ++ '$7' ++ [ '$4'#case_dcl{label=reverse('$2')} ] . + + +%% Added clause +%%'OorM_' -> '' : ['$1'] . +%%'OorM_' -> 'OorM_' '' : ['$2' | '$1'] . + +'OorM_' -> 'Ugly_pragmas' '' 'Ugly_pragmas' + : '$1' ++ ['$2'] ++ '$3' . +'OorM_' -> 'OorM_' 'Ugly_pragmas' '' 'Ugly_pragmas' + : '$2' ++ ['$3'|'$1'] ++ '$4'. + + +%% (57) +'' -> 'case' '' ':' : '$2' . +'' -> 'default' ':' : '$1' . + + +%% (58) +'' -> '' '' +: #case_dcl{type='$1', id='$2'} . + + +%% (59) +%%'' -> 'enum' '' +%%'{' '' 'ZorM_' '}' +%%: #enum{id='$2', body=['$4' | reverse('$5')]} . + +'' -> 'enum' '' +'{' 'Ugly_pragmas' '' 'Ugly_pragmas' 'ZorM_' 'Ugly_pragmas' '}' +: #enum{id='$2', body='$4'++'$6'++'$8'++['$5' | reverse('$7')]} . + + + +%% Added clause +%%'ZorM_' -> '$empty' : [] . +%%'ZorM_' -> 'ZorM_' ',' '' : ['$3' | '$1'] . + +'ZorM_' -> '$empty' : [] . +'ZorM_' -> 'ZorM_' 'Ugly_pragmas' ',' 'Ugly_pragmas' '' + : '$2'++'$4'++['$5' | '$1'] . + +%% (60) +'' -> '' : #enumerator{id='$1'} . + + +%% (61) +'' -> 'sequence' '<' '' ',' + '' '>' + : #sequence{type='$3', length='$5'} . +'' -> 'sequence' '<' '' '>' + : #sequence{type='$3'} . + + +%% (62) +'' -> 'string' '<' '' '>' + : #string{length='$3'} . +'' -> 'string' : #string{} . + +'' -> 'wstring' '<' '' '>' %% WSTRING + : #wstring{length='$3'} . +'' -> 'wstring' : #wstring{} . %% WSTRING + + +%% (63) +'' -> '' 'OorM_' + : #array{id='$1', size=reverse('$2')} . + + +%% Added clause +'OorM_' -> '' : ['$1'] . +'OorM_' -> 'OorM_' '' + : ['$2' | '$1'] . + + +%% (64) +'' -> '[' '' ']' : '$2' . + + +%% (65) NIY: multiple attribute declarators (FIXED) +'' -> 'Opt_readonly' 'attribute' '' + '' 'ZorM_' + : #attr{readonly='$1', type='$3', id=['$4' | reverse('$5')]} . +%% : ic:unfold(#attr{readonly='$1', type='$3', id=['$4' | reverse('$5')]}) . +%%'' -> 'Opt_readonly' 'attribute' '' +%% '' + + +%% (66) NIY: unfolding of exception bodies (FIXED) +%%'' -> 'exception' '' '{' 'ZorM_' '}' +%% : #except{id='$2', body=ic:unfold('$4')} . +'' -> 'exception' '' '{' 'ZorM_' '}' + : #except{id='$2', body=reverse('$4')} . + +%% (67) +'' -> 'Opt_' '' '' '' 'Opt_' 'Opt_' + : #op{oneway='$1', type='$2', id='$3', params='$4', raises='$5', ctx='$6'} . + +%% Added clause +'Opt_' -> '$empty' : nil. +'Opt_' -> '' : '$1'. + +%% (68) +'' -> 'oneway' : '$1' . + + +%% (69) +'' -> '' : '$1' . +'' -> 'void' : '$1' . + + +%% (70) Rewritten +%'' -> '(' '' 'ZorM_' ')' +% : ['$2' | reverse('$3')] . +%'' -> '(' ')' : [] . + +'' -> '(' 'Ugly_pragmas' '' 'ZorM_' ')' + : '$2' ++ ['$3' | reverse('$4')] . +'' -> '(' 'Ugly_pragmas' ')' : '$2' . + + +%% Added clause +%'ZorM_' -> '$empty' : [] . +%'ZorM_' -> 'ZorM_' ',' '' : ['$3' | '$1'] . + + +'ZorM_' -> 'Ugly_pragmas' : '$1' . +'ZorM_' -> 'ZorM_' 'Ugly_pragmas' ',' 'Ugly_pragmas' '' 'Ugly_pragmas' + : '$2' ++ '$4' ++ '$6' ++ ['$5' | '$1'] . + + + + +%% (71) +'' -> '' '' '' + : #param{inout='$1', type='$2', id='$3'} . + + +%% (72) +'' -> 'in' : '$1' . +'' -> 'out' : '$1' . +'' -> 'inout' : '$1' . + + +%% Added clause +'Opt_' -> '$empty' : [] . +'Opt_' -> '' : '$1' . + +%% (73) +'' -> 'raises' '(' '' 'ZorM_' ')' + : ['$3'| reverse('$4')] . + + +%% Added clause +'Opt_' -> '$empty' : [] . +'Opt_' -> '' : '$1'. + +%% (74) +'' -> 'context' '(' '' 'ZorM_'')' + : ['$3' | reverse('$4')] . + + + +%% (75) +'' -> '' : '$1' . +'' -> '' : '$1' . +'' -> '' : '$1' . + + +%% (96) +'' -> 'fixed' '<' '' ',' '' '>' + : #fixed{digits='$3',scale='$5'} . + + +%% Added clause +'ZorM_' -> '$empty' : [] . +'ZorM_' -> 'ZorM_' ',' '' + : ['$3' | '$1'] . + +%% Added clause +'ZorM_' -> '$empty' : [] . +'ZorM_' -> 'ZorM_' ',' +'' : ['$3' | '$1'] . + +%% Added clause +%%'ZorM_' -> '$empty' : [] . +%%'ZorM_' -> 'ZorM_' '' : ['$2' | '$1'] . + +'ZorM_' -> 'Ugly_pragmas' : '$1' . +'ZorM_' -> 'ZorM_' '' : '$2' ++ '$1' . + + +%% Added clause +'Opt_readonly' -> '$empty' : nil. +'Opt_readonly' -> 'readonly' : '$1'. + + + +Erlang code. +%%----------------------------------------------------------- + + + diff --git a/lib/ic/src/icpreproc.erl b/lib/ic/src/icpreproc.erl new file mode 100644 index 0000000..0ed7813 --- /dev/null +++ b/lib/ic/src/icpreproc.erl @@ -0,0 +1,111 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(icpreproc). + + + +-export([preproc/2]). + + +-import(lists, [filter/2]). + + +%%---------------------------------------------------------------------- +%%---------------------------------------------------------------------- + + +preproc(G, File) -> + Cmd = ic_options:get_opt(G, preproc_cmd), + Flags = ic_options:get_opt(G, preproc_flags), + + + case Cmd of + "erl" -> + case ic_pp:run(File,Flags) of + {ok, [$#, $ , $1 | Rest], []} -> + [$#, $ , $1 | Rest]; + {ok, [$#, $ , $1 | Rest], Warning} -> + print_warning(G,Warning), + [$#, $ , $1 | Rest]; + {error,Error} -> + print_error(G,Error) + end; + + _ -> + Line = Cmd++" "++Flags++" "++File, + % FIXME: Check status code of command instead of this test + case os:cmd(Line) of + [$#, $ , C | Rest] when is_integer(C), C > $0, C =< $9 -> + [$#, $ , C | Rest]; + X -> + ic_error:fatal_error(G, {preproc, filter(X)}) + end + end. + + +filter(X) -> + X2 = divide_nl(X, []), + filter_x_switch(X2). + + +divide_nl([10 | Xs], Out) -> + [lists:reverse(Out) | divide_nl(Xs, [])]; +divide_nl([X | Xs], Out) -> divide_nl(Xs, [X|Out]); +divide_nl([], Out) -> lists:reverse(Out). + + +filter_x_switch(L) -> + filter(fun([$g,$c,$c,$:,$ ,$W,$a,$r,$n,$i,$n,$g,$:,$ ,$`,$-,$x,$ | _]) -> + false; + (_) -> true end, L). + + +print_error(_G,[]) -> + ok; +print_error(G,[{File,Line,Text}]) -> + ErrorText = File++":"++integer_to_list(Line)++": "++Text, + ic_error:fatal_error(G, {ic_pp_error, ErrorText}), + ok; +print_error(G,[{File,Line,Text}|T]) -> + ErrorText = File++":"++integer_to_list(Line)++": "++Text, + ic_error:error(G, {ic_pp_error, ErrorText}), + print_error(G,T); +print_error(G,[H]) -> + ErrorText = H++"\n", + ic_error:fatal_error(G, {ic_pp_error, ErrorText}), + ok; +print_error(G,[H|T]) -> + ErrorText = H++"\n", + ic_error:error(G, {ic_pp_error, ErrorText}), + print_error(G,T). + + +print_warning(_G,[]) -> + ok; +print_warning(G,[{File,Line,Text}|T]) -> + WarText = File++":"++integer_to_list(Line)++": "++Text, + ic_error:warn(G, {ic_pp_warning, WarText}), + print_warning(G,T); +print_warning(G,[H|T]) -> + WarText = H++"\n", + ic_error:warn(G, {ic_pp_warning, WarText}), + print_warning(G,T). + + diff --git a/lib/ic/src/icscan.erl b/lib/ic/src/icscan.erl new file mode 100644 index 0000000..0960ba5 --- /dev/null +++ b/lib/ic/src/icscan.erl @@ -0,0 +1,452 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(icscan). + + +-export([scan/2]). + +-include("ic.hrl"). + + +%%---------------------------------------------------------------------- +%%---------------------------------------------------------------------- + +-import(lists, [reverse/1]). + + +scan(G, File) -> + PL = call_preproc(G, File), + call_scan(G, PL). + +call_preproc(G, File) -> + case ic_options:get_opt(G, use_preproc) of + true -> + icpreproc:preproc(G, File); + false -> + case catch file:read_file(File) of + {ok, Bin} -> + binary_to_list(Bin); + Other -> + exit(Other) + end + end. + +call_scan(G, PL) -> + BE = ic_options:get_opt(G, be), + RSL = scan(G, BE, PL, 1, []), + lists:reverse(RSL). + + +%% Guard macros used at top scan functions only +-define(is_number(X), X >= $0 , X =< $9). +-define(is_upper(X), X >= $A , X =< $Z). +-define(is_lower(X), X >= $a, X =< $z). +-define(is_hex_uc(X), X >= $A , X =< $F). +-define(is_hex_lc(X), X >= $a , X =< $f). +-define(is_octal(X), X >=$0, X =< $7). + +%% Handle: +%% const wchar aWChar = L'X'; +scan(G, BE, [$L, $'|Str], Line, Out) -> + scan_const(G, BE, wchar, Str, [], Line, Out); +scan(G, BE, [$L, $"|Str], Line, Out) -> + scan_const(G, BE, wstring, Str, [], Line, Out); +scan(G, BE, [$_, X|Str], Line, Out) when ?is_upper(X) -> + scan_name(G, BE, Str, [X], false, Line, Out); +scan(G, BE, [$_, X|Str], Line, Out) when ?is_lower(X) -> + scan_name(G, BE, Str, [X], false, Line, Out); +scan(G, BE, [X|Str], Line, Out) when ?is_upper(X) -> + scan_name(G, BE, Str, [X], true, Line, Out); +scan(G, BE, [X|Str], Line, Out) when ?is_lower(X) -> + scan_name(G, BE, Str, [X], true, Line, Out); +scan(G, BE, [X|Str], Line, Out) when ?is_number(X) -> + scan_number(G, BE, Str, [X], Line, Out); +scan(G, BE, [9| T], Line, Out) -> scan(G, BE, T, Line, Out); +scan(G, BE, [32| T], Line, Out) -> scan(G, BE, T, Line, Out); +scan(G, BE, [$\r|Str], Line, Out) -> + scan(G, BE, Str, Line, Out); +scan(G, BE, [$\n|Str], Line, Out) -> + scan(G, BE, Str, Line+1, Out); +scan(G, BE, [$:, $: | Str], Line, Out) -> + scan(G, BE, Str, Line, [{'::', Line} | Out]); +scan(G, BE, [$/, $/ | Str], Line, Out) -> + Rest = skip_to_nl(Str), + scan(G, BE, Rest, Line, Out); +scan(G, BE, [$/, $* | Str], Line, Out) -> + Rest = skip_comment(Str), + scan(G, BE, Rest, Line, Out); +scan(G, BE, [$", $\\|Str], Line, Out) -> + scan_const(G, BE, string, [$\\|Str], [], Line, Out); +scan(G, BE, [$"|Str], Line, Out) -> + scan_const(G, BE, string, Str, [], Line, Out); +scan(G, BE, [$', $\\|Str], Line, Out) -> + scan_const(G, BE, char, [$\\|Str], [], Line, Out); +scan(G, BE, [$'|Str], Line, Out) -> + scan_const(G, BE, char, Str, [], Line, Out); +scan(G, BE, [$\\|Str], Line, Out) -> + scan_const(G, BE, escaped, [$\\|Str], [], Line, Out); +scan(G, BE, [$. | Str], Line, Out) -> + scan_frac(G, BE, Str, [$.], Line, Out); +scan(G, BE, [$# | Str], Line, Out) -> + scan_preproc(G, BE, Str, Line, Out); +scan(G, BE, [$<, $< | Str], Line, Out) -> + scan(G, BE, Str, Line, [{'<<', Line} | Out]); +scan(G, BE, [$>, $> | Str], Line, Out) -> + scan(G, BE, Str, Line, [{'>>', Line} | Out]); +scan(G, BE, [C|Str], Line, Out) -> + scan(G, BE, Str, Line, [{list_to_atom([C]), Line} | Out]); + +scan(_G, _BE, [], _Line, Out) -> + Out. + + +scan_number(G, BE, [X|Str], [$0], Line, Out) when X == $X ; X ==$x -> + case Str of + [D|_TmpStr] when ?is_number(D); ?is_hex_uc(D); ?is_hex_lc(D) -> + {Num,Rest} = scan_hex_number(Str,0), + scan(G, BE, Rest, Line, [{'', Line, + integer_to_list(Num)} | Out]); + [D|TmpStr] -> + scan(G, BE, TmpStr, Line, [{list_to_atom([D]), Line} | Out]) + end; +scan_number(G, BE, Str, [$0], Line, Out) -> + %% If an integer literal starts with a 0 it may indicate that + %% it is represented as an octal number. But, it can also be a fixed + %% type which must use padding to match a fixed typedef. For example: + %% typedef fixed<5,2> fixed52; + %% 123.45d, 123.00d and 023.00d is all valid fixed values. + %% Naturally, a float can be defined as 0.14 or 00.14. + case pre_scan_number(Str, [], octal) of + octal -> + {Num, Rest} = scan_octal_number(Str,0), + scan(G, BE, Rest, Line, [{'', Line, + integer_to_list(Num)} | Out]); + {fixed, Fixed, Rest} -> + scan(G, BE, Rest, Line, [{'', Line, Fixed} | Out]); + float -> + %% Not very likely that someone defines a constant as 00.14 but ... + NewStr = remove_leading_zeroes(Str), + scan(G, BE, NewStr, Line, Out) + end; +scan_number(G, BE, [X|Str], Accum, Line, Out) when ?is_number(X) -> + scan_number(G, BE, Str, [X|Accum], Line, Out); +scan_number(G, BE, [X|Str], Accum, Line, Out) when X==$. -> + scan_frac(G, BE, Str, [X|Accum], Line, Out); +scan_number(G, BE, [X|Str], Accum, Line, Out) when X==$e ; X==$e -> + scan_exp(G, BE, Str, [X|Accum], Line, Out); +scan_number(G, BE, [X|Str], Accum, Line, Out) when X==$D ; X==$d -> + scan(G, BE, Str, Line, [{'', Line, + (lists:reverse(Accum))} | Out]); +scan_number(G, BE, Str, Accum, Line, Out) -> + scan(G, BE, Str, Line, [{'', Line, + (lists:reverse(Accum))} | Out]). + + +remove_leading_zeroes([$0|Rest]) -> + remove_leading_zeroes(Rest); +remove_leading_zeroes(L) -> + L. + +scan_hex_number([X|Rest],Acc) when X >=$a, X =< $f -> + scan_hex_number(Rest,(Acc bsl 4) + (X - $a + 10)); +scan_hex_number([X|Rest],Acc) when X >=$A, X =< $F -> + scan_hex_number(Rest,(Acc bsl 4) + (X - $A + 10)); +scan_hex_number([X|Rest],Acc) when X >=$0, X =< $9 -> + scan_hex_number(Rest,(Acc bsl 4) + (X-$0)); +scan_hex_number(Rest,Acc) -> + {Acc,Rest}. + +pre_scan_number([$d|Rest], Acc, _) -> + {fixed, [$0|lists:reverse(Acc)], Rest}; +pre_scan_number([$D|Rest], Acc, _) -> + {fixed, [$0|lists:reverse(Acc)], Rest}; +pre_scan_number([$.|Rest], Acc, _) -> + %% Actually, we don't know if it's a float since it can be a fixed. + pre_scan_number(Rest, [$.|Acc], float); +pre_scan_number([X|_], _Acc, _) when X == $E ; X ==$e -> + %% Now we now it's a float. + float; +pre_scan_number([X|Rest], Acc, Type) when ?is_number(X) -> + pre_scan_number(Rest, [X|Acc], Type); +pre_scan_number(_Rest, _Acc, Type) -> + %% At this point we know it's a octal or float. + Type. + +scan_octal_number([X|Rest],Acc) when ?is_octal(X) -> + scan_octal_number(Rest,(Acc bsl 3) + (X-$0)); +scan_octal_number(Rest,Acc) -> + {Acc, Rest}. + +%% Floating point number scan. +%% +%% Non trivial scan. A float consists of an integral part, a +%% decimal point, a fraction part, an e or E and a signed integer +%% exponent. Either the integer part or the fraction part but not +%% both may be missing, and either the decimal point or the +%% exponent part but not both may be missing. The exponent part +%% must consist of an e or E and a possibly signed exponent. +%% +%% Analysis shows that "1." ".7" "1e2" ".5e-3" "1.7e2" "1.7e-2" +%% is allowed and "1" ".e9" is not. The sign is only allowed just +%% after an e or E. The scanner reads a number as an integer +%% until it encounters a "." so the integer part only error case +%% will not be caught in the scanner (but rather in expression +%% evaluation) + +scan_frac(G, _BE, [$e | _Str], [$.], Line, _Out) -> + ic_error:fatal_error(G, {illegal_float, Line}); +scan_frac(G, _BE, [$E | _Str], [$.], Line, _Out) -> + ic_error:fatal_error(G, {illegal_float, Line}); +scan_frac(G, BE, Str, Accum, Line, Out) -> + scan_frac2(G, BE, Str, Accum, Line, Out). + +scan_frac2(G, BE, [X|Str], Accum, Line, Out) when ?is_number(X) -> + scan_frac2(G, BE, Str, [X|Accum], Line, Out); +scan_frac2(G, BE, [X|Str], Accum, Line, Out) when X==$e ; X==$E -> + scan_exp(G, BE, Str, [X|Accum], Line, Out); +%% The following case is for fixed (e.g. 123.45d). +scan_frac2(G, BE, [X|Str], Accum, Line, Out) when X==$d ; X==$D -> + scan(G, BE, Str, Line, [{'', Line, + (lists:reverse(Accum))} | Out]); +scan_frac2(G, BE, Str, Accum, Line, Out) -> + scan(G, BE, Str, Line, [{'', Line, + (lists:reverse(Accum))} | Out]). + +scan_exp(G, BE, [X|Str], Accum, Line, Out) when X==$- -> + scan_exp2(G, BE, Str, [X|Accum], Line, Out); +scan_exp(G, BE, Str, Accum, Line, Out) -> + scan_exp2(G, BE, Str, Accum, Line, Out). + +scan_exp2(G, BE, [X|Str], Accum, Line, Out) when ?is_number(X) -> + scan_exp2(G, BE, Str, [X|Accum], Line, Out); +scan_exp2(G, BE, Str, Accum, Line, Out) -> + scan(G, BE, Str, Line, [{'', Line, + (lists:reverse(Accum))} | Out]). + + +scan_name(G, BE, [X|Str], Accum, TypeCheck, Line, Out) when ?is_upper(X) -> + scan_name(G, BE, Str, [X|Accum], TypeCheck, Line, Out); +scan_name(G, BE, [X|Str], Accum, TypeCheck, Line, Out) when ?is_lower(X) -> + scan_name(G, BE, Str, [X|Accum], TypeCheck, Line, Out); +scan_name(G, BE, [X|Str], Accum, TypeCheck, Line, Out) when ?is_number(X) -> + scan_name(G, BE, Str, [X|Accum], TypeCheck, Line, Out); +scan_name(G, BE, [$_|Str], Accum, TypeCheck, Line, Out) -> + scan_name(G, BE, Str, [$_|Accum], TypeCheck, Line, Out); +scan_name(G, BE, S, Accum, false, Line, Out) -> + %% The CORBA 2.3 specification allows the user to override typechecking: + %% typedef string _native; + %% interface i { + %% void foo(in _native VT); + %% }; + %% BUT, the IFR-id remains the same ("IDL:native:1.0") etc. The reason for + %% this is that one don't have to re-write a large chunk of IDL- and + %% application-code. + scan(G, BE, S, Line, [{'', Line, lists:reverse(Accum)} | Out]); +scan_name(G, BE, S, Accum, _, Line, Out) -> + L = lists:reverse(Accum), + X = case is_reserved(L, BE) of + undefined -> + {'', Line, L}; + Yes -> + {Yes, Line} + end, + scan(G, BE, S, Line, [X | Out]). + +%% Shall scan a constant +scan_const(G, BE, string, [$" | Rest], Accum, Line, [{'', _, Str}|Out]) -> + scan(G, BE, Rest, Line, + [{'', Line, Str ++ lists:reverse(Accum)} | Out]); +scan_const(G, BE, string, [$" | Rest], Accum, Line, Out) -> + scan(G, BE, Rest, Line, + [{'', Line, lists:reverse(Accum)} | Out]); +scan_const(G, BE, wstring, [$" | Rest], Accum, Line, [{'', _,Wstr}|Out]) -> %% WSTRING + scan(G, BE, Rest, Line, + [{'', Line, Wstr ++ lists:reverse(Accum)} | Out]); +scan_const(G, BE, wstring, [$" | Rest], Accum, Line, Out) -> %% WSTRING + scan(G, BE, Rest, Line, + [{'', Line, lists:reverse(Accum)} | Out]); +scan_const(G, _BE, string, [], _Accum, Line, Out) -> %% Bad string + ic_error:error(G, {bad_string, Line}), + Out; +scan_const(G, _BE, wstring, [], _Accum, Line, Out) -> %% Bad WSTRING + ic_error:error(G, {bad_string, Line}), + Out; +scan_const(G, BE, char, [$' | Rest], Accum, Line, Out) -> + scan(G, BE, Rest, Line, + [{'', Line, lists:reverse(Accum)} | Out]); +scan_const(G, BE, wchar, [$' | Rest], Accum, Line, Out) -> %% WCHAR + scan(G, BE, Rest, Line, + [{'', Line, lists:reverse(Accum)} | Out]); +scan_const(G, BE, Mode, [$\\, C | Rest], Accum, Line, Out) -> + case escaped_char(C) of + error -> + ic_error:error(G, {bad_escape_character, Line, C}), %% Bad escape character + scan_const(G, BE, Mode, Rest, [C | Accum], Line, Out); + octal -> + {Num,Rest2} = scan_octal_number([C|Rest], 0), + scan_const(G, BE, Mode, Rest2, [Num|Accum], Line, Out); + hexadecimal -> + {Num,Rest2} = scan_hex_number(Rest, 0), + if + Num > 255 -> %% 16#FF + ic_error:error(G, {bad_escape_character, Line, C}), + scan_const(G, BE, Mode, Rest, [C | Accum], Line, Out); + true -> + scan_const(G, BE, Mode, Rest2, [Num|Accum], Line, Out) + end; + unicode -> + {Num,Rest2} = scan_hex_number(Rest, 0), + if + Num > 65535 -> %% 16#FFFF + ic_error:error(G, {bad_escape_character, Line, C}), + scan_const(G, BE, Mode, Rest, [C | Accum], Line, Out); + true -> + scan_const(G, BE, Mode, Rest2, [Num|Accum], Line, Out) + end; + EC -> + scan_const(G, BE, Mode, Rest, [EC | Accum], Line, Out) + end; +scan_const(G, BE, Mode, [C | Rest], Accum, Line, Out) -> + scan_const(G, BE, Mode, Rest, [C | Accum], Line, Out). + + +%% +%% Preprocessor output handling +%% +%% gcc outputs a line with line number, file name (within \") and +%% one or more integer flags. The scanner scans the line number, +%% the id and all integers up to nl. +%% +%% NOTE: This will have to be enhanced in order to eat #pragma +%% +scan_preproc(G, BE, Str, Line, Out) -> + {List, Rest} = scan_to_nl(strip(Str), []), + NewLine = get_new_line_nr(strip(List), Line+1, []), + case scan_number(G, BE, List, [], Line, [{'#', Line} | Out]) of + L when is_list(L) -> + scan(G, BE, Rest, NewLine, [{'#', Line} | L]) + end. + +get_new_line_nr([C|R], Line, Acc) when C>=$0, C=<$9 -> + get_new_line_nr(R, Line, [C|Acc]); +get_new_line_nr(_, Line, []) -> Line; % No line nr found +get_new_line_nr(_, _, Acc) -> list_to_integer(reverse(Acc)). + +scan_to_nl([], Acc) -> {reverse(Acc), []}; +scan_to_nl([$\n|Str], Acc) -> {reverse(Acc), Str}; +scan_to_nl([$\r|R], Acc) -> scan_to_nl(R, Acc); +scan_to_nl([C|R], Acc) -> scan_to_nl(R, [C|Acc]). + +strip([$ |R]) -> strip(R); +strip(L) -> L. + +%% Escaped character. Escaped chars are repr as two characters in the +%% input list of letters and this is translated into one char. +escaped_char($n) -> $\n; +escaped_char($t) -> $\t; +escaped_char($v) -> $\v; +escaped_char($b) -> $\b; +escaped_char($r) -> $ ; +escaped_char($f) -> $\f; +escaped_char($a) -> $\a; +escaped_char($\\) -> $\\; +escaped_char($?) -> $?; +escaped_char($') -> $'; +escaped_char($") -> $"; +escaped_char($x) -> hexadecimal; +escaped_char($u) -> unicode; +escaped_char(X) when ?is_octal(X) -> octal; +%% Error +escaped_char(_Other) -> error. + +skip_to_nl([]) -> []; +skip_to_nl([$\n | Str]) ->[$\n | Str]; +skip_to_nl([_|Str]) -> + skip_to_nl(Str). + +skip_comment([$\\, _ | Str]) -> + skip_comment(Str); +skip_comment([$*, $/ | Str]) -> Str; +skip_comment([_|Str]) -> + skip_comment(Str). + + +%%---------------------------------------------------------------------- +%% Shall separate keywords from identifiers and numbers + +%% Fill in the ets of reserved words +is_reserved("Object", _) -> 'Object'; +is_reserved("in", _) -> in; +is_reserved("interface", _) -> interface; +is_reserved("case", _) -> 'case'; +is_reserved("union", _) -> union; +is_reserved("struct", _) -> struct; +is_reserved("any", _) -> any; +is_reserved("long", _) -> long; +is_reserved("float", _) -> float; +is_reserved("out", _) -> out; +is_reserved("enum", _) -> enum; +is_reserved("double", _) -> double; +is_reserved("context", _) -> context; +is_reserved("oneway", _) -> oneway; +is_reserved("sequence", _) -> sequence; +is_reserved("FALSE", _) -> 'FALSE'; +is_reserved("readonly", _) -> readonly; +is_reserved("char", _) -> char; +is_reserved("wchar", _) -> wchar; +is_reserved("void", _) -> void; +is_reserved("inout", _) -> inout; +is_reserved("attribute", _) -> attribute; +is_reserved("octet", _) -> octet; +is_reserved("TRUE", _) -> 'TRUE'; +is_reserved("switch", _) -> switch; +is_reserved("unsigned", _) -> unsigned; +is_reserved("typedef", _) -> typedef; +is_reserved("const", _) -> const; +is_reserved("raises", _) -> raises; +is_reserved("string", _) -> string; +is_reserved("wstring", _) -> wstring; +is_reserved("default", _) -> default; +is_reserved("short", _) -> short; +is_reserved("module", _) -> module; +is_reserved("exception", _) -> exception; +is_reserved("boolean", _) -> boolean; +%% --- New keywords Introduced in CORBA-2.3.1 --- +%% For now we cannot add these for all backends right now since it would cause +%% some problems for at least one customer. +is_reserved("fixed", BE) -> check_be(BE, fixed); +%is_reserved("abstract", BE) -> check_be(BE, abstract); +%is_reserved("custom", BE) -> check_be(BE, custom); +%is_reserved("factory", BE) -> check_be(BE, factory); +%is_reserved("local", BE) -> check_be(BE, local); +%is_reserved("native", BE) -> check_be(BE, native); +%is_reserved("private", BE) -> check_be(BE, private); +%is_reserved("public", BE) -> check_be(BE, public); +%is_reserved("supports", BE) -> check_be(BE, supports); +%is_reserved("truncatable", BE) -> check_be(BE, truncatable); +%is_reserved("ValueBase", BE) -> check_be(BE, 'ValueBase'); +%is_reserved("valuetype", BE) -> check_be(BE, valuetype); +is_reserved(_, _) -> undefined. + +check_be(erl_corba, KeyWord) -> + KeyWord; +check_be(_, _) -> + undefined. + diff --git a/lib/ic/src/icstruct.erl b/lib/ic/src/icstruct.erl new file mode 100644 index 0000000..6058b3c --- /dev/null +++ b/lib/ic/src/icstruct.erl @@ -0,0 +1,1916 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(icstruct). + + +-export([struct_gen/4, except_gen/4, create_c_array_coding_file/5]). + +%%------------------------------------------------------------ +%% +%% Internal stuff +%% +%%------------------------------------------------------------ +-import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]). + +-include("icforms.hrl"). +-include("ic.hrl"). + + + +%%------------------------------------------------------------ + +%%------------------------------------------------------------ +%% +%% File handling stuff +%% +%%------------------------------------------------------------ + + + +%%------------------------------------------------------------ +%% +%% Generation loop +%% +%% The idea is to traverse everything and find every struct that +%% may be hiding down in nested types. All structs that are found +%% are generated to a hrl file. +%% +%% struct_gen is entry point for structs and types, except_gen is +%% for exceptions +%% +%%------------------------------------------------------------ + + +except_gen(G, N, X, L) when is_record(X, except) -> + N2 = [ic_forms:get_id2(X) | N], + if + L == c -> + io:format("Warning : Exception not defined for c mapping\n", []); + true -> + emit_struct(G, N, X, L) + end, + struct_gen_list(G, N2, ic_forms:get_body(X), L). + +struct_gen(G, N, X, L) when is_record(X, struct) -> + N2 = [ic_forms:get_id2(X) | N], + struct_gen_list(G, N2, ic_forms:get_body(X), L), + emit_struct(G, N, X, L); +struct_gen(G, N, X, L) when is_record(X, union) -> + N2 = [ic_forms:get_id2(X) | N], + if + L == c -> + %% Produce the "body" first + struct_gen_list(G, N2, ic_forms:get_body(X), L), + icunion:union_gen(G, N, X, c); + true -> + struct_gen(G, N, ic_forms:get_type(X), L), + struct_gen_list(G, N2, ic_forms:get_body(X), L) + end, + emit_union(G, N, X, L); +struct_gen(G, N, X, L) when is_record(X, member) -> + struct_gen(G, N, ic_forms:get_type(X), L); +struct_gen(G, N, X, L) when is_record(X, typedef) -> + struct_gen(G, N, ic_forms:get_body(X), L), + emit_typedef(G, N, X, L); +struct_gen(G, N, X, L) when is_record(X, type_dcl) -> + struct_gen_list(G, N, ic_forms:get_type(X), L); +struct_gen(G, N, X, L) when is_record(X, case_dcl) -> + struct_gen(G, N, ic_forms:get_type(X), L); +struct_gen(G, N, X, L) when is_record(X, sequence) -> + struct_gen(G, N, ic_forms:get_type(X), L), + X; +struct_gen(G, N, X, L) when is_record(X, enum) -> + icenum:enum_gen(G, N, X, L); +struct_gen(_G, _N, _X, _L) -> + ok. + +%% List clause for struct_gen +struct_gen_list(G, N, Xs, L) -> + lists:foreach( + fun(X) -> + R = struct_gen(G, N, X, L), + if + L == c -> + if + is_record(R,sequence) -> + emit_sequence_head_def(G,N,X,R,L); + true -> + ok + end; + true -> + ok + end + end, Xs). + + +%% emit primitive for structs. +emit_struct(G, N, X, erlang) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + %% Make a straight list of all member ids (this is a + %% variant of flatten) + EList = lists:map( + fun(XX) -> + lists:map( + fun(XXX) -> + ic_util:to_atom(ic_forms:get_id2(XXX)) + end, + ic_forms:get_idlist(XX)) + end, + ic_forms:get_body(X)), + ic_codegen:record(G, X, + ic_util:to_undersc([ic_forms:get_id2(X) | N]), + ictk:get_IR_ID(G, N, X), lists:flatten(EList)), + mkFileRecObj(G,N,X,erlang); + false -> + ok + end; +emit_struct(G, N, X, c) -> + + N1 = [ic_forms:get_id2(X) | N], + case ic_pragma:is_local(G,N1) of + true -> + emit_c_struct(G, N, X,local); + false -> + emit_c_struct(G, N, X,included) + end. + + +emit_c_struct(_G, _N, _X, included) -> + %% Do not generate included types att all. + ok; +emit_c_struct(G, N, X, local) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + + N1 = [ic_forms:get_id2(X) | N], + StructName = ic_util:to_undersc(N1), + + %% Make a straight list of all member ids (this is a + %% variant of flatten) + M = lists:map( + fun(XX) -> + lists:map( + fun(XXX) -> + if + is_record(XXX, array) -> + Type = ic_forms:get_type(XX), + Name = element(3,element(2,XXX)), + {_, _, StructTK, _} = + ic_symtab:get_full_scoped_name( + G, + N, + ic_symtab:scoped_id_new( + ic_forms:get_id2(X))), + ArrayTK = + get_structelement_tk(StructTK, + Name), + Dim = extract_dim(ArrayTK), + %% emit array file + emit(Fd, "\n#ifndef __~s__\n", + [ic_util:to_uppercase( + StructName ++ "_" + ++ Name)]), + emit(Fd, "#define __~s__\n\n", + [ic_util:to_uppercase( + StructName ++ "_" + ++ Name)]), + create_c_array_coding_file( + G, + N, + {StructName ++ "_" ++ Name, Dim}, + Type, + no_typedef), + emit(Fd, "\n#endif\n\n"), + {{Type, XXX}, + ic_forms:get_id2(XXX)}; + true -> + %% Ugly work around to fix the ETO + %% return patch problem + Name = + case ic_forms:get_id2(XXX) of + "return" -> + "return1"; + Other -> + Other + end, + {ic_forms:get_type(XX), Name} + end + end, + ic_forms:get_idlist(XX)) + end, + ic_forms:get_body(X)), + EList = lists:flatten(M), + %%io:format("Elist = ~p~n",[EList]), + + emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(StructName)]), + emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(StructName)]), + ic_codegen:mcomment_light(Fd, + [io_lib:format("Struct definition: ~s", + [StructName])], + c), + emit(Fd, "typedef struct {\n"), + lists:foreach( + fun({Type, Name}) -> + emit_struct_member(Fd, G, N1, X, Name, Type) + end, + EList), + emit(Fd, "} ~s;\n\n", [StructName]), + create_c_struct_coding_file(G, N, X, nil, StructName, + EList, struct), + emit(Fd, "\n#endif\n\n"); + false -> + ok + end. + +%% Extracts array dimention(s) + +get_structelement_tk({tk_struct, _, _, EList}, EN) -> + {value, {EN, ArrayTK}} = lists:keysearch(EN, 1, EList), + ArrayTK. + +extract_dim({tk_array, {tk_array, T, D1}, D}) -> + [integer_to_list(D) | extract_dim({tk_array, T, D1})]; +extract_dim({tk_array, _, D}) -> + [integer_to_list(D)]. + +%% Makes the array name +mk_array_name(Name,Dim) -> + Name ++ mk_array_name(Dim). + +mk_array_name([]) -> + ""; +mk_array_name([Dim|Dims]) -> + "[" ++ Dim ++ "]" ++ mk_array_name(Dims). + + +emit_struct_member(Fd, G, N, X, Name,{Type,Array}) when is_record(Array, array)-> + {_, _, StructTK, _} = + ic_symtab:get_full_scoped_name( + G, + N, + ic_symtab:scoped_id_new(ic_forms:get_id2(X))), + ArrayTK = get_structelement_tk(StructTK, Name), + Dim = extract_dim(ArrayTK), + emit(Fd, " ~s ~s;\n", + [ic_cbe:mk_c_type(G, N, Type),mk_array_name(Name,Dim)]); +emit_struct_member(Fd, _G, N, _X, Name, Union) when is_record(Union, union)-> + emit(Fd, " ~s ~s;\n", + [ic_util:to_undersc([ic_forms:get_id2(Union) | N]),Name]); +emit_struct_member(Fd, _G, _N, _X, Name, {string, _}) -> + emit(Fd, " CORBA_char *~s;\n", + [Name]); +emit_struct_member(Fd, _G, N, _X, Name, {sequence, _Type, _Length}) -> + %% Sequence used as struct + emit(Fd, " ~s ~s;\n", + [ic_util:to_undersc([Name | N]), Name]); +emit_struct_member(Fd, G, N, X, Name, Type) + when element(1, Type) == scoped_id -> + CType = ic_cbe:mk_c_type(G, N, Type, evaluate_not), + emit_struct_member(Fd, G, N, X, Name, CType); +emit_struct_member(Fd, G, N, _X, Name, {enum, Type}) -> + emit(Fd, " ~s ~s;\n", + [ic_cbe:mk_c_type(G, N, Type), + Name]); +emit_struct_member(Fd, _G, _N, _X, Name, "ETERM*") -> + emit(Fd, " ETERM* ~s;\n", + [Name]); +emit_struct_member(Fd, _G, _N, _X, Name, Type) when is_list(Type) -> + emit(Fd, " ~s ~s;\n", + [Type, Name]); +emit_struct_member(Fd, G, N, _X, Name, Type) -> + emit(Fd, " ~s ~s;\n", + [ic_cbe:mk_c_type(G, N, Type), + Name]). + + +emit_typedef(G, N, X, erlang) -> + case X of + {typedef,_,[{array,_,_}],_} -> %% Array but not a typedef of + %% an array definition + case ic_options:get_opt(G, be) of + noc -> + mkFileArrObj(G,N,X,erlang); + _ -> + %% Search the table to see if the type is local or + %% inherited. + PTab = ic_genobj:pragmatab(G), + Id = ic_forms:get_id2(X), + case ets:match(PTab,{file_data_local,'_','_', + typedef,N,Id, + ic_util:to_undersc([Id | N]), + '_','_'}) of + [[]] -> + %% Local, create erlang file for the array + mkFileArrObj(G,N,X,erlang); + _ -> + %% Inherited, do nothing + ok + end + end; + + {typedef,{sequence,_,_},_,{tk_sequence,_,_}} -> + %% Sequence but not a typedef of + %% a typedef of a sequence definition + case ic_options:get_opt(G, be) of + noc -> + mkFileRecObj(G,N,X,erlang); + _ -> + %% Search the table to see if the type is local or + %% inherited. + PTab = ic_genobj:pragmatab(G), + Id = ic_forms:get_id2(X), + case ets:match(PTab,{file_data_local,'_','_',typedef, + N,Id, + ic_util:to_undersc([Id | N]), + '_','_'}) of + [[]] -> + %% Local, create erlang file for the sequence + mkFileRecObj(G,N,X,erlang); + _ -> + %% Inherited, do nothing + ok + end + end; + _ -> + ok + end; +emit_typedef(G, N, X, c) -> + B = ic_forms:get_body(X), + if + is_record(B, sequence) -> + emit_sequence_head_def(G, N, X, B, c); + true -> + lists:foreach(fun(D) -> + emit_typedef(G, N, D, B, c) + end, + ic_forms:get_idlist(X)) + end. + +emit_typedef(G, N, D, Type, c) when is_record(D, array) -> + emit_array(G, N, D, Type); +emit_typedef(G, N, D, Type, c) -> + Name = ic_util:to_undersc([ic_forms:get_id2(D) | N]), + CType = ic_cbe:mk_c_type(G, N, Type), + TDType = mk_base_type(G, N, Type), + ic_code:insert_typedef(G, Name, TDType), + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(Name)]), + emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(Name)]), + ic_codegen:mcomment_light(Fd, + [io_lib:format("Type definition ~s " + "for type ~s", + [Name, CType])], + c), + emit(Fd, "typedef ~s ~s;\n", + [CType, Name]), + emit(Fd, "\n#endif\n\n"), + ic_codegen:nl(Fd); + false -> + ok + end. + + +mk_base_type(G, N, S) when element(1, S) == scoped_id -> + {FullScopedName, _T, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + BT = ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)), + case BT of + "erlang_binary" -> + "erlang_binary"; + "erlang_pid" -> + "erlang_pid"; + "erlang_port" -> + "erlang_port"; + "erlang_ref" -> + "erlang_ref"; + "erlang_term" -> + "ETERM*"; + Type -> + Type + end; +mk_base_type(_G, _N, S) -> + S. + +emit_array(G, N, D, Type) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + Name = ic_util:to_undersc([ic_forms:get_id2(D) | N]), + {_, _, ArrayTK, _} = + ic_symtab:get_full_scoped_name(G, N, + ic_symtab:scoped_id_new( + ic_forms:get_id(D))), + Dim = extract_dim(ArrayTK), + CType = ic_cbe:mk_c_type(G, N, Type), + emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(Name)]), + emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(Name)]), + ic_codegen:mcomment_light(Fd, + [io_lib:format("Array definition ~s " + "for type ~s", + [Name, CType])], + c), + emit(Fd, "typedef ~s ~s~s;\n", + [CType, Name, ic_cbe:mk_dim(Dim)]), + emit(Fd, "typedef ~s ~s_slice~s;\n", + [CType, Name, ic_cbe:mk_slice_dim(Dim)]), + ic_codegen:nl(Fd), + create_c_array_coding_file(G, N, {Name, Dim}, Type, typedef), + emit(Fd, "\n#endif\n\n"); + false -> + ok + end. + +open_c_coding_file(G, Name) -> + SName = string:concat(ic_util:mk_oe_name(G, "code_"), Name), + FName = + ic_file:join(ic_options:get_opt(G, stubdir),ic_file:add_dot_c(SName)), + case file:open(FName, [write]) of + {ok, Fd} -> + {Fd, SName}; + Other -> + exit(Other) + end. + + + +create_c_array_coding_file(G, N, {Name, Dim}, Type, TypeDefFlag) -> + + {Fd , SName} = open_c_coding_file(G, Name), + HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header + HrlFName = filename:basename(ic_genobj:include_file(G)), + ic_codegen:emit_stub_head(G, Fd, SName, c), + emit(Fd, "#include \"~s\"\n\n",[HrlFName]), + + %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Fd = ic_genobj:stubfiled(G), %% Write on stubfile + %% HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header + %% HrlFName = filename:basename(ic_genobj:include_file(G)), + %% emit(Fd, "#include \"~s\"\n\n",[HrlFName]), + %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + put(op_variable_count, 0), + put(tmp_declarations, []), + + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, int*, int*);\n", + [ic_util:mk_oe_name(G, "sizecalc_"), Name]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, int* oe_size_count_index, " + "int* oe_size) {\n", [ic_util:mk_oe_name(G, "sizecalc_"), Name]), + + emit(Fd, " int oe_malloc_size = 0;\n",[]), + emit(Fd, " int oe_error_code = 0;\n",[]), + emit(Fd, " int oe_type = 0;\n",[]), + emit(Fd, " int oe_array_size = 0;\n",[]), + + {ok, RamFd} = ram_file:open([], [binary, write]), + + emit_sizecount(array, G, N, nil, RamFd, {Name, Dim}, Type), + + ic_cbe:emit_tmp_variables(Fd), + ic_codegen:nl(Fd), + %% Move data from ram file to output file. + {ok, Data} = ram_file:get_file(RamFd), + emit(Fd, Data), + ram_file:close(RamFd), + + emit(Fd, " return 0;\n\n",[]), + emit(Fd, "}\n",[]), + + put(op_variable_count, 0), + put(tmp_declarations, []), + + RefStr = get_refStr(Dim), + + case TypeDefFlag of + typedef -> + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s);\n", + [ic_util:mk_oe_name(G, "encode_"), Name, Name]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s oe_rec) {\n", + [ic_util:mk_oe_name(G, "encode_"), Name, Name]); + no_typedef -> + + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s oe_rec~s);\n", + [ic_util:mk_oe_name(G, "encode_"), + Name, + ic_cbe:mk_c_type(G, N, Type), + RefStr]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s oe_rec~s) {\n", + [ic_util:mk_oe_name(G, "encode_"), + Name, + ic_cbe:mk_c_type(G, N, Type), + RefStr]) + end, + + emit(Fd, " int oe_error_code = 0;\n",[]), + + {ok, RamFd1} = ram_file:open([], [binary, write]), + + case TypeDefFlag of + typedef -> + emit_encode(array, G, N, nil, RamFd1, {Name, Dim}, Type); + no_typedef -> + emit_encode(array_no_typedef, G, N, nil, RamFd1, {Name, Dim}, Type) + end, + + ic_cbe:emit_tmp_variables(Fd), + ic_codegen:nl(Fd), + %% Move data from ram file to output file. + {ok, Data1} = ram_file:get_file(RamFd1), + emit(Fd, Data1), + ram_file:close(RamFd1), + + emit(Fd, " return 0;\n\n",[]), + emit(Fd, "}\n",[]), + + put(op_variable_count, 0), + put(tmp_declarations, []), + + case TypeDefFlag of + typedef -> + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, " + "int*, ~s);\n", + [ic_util:mk_oe_name(G, "decode_"), Name, Name]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, " + "int* oe_outindex, ~s oe_out) {\n", + [ic_util:mk_oe_name(G, "decode_"), Name, Name]); + no_typedef -> + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, int*, " + "~s oe_rec~s);\n", + [ic_util:mk_oe_name(G, "decode_"), + Name, + ic_cbe:mk_c_type(G, N, Type), + RefStr]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, " + "int* oe_outindex, ~s oe_out~s) {\n", + [ic_util:mk_oe_name(G, "decode_"), + Name, + ic_cbe:mk_c_type(G, N, Type), + RefStr]) + end, + + emit(Fd, " int oe_error_code = 0;\n",[]), + emit(Fd, " int oe_array_size = 0;\n",[]), + + {ok, RamFd2} = ram_file:open([], [binary, write]), + + case TypeDefFlag of + typedef -> + emit_decode(array, G, N, nil, RamFd2, {Name, Dim}, Type); + no_typedef -> + emit_decode(array_no_typedef, G, N, nil, RamFd2, {Name, Dim}, Type) + end, + + + ic_cbe:emit_tmp_variables(Fd), + ic_codegen:nl(Fd), + %% Move data from ram file to output file. + {ok, Data2} = ram_file:get_file(RamFd2), + emit(Fd, Data2), + ram_file:close(RamFd2), + + emit(Fd, " *oe_outindex = ~s;\n\n",[align("*oe_outindex")]), + + emit(Fd, " return 0;\n\n",[]), + emit(Fd, "}\n",[]), + file:close(Fd). + + +get_refStr([]) -> + ""; +get_refStr([X|Xs]) -> + "[" ++ X ++ "]" ++ get_refStr(Xs). + + +emit_sequence_head_def(G, N, X, T, c) -> + %% T is the sequence + case ic_genobj:is_hrlfile_open(G) of + true -> + Fd = ic_genobj:hrlfiled(G), + SeqName = ic_util:to_undersc([ic_forms:get_id2(X) | N]), + emit(Fd, "\n#ifndef __~s__\n",[ic_util:to_uppercase(SeqName)]), + emit(Fd, "#define __~s__\n",[ic_util:to_uppercase(SeqName)]), + ic_codegen:mcomment_light(Fd, + [io_lib:format("Struct definition: ~s", + [SeqName])], + c), + emit(Fd, "typedef struct {\n"), + emit(Fd, " CORBA_unsigned_long _maximum;\n"), + emit(Fd, " CORBA_unsigned_long _length;\n"), + emit_seq_buffer(Fd, G, N, T#sequence.type), + emit(Fd, "} ~s;\n\n", [SeqName]), + create_c_struct_coding_file(G, N, X, T, SeqName, + T#sequence.type, sequence_head), + emit(Fd, "\n#endif\n\n"); + + false -> + ok + end. + +emit_seq_buffer(Fd, G, N, Type) -> + emit(Fd, " ~s* _buffer;\n", + [ic_cbe:mk_c_type(G, N, Type)]). + +%%------------------------------------------------------------ +%% +%% Emit decode bodies for functions in C for array, sequences and +%% structs. +%% +%%------------------------------------------------------------ +emit_decode(array, G, N, _T, Fd, {_Name, Dim}, Type) -> + emit(Fd, " if((char*) oe_out == oe_first)\n",[]), + AlignName = + lists:concat(["*oe_outindex + ", dim_multiplication(Dim), + " * sizeof(", ic_cbe:mk_c_type(G, N, Type),")"]), + emit(Fd, " *oe_outindex = ~s;\n\n",[align(AlignName)]), + array_decode_dimension_loop(G, N, Fd, Dim, "", Type, array); +emit_decode(array_no_typedef, G, N, _T, Fd, {_Name, Dim}, Type) -> + emit(Fd, " if((char*) oe_out == oe_first)\n",[]), + AlignName = + lists:concat(["*oe_outindex + ", dim_multiplication(Dim), + " * sizeof(", ic_cbe:mk_c_type(G, N, Type),")"]), + emit(Fd, " *oe_outindex = ~s;\n\n",[align(AlignName)]), + array_decode_dimension_loop(G, N, Fd, Dim, "", Type, array_no_typedef); +emit_decode(sequence_head, G, N, T, Fd, SeqName, ElType) -> + ic_cbe:store_tmp_decl(" int oe_seq_len = 0;\n", []), + ic_cbe:store_tmp_decl(" int oe_seq_count = 0;\n", []), + ic_cbe:store_tmp_decl(" int oe_seq_dummy = 0;\n", []), + + TmpBuf = + case ictype:isBasicTypeOrEterm(G, N, ElType) of + true -> + Tmp = "oe_seq_tmpbuf", + ic_cbe:store_tmp_decl(" char* ~s = 0;\n", [Tmp]), + Tmp; + false -> + "NOT USED" + end, + + MaxSize = get_seq_max(T), + emit(Fd, " if((char*) oe_out == oe_first)\n",[]), + emit(Fd, " *oe_outindex = ~s;\n\n", + [align(["*oe_outindex + sizeof(", SeqName, ")"])]), + + Ctype = ic_cbe:mk_c_type(G, N, ElType), + emit(Fd, " if ((oe_error_code = ei_decode_list_header(oe_env->_inbuf, " + "&oe_env->_iin, &oe_seq_len)) < 0) {\n"), + case ictype:isBasicTypeOrEterm(G, N, ElType) of + true -> + emit(Fd, " int oe_type = 0;\n"), + emit(Fd, " (int) ei_get_type(oe_env->_inbuf, &oe_env->_iin, " + "&oe_type, &oe_seq_len);\n\n"), + + if + MaxSize == infinity -> + ok; + true -> + emit(Fd, " if (oe_seq_len > ~w) {\n", [MaxSize]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, DATA_CONVERSION, " + "\"Length of sequence `~s' out of bound\");\n" + " return -1;\n }\n", [SeqName]) + end, + emit(Fd, " oe_out->_maximum = oe_seq_len;\n"), + emit(Fd, " oe_out->_length = oe_seq_len;\n"), + emit(Fd, " oe_out->_buffer = (void *) (oe_first + " + "*oe_outindex);\n"), + emit(Fd, " *oe_outindex = ~s;\n", + [align(["*oe_outindex + (sizeof(", Ctype, ") * " + "oe_out->_length)"])]), + emit(Fd, + " if ((~s = malloc(oe_seq_len + 1)) == NULL) {\n" + " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "NO_MEMORY, \"Cannot malloc\");\n" + " return -1;\n" + " }\n", [TmpBuf]), + emit(Fd, " if ((oe_error_code = ei_decode_string(" + "oe_env->_inbuf, &oe_env->_iin, ~s)) < 0) {\n", [TmpBuf]), + emit(Fd, " CORBA_free(~s);\n\n", [TmpBuf]), + emit_c_dec_rpt(Fd, " ", "string1", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " for (oe_seq_count = 0; " + "oe_seq_count < oe_out->_length; oe_seq_count++)\n"), + case ictype:isBasicType(G, N, ElType) of + true -> + emit(Fd, " oe_out->_buffer[oe_seq_count] = (unsigned char) " + "~s[oe_seq_count];\n\n", [TmpBuf]); + false -> %% Term + emit(Fd, " oe_out->_buffer[oe_seq_count] = " + "erl_mk_int(~s[oe_seq_count]);\n\n",[TmpBuf]) % XXXX What? + end, + emit(Fd, " CORBA_free(~s);\n\n", [TmpBuf]); + false -> + emit(Fd, " return oe_error_code;\n") + end, + + emit(Fd, " } else {\n"), + + if + MaxSize == infinity -> + ok; + true -> + emit(Fd, " if (oe_seq_len > ~w) {\n", [MaxSize]), + emit(Fd, " CORBA_exc_set(oe_env, " + "CORBA_SYSTEM_EXCEPTION, DATA_CONVERSION, " + "\"Length of sequence `~s' out of bound\");\n" + " return -1;\n }\n", [SeqName]) + end, + + emit(Fd, " oe_out->_maximum = oe_seq_len;\n"), + emit(Fd, " oe_out->_length = oe_seq_len;\n"), + emit(Fd, " oe_out->_buffer = (void *) (oe_first + *oe_outindex);\n"), + emit(Fd, " *oe_outindex = ~s;\n\n", + [align(["*oe_outindex + (sizeof(", Ctype, ") * oe_out->_length)"])]), + + if + Ctype == "CORBA_char *" -> + emit(Fd, " for (oe_seq_count = 0; " + "oe_seq_count < oe_out->_length; oe_seq_count++) {\n"), + emit(Fd, " oe_out->_buffer[oe_seq_count] = " + "(void*) (oe_first + *oe_outindex);\n\n"), + ic_cbe:emit_decoding_stmt(G, N, Fd, ElType, + "oe_out->_buffer[oe_seq_count]", + "", + "oe_env->_inbuf", 0, "", caller_dyn), + emit(Fd, " *oe_outindex = ~s;", + [align(["*oe_outindex + strlen(oe_out->_buffer[" + "oe_seq_count]) + 1"])]); + true -> + emit(Fd, " for (oe_seq_count = 0; " + "oe_seq_count < oe_out->_length; oe_seq_count++) {\n"), + case ictype:isArray(G, N, ElType) of + %% XXX Silly. There is no real difference between the + %% C statements produced by the following calls. + true -> + ic_cbe:emit_decoding_stmt(G, N, Fd, ElType, + "oe_out->_buffer[oe_seq_count]", + "", + "oe_env->_inbuf", + 0, "oe_outindex", generator); + false -> + ic_cbe:emit_decoding_stmt(G, N, Fd, ElType, + "oe_out->_buffer + oe_seq_count", + "", + "oe_env->_inbuf", + 0, "oe_outindex", generator) + end + end, + emit(Fd, " }\n"), + emit(Fd, " if (oe_out->_length != 0) {\n"), + emit(Fd, " if ((oe_error_code = ei_decode_list_header(" + "oe_env->_inbuf, &oe_env->_iin, &oe_seq_dummy)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_list_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " } else\n"), + emit(Fd, " oe_out->_buffer = NULL;\n"), + emit(Fd, " }\n"); + +emit_decode(struct, G, N, _T, Fd, StructName, ElTypes) -> + Length = length(ElTypes) + 1, + Tname = ic_cbe:mk_variable_name(op_variable_count), + Tname1 = ic_cbe:mk_variable_name(op_variable_count), + + ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]), + ic_cbe:store_tmp_decl(" char ~s[256];\n\n",[Tname1]), + + emit(Fd, " if((char*) oe_out == oe_first)\n",[]), + AlignName = lists:concat(["*oe_outindex + sizeof(",StructName,")"]), + emit(Fd, " *oe_outindex = ~s;\n\n", [align(AlignName)]), + + emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, " + "&oe_env->_iin, &~s)) < 0) {\n", [Tname]), + emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " if (~s != ~p) {\n",[Tname, Length]), + emit_c_dec_rpt(Fd, " ", "tuple header size != ~p", [Length]), + emit(Fd, " return -1;\n }\n"), + + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, " + "&oe_env->_iin, ~s)) < 0) {\n", [Tname1]), + emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if (strcmp(~s, ~p) != 0)\n",[Tname1, StructName]), + emit(Fd, " return -1;\n\n"), + lists:foreach( + fun({ET, EN}) -> + case ic_cbe:is_variable_size(G, N, ET) of + true -> + case ET of + + {struct, _, _, _} -> + %% Sequence member = a struct + ic_cbe:emit_decoding_stmt(G, N, Fd, + StructName ++ "_" ++ + ic_forms:get_id2(ET), + "&oe_out->" ++ EN, + "", "oe_env->_inbuf", + 0, + "oe_outindex", + generator); + + {sequence, _, _} -> + %% Sequence member = a struct XXX ?? + ic_cbe:emit_decoding_stmt(G, N, Fd, + StructName ++ "_" ++ + EN, + "&oe_out->" ++ EN, + "", + "oe_env->_inbuf", + 0, + "oe_outindex", + generator); + {_,{array, _, _}} -> + emit(Fd, " oe_out->~s = (void *) " + "(oe_first+*oe_outindex);\n\n",[EN]), + ic_cbe:emit_decoding_stmt(G, N, Fd, + StructName ++ "_" ++ + EN, "oe_out->" ++ EN , + "", + "oe_env->_inbuf", + 0, + "oe_outindex", + generator); + + {union, _, _, _, _} -> + %% Sequence member = a union + ic_cbe:emit_decoding_stmt(G, N, Fd, + StructName ++ "_" ++ + ic_forms:get_id2(ET), + "&oe_out->" ++ EN, + "", + "oe_env->_inbuf", + 0, + "oe_outindex", + generator); + + {string,_} -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "oe_out->" ++ EN , + "", + "oe_env->_inbuf", + 0, + "oe_outindex", + generator_malloc); + + {scoped_id,_,_,_} -> + case ictype:member2type(G,StructName,EN) of + array -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "oe_out->" ++ + EN, + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator); + struct -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "&oe_out->" ++ + EN , + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator); + sequence -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "&oe_out->" ++ + EN, + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator); + union -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "&oe_out->" ++ + EN, + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator); + _ -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "oe_out->" ++ + EN, + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator) + end; + + _ -> + emit(Fd, " oe_out->~s = (void *) " + "(oe_first+*oe_outindex);\n\n",[EN]), + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "oe_out->" ++ EN , + "", + "oe_env->_inbuf", + 0, "oe_outindex", + generator) + end; + false -> + case ET of + + {struct, _, _, _} -> + %% A struct member + ic_cbe:emit_decoding_stmt(G, N, Fd, + StructName ++ "_" ++ + ic_forms:get_id2(ET), + "&oe_out->" ++ EN , + "", + "oe_env->_inbuf", + 0, + "oe_outindex", + generator); + + {_,{array, _, _}} -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + StructName ++ "_" ++ + EN, + "oe_out->" ++ EN , + "", + "oe_env->_inbuf", + 0, + "oe_outindex", + generator); + + {union, _, _, _, _} -> + %% Sequence member = a union + ic_cbe:emit_decoding_stmt(G, N, Fd, + StructName ++ "_" ++ + ic_forms:get_id2(ET), + "&oe_out->" ++ EN , + "", + "oe_env->_inbuf", + 0, + "oe_outindex", + generator); + + {_,_} -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "&oe_out->" ++ EN , + "", + "oe_env->_inbuf", + 0, + "oe_outindex", + generator); + {scoped_id,_,_,_} -> + case ic_symtab:get_full_scoped_name(G, N, ET) of + {_FullScopedName, _, {tk_array,_,_}, _} -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "oe_out->" ++ + EN, + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator); + {_FullScopedName, _, {tk_string,_}, _} -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "oe_out->" ++ + EN, + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator); + {_FullScopedName, _, {tk_struct,_,_,_}, _} -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "&oe_out->" ++ + EN, + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator); + + {_FullScopedName, _, + {tk_union,_,_,_,_,_}, _} -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "&oe_out->" ++ + EN, + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator); + + _ -> + ic_cbe:emit_decoding_stmt(G, N, Fd, + ET, + "&oe_out->" ++ + EN, + "", + "oe_env->" + "_inbuf", + 0, + "oe_outindex", + generator) + end + end + end + end, + ElTypes). + + +ref_array_static_dec(array, true) -> + %% Typedef, Static, Basic Type + "&(oe_out)"; +ref_array_static_dec(array, false) -> + %% Typedef, Static, Constr Type + "&(oe_out)"; +ref_array_static_dec(array_no_typedef, true) -> + %% No Typedef, Static, Basic Type + "&oe_out"; +ref_array_static_dec(array_no_typedef, false) -> + %% No Typedef, Static, Constr Type + "&oe_out". + + +ref_array_dynamic_dec(G, N, T, array) -> + case ictype:isString(G, N, T) of + true -> % Typedef, Dynamic, String + "oe_out"; + false -> % Typedef, Dynamic, No String + "&(oe_out)" + end; +ref_array_dynamic_dec(G, N, T, array_no_typedef) -> + case ictype:isString(G, N, T) of + true -> % No Typedef, Dynamic, String + "oe_out"; + false -> % No Typedef, Dynamic, No String + "&oe_out" + end. + + + +array_decode_dimension_loop(G, N, Fd, [Dim], Dimstr, Type, TDFlag) -> + Tname = ic_cbe:mk_variable_name(op_variable_count), + ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]), + + emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, " + "&oe_env->_iin, &oe_array_size)) < 0) {\n", + []), + emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + %% This is disabled due to a bug in erl_interface : + %% tuples inside tuples hae no correct data about the size + %% of the tuple........( allways = 0 ) + %%emit(Fd, " if (oe_array_size != ~s)\n",[Dim]), + %%emit(Fd, " return -1;\n\n"), + + emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n", + [Tname, Tname, Dim, Tname]), + + + ArrAccess = + case ic_cbe:is_variable_size(G, N, Type) of + true -> + ref_array_dynamic_dec(G, N, Type, TDFlag) ++ + Dimstr ++ "[" ++ Tname ++ "]"; + false -> + ref_array_static_dec(TDFlag, ictype:isBasicType(G,N,Type)) ++ + Dimstr ++ "[" ++ Tname ++ "]" + end, + + ic_cbe:emit_decoding_stmt(G, N, Fd, Type, + ArrAccess, + "", "oe_env->_inbuf", 0, + "oe_outindex", generator), + + %% emit(Fd, "\n *oe_outindex += + %% sizeof(~s);\n",[ic_cbe:mk_c_type(G, N, Type)]), + emit(Fd, " }\n"); +array_decode_dimension_loop(G, N, Fd, [Dim | Ds], _Dimstr, Type, TDFlag) -> + Tname = ic_cbe:mk_variable_name(op_variable_count), + ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]), + + emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, " + "&oe_env->_iin, &oe_array_size)) < 0) {\n", + []), + emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + %% This is disabled due to a bug in erl_interface : + %% tuples inside tuples hae no correct data about the size + %% of the tuple........( allways = 0 ) + %%emit(Fd, " if (oe_array_size != ~s)\n",[Dim]), + %%emit(Fd, " return -1;\n\n"), + + emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n", + [Tname, Tname, Dim, Tname]), + array_decode_dimension_loop(G, N, Fd, Ds, "[" ++ Tname ++ "]" , Type, + TDFlag), + + emit(Fd, " }\n"). + +dim_multiplication([D]) -> + D; +dim_multiplication([D |Ds]) -> + D ++ "*" ++ dim_multiplication(Ds). + +emit_encode(array, G, N, _T, Fd, {_Name, Dim}, Type) -> + array_encode_dimension_loop(G, N, Fd, Dim, {"",""}, Type, array); +emit_encode(array_no_typedef, G, N, _T, Fd, {_Name, Dim}, Type) -> + array_encode_dimension_loop(G, N, Fd, Dim, {"",""}, Type, + array_no_typedef); +emit_encode(sequence_head, G, N, T, Fd, SeqName, ElType) -> + Tname = ic_cbe:mk_variable_name(op_variable_count), + ic_cbe:store_tmp_decl(" int ~s = 0;\n\n",[Tname]), + + MaxSize = get_seq_max(T), + if + MaxSize == infinity -> + ok; + true -> + emit(Fd, " if (oe_rec->_length > ~w) {\n", [MaxSize]), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "DATA_CONVERSION, \"Length of sequence `~s' " + "out of bound\");\n" + " return -1;\n }\n", [SeqName]) + end, + + emit(Fd, " if (oe_rec->_length != 0) {\n"), + + emit(Fd, " if ((oe_error_code = oe_ei_encode_list_header(oe_env, " + "oe_rec->_length)) < 0) {\n", + []), + emit_c_enc_rpt(Fd, " ", "oi_ei_encode_list_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " for (~s = 0; ~s < oe_rec->_length; ~s++) {\n", + [Tname, Tname, Tname]), + case ElType of + {_,_} -> %% ElType = elementary type or pointer type + ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, "oe_rec->_buffer[" ++ + Tname ++ "]", "oe_env->_outbuf"); + + {scoped_id,local,_,["term","erlang"]} -> + ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, "oe_rec->_buffer[" ++ + Tname ++ "]", "oe_env->_outbuf"); + + {scoped_id,_,_,_} -> + case ic_symtab:get_full_scoped_name(G, N, ElType) of + {_, typedef, TDef, _} -> + case TDef of + {tk_struct,_,_,_} -> + ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, + "&oe_rec->_buffer[" ++ + Tname ++ "]", + "oe_env->_outbuf"); + {tk_sequence,_,_} -> + ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, + "&oe_rec->_buffer[" ++ + Tname ++ "]", + "oe_env->_outbuf"); + {tk_union,_,_,_,_,_} -> + ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, + "&oe_rec->_buffer[" ++ + Tname ++ "]", + "oe_env->_outbuf"); + _ -> + ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, + "oe_rec->_buffer[" ++ + Tname ++ "]", + "oe_env->_outbuf") + end; + {_,enum,_,_} -> + ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, + "oe_rec->_buffer[" ++ + Tname ++ "]", + "oe_env->_outbuf"); + _ -> + ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, + "&oe_rec->_buffer[" ++ + Tname ++ "]", + "oe_env->_outbuf") + end; + + _ -> %% ElType = structure + ic_cbe:emit_encoding_stmt(G, N, Fd, ElType, + "&oe_rec->_buffer[" ++ Tname ++ "]", + "oe_env->_outbuf") + end, + emit(Fd, " }\n"), + emit(Fd, " }\n"), + emit(Fd, " if ((oe_error_code = oe_ei_encode_empty_list(oe_env)) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_empty_list", []), + emit(Fd, " return oe_error_code;\n }\n"); +emit_encode(struct, G, N, _T, Fd, StructName, ElTypes) -> + Length = length(ElTypes) + 1, + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_tuple_header(oe_env, ~p)) < 0) {\n", [Length]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_atom(oe_env, ~p)) < 0) {\n", [StructName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + lists:foreach( + fun({ET, EN}) -> + case ET of + {sequence, _, _} -> + %% Sequence = struct + ic_cbe:emit_encoding_stmt(G, N, Fd, + StructName ++ "_" ++ EN, + "&oe_rec->" ++ EN, + "oe_env->_outbuf"); + {_,{array, _, _Dims}} -> + ic_cbe:emit_encoding_stmt(G, N, Fd, + StructName ++ "_" ++ EN, + "oe_rec->" ++ EN, + "oe_env->_outbuf"); + + {union,_,_,_,_} -> + ic_cbe:emit_encoding_stmt(G, N, Fd, + StructName ++ "_" ++ + ic_forms:get_id2(ET), + "&oe_rec->" ++ EN, + "oe_env->_outbuf"); + + {struct,_,_,_} -> + ic_cbe:emit_encoding_stmt(G, N, Fd, + StructName ++ "_" ++ + ic_forms:get_id2(ET), + "&oe_rec->" ++ EN, + "oe_env->_outbuf"); + + {scoped_id,_,_,_} -> + case ictype:member2type(G,StructName,EN) of + struct -> + ic_cbe:emit_encoding_stmt(G, N, Fd, + ET, + "&oe_rec->" ++ EN, + "oe_env->_outbuf"); + sequence -> + ic_cbe:emit_encoding_stmt(G, N, Fd, + ET, + "&oe_rec->" ++ EN, + "oe_env->_outbuf"); + union -> + ic_cbe:emit_encoding_stmt(G, N, Fd, + ET, + "&oe_rec->" ++ EN, + "oe_env->_outbuf"); + array -> + ic_cbe:emit_encoding_stmt(G, N, Fd, + ET, + "oe_rec->" ++ EN, + "oe_env->_outbuf"); + _ -> + ic_cbe:emit_encoding_stmt(G, N, Fd, + ET, + "oe_rec->" ++ EN, + "oe_env->_outbuf") + end; + _ -> + ic_cbe:emit_encoding_stmt(G, N, Fd, + ET, + "oe_rec->" ++ EN, + "oe_env->_outbuf") + end + end, + ElTypes). + +ref_array_static_enc(array, true) -> + %% Typedef, Static, Basic Type + "oe_rec"; +ref_array_static_enc(array, false) -> + %% Typedef, Static, Constr Type + "&(oe_rec)"; +ref_array_static_enc(array_no_typedef, true) -> + %% No Typedef, Static, Basic Type + "oe_rec"; +ref_array_static_enc(array_no_typedef, false) -> + %% No Typedef, Static, Constr Type + "&oe_rec". + + +ref_array_dynamic_enc(G, N, T, array) -> + case ictype:isString(G, N, T) of + true -> % Typedef, Dynamic, String + "oe_rec"; + false -> % Typedef, Dynamic, No String + "&(oe_rec)" + end; +ref_array_dynamic_enc(G, N, T, array_no_typedef) -> + case ictype:isString(G, N, T) of + true -> % No Typedef, Dynamic, String + "oe_rec"; + false -> % No Typedef, Dynamic, No String + "&oe_rec" + end. + + + +array_encode_dimension_loop(G, N, Fd, [Dim], {Str1,_Str2}, Type, TDFlag) -> + Tname = ic_cbe:mk_variable_name(op_variable_count), + ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]), + + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_tuple_header(oe_env, ~s)) < 0) {\n", [Dim]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n", + [Tname, Tname, Dim, Tname]), + + ArrAccess = + case ic_cbe:is_variable_size(G, N, Type) of + true -> + ref_array_dynamic_enc(G, N, Type, TDFlag) ++ + Str1 ++ "[" ++ Tname ++ "]"; + false -> + ref_array_static_enc(TDFlag, ictype:isBasicType(G,N,Type)) ++ + Str1 ++ "[" ++ Tname ++ "]" + end, + + ic_cbe:emit_encoding_stmt(G, N, Fd, Type, ArrAccess, "oe_env->_outbuf"), + emit(Fd, " }\n"); +array_encode_dimension_loop(G, N, Fd, [Dim | Ds],{Str1,Str2}, Type, TDFlag) -> + Tname = ic_cbe:mk_variable_name(op_variable_count), + ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]), + + emit(Fd, " if ((oe_error_code = " + "oe_ei_encode_tuple_header(oe_env, ~s)) < 0) {\n", [Dim]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n", + [Tname, Tname, Dim, Tname]), + array_encode_dimension_loop(G, N, Fd, Ds, + {Str1 ++ "[" ++ Tname ++ "]", Str2}, + Type, TDFlag), + emit(Fd, " }\n"). + + +emit_sizecount(array, G, N, _T, Fd, {_Name, Dim}, Type) -> + emit(Fd, " if(*oe_size == 0)\n",[]), + AlignName = lists:concat(["*oe_size + ", dim_multiplication(Dim), + " * sizeof(", ic_cbe:mk_c_type(G, N, Type),")"]), + emit(Fd, " *oe_size = ~s;\n\n",[align(AlignName)]), + array_size_dimension_loop(G, N, Fd, Dim, Type), + emit(Fd, " *oe_size = ~s;\n\n", + [align("*oe_size + oe_malloc_size")]), + ic_codegen:nl(Fd); + +emit_sizecount(sequence_head, G, N, T, Fd, SeqName, ElType) -> + ic_cbe:store_tmp_decl(" int oe_seq_len = 0;\n", []), + ic_cbe:store_tmp_decl(" int oe_seq_count = 0;\n", []), + + emit(Fd, " if(*oe_size == 0)\n",[]), + emit(Fd, " *oe_size = ~s;\n\n", + [align(["*oe_size + sizeof(", SeqName, ")"])]), + + MaxSize = get_seq_max(T), + + emit(Fd, " if ((oe_error_code = ei_get_type(oe_env->_inbuf, " + "oe_size_count_index, &oe_type, &oe_seq_len)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_get_type", []), + emit(Fd, " return oe_error_code;\n }\n"), + + if + MaxSize == infinity -> + ok; + true -> + emit(Fd, " if (oe_seq_len > ~w) {\n", [MaxSize]), + emit(Fd, " CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, " + "DATA_CONVERSION, \"Length of sequence `~s' " + "out of bound\");\n" + " return -1;\n }\n", [SeqName]) + end, + + CType = ic_cbe:mk_c_type(G, N, ElType), + + emit(Fd, " if ((oe_error_code = ei_decode_list_header(oe_env->_inbuf, " + "oe_size_count_index, NULL)) < 0) {\n"), + + case ictype:isBasicTypeOrEterm(G, N, ElType) of + true -> + emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->" + "_inbuf, oe_size_count_index, NULL)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_string", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " oe_malloc_size = ~s;\n\n", + [align(["sizeof(", CType, ") * oe_seq_len"])]); + false -> + emit_c_dec_rpt(Fd, " ", "non mea culpa", []), + emit(Fd, " return oe_error_code;\n\n") + end, + + emit(Fd, " } else {\n"), + + emit(Fd, " oe_malloc_size = ~s;\n\n", + [align(["sizeof(", CType, ") * oe_seq_len"])]), + + emit(Fd, " for (oe_seq_count = 0; oe_seq_count < oe_seq_len; " + "oe_seq_count++) {\n"), + ic_cbe:emit_malloc_size_stmt(G, N, Fd, ElType, + "oe_env->_inbuf", 0, generator), + emit(Fd, " }\n"), + + emit(Fd, " if (oe_seq_len != 0) \n"), + emit(Fd, " if ((oe_error_code = ei_decode_list_header(oe_env->_inbuf," + "oe_size_count_index, NULL)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_list_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " }\n"), + emit(Fd, " *oe_size = ~s;\n\n", [align("*oe_size + oe_malloc_size")]); + +emit_sizecount(struct, G, N, _T, Fd, StructName, ElTypes) -> + Length = length(ElTypes) + 1, + Tname = ic_cbe:mk_variable_name(op_variable_count), + ic_cbe:store_tmp_decl(" int ~s = 0;\n\n",[Tname]), + + emit(Fd, " if(*oe_size == 0)\n",[]), + AlignName = lists:concat(["*oe_size + sizeof(",StructName,")"]), + emit(Fd, " *oe_size = ~s;\n\n", [align(AlignName)]), + ic_codegen:nl(Fd), + + emit(Fd, " if ((oe_error_code = " + "ei_get_type(oe_env->_inbuf, oe_size_count_index, &oe_type, " + "&~s)) < 0) {\n", [Tname]), + emit_c_dec_rpt(Fd, " ", "ei_get_type", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " if (~s != ~p) {\n",[Tname, Length]), + emit_c_dec_rpt(Fd, " ", "~s != ~p", [Tname, Length]), + emit(Fd, " return -1;\n }\n"), + + + emit(Fd, " if ((oe_error_code = " + "ei_decode_tuple_header(oe_env->_inbuf, " + "oe_size_count_index, 0)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if ((oe_error_code = " + "ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n", []), + emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + lists:foreach( + fun({ET, EN}) -> + case ic_cbe:is_variable_size(G, N, ET) of + true -> + case ET of + {sequence, _, _} -> + ic_cbe:emit_malloc_size_stmt( + G, N, Fd, + StructName ++ "_" ++ EN, + "oe_env->_inbuf", + 0, + generator); + {_,{array, _, _}} -> + ic_cbe:emit_malloc_size_stmt( + G, N, Fd, + StructName ++ "_" ++ EN, + "oe_env->_inbuf", + 0, + generator); + {union,_,_,_,_} -> + ic_cbe:emit_malloc_size_stmt( + G, N, Fd, + StructName ++ "_" ++ ic_forms:get_id2(ET), + "oe_env->_inbuf", + 0, + generator); + + {struct,_,_,_} -> + ic_cbe:emit_malloc_size_stmt( + G, N, Fd, + StructName ++ "_" ++ ic_forms:get_id2(ET), + "oe_env->_inbuf", + 0, + generator); + + _ -> + ic_cbe:emit_malloc_size_stmt( + G, N, Fd, + ET, + "oe_env->_inbuf", + 0, + generator) + end; + false -> + case ET of + {_,{array, _, _}} -> + ic_cbe:emit_malloc_size_stmt( + G, N, Fd, + StructName ++ "_" ++ EN, + "oe_env->_inbuf", + 0, + generator); + + {union,_,_,_,_} -> + ic_cbe:emit_malloc_size_stmt( + G, N, Fd, + StructName ++ "_" ++ ic_forms:get_id2(ET), + "oe_env->_inbuf", + 0, + generator); + + {struct,_,_,_} -> + ic_cbe:emit_malloc_size_stmt( + G, N, Fd, + StructName ++ "_" ++ ic_forms:get_id2(ET), + "oe_env->_inbuf", + 0, + generator); + _ -> + ic_cbe:emit_malloc_size_stmt( + G, N, Fd, + ET, + "oe_env->_inbuf", + 1, + generator) + end + end + end, + ElTypes), + + emit(Fd, " *oe_size = ~s;\n\n", + [align("*oe_size + oe_malloc_size")]). + + +array_size_dimension_loop(G, N, Fd, [Dim], Type) -> + Tname = ic_cbe:mk_variable_name(op_variable_count), + + ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]), + emit(Fd, " if ((oe_error_code = " + "ei_get_type(oe_env->_inbuf, oe_size_count_index, " + "&oe_type, &oe_array_size)) < 0) {\n", + []), + emit_c_dec_rpt(Fd, " ", "ei_get_type", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " if (oe_array_size != ~s) {\n",[Dim]), + emit_c_dec_rpt(Fd, " ", "array size != ~s", [Dim]), + emit(Fd, " return -1;\n }\n"), + + emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, " + "oe_size_count_index, 0)) < 0) {\n", []), + emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n", + [Tname, Tname, Dim, Tname]), + ic_cbe:emit_malloc_size_stmt(G, N, Fd, + Type, "oe_env->_inbuf", 0, generator), + emit(Fd, " }\n"); +array_size_dimension_loop(G, N, Fd, [Dim | Ds], Type) -> + Tname = ic_cbe:mk_variable_name(op_variable_count), + + ic_cbe:store_tmp_decl(" int ~s = 0;\n",[Tname]), + emit(Fd, " if ((oe_error_code = " + "ei_get_type(oe_env->_inbuf, oe_size_count_index, " + "&oe_type, &oe_array_size)) < 0) {\n", []), + emit_c_dec_rpt(Fd, " ", "ei_get_type", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " if (oe_array_size != ~s) {\n",[Dim]), + emit_c_dec_rpt(Fd, " ", "array size != ~s", [Dim]), + emit(Fd, " return -1;\n }\n"), + + emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, " + "oe_size_count_index, 0)) < 0) {\n", + []), + emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " for (~s = 0; ~s < ~s; ~s++) {\n", + [Tname, Tname, Dim, Tname]), + array_size_dimension_loop(G, N, Fd, Ds, Type), + emit(Fd, " }\n"). + + +create_c_struct_coding_file(G, N, _X, T, StructName, ElTypes, StructType) -> + + {Fd , SName} = open_c_coding_file(G, StructName), % stub file + HFd = ic_genobj:hrlfiled(G), % stub header file + HrlFName = filename:basename(ic_genobj:include_file(G)), + + ic_codegen:emit_stub_head(G, Fd, SName, c), + HrlFName = filename:basename(ic_genobj:include_file(G)), + emit(Fd, "#include \"~s\"\n\n",[HrlFName]), + + %% Size count + + put(op_variable_count, 0), + put(tmp_declarations, []), + + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, int*, int*);\n", + [ic_util:mk_oe_name(G, "sizecalc_"), StructName]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, " + "int* oe_size_count_index, int* oe_size)\n{\n", + [ic_util:mk_oe_name(G, "sizecalc_"), StructName]), + + emit(Fd, " int oe_malloc_size = 0;\n",[]), + emit(Fd, " int oe_error_code = 0;\n",[]), + emit(Fd, " int oe_type = 0;\n",[]), + + {ok, RamFd} = ram_file:open([], [binary, write]), + + emit_sizecount(StructType, G, N, T, RamFd, StructName, ElTypes), + + ic_cbe:emit_tmp_variables(Fd), + ic_codegen:nl(Fd), + %% Move data from ram file to output file. + {ok, Data} = ram_file:get_file(RamFd), + emit(Fd, Data), + ram_file:close(RamFd), + + emit(Fd, " return 0;\n\n",[]), + emit(Fd, "}\n\n",[]), + + %% Encode + + put(op_variable_count, 0), + put(tmp_declarations, []), + + + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s*);\n", + [ic_util:mk_oe_name(G, "encode_"), StructName, StructName]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s* oe_rec)\n{\n", + [ic_util:mk_oe_name(G, "encode_"), StructName, StructName]), + + emit(Fd, " int oe_error_code = 0;\n",[]), + + {ok, RamFd1} = ram_file:open([], [binary, write]), + + emit_encode(StructType, G, N, T, RamFd1, StructName, ElTypes), + + ic_cbe:emit_tmp_variables(Fd), + ic_codegen:nl(Fd), + %% Move data from ram file to output file. + {ok, Data1} = ram_file:get_file(RamFd1), + emit(Fd, Data1), + ram_file:close(RamFd1), + + emit(Fd, " return 0;\n\n",[]), + emit(Fd, "}\n\n",[]), + + %% Decode + + put(op_variable_count, 0), + put(tmp_declarations, []), + + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, int*, ~s *);\n", + [ic_util:mk_oe_name(G, "decode_"), StructName, StructName]), + + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, " + "int* oe_outindex, " + "~s *oe_out)\n{\n", + [ic_util:mk_oe_name(G, "decode_"), StructName, StructName]), + + emit(Fd, " int oe_error_code = 0;\n",[]), + + {ok, RamFd2} = ram_file:open([], [binary, write]), + + emit_decode(StructType, G, N, T, RamFd2, StructName, ElTypes), + + ic_cbe:emit_tmp_variables(Fd), + ic_codegen:nl(Fd), + %% Move data from ram file to output file. + {ok, Data2} = ram_file:get_file(RamFd2), + emit(Fd, Data2), + ram_file:close(RamFd2), + + emit(Fd, " *oe_outindex = ~s;\n",[align("*oe_outindex")]), + emit(Fd, " return 0;\n\n",[]), + emit(Fd, "}\n\n",[]), + file:close(Fd). + + +%%------------------------------------------------------------ +%% +%% emit primitive for unions. +%% +%%------------------------------------------------------------ +emit_union(G, N, X, erlang) -> + case ic_genobj:is_hrlfile_open(G) of + true -> + ic_codegen:record(G, X, + ic_util:to_undersc([ic_forms:get_id2(X) | N]), + nil,nil), + mkFileRecObj(G,N,X,erlang); + false -> ok + end; +emit_union(_G, _N, _X, c) -> %% Not supported in c backend + true. + + +%%------------------------------------------------------------ +%% +%% emit erlang modules for objects with record definitions +%% (such as unions or structs), or sequences +%% +%% The record files, other than headers are only generated +%% for CORBA...... If wished an option could allows even +%% for other backends ( not necessary anyway ) +%% +%%------------------------------------------------------------ +mkFileRecObj(G,N,X,erlang) -> + case ic_options:get_opt(G, be) of + erl_corba -> + SName = + ic_util:to_undersc([ic_forms:get_id2(X) | N]), + FName = + ic_file:join(ic_options:get_opt(G, stubdir), + ic_file:add_dot_erl(SName)), + + case file:open(FName, [write]) of + {ok, Fd} -> + HrlFName = filename:basename(ic_genobj:include_file(G)), + + ic_codegen:emit_stub_head(G, Fd, SName, erlang), + emit(Fd, "-include(~p).\n\n",[HrlFName]), + emit_exports(G,Fd), + emit_rec_methods(G,N,X,SName,Fd), + ic_codegen:nl(Fd), + ic_codegen:nl(Fd), + file:close(Fd); + Other -> + exit(Other) + end; + _ -> + true + end. + + +%%------------------------------------------------------------ +%% +%% emit erlang modules for objects with array definitions.. +%% +%%------------------------------------------------------------ +mkFileArrObj(G,N,X,erlang) -> + SName = + ic_util:to_undersc([ic_forms:get_id2(X) | N]), + FName = + ic_file:join(ic_options:get_opt(G, stubdir), + ic_file:add_dot_erl(SName)), + + case file:open(FName, [write]) of + {ok, Fd} -> + HrlFName = filename:basename(ic_genobj:include_file(G)), + + ic_codegen:emit_stub_head(G, Fd, SName, erlang), + emit(Fd, "-include(~p).\n\n",[HrlFName]), + emit_exports(G,Fd), + emit_arr_methods(G,N,X,SName,Fd), + ic_codegen:nl(Fd), + ic_codegen:nl(Fd), + file:close(Fd); + Other -> + exit(Other) + end. + + + + +%%------------------------------------------------------------ +%% +%% emit exports for erlang modules which represent records. +%% +%%------------------------------------------------------------ +emit_exports(G,Fd) -> + case ic_options:get_opt(G, be) of + erl_corba -> + emit(Fd, "-export([tc/0,id/0,name/0]).\n\n\n\n",[]); + _ -> + emit(Fd, "-export([id/0,name/0]).\n\n\n\n",[]) + end. + + +%%------------------------------------------------------------ +%% +%% emit erlang module functions which represent records, yields +%% record information such as type code, identity and name. +%% +%%------------------------------------------------------------ +emit_rec_methods(G,N,X,Name,Fd) -> + + IR_ID = ictk:get_IR_ID(G, N, X), + + case ic_options:get_opt(G, be) of + + erl_corba -> + TK = ic_forms:get_tk(X), + + case TK of + undefined -> + STK = ic_forms:search_tk(G,ictk:get_IR_ID(G, N, X)), + emit(Fd, "%% returns type code\n",[]), + emit(Fd, "tc() -> ~p.\n\n",[STK]), + emit(Fd, "%% returns id\n",[]), + emit(Fd, "id() -> ~p.\n\n",[IR_ID]), + emit(Fd, "%% returns name\n",[]), + emit(Fd, "name() -> ~p.\n\n",[Name]); + _ -> + emit(Fd, "%% returns type code\n",[]), + emit(Fd, "tc() -> ~p.\n\n",[TK]), + emit(Fd, "%% returns id\n",[]), + emit(Fd, "id() -> ~p.\n\n",[IR_ID]), + emit(Fd, "%% returns name\n",[]), + emit(Fd, "name() -> ~p.\n\n",[Name]) + end; + + _ -> + emit(Fd, "%% returns id\n",[]), + emit(Fd, "id() -> ~p.\n\n",[IR_ID]), + emit(Fd, "%% returns name\n",[]), + emit(Fd, "name() -> ~p.\n\n",[Name]) + end. + + + +%%------------------------------------------------------------ +%% +%% emit erlang module functions which represent arrays, yields +%% record information such as type code, identity and name. +%% +%%------------------------------------------------------------ +emit_arr_methods(G,N,X,Name,Fd) -> + + IR_ID = ictk:get_IR_ID(G, N, X), + + case ic_options:get_opt(G, be) of + + erl_corba -> + + TK = ic_forms:get_type_code(G, N, X), + + emit(Fd, "%% returns type code\n",[]), + emit(Fd, "tc() -> ~p.\n\n",[TK]), + emit(Fd, "%% returns id\n",[]), + emit(Fd, "id() -> ~p.\n\n",[IR_ID]), + emit(Fd, "%% returns name\n",[]), + emit(Fd, "name() -> ~p.\n\n",[Name]); + + _ -> + + emit(Fd, "%% returns id\n",[]), + emit(Fd, "id() -> ~p.\n\n",[IR_ID]), + emit(Fd, "%% returns name\n",[]), + emit(Fd, "name() -> ~p.\n\n",[Name]) + end. + +get_seq_max(T) when is_record(T, sequence) andalso T#sequence.length == 0 -> + infinity; +get_seq_max(T) when is_record(T, sequence) andalso is_tuple(T#sequence.length) -> + list_to_integer(element(3, T#sequence.length)). + + +align(Cs) -> + ic_util:mk_align(Cs). + diff --git a/lib/ic/src/ictk.erl b/lib/ic/src/ictk.erl new file mode 100644 index 0000000..63a7705 --- /dev/null +++ b/lib/ic/src/ictk.erl @@ -0,0 +1,873 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ictk). + + +%% Toplevel generation functions +-export([reg_gen/3, unreg_gen/3]). + + +%% Utilities +-export([get_IR_ID/3, get_IR_VSN/3, register_name/1, unregister_name/1]). + +-import(ic_forms, [get_id2/1, get_body/1, get_idlist/1]). +-import(ic_util, [mk_name/2, mk_oe_name/2, to_atom/1, to_list/1]). +-import(ic_codegen, [emit/2, emit/3, nl/1]). + +-include("icforms.hrl"). +-include("ic.hrl"). + +%%-------------------------------------------------------------------- +%% +%% IFR Registration Generation +%% +%% +%%-------------------------------------------------------------------- + +-define(IFRID(G), mk_name(G, "IFR")). +-define(VARID(G), mk_name(G, "VAR")). +-define(IFRMOD, orber_ifr). + +reg_gen(G, N, X) -> + S = ic_genobj:tktab(G), + Light = ic_options:get_opt(G, light_ifr), + init_var(), + case ic_genobj:is_stubfile_open(G) of + true when Light == false -> + Var = ?IFRID(G), + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), nl(Fd), + emit(Fd, "~p() ->\n", [to_atom(register_name(G))]), + emit(Fd, " ~s = ~p:find_repository(),\n", + [Var, ?IFRMOD]), + nl(Fd), + + %% Write call function that checks if included + %% modules and interfaces are created. + emit(Fd, " register_tests(~s),\n",[?IFRID(G)]), + + reg2(G, S, N, Var, X), + nl(Fd), + emit(Fd, " ok.\n"), + + %% Write general register test function. + register_tests(Fd,G), + + %% Write functopn that registers modules only if + %% they are not registered. + register_if_unregistered(Fd); + true when Light == true -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), nl(Fd), + Regname = to_atom(register_name(G)), + emit(Fd, "~p() ->\n\t~p([]).\n\n", [Regname, Regname]), + emit(Fd, "~p(OE_Options) ->\n\t~p:add_items(?MODULE, OE_Options,\n\t[", + [Regname, ?IFRMOD]), + reg_light(G, N, X), + emit(Fd, "ok]),\n\tok.\n"); + false -> + ok + end. + +reg_light(G, N, X) when is_list(X) -> + reg_light_list(G, N, X); +reg_light(G, N, X) when is_record(X, module) -> + reg_light_list(G, [get_id2(X) | N], get_body(X)); +reg_light(G, N, X) when is_record(X, struct) -> + emit(ic_genobj:stubfiled(G), "{~p, ~p, struct},\n\t", + [get_IR_ID(G, N, X), get_module(X, N)]); +reg_light(G, N, X) when is_record(X, except) -> + emit(ic_genobj:stubfiled(G), "{~p, ~p, except},\n\t", + [get_IR_ID(G, N, X), get_module(X, N)]); +reg_light(G, N, X) when is_record(X, union) -> + emit(ic_genobj:stubfiled(G), "{~p, ~p, union},\n\t", + [get_IR_ID(G, N, X), get_module(X, N)]); +reg_light(G, N, X) when is_record(X, interface) -> + emit(ic_genobj:stubfiled(G), "{~p, ~p, interface},\n\t", + [get_IR_ID(G, N, X), get_module(X, N)]), + reg_light_list(G, [get_id2(X)|N], get_body(X)); +reg_light(_G, _N, _X) -> + ok. + +get_module(X, N) -> + List = [get_id2(X) | N], + list_to_atom(lists:foldl(fun(E, Acc) -> E++"_"++Acc end, + hd(List), tl(List))). + +%% This function filters off all "#include .idl" code that +%% come along from preprocessor and scanner. Produces code ONLY for +%% the actuall file. See ticket OTP-2133 +reg_light_list(_G, _N, []) -> []; +reg_light_list(G, N, List ) -> + CurrentFileName = ic_genobj:idlfile(G), + reg_light_list(G, N, {CurrentFileName,true}, List). + +%% The filter function + loop +reg_light_list(_G, _N, {_CFN, _Status}, []) -> []; +reg_light_list(G, N, {CFN,Status}, [X | Xs]) -> + case Status of + true -> + case X of + {preproc,_,{_,_,_FileName},[{_,_,"1"}]} -> + reg_light_list(G, N, {CFN,false}, Xs); + _ -> + reg_light(G, N, X), + reg_light_list(G, N, {CFN,Status}, Xs) + end; + false -> + case X of + {preproc,_,{_,_,CFN},[{_,_,"2"}]} -> + reg_light(G, N, X), + reg_light_list(G, N, {CFN,true}, Xs); + _ -> + reg_light_list(G, N, {CFN,Status}, Xs) + end + end. + + +%% reg2 is top level registration + +reg2(G, S, N, Var, X) -> + reg2(G, S, N, "Repository_create_", Var, X). + +reg2(G, S, N, C, V, X) when is_list(X) -> reg2_list(G, S, N, C, V, X); + +reg2(G, S, N, C, V, X) when is_record(X, module) -> + NewV = r_emit2(G, S, N, C, V, X, "", []), + reg2_list(G, S, [get_id2(X) | N], "ModuleDef_create_", NewV, get_body(X)); + +reg2(G, S, N, C, V, X) when is_record(X, const) -> + r_emit2(G, S, N, C, V, X, ", ~s, ~p", + [get_idltype(G, S, N, X), {X#const.tk, X#const.val}]); + +reg2(G, S, N, C, V, X) when is_record(X, struct) -> + do_struct(G, S, N, C, V, X, ic_forms:get_tk(X)); + +reg2(G, S, N, C, V, X) when is_record(X, except) -> + do_except(G, S, N, C, V, X, ic_forms:get_tk(X)); + +reg2(G, S, N, C, V, X) when is_record(X, union) -> + do_union(G, S, N, C, V, X, ic_forms:get_tk(X)); + +reg2(G, S, N, C, V, X) when is_record(X, enum) -> + r_emit2(G, S, N, C, V, X, ", ~p", + [get_enum_member_list(G, S, N, get_body(X))]); + +reg2(G, S, N, C, V, X) when is_record(X, typedef) -> + do_typedef(G, S, N, C, V, X), + look_for_types(G, S, N, C, V, get_body(X)); + +reg2(G, S, N, C, V, X) when is_record(X, attr) -> + XX = #id_of{type=X}, + lists:foreach(fun(Id) -> r_emit2(G, S, N, C, V, XX#id_of{id=Id}, ", ~s, ~p", + [get_idltype(G, S, N, X), get_mode(G, N, X)]) + end, + get_idlist(X)); + +reg2(G, S, N, C, V, X) when is_record(X, interface) -> + N2 = [get_id2(X) | N], + Body = get_body(X), + BIs = get_base_interfaces(G,X), %% produce code for the interface inheritance + NewV = r_emit2(G, S, N, C, V, X, ", " ++ BIs,[]), + reg2_list(G, S, N2, "InterfaceDef_create_", NewV, Body); + + +reg2(G, S, N, C, V, X) when is_record(X, op) -> + r_emit2(G, S, N, C, V, X, ", ~s, ~p, [~s], [~s], ~p", + [get_idltype(G, S, N, X), get_mode(G, N, X), + get_params(G, S, N, X#op.params), get_exceptions(G, S, N, X), + get_context(G, S, N, X)]); + +reg2(_G, _S, _N, _C, _V, X) when is_record(X, preproc) -> ok; + +reg2(_G, _S, _N, _C, _V, X) when is_record(X, pragma) -> ok; + +reg2(_G, _S, _N, _C, _V, _X) -> ok. + + +%% This function filters off all "#include .idl" code that +%% come along from preprocessor and scanner. Produces code ONLY for +%% the actuall file. See ticket OTP-2133 +reg2_list(_G, _S, _N, _C, _V, []) -> []; +reg2_list(G, S, N, C, V, List ) -> + CurrentFileName = ic_genobj:idlfile(G), + reg2_list(G, S, N, C, V, {CurrentFileName,true}, List). + +%% The filter function + loop +reg2_list(_G, _S, _N, _C, _V, {_CFN, _Status}, []) -> []; +reg2_list(G, S, N, C, V, {CFN,Status}, [X | Xs]) -> + case Status of + true -> + case X of + {preproc,_,{_,_,_FileName},[{_,_,"1"}]} -> + reg2_list(G, S, N, C, V, {CFN,false}, Xs); + _ -> + F = reg2(G, S, N, C, V, X), + [F | reg2_list(G, S, N, C, V, {CFN,Status}, Xs)] + end; + false -> + case X of + {preproc,_,{_,_,CFN},[{_,_,"2"}]} -> + F = reg2(G, S, N, C, V, X), + [F | reg2_list(G, S, N, C, V, {CFN,true}, Xs)]; + _ -> + reg2_list(G, S, N, C, V, {CFN,Status}, Xs) + end + end. + + + + + +%% General registration tests +register_tests(Fd,G) -> + IfrId = ?IFRID(G), + emit(Fd,"\n\n%% General IFR registration checks.\n", []), + emit(Fd,"register_tests(~s)->\n",[IfrId]), + emit(Fd," re_register_test(~s),\n",[IfrId]), + emit(Fd," include_reg_test(~s).\n\n",[IfrId]), + + emit(Fd,"\n%% IFR type Re-registration checks.\n", []), + case ic_pragma:fetchRandomLocalType(G) of + {ok,TypeId} -> + emit(Fd,"re_register_test(~s)->\n",[IfrId]), + emit(Fd," case orber_ifr:'Repository_lookup_id'(~s,~p) of\n", [IfrId,TypeId]), + emit(Fd," [] ->\n true;\n",[]), + emit(Fd," _ ->\n exit({allready_registered,~p})\n end.\n\n", [TypeId]); + false -> + emit(Fd,"re_register_test(_)-> true.\n",[]) + end, + + emit(Fd,"~s",[check_include_regs(G)]). + + + + +%% This function produces code for existance check over +%% top level included modules and interfaces +check_include_regs(G) -> + IfrId = ?IFRID(G), + case ic_pragma:get_incl_refs(G) of + none -> + io_lib:format("\n%% No included idl-files detected.\n", []) ++ + io_lib:format("include_reg_test(_~s) -> true.\n",[IfrId]); + IMs -> + io_lib:format("\n%% IFR registration checks for included idl files.\n", []) ++ + io_lib:format("include_reg_test(~s) ->\n",[IfrId]) ++ + check_incl_refs(G,IfrId,IMs) + end. + + + +check_incl_refs(_,_,[]) -> + io_lib:format(" true.\n",[]); +check_incl_refs(G,IfrId,[[First]|Rest]) -> + ModId = ic_pragma:scope2id(G,First), + io_lib:format(" case orber_ifr:'Repository_lookup_id'(~s,~p) of~n", [IfrId,ModId]) ++ + io_lib:format(" [] ->~n exit({unregistered,~p});~n", [ModId]) ++ + io_lib:format(" _ ->~n true~n end,~n",[]) ++ + check_incl_refs(G,IfrId,Rest). + + + +%% This function will return module ref, it will +%% also register module if not registered. +register_if_unregistered(Fd) -> + emit(Fd, "\n\n%% Fetch top module reference, register if unregistered.\n"), + emit(Fd, "oe_get_top_module(OE_IFR, ID, Name, Version) ->\n"), + emit(Fd, " case orber_ifr:'Repository_lookup_id'(OE_IFR, ID) of\n"), + emit(Fd, " [] ->\n"), + emit(Fd, " orber_ifr:'Repository_create_module'(OE_IFR, ID, Name, Version);\n"), + emit(Fd, " Mod ->\n"), + emit(Fd, " Mod\n",[]), + emit(Fd, " end.\n\n"), + emit(Fd, "%% Fetch module reference, register if unregistered.\n"), + emit(Fd, "oe_get_module(OE_IFR, OE_Parent, ID, Name, Version) ->\n"), + emit(Fd, " case orber_ifr:'Repository_lookup_id'(OE_IFR, ID) of\n"), + emit(Fd, " [] ->\n"), + emit(Fd, " orber_ifr:'ModuleDef_create_module'(OE_Parent, ID, Name, Version);\n"), + emit(Fd, " Mod ->\n"), + emit(Fd, " Mod\n",[]), + emit(Fd, " end.\n"). + + + +do_typedef(G, S, N, C, V, X) -> + case ic_genobj:is_stubfile_open(G) of + false -> ok; + true -> + Fd = ic_genobj:stubfiled(G), + Thing = get_thing_name(X), + IR_VSN = get_IR_VSN(G, N, X), + TK = ic_forms:get_tk(X), + + lists:foreach( + fun(Id) -> + r_emit_raw(G, X, Fd, "", C, Thing, V, + get_IR_ID(G, N, Id), get_id2(Id), + IR_VSN, ", ~s", + [get_idltype_tk(G, S, N, + ictype:maybe_array(G, S, N, + Id, TK))]) + end, get_idlist(X)) + end. + + +do_union(G, S, N, C, V, X, {tk_union, _IFRID, _Name, DiscrTK, _DefNr, L}) -> + N2 = [get_id2(X) | N], + r_emit2(G, S, N, C, V, X, ", ~s, [~s]", + [get_idltype_tk(G, S, N, DiscrTK), + get_union_member_def(G, S, N2, L)]), + look_for_types(G, S, N2, C, V, get_body(X)). + +do_struct(G, S, N, C, V, X, {tk_struct, _IFRID, _Name, ElemList}) -> + N2 = [get_id2(X) | N], + r_emit2(G, S, N, C, V, X, ", [~s]", + [get_member_def(G, S, N, ElemList)]), + look_for_types(G, S, N2, C, V, get_body(X)). + +do_except(G, S, N, C, V, X, {tk_except, _IFRID, _Name, ElemList}) -> + N2 = [get_id2(X) | N], + r_emit2(G, S, N, C, V, X, ", [~s]", + [get_member_def(G, S, N, ElemList)]), + look_for_types(G, S, N2, C, V, get_body(X)). + + +%% new_var finds an unused Erlang variable name by increasing a +%% counter. +new_var(_G) -> + lists:flatten(["_OE_", integer_to_list(put(var_count, get(var_count) + 1))]). +init_var() -> + put(var_count, 1). + +%% Public interface. The name of the register function. +register_name(G) -> + mk_oe_name(G, "register"). +unregister_name(G) -> + mk_oe_name(G, "unregister"). + + + +look_for_types(G, S, N, C, V, L) when is_list(L) -> + lists:foreach(fun(X) -> look_for_types(G, S, N, C, V, X) end, L); +look_for_types(G, S, N, C, V, {_Name, TK}) -> % member + look_for_types(G, S, N, C, V, TK); +look_for_types(_G, _S, _N, _C, _V, {tk_union, _IFRID, _Name, _DT, _Def, _L}) -> + ok; +look_for_types(G, S, N, C, V, {_Label, _Name, TK}) -> % case_dcl + look_for_types(G, S, N, C, V, TK); +look_for_types(_G, _S, _N, _C, _V, {tk_struct, _IFRID, _Name, _L}) -> + ok; +look_for_types(_G, _S, _N, _C, _V, _X) -> + ok. + + + + +%% This function produces code for the interface inheritance registration. +%% It produces a string that represents a list of function calls. +%% This list becomes a list of object references when the main function +%% "orber_ifr:ModuleDef_create_interface" is called. + +get_base_interfaces(G,X) -> + case element(3,X) of + [] -> + "[]"; + L -> + "[" ++ + lists:flatten( + lists:foldl( + fun(E, Acc) -> [call_fun_str(G,E), ", " | Acc] end, + call_fun_str(G,hd(L)), + tl(L) + ) + ) ++ "]" + end. + +call_fun_str(G,S) -> + lists:flatten( + io_lib:format("orber_ifr:lookup_id(~s,\"~s\")", + [ ?IFRID(G), + ic_pragma:scope2id(G,S)] )). + + + + + +%%-------------------------------------------------------------------- +%% +%% r_emit emits an IFR register function call. It returns a new +%% variable (if further defs should be added to that one) +%% +%% G is genobj +%% +%% S is symbol table (ets) +%% +%% N is list of ids describing scope +%% +%% C is create stub (eg. "Repository_create_") +%% +%% V is variable name where current def should be added, +%% +%% X is the current def item, +%% +%% F and A is auxillary format and args that will be io_lib +%% formatted and inserted as a string (don't forget to start with +%% ", ") +%% +r_emit2(G, _S, N, C, V, X, F, A) -> + case ic_genobj:is_stubfile_open(G) of + false -> ok; + true -> + {NewV, Str} = get_assign(G, V, X), + r_emit_raw(G, X, ic_genobj:stubfiled(G), Str, + C, get_thing_name(X), V, + get_IR_ID(G, N, X), get_id2(X), get_IR_VSN(G, N, X), + F, A), + NewV + end. + + +%%-------------------------------------------------------------------- +%% +%% An IFR register line registers an entity (Thing) into the IFR. The +%% thing is registered INTO something, an type is registered into a +%% module for instance, and this is reflected in the Var parameter +%% below. The var parameter is the name of the parent IFR object. The +%% Thing parameter is the name of the thing we're trying to register, +%% a typdef is called an alias and an interface is called an +%% interface. Sometimes we need to store the thing we're registering +%% into a variable because we're going to add other things to it +%% later, modules and interfaces are such containers, so we must +%% remember that variable for later use. +%% +%% All parameters shall be strings unless otherwise noted +%% +%% Fd - File descriptor +%% AssignStr - Assign or not, empty except for interfaces and modules +%% Create - Create has diff. names dep. on into what we register +%% Thing - WHAT is registered, interface +%% Var - The name of the variable we register into +%% IR_ID - The IFR identifier (may be "") +%% Id - The identifier (name) of the object +%% IR_VSN - The IFR version as a string +%% AuxStr - An auxillary string +%% +%%r_emit_raw(Fd, AssignStr, Create, Thing, Var, IR_ID, Id, IR_VSN) -> +%% r_emit_raw(Fd, AssignStr, Create, Thing, Var, IR_ID, Id, IR_VSN, "", []). +r_emit_raw(_G, X, Fd, AssignStr, "Repository_create_", Thing, Var, IR_ID, Id, IR_VSN, F, A) + when is_record(X, module) -> + emit(Fd, "~n ~s~p(~s, \"~s\", \"~s\", \"~s\"~s),~n", + [AssignStr, to_atom("oe_get_top_"++Thing), Var, IR_ID, Id, + IR_VSN, io_lib:format(F, A)]); +r_emit_raw(G, X, Fd, AssignStr, "ModuleDef_create_", Thing, Var, IR_ID, Id, IR_VSN, F, A) + when is_record(X, module) -> + emit(Fd, "~n ~s~p(~s, ~s, \"~s\", \"~s\", \"~s\"~s),~n", + [AssignStr, to_atom("oe_get_"++Thing), ?IFRID(G), Var, IR_ID, Id, + IR_VSN, io_lib:format(F, A)]); +r_emit_raw(_G, _X, Fd, AssignStr, Create, Thing, Var, IR_ID, Id, IR_VSN, F, A) -> + emit(Fd, "~n ~s~p:~p(~s, \"~s\", \"~s\", \"~s\"~s),~n", + [AssignStr, ?IFRMOD, to_atom(Create++Thing), Var, IR_ID, Id, + IR_VSN, io_lib:format(F, A)]). + + + + +%% Used by r_emit. Returns tuple {Var, Str} where Var is the resulting +%% output var (if any, otherwise same as input arg) and Str is a +%% string of the assignment if any ("" or "Var = ") +get_assign(G, _V, X) when is_record(X, module) -> + mk_assign(G); +get_assign(G, _V, X) when is_record(X, interface) -> + mk_assign(G); +get_assign(_G, V, _X) -> {V, ""}. +mk_assign(G) -> + V = new_var(G), + {V, io_lib:format("~s = ", [V])}. + +%% Returns a list of strings of all enum members (suitable for ~p) +get_enum_member_list(_G, _S, _N, L) -> + lists:map(fun(M) -> get_id2(M) end, L). + +%% Will output a string of the union members. +get_union_member_def(_G, _S, _N, []) -> []; +get_union_member_def(G, S, N, L) -> + [union_member2str(G, S, N, hd(L)) | + lists:map(fun(M) -> [", ", union_member2str(G, S, N, M)] end, tl(L))]. +%% lists:foldl(fun(M, Acc) -> +%% [union_member2str(G, S, N, M),", " | Acc] end, +%% union_member2str(G, S, N, hd(L)), tl(L)). + +union_member2str(G, S, N, {Label, Name, TK}) -> + io_lib:format("~s{name=~p, label=~p, type=~p, type_def=~s}", + ["#unionmember", Name, Label, TK, + get_idltype_tk(G, S, N, TK)]). + + +%% Will output a string of the struct members. Works for exceptions +%% and structs +%% +get_member_def(_G, _S, _N, []) -> []; +get_member_def(G, S, N, L) -> + [member2str(G, S, N, hd(L)) | + lists:map(fun(M) -> [", ", member2str(G, S, N, M)] end, tl(L))]. + +member2str(G, S, N, {Id, TK}) -> + io_lib:format("~s{name=~p, type=~p, type_def=~s}", + ["#structmember", Id, TK, get_idltype_tk(G, S, N, TK)]). + +%% Translates between record names and create operation names. +get_thing_name(X) when is_record(X, op) -> "operation"; +get_thing_name(X) when is_record(X, const) -> "constant"; +get_thing_name(X) when is_record(X, typedef) -> "alias"; +get_thing_name(X) when is_record(X, attr) -> "attribute"; +get_thing_name(X) when is_record(X, except) -> "exception"; +get_thing_name(X) when is_record(X, id_of) -> get_thing_name(X#id_of.type); +get_thing_name(X) -> to_list(element(1,X)). + + +%% Returns the mode (in, out, oneway etc) of ops and params. Return +%% value is an atom. +get_mode(_G, _N, X) when is_record(X, op) -> + case X#op.oneway of + {oneway, _} -> 'OP_ONEWAY'; + _ -> 'OP_NORMAL' + end; +get_mode(_G, _N, X) when is_record(X, attr) -> + case X#attr.readonly of + {readonly, _} -> 'ATTR_READONLY'; + _ -> 'ATTR_NORMAL' + end; +get_mode(_G, _N, X) when is_record(X, param) -> + case X#param.inout of + {in, _} -> 'PARAM_IN'; + {inout, _} -> 'PARAM_INOUT'; + {out, _} -> 'PARAM_OUT' + end. + + +%% Returns a string form of idltype creation. +%%get_idltype_id(G, S, N, X, Id) -> +%% TK = ictype:tk_lookup(G, S, N, Id), +%% get_idltype_tk(G, S, N, TK). +get_idltype(G, S, N, X) -> + get_idltype_tk(G, S, N, ic_forms:get_tk(X)). +get_idltype_tk(G, _S, _N, TK) -> + io_lib:format("~p:~p(~s, ~p)", [orber_ifr, 'Repository_create_idltype', + ?IFRID(G), TK]). + +%% Returns a string form of typecode creation. This shall be found in +%% the type code symbol table. +%%get_typecode(G, S, N, X) -> typecode. +%%get_typecode(G, S, N, X) -> tk(G, S, N, get_type(X)). + + +%% Returns the string form of a list of parameters. +get_params(_G, _S, _N, []) -> ""; +get_params(G, S, N, L) -> + lists:foldl(fun(X, Acc) -> param2str(G, S, N, X)++", "++Acc end, + param2str(G, S, N, hd(L)), tl(L)). + + +%% Converts a parameter to a string. +param2str(G, S, N, X) -> + io_lib:format("~s{name=~p, type=~p, type_def=~s, mode=~p}~n", + ["#parameterdescription", get_id2(X), + ic_forms:get_tk(X), + %%tk_lookup(G, S, N, get_type(X)), + get_idltype(G, S, N, X), + get_mode(G, N, X)]). + + + + +%% Public interface. Returns the IFR ID of an object. This +%% is updated to comply with CORBA 2.0 pragma directives. +get_IR_ID(G, N, X) -> + ScopedId = [get_id2(X) | N], + case ic_pragma:get_alias(G,ScopedId) of + none -> + case ic_pragma:pragma_id(G, N, X) of + none -> + case ic_pragma:pragma_prefix(G, N, X) of + none -> + IR_ID = lists:flatten( + io_lib:format("IDL:~s:~s", + [slashify(ScopedId), + get_IR_VSN(G, N, X)])), + ic_pragma:mk_alias(G,IR_ID,ScopedId), + IR_ID; + PF -> + IR_ID = lists:flatten( + io_lib:format("IDL:~s:~s", + [ PF ++ "/" ++ + get_id2(X), + get_IR_VSN(G, N, X)])), + ic_pragma:mk_alias(G,IR_ID,ScopedId), + IR_ID + end; + PI -> + ic_pragma:mk_alias(G,PI,ScopedId), + PI + end; + Alias -> + Alias + end. + + +%% Public interface. Returns the IFR Version of an object. This +%% is updated to comply with CORBA 2.0 pragma directives. +get_IR_VSN(G, N, X) -> + ic_pragma:pragma_version(G,N,X). + + + + + +%% Returns a slashified name, [I1, M1] becomes "M1/I1" +%slashify(List) -> lists:foldl(fun(X, Acc) -> get_id2(X)++"/"++Acc end, +% hd(List), tl(List)). + +%% Returns a slashified name, [I1, M1] becomes "M1/I1" +slashify(List) -> lists:foldl(fun(X, Acc) -> X++"/"++Acc end, + hd(List), tl(List)). + + +%% Returns the context literals of an op +get_context(_G, _S, _N, X) -> + lists:map(fun(C) -> element(3, C) end, X#op.ctx). + + + +%% Returns the list of the exceptions of an operation +get_exceptions(G, S, N, X) -> + case X#op.raises of + [] -> + ""; + L -> + lists:flatten( + lists:foldl( + fun(E, Acc) -> [excdef(G, S, N, X, E), ", " | Acc] end, + excdef(G, S, N, X, hd(L)), + tl(L) + ) + ) + end. + + +%% Returns the definition of an exception of an operation +excdef(G, S, N, X, L) -> + io_lib:format("orber_ifr:lookup_id(~s,\"~s\")", + [ ?IFRID(G), + get_EXC_ID(G, S, N, X, L) ] ). + + + + + + +%% This function produces code for the exception registration. +%% It produces a string that represents a list of function calls. +%% This list becomes a list of object references when the main function +%% "orber_ifr:InterfaceDef_create_operation" is called. + +get_EXC_ID(G, _S, N, X, ScopedId) -> + case ic_pragma:get_alias(G,ScopedId) of + none -> + case ic_pragma:pragma_id(G, N, X) of + none -> + case ic_pragma:pragma_prefix(G, N, X) of + none -> + EXC_ID = lists:flatten( + io_lib:format("IDL:~s:~s", [slashify(ScopedId), + get_IR_VSN(G, N, X)])), + ic_pragma:mk_alias(G,EXC_ID,ScopedId), + EXC_ID; + PF -> + EXC_ID = lists:flatten( + io_lib:format("IDL:~s:~s", [ PF ++ "/" ++ + hd(ScopedId), + get_IR_VSN(G, N, X)])), + ic_pragma:mk_alias(G,EXC_ID,ScopedId), + EXC_ID + end; + PI -> + ic_pragma:mk_alias(G,PI,ScopedId), + PI + end; + Alias -> + Alias + end. + + + + + +%% unreg_gen/1 uses the information stored in pragma table +%% to decide which modules are to be unregistered +unreg_gen(G, N, X) -> + Light = ic_options:get_opt(G, light_ifr), + case ic_genobj:is_stubfile_open(G) of + true when Light == false -> + Var = ?IFRID(G), + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), nl(Fd), + emit(Fd, "~p() ->\n", [to_atom(unregister_name(G))]), + emit(Fd, " ~s = ~p:find_repository(),\n", + [Var, ?IFRMOD]), + nl(Fd), + + unreg2(G, N, X), + emit(Fd, " ok.\n\n"), + destroy(Fd); + true -> + Fd = ic_genobj:stubfiled(G), + nl(Fd), nl(Fd), + Unregname = to_atom(unregister_name(G)), + emit(Fd, "~p() ->\n\t~p([]).\n\n~p(OE_Options) ->\n", + [Unregname, Unregname, Unregname]), + emit(Fd, "\t~p:remove(?MODULE, OE_Options),\n\tok.\n\n", [?IFRMOD]); + false -> ok + end. + + +destroy(Fd) -> +emit(Fd," +oe_destroy_if_empty(OE_IFR,IFR_ID) -> + case orber_ifr:'Repository_lookup_id'(OE_IFR, IFR_ID) of + [] -> + ok; + Ref -> + case orber_ifr:contents(Ref, \'dk_All\', \'true\') of + [] -> + orber_ifr:destroy(Ref), + ok; + _ -> + ok + end + end. + +oe_destroy(OE_IFR,IFR_ID) -> + case orber_ifr:'Repository_lookup_id'(OE_IFR, IFR_ID) of + [] -> + ok; + Ref -> + orber_ifr:destroy(Ref), + ok + end. + +",[]). + + + + + + + + + + +%% unreg2 is top level registration + +unreg2(G, N, X) -> + emit(ic_genobj:stubfiled(G),"~s",[lists:flatten(unreg3(G, N, X))]). + +unreg3(G, N, X) when is_list(X) -> + unreg3_list(G, N, X, []); + +unreg3(G, N, X) when is_record(X, module) -> + unreg3_list(G, [get_id2(X) | N], get_body(X), [unreg_collect(G, N, X)]); + +unreg3(G, N, X) when is_record(X, const) -> + unreg_collect(G, N, X); + +unreg3(G, N, X) when is_record(X, struct) -> + unreg_collect(G, N, X); + +unreg3(G, N, X) when is_record(X, except) -> + unreg_collect(G, N, X); + +unreg3(G, N, X) when is_record(X, union) -> + unreg_collect(G, N, X); + +unreg3(G, N, X) when is_record(X, enum) -> + unreg_collect(G, N, X); + +unreg3(G, N, X) when is_record(X, typedef) -> + unreg_collect(G, N, X); + +unreg3(G, N, X) when is_record(X, interface) -> + unreg_collect(G, N, X); + +unreg3(_G, _N, X) when is_record(X, op) -> []; + +unreg3(_G, _N, X) when is_record(X, attr) -> []; + +unreg3(_G, _N, X) when is_record(X, preproc) -> []; + +unreg3(_G, _N, X) when is_record(X, pragma) -> []; + +unreg3(_G, _N, _X) -> []. + + +unreg3_list(_G, _N, [], Found) -> + Found; +unreg3_list(G, N, List, Found) -> + CurrentFileName = ic_genobj:idlfile(G), + unreg3_list(G, N, {CurrentFileName,true}, List, Found). + +%% The filter function + loop +unreg3_list(_G, _N, {_CFN, _Status}, [], Found) -> + Found; +unreg3_list(G, N, {CFN,Status}, [X | Xs], Found) -> + case Status of + true -> + case X of + {preproc,_,{_,_,_FileName},[{_,_,"1"}]} -> + unreg3_list(G, N, {CFN,false}, Xs, Found); + _ -> + unreg3_list(G, N, {CFN,Status}, Xs, [unreg3(G, N, X) | Found]) + end; + false -> + case X of + {preproc,_,{_,_,CFN},[{_,_,"2"}]} -> + unreg3_list(G, N, {CFN,true}, Xs,[unreg3(G, N, X) | Found]); + _ -> + unreg3_list(G, N, {CFN,Status}, Xs, Found) + end + end. + + + +unreg_collect(G, N, X) when is_record(X, module) -> + io_lib:format(" oe_destroy_if_empty(OE_IFR, ~p),\n", + [get_IR_ID(G, N, X)]); +unreg_collect(G, N, X) when is_record(X, typedef) -> + lists:map(fun(Id) -> + io_lib:format(" oe_destroy(OE_IFR, ~p),\n", + [get_IR_ID(G, N, Id)]) + end, + ic_forms:get_idlist(X)); +unreg_collect(G, N, X) -> + io_lib:format(" oe_destroy(OE_IFR, ~p),\n", + [get_IR_ID(G, N, X)]). + + + diff --git a/lib/ic/src/ictype.erl b/lib/ic/src/ictype.erl new file mode 100644 index 0000000..4704191 --- /dev/null +++ b/lib/ic/src/ictype.erl @@ -0,0 +1,1413 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(ictype). + + +-include("ic.hrl"). +-include("icforms.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([type_check/2, scoped_lookup/4, maybe_array/5, to_uppercase/1]). + +-export([name2type/2, member2type/3, isBasicTypeOrEterm/3, isEterm/3]). +-export([isBasicType/1, isBasicType/2, isBasicType/3, isString/3, isWString/3, + isArray/3, isStruct/3, isUnion/3, isEnum/3, isSequence/3, isBoolean/3 ]). +-export([fetchTk/3, fetchType/1, tk/4]). +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% Macros +%%----------------------------------------------------------------- +%%-define(DBG(F,A), io:format(F,A)). +-define(DBG(F,A), true). +-define(STDDBG, ?DBG(" dbg: ~p: ~p~n", [element(1,X), ic_forms:get_id2(X)])). + +%%----------------------------------------------------------------- +%% External functions +%%----------------------------------------------------------------- + +type_check(G, Forms) -> + S = ic_genobj:tktab(G), + check_list(G, S, [], Forms). + +scoped_lookup(G, S, N, X) -> + Id = ic_symtab:scoped_id_strip(X), + case ic_symtab:scoped_id_is_global(X) of + true -> + lookup(G, S, [], X, Id); + false -> + lookup(G, S, N, X, Id) + end. + + +%%-------------------------------------------------------------------- +%% maybe_array +%% +%% Array declarators are indicated on the declarator and not on +%% the type, therefore the declarator decides if the array type +%% kind is added or not. +%% +maybe_array(G, S, N, X, TK) when is_record(X, array) -> + mk_array(G, S, N, X#array.size, TK); +maybe_array(_G, _S, _N, _, TK) -> TK. + + + +name2type(G, Name) -> + S = ic_genobj:tktab(G), + ScopedName = lists:reverse(string:tokens(Name, "_")), + InfoList = ets:lookup(S, ScopedName ), + filter( InfoList ). + + +%% This is en overloaded function, +%% differs in input on unions +member2type(_G, X, I) when is_record(X, union)-> + Name = ic_forms:get_id2(I), + case lists:keysearch(Name,2,element(6,X#union.tk)) of + false -> + error; + {value,Rec} -> + fetchType(element(3,Rec)) + end; +member2type( G, SName, MName ) -> + + S = ic_genobj:tktab( G ), + SNList = lists:reverse(string:tokens(SName,"_")), + ScopedName = [MName | SNList], + InfoList = ets:lookup( S, ScopedName ), + + case filter( InfoList ) of + error -> + %% Try a little harder, seeking inside tktab + case lookup_member_type_in_tktab(S, ScopedName, MName) of + error -> + %% Check if this is the "return to return1" case + case MName of + "return1" -> + %% Do it all over again ! + ScopedName2 = ["return" | SNList], + InfoList2 = ets:lookup( S, ScopedName2 ), + case filter( InfoList2 ) of + error -> + %% Last resort: seek in pragma table + lookup_type_in_pragmatab(G, SName); + + Other -> + Other + end; + _ -> + %% Last resort: seek in pragma table + lookup_type_in_pragmatab(G, SName) + end; + Other -> + Other + end; + Other -> + Other + end. + + +lookup_member_type_in_tktab(S, ScopedName, MName) -> + case ets:match_object(S, {'_',member,{MName,'_'},nil}) of + [] -> + error; + [{_FullScopedName,member,{MName,TKInfo},nil}]-> + fetchType( TKInfo ); + List -> + lookup_member_type_in_tktab(List,ScopedName) + end. + +lookup_member_type_in_tktab([], _ScopedName) -> + error; +lookup_member_type_in_tktab([{FullScopedName,_,{_,TKInfo},_}|Rest],ScopedName) -> + case lists:reverse(string:tokens(ic_util:to_undersc(FullScopedName),"_")) of + ScopedName -> + fetchType(TKInfo); + _ -> + lookup_member_type_in_tktab(Rest,ScopedName) + end. + + +lookup_type_in_pragmatab(G, SName) -> + S = ic_genobj:pragmatab(G), + + %% Look locally first + case ets:match(S,{file_data_local,'_','_','$2','_','_',SName,'_','_'}) of + [] -> + %% No match, seek included + case ets:match(S,{file_data_included,'_','_','$2','_','_',SName,'_','_'}) of + + [] -> + error; + [[Type]] -> + io:format("1 Found(~p) : ~p~n",[SName,Type]), + Type + end; + + [[Type]] -> + io:format("2 Found(~p) : ~p~n",[SName,Type]), + Type + end. + + + + +isString(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_string',_}, _} -> + true; + _ -> + false + end; +isString(_G, _N, T) when is_record(T, string) -> + true; +isString(_G, _N, _Other) -> + false. + + +isWString(G, N, T) when element(1, T) == scoped_id -> %% WSTRING + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_wstring',_}, _} -> + true; + _ -> + false + end; +isWString(_G, _N, T) when is_record(T, wstring) -> + true; +isWString(_G, _N, _Other) -> + false. + + +isArray(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_array', _, _}, _} -> + true; + _ -> + false + end; +isArray(_G, _N, T) when is_record(T, array) -> + true; +isArray(_G, _N, _Other) -> + false. + + +isSequence(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_sequence', _, _}, _} -> + true; + _ -> + false + end; +isSequence(_G, _N, T) when is_record(T, sequence) -> + true; +isSequence(_G, _N, _Other) -> + false. + + +isStruct(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_struct', _, _, _}, _} -> + true; + _ -> + false + end; +isStruct(_G, _N, T) when is_record(T, struct) -> + true; +isStruct(_G, _N, _Other) -> + false. + + +isUnion(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_union', _, _, _,_,_}, _} -> + true; + _Other -> + false + end; +isUnion(_G, _N, T) when is_record(T, union) -> + true; +isUnion(_G, _N, _Other) -> + false. + + + +isEnum(G, N, T) when element(1, T) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, T) of + {_FullScopedName, _, {'tk_enum',_,_,_}, _} -> + true; + _Other -> + false + end; +isEnum(_G, _N, T) when is_record(T, enum) -> + true; +isEnum(_G, _N, _Other) -> + false. + + + +isBoolean(G, N, T) when element(1, T) == scoped_id -> + {_, _, TK, _} = + ic_symtab:get_full_scoped_name(G, N, T), + case fetchType(TK) of + 'boolean' -> + true; + _ -> + false + end; +isBoolean(_, _, {'tk_boolean',_}) -> + true; +isBoolean(_, _, {'boolean',_}) -> + true; +isBoolean(_, _, _) -> + false. + + +%%% Just used for C + +isBasicTypeOrEterm(G, N, S) -> + case isBasicType(G, N, S) of + true -> + true; + false -> + isEterm(G, N, S) + end. + +isEterm(G, N, S) when element(1, S) == scoped_id -> + {FullScopedName, _, _TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + case ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)) of + "erlang_term" -> + true; + "ETERM*" -> + true; + _X -> + false + end; +isEterm(_G, _Ni, _X) -> + false. + +isBasicType(_G, _N, {scoped_id,_,_,["term","erlang"]}) -> + false; +isBasicType(G, N, S) when element(1, S) == scoped_id -> + {_, _, TK, _} = ic_symtab:get_full_scoped_name(G, N, S), + isBasicType(fetchType(TK)); +isBasicType(_G, _N, {string, _} ) -> + false; +isBasicType(_G, _N, {wstring, _} ) -> %% WSTRING + false; +isBasicType(_G, _N, {unsigned, {long, _}} ) -> + true; +isBasicType(_G, _N, {unsigned, {short, _}} ) -> + true; +isBasicType(_G, _N, {Type, _} ) -> + isBasicType(Type); +isBasicType(_G, _N, _X) -> + false. + + +isBasicType( G, Name ) -> + isBasicType( name2type( G, Name ) ). + + +isBasicType( Type ) -> + lists:member(Type, + [tk_short,short, + tk_long,long, + tk_longlong,longlong, %% LLONG + tk_ushort,ushort, + tk_ulong,ulong, + tk_ulonglong,ulonglong, %% ULLONG + tk_float,float, + tk_double,double, + tk_boolean,boolean, + tk_char,char, + tk_wchar,wchar, %% WCHAR + tk_octet,octet, + tk_any,any]). %% Fix for any + + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- +check(G, _S, N, X) when is_record(X, preproc) -> + handle_preproc(G, N, X#preproc.cat, X), + X; + +check(G, S, N, X) when is_record(X, op) -> + ?STDDBG, + TK = tk_base(G, S, N, ic_forms:get_type(X)), + tktab_add(G, S, N, X), + N2 = [ic_forms:get_id2(X) | N], + Ps = lists:map(fun(P) -> + tktab_add(G, S, N2, P), + P#param{tk=tk_base(G, S, N, ic_forms:get_type(P))} end, + X#op.params), + %% Check for exception defs. + Raises = lists:map(fun(E) -> name_lookup(G, S, N, E) end, + X#op.raises), + case ic_forms:is_oneway(X) of + true -> + if TK /= tk_void -> + ic_error:error(G, {bad_oneway_type, X, TK}); + true -> ok + end, + case ic:filter_params([inout, out], X#op.params) of + [] -> ok; % No out parameters! + _ -> + ic_error:error(G, {oneway_outparams, X}) + end, + case X#op.raises of + [] -> ok; + _ -> + ic_error:error(G, {oneway_raises, X}) + end; + false -> + ok + end, + X#op{params=Ps, tk=TK, raises=Raises}; + +check(G, S, N, X) when is_record(X, interface) -> + ?STDDBG, + N2 = [ic_forms:get_id2(X) | N], + TK = {tk_objref, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X)}, + Inherit = inherit_resolve(G, S, N, X#interface.inherit, []), + tktab_add(G, S, N, X, TK, Inherit), + CheckedBody = check_list(G, S, N2, ic_forms:get_body(X)), + InhBody = calc_inherit_body(G, N2, CheckedBody, Inherit, []), + X2 = X#interface{inherit=Inherit, tk=TK, body=CheckedBody, + inherit_body=InhBody}, + ic_symtab:store(G, N, X2), + X2; + +check(G, S, N, X) when is_record(X, forward) -> + ?STDDBG, + tktab_add(G, S, N, X, {tk_objref, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X)}), + X; + + +check(G, S, N, X) when is_record(X, const) -> + ?STDDBG, + case tk_base(G, S, N, ic_forms:get_type(X)) of + Err when element(1, Err) == error -> X; + TK -> + check_const_tk(G, S, N, X, TK), + case iceval:eval_const(G, S, N, TK, X#const.val) of + Err when element(1, Err) == error -> X; + {ok, NewTK, Val} -> + V = iceval:get_val(Val), + tktab_add(G, S, N, X, NewTK, V), + X#const{val=V, tk=NewTK}; + Val -> + V = iceval:get_val(Val), + tktab_add(G, S, N, X, TK, V), + X#const{val=V, tk=TK} + end + end; + +check(G, S, N, X) when is_record(X, const) -> + ?STDDBG, + case tk_base(G, S, N, ic_forms:get_type(X)) of + Err when element(1, Err) == error -> X; + TK -> + check_const_tk(G, S, N, X, TK), + case iceval:eval_const(G, S, N, TK, X#const.val) of + Err when element(1, Err) == error -> X; + Val -> + V = iceval:get_val(Val), + tktab_add(G, S, N, X, TK, V), + X#const{val=V, tk=TK} + end + end; + +check(G, S, N, X) when is_record(X, except) -> + ?STDDBG, + TK = tk(G, S, N, X), + X#except{tk=TK}; + +check(G, S, N, X) when is_record(X, struct) -> + ?STDDBG, + TK = tk(G, S, N, X), + X#struct{tk=TK}; + +check(G, S, N, X) when is_record(X, enum) -> + ?STDDBG, + TK = tk(G, S, N, X), + X#enum{tk=TK}; + +check(G, S, N, X) when is_record(X, union) -> + ?STDDBG, + TK = tk(G, S, N, X), + X#union{tk=TK}; + +check(G, S, N, X) when is_record(X, attr) -> + ?STDDBG, + TK = tk_base(G, S, N, ic_forms:get_type(X)), + XX = #id_of{type=X}, + lists:foreach(fun(Id) -> tktab_add(G, S, N, XX#id_of{id=Id}) end, + ic_forms:get_idlist(X)), + X#attr{tk=TK}; + +check(G, S, N, X) when is_record(X, module) -> + ?STDDBG, + tktab_add(G, S, N, X), + X#module{body=check_list(G, S, [ic_forms:get_id2(X) | N], ic_forms:get_body(X))}; + +check(G, S, N, X) when is_record(X, typedef) -> + ?STDDBG, + TKbase = tk(G, S, N, X), + X#typedef{tk=TKbase}; + +check(_G, _S, _N, X) -> + ?DBG(" dbg: ~p~n", [element(1,X)]), + X. + +handle_preproc(G, _N, line_nr, X) -> ic_genobj:set_idlfile(G, ic_forms:get_id2(X)); +handle_preproc(_G, _N, _C, _X) -> ok. + + +%%-------------------------------------------------------------------- +%% +%% TK calculation +%% +%%-------------------------------------------------------------------- + +tk(G, S, N, X) when is_record(X, union) -> + N2 = [ic_forms:get_id2(X) | N], + DisrcTK = tk(G, S, N, ic_forms:get_type(X)), + case check_switch_tk(G, S, N, X, DisrcTK) of + true -> + do_special_enum(G, S, N2, ic_forms:get_type(X)), + BodyTK = lists:reverse( + tk_caselist(G, S, N2, DisrcTK, ic_forms:get_body(X))), + tktab_add(G, S, N, X, + {tk_union, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X), + DisrcTK, default_count(ic_forms:get_body(X)), BodyTK}); + false -> + tk_void + end; + +tk(G, S, N, X) when is_record(X, enum) -> + N2 = [ic_forms:get_id2(X) | N], + tktab_add(G, S, N, X, + {tk_enum, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X), + enum_body(G, S, N2, ic_forms:get_body(X))}); + + +%% Note that the TK returned from this function is the base TK. It +%% must be modified for each of the identifiers in the idlist (for +%% array reasons). +tk(G, S, N, X) when is_record(X, typedef) -> + case X of + %% Special case only for term and java backend ! + {typedef,{any,_},[{'',_,"term"}],undefined} -> + case ic_options:get_opt(G, be) of + java -> + tktab_add(G, S, N, X, tk_term), + tk_term; + _ -> + TK = tk(G, S, N, ic_forms:get_body(X)), + lists:foreach(fun(Id) -> + tktab_add(G, S, N, #id_of{id=Id, type=X}, + maybe_array(G, S, N, Id, TK)) + end, + X#typedef.id), + TK + end; + _ -> + TK = tk(G, S, N, ic_forms:get_body(X)), + lists:foreach(fun(Id) -> + tktab_add(G, S, N, #id_of{id=Id, type=X}, + maybe_array(G, S, N, Id, TK)) + end, + X#typedef.id), + TK + end; + +tk(G, S, N, X) when is_record(X, struct) -> + N2 = [ic_forms:get_id2(X) | N], + tktab_add(G, S, N, X, {tk_struct, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X), + tk_memberlist(G, S, N2, ic_forms:get_body(X))}); + +tk(G, S, N, X) when is_record(X, except) -> + N2 = [ic_forms:get_id2(X) | N], + tktab_add(G, S, N, X, {tk_except, ictk:get_IR_ID(G, N, X), ic_forms:get_id2(X), + tk_memberlist(G, S, N2, ic_forms:get_body(X))}); + +tk(G, S, N, X) -> tk_base(G, S, N, X). + + +tk_base(G, S, N, X) when is_record(X, sequence) -> + {tk_sequence, tk(G, S, N, X#sequence.type), + len_eval(G, S, N, X#sequence.length)}; + +tk_base(G, S, N, X) when is_record(X, string) -> + {tk_string, len_eval(G, S, N, X#string.length)}; + +tk_base(G, S, N, X) when is_record(X, wstring) -> %% WSTRING + {tk_wstring, len_eval(G, S, N, X#wstring.length)}; + +%% Fixed constants can be declared as: +%% (1) const fixed pi = 3.14D; or +%% (2) typedef fixed<3,2> f32; +%% const f32 pi = 3.14D; +tk_base(G, S, N, X) when is_record(X, fixed) -> + %% Case 2 + {tk_fixed, len_eval(G, S, N, X#fixed.digits), len_eval(G, S, N, X#fixed.scale)}; +tk_base(_G, _S, _N, {fixed, _}) -> + %% Case 1 + tk_fixed; + + +%% Special case, here CORBA::TypeCode is built in +%% ONLY when erl_corba is the backend of choice +tk_base(G, S, N, {scoped_id,V1,V2,["TypeCode","CORBA"]}) -> + case ic_options:get_opt(G, be) of + false -> + tk_TypeCode; + erl_corba -> + tk_TypeCode; + erl_template -> + tk_TypeCode; + _ -> + case scoped_lookup(G, S, N, {scoped_id,V1,V2,["TypeCode","CORBA"]}) of + T when element(1, T) == error -> T; + T when is_tuple(T) -> element(3, T) + end + end; + +tk_base(G, S, N, X) when element(1, X) == scoped_id -> + case scoped_lookup(G, S, N, X) of + T when element(1, T) == error -> T; + T when is_tuple(T) -> element(3, T) + end; +tk_base(_G, _S, _N, {long, _}) -> tk_long; +tk_base(_G, _S, _N, {'long long', _}) -> tk_longlong; %% LLONG +tk_base(_G, _S, _N, {short, _}) -> tk_short; +tk_base(_G, _S, _N, {'unsigned', {short, _}}) -> tk_ushort; +tk_base(_G, _S, _N, {'unsigned', {long, _}}) -> tk_ulong; +tk_base(_G, _S, _N, {'unsigned', {'long long', _}})-> tk_ulonglong; %% ULLONG +tk_base(_G, _S, _N, {float, _}) -> tk_float; +tk_base(_G, _S, _N, {double, _}) -> tk_double; +tk_base(_G, _S, _N, {boolean, _}) -> tk_boolean; +tk_base(_G, _S, _N, {char, _}) -> tk_char; +tk_base(_G, _S, _N, {wchar, _}) -> tk_wchar; %% WCHAR +tk_base(_G, _S, _N, {octet, _}) -> tk_octet; +tk_base(_G, _S, _N, {null, _}) -> tk_null; +tk_base(_G, _S, _N, {void, _}) -> tk_void; +tk_base(_G, _S, _N, {any, _}) -> tk_any; +tk_base(_G, _S, _N, {'Object', _}) -> {tk_objref, "", "Object"}. + + +%%-------------------------------------------------------------------- +%% +%% Special handling of idlists. Note that the recursion case is given +%% as accumulator to foldr. Idlists are those lists of identifiers +%% that share the same definition, i.e. multiple cases, multiple type +%% declarations, multiple member names. +%% +tk_memberlist(G, S, N, [X | Xs]) -> + BaseTK = tk(G, S, N, ic_forms:get_type(X)), + + XX = #id_of{type=X}, + lists:foldr(fun(Id, Acc) -> + [tk_member(G, S, N, XX#id_of{id=Id}, BaseTK) | Acc] end, + tk_memberlist(G, S, N, Xs), + ic_forms:get_idlist(X)); +tk_memberlist(_G, _S, _N, []) -> []. + +%% same as above but for case dcls +tk_caselist(G, S, N, DiscrTK, Xs) -> + lists:foldl(fun(Case, Acc) -> + BaseTK = tk(G, S, N, ic_forms:get_type(Case)), + %% tktab_add for the uniqueness check of the declarator + tktab_add(G, S, N, Case), + lists:foldl(fun(Id, Acc2) -> + case tk_case(G, S, N, Case, BaseTK, + DiscrTK, Id) of + Err when element(1, Err)==error -> + Acc2; + TK -> + unique_add_case_label(G, S, N, Id, + TK, Acc2) + end + end, + Acc, + ic_forms:get_idlist(Case)) + end, + [], + Xs). + + +%% Handling of the things that can be in an idlist or caselist +tk_member(G, S, N, X, BaseTK) -> + tktab_add(G, S, N, X, + {ic_forms:get_id2(X), maybe_array(G, S, N, X#id_of.id, BaseTK)}). + + +get_case_id_and_check(G, _S, _N, _X, ScopedId) -> + case ic_symtab:scoped_id_is_global(ScopedId) of + true -> ic_error:error(G, {bad_scope_enum_case, ScopedId}); + false -> ok + end, + case ic_symtab:scoped_id_strip(ScopedId) of + [Id] -> Id; + _List -> + ic_error:error(G, {bad_scope_enum_case, ScopedId}), + "" + end. + + +tk_case(G, S, N, X, BaseTK, DiscrTK, Id) -> + case case_eval(G, S, N, DiscrTK, Id) of + Err when element(1, Err) == error -> Err; + Val -> + case iceval:check_tk(G, DiscrTK, Val) of + true -> + {iceval:get_val(Val), ic_forms:get_id2(X), + maybe_array(G, S, N, X#case_dcl.id, BaseTK)}; + false -> + ic_error:error(G, {bad_case_type, DiscrTK, X, + iceval:get_val(Val)}) + end + end. + +tktab_add(G, S, N, X) -> + tktab_add_id(G, S, N, X, ic_forms:get_id2(X), nil, nil). +tktab_add(G, S, N, X, TK) -> + tktab_add_id(G, S, N, X, ic_forms:get_id2(X), TK, nil). +tktab_add(G, S, N, X, TK, Aux) -> + tktab_add_id(G, S, N, X, ic_forms:get_id2(X), TK, Aux). + + +tktab_add_id(G, S, N, X, Id, TK, Aux) when is_record(X,enumerator) -> + + %% Check if the "scl" flag is set to true + %% if so, allow old semantics ( errornous ) + %% Warning, this is for compatibility reasons only. + Name = case ic_options:get_opt(G, scl) of + true -> + [Id | N]; + false -> + [Id | tl(N)] + end, + + UName = mk_uppercase(Name), + case ets:lookup(S, Name) of + [_] -> ic_error:error(G, {multiply_defined, X}); + [] -> + case ets:lookup(S, UName) of + [] -> ok; + [_] -> ic_error:error(G, {illegal_spelling, X}) + end + end, + ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), + if UName =/= Name -> ets:insert(S, {UName, spellcheck}); + true -> true end, + TK; +%% +%% Fixes the multiple file module definition check +%% but ONLY for Corba backend +%% +tktab_add_id(G, S, N, X, Id, TK, Aux) when is_record(X,module) -> + case ic_options:get_opt(G, be) of + erl_template -> + Name = [Id | N], + UName = mk_uppercase(Name), + ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), + if UName =/= Name -> ets:insert(S, {UName, spellcheck}); + true -> true end, + TK; + erl_corba -> + Name = [Id | N], + UName = mk_uppercase(Name), + ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), + if UName =/= Name -> ets:insert(S, {UName, spellcheck}); + true -> true end, + TK; + false -> %% default == erl_corba + Name = [Id | N], + UName = mk_uppercase(Name), + ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), + if UName =/= Name -> ets:insert(S, {UName, spellcheck}); + true -> true end, + TK; + java -> + Name = [Id | N], + UName = mk_uppercase(Name), + ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), + if UName =/= Name -> ets:insert(S, {UName, spellcheck}); + true -> true end, + TK; + erl_genserv -> + Name = [Id | N], + UName = mk_uppercase(Name), + ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), + if UName =/= Name -> ets:insert(S, {UName, spellcheck}); + true -> true end, + TK; + erl_plain -> + Name = [Id | N], + UName = mk_uppercase(Name), + ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), + if UName =/= Name -> ets:insert(S, {UName, spellcheck}); + true -> true end, + TK; + _Be -> + Name = [Id | N], + UName = mk_uppercase(Name), + case ets:lookup(S, Name) of + [_] -> ic_error:error(G, {multiply_defined, X}); + [] -> + case ets:lookup(S, UName) of + [] -> ok; + [_] -> ic_error:error(G, {illegal_spelling, X}) + end + end, + ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), + if UName =/= Name -> ets:insert(S, {UName, spellcheck}); + true -> true end, + TK + end; +tktab_add_id(G, S, N, X, Id, TK, Aux) -> + Name = [Id | N], + UName = mk_uppercase(Name), + case ets:lookup(S, Name) of + [{_, forward, _, _}] when is_record(X, interface) -> ok; + [XX] when is_record(X, forward) andalso element(2, XX)==interface -> ok; + [_] -> ic_error:error(G, {multiply_defined, X}); + [] -> + case ets:lookup(S, UName) of + [] -> ok; + [_] -> ic_error:error(G, {illegal_spelling, X}) + end + end, + ets:insert(S, {Name, element(1, get_beef(X)), TK, Aux}), + if UName =/= Name -> ets:insert(S, {UName, spellcheck}); + true -> true end, + TK. + + + + +%%-------------------------------------------------------------------- +%% enum_body +%% +%% Special because ids are treated different than usual. +%% +enum_body(G, S, N, [Enum | EnumList]) -> + tktab_add(G, S, N, Enum), %%%, enum_val, Enum), + %% tktab_add(G, S, N, X, TK, V), + [ic_forms:get_id2(Enum) | enum_body(G, S, N, EnumList)]; +enum_body(_G, _S, _N, []) -> []. + + +%%-------------------------------------------------------------------- +%% mk_array +%% +%% Multi dimensional arrays are written as nested tk_array +%% +mk_array(G, S, N, [Sz | Szs], TK) -> + case iceval:eval_const(G, S, N, positive_int, Sz) of + Err when element(1, Err) == error -> TK; + Val -> + {tk_array, mk_array(G, S, N, Szs, TK), iceval:get_val(Val)} + end; +mk_array(_G, _S, _N, [], TK) -> TK. + + +%%-------------------------------------------------------------------- +%% len_eval +%% +%% Evaluates the length, which in case it has been left out is a +%% plain 0 (zero) +%% +len_eval(_G, _S, _N, 0) -> 0; +len_eval(G, S, N, X) -> %%iceval:eval_const(G, S, N, positive_int, X). + case iceval:eval_const(G, S, N, positive_int, X) of + Err when element(1, Err) == error -> 0; + Val -> iceval:get_val(Val) + end. + + +%%-------------------------------------------------------------------- +%% case_eval +%% +%% Evaluates the case label. +%% + +case_eval(G, S, N, DiscrTK, X) when element(1, DiscrTK) == tk_enum, + element(1, X) == scoped_id -> + {tk_enum, _, _, Cases} = DiscrTK, + Id = get_case_id_and_check(G, S, N, X, X), + %%io:format("Matching: ~p to ~p~n", [Id, Cases]), + case lists:member(Id, Cases) of + true -> + {enum_id, Id}; + false -> + iceval:mk_val(scoped_lookup(G, S, N, X)) % Will generate error + end; + +case_eval(G, S, N, DiscrTK, X) -> + iceval:eval_e(G, S, N, DiscrTK, X). + + +%% The enum declarator is in the union scope. +do_special_enum(G, S, N, X) when is_record(X, enum) -> + tktab_add(G, S, N, #id_of{id=X#enum.id, type=X}); +do_special_enum(_G, _S, _N, _X) -> + ok. + + +unique_add_case_label(G, _S, _N, Id, TK, TKList) -> +%%%io:format("check_case_labels: TK:~p TKLIST:~p ~n", [TK, TKList]), + if element(1, TK) == error -> + TKList; + true -> + case lists:keysearch(element(1, TK), 1, TKList) of + {value, _} -> + ic_error:error(G, {multiple_cases, Id}), + TKList; + false -> + [TK | TKList] + end + end. + + +%%-------------------------------------------------------------------- +%% default_count +%% +%% Returns the position of the default case. +%% +%% Modified for OTP-2007 +%% +default_count(Xs) -> + default_count2(Xs, 0). + +default_count2([X | Xs], N) -> default_count3(X#case_dcl.label, Xs, N); +default_count2([], _) -> -1. + +default_count3([{default, _} | _Ys], _Xs, N) -> N; +default_count3([_ | Ys], Xs, N) -> default_count3(Ys, Xs, N+1); +default_count3([], Xs, N) -> default_count2(Xs, N). + + + + +%% +%% Type checks. +%% +%% Check constant type references (only for the scoped id case, others +%% are caught by the BNF) +%% +check_const_tk(_G, _S, _N, _X, tk_long) -> true; +check_const_tk(_G, _S, _N, _X, tk_longlong) -> true; %% LLONG +check_const_tk(_G, _S, _N, _X, tk_short) -> true; +check_const_tk(_G, _S, _N, _X, tk_ushort) -> true; +check_const_tk(_G, _S, _N, _X, tk_ulong) -> true; +check_const_tk(_G, _S, _N, _X, tk_ulonglong) -> true; %% ULLONG +check_const_tk(_G, _S, _N, _X, tk_float) -> true; +check_const_tk(_G, _S, _N, _X, tk_double) -> true; +check_const_tk(_G, _S, _N, _X, tk_boolean) -> true; +check_const_tk(_G, _S, _N, _X, tk_char) -> true; +check_const_tk(_G, _S, _N, _X, tk_wchar) -> true; %% WCHAR +check_const_tk(_G, _S, _N, _X, tk_octet) -> true; +check_const_tk(_G, _S, _N, _X, {tk_string, _Len}) -> true; +check_const_tk(_G, _S, _N, _X, {tk_wstring, _Len}) -> true; %% WSTRING +check_const_tk(_G, _S, _N, _X, tk_fixed) -> true; +check_const_tk(_G, _S, _N, _X, {tk_fixed, _Digits, _Scale}) -> true; +check_const_tk(G, _S, _N, X, TK) -> ic_error:error(G, {illegal_const_t, X, TK}). + + +check_switch_tk(_G, _S, _N, _X, tk_long) -> true; +check_switch_tk(_G, _S, _N, _X, tk_longlong) -> true; %% LLONG +check_switch_tk(_G, _S, _N, _X, tk_short) -> true; +check_switch_tk(_G, _S, _N, _X, tk_ushort) -> true; +check_switch_tk(_G, _S, _N, _X, tk_ulong) -> true; +check_switch_tk(_G, _S, _N, _X, tk_ulonglong) -> true; %% ULLONG +check_switch_tk(_G, _S, _N, _X, tk_boolean) -> true; +check_switch_tk(_G, _S, _N, _X, tk_char) -> true; +check_switch_tk(_G, _S, _N, _X, tk_wchar) -> true; %% WCHAR +check_switch_tk(_G, _S, _N, _X, TK) when element(1, TK) == tk_enum -> true; +check_switch_tk(G, _S, _N, X, TK) -> ic_error:error(G, {illegal_switch_t, X, TK}), + false. + + + +%% Lookup a name +name_lookup(G, S, N, X) -> + case scoped_lookup(G, S, N, X) of + T when is_tuple(T) -> element(1, T) + end. + + +lookup(G, S, N, X, Id) -> + N2 = Id ++ N, + ?DBG(" Trying ~p ...~n", [N2]), + case ets:lookup(S, N2) of + [] -> + case look_for_interface(G, S, [hd(N2)], tl(N2)) of + + %% First attempt: filtering inherited members ! + [{_, member, _, _}] -> + case look_for_interface(G, S, [hd(N)], tl(N2)) of + [T] -> + ?DBG(" -- found ~p~n", [T]), + T; + _ -> + lookup(G, S, tl(N), X, Id) + end; + %% + + [T] -> + ?DBG(" -- found ~p~n", [T]), + T; + + _ -> + if N == [] -> + ic_error:error(G, {tk_not_found, X}); + true -> + lookup(G, S, tl(N), X, Id) + end + + end; + + %% Second attempt: filtering members ! + [{_, member, _, _}] -> + case look_for_interface(G, S, [hd(N2)], tl(N2)) of + [T] -> + ?DBG(" -- found ~p~n", [T]), + T; + _ -> + if N == [] -> + ic_error:error(G, {tk_not_found, X}); + true -> + lookup(G, S, tl(N), X, Id) + end + end; + %% + [T] -> + ?DBG(" -- found ~p~n", [T]), + T + end. + + +look_for_interface(_G, _S, _Hd, []) -> + false; +look_for_interface(G, S, Hd, Tl) -> + case ets:lookup(S, Tl) of + [{_, interface, _TK, Inh}] -> + case look_in_inherit(G, S, Hd, Inh) of + %% gather_inherit(G, S, Inh, [])) of + [X] when is_tuple(X) -> + [X]; + _ -> + look_for_interface(G, S, Hd ++ [hd(Tl)], tl(Tl)) + end; + _ -> + look_for_interface(G, S, Hd ++ [hd(Tl)], tl(Tl)) + end. + +look_in_inherit(G, S, Id, [I | Is]) -> + case ets:lookup(S, Id ++ I) of + [X] when is_tuple(X) -> + [X]; + [] -> + look_in_inherit(G, S, Id, Is) + end; +look_in_inherit(_G, _S, _Id, []) -> + false. + + +%% L is a list of names +mk_uppercase(L) -> + lists:map(fun(Z) -> lists:map(fun(X) when X>=$a, X=<$z -> X-$a+$A; + (X) -> X end, Z) end, L). + + +%%-------------------------------------------------------------------- +%% +%% Inheritance stuff +%% +%% +%%-------------------------------------------------------------------- + +%% InhBody is an accumulating parameter + +calc_inherit_body(G, N, OrigBody, [X|Xs], InhBody) -> + case ic_symtab:retrieve(G, X) of + Intf when is_record(Intf, interface) -> + Body = filter_body(G, X, ic_forms:get_body(Intf), N, OrigBody, InhBody), + calc_inherit_body(G, N, OrigBody, Xs, [{X, Body} | InhBody]); + XXX -> + io:format("Oops, not found ~p~n", [XXX]), + calc_inherit_body(G, N, OrigBody, Xs, InhBody) + end; +calc_inherit_body(_G, _N, _OrigBody, [], InhBody) -> lists:reverse(InhBody). + + +filter_body(G, XPath, [X | Xs], OrigPath, OrigBody, InhBody) -> + case complex_body_member(G, XPath, X, OrigPath, OrigBody, InhBody) of + true -> + %%io:format("NOT adding ~p~n", [ic_forms:get_id2(X)]), + filter_body(G, XPath, Xs, OrigPath, OrigBody, InhBody); + {false, NewX} -> % For those with idlist + %%io:format("Adding from idlist~n", []), + [NewX | filter_body(G, XPath, Xs, OrigPath, OrigBody, InhBody)]; + false -> + %%io:format("Adding: ~p~n", [ic_forms:get_id2(X)]), + [X | filter_body(G, XPath, Xs, OrigPath, OrigBody, InhBody)] + end; +filter_body(_G, _XPath, [], _OrigPath, _OrigBody, _InhBody) -> []. + + +complex_body_member(G, XPath, X, OrigPath, OrigBody, InhBody) -> + case has_idlist(X) of + true -> + idlist_member(G, XPath, X, OrigPath, OrigBody, InhBody); + false -> + straight_member(G, XPath, X, OrigPath, OrigBody, InhBody) + end. + + +idlist_member(G, XPath, X, OrigPath, OrigBody, InhBody) -> + XX = #id_of{type=X}, + F = fun(Id) -> + not(straight_member(G, XPath, XX#id_of{id=Id}, OrigPath, + OrigBody, InhBody)) + end, + case lists:filter(F, ic_forms:get_idlist(X)) of + [] -> + true; + IdList -> +%%% io:format("Idlist added: ~p~n",[IdList]), + {false, replace_idlist(X, IdList)} + end. + + +straight_member(G, XPath, X, OrigPath, OrigBody, InhBody) -> + %%io:format("straight member: ~p~n", [ic_forms:get_id2(X)]), + case body_member(G, XPath, X, OrigPath, OrigBody) of + true -> + true; + false -> + inh_body_member(G, XPath, X, InhBody) + end. + + +inh_body_member(G, XPath, X, [{Name, Body} | InhBody]) -> + case body_member(G, XPath, X, Name, Body) of + true -> + true; + false -> + inh_body_member(G, XPath, X, InhBody) + end; +inh_body_member(_G, _XPath, _X, []) -> false. + + +body_member(G, XPath, X, YPath, [Y|Ys]) -> + case has_idlist(Y) of + true -> + YY = #id_of{type=Y}, + case list_and(fun(Y2) -> + not(is_equal(G, XPath, X, YPath, + YY#id_of{id=Y2})) end, + ic_forms:get_idlist(Y)) of + true -> + body_member(G, XPath, X, YPath, Ys); + false -> + true + end; + false -> + case is_equal(G, XPath, X, YPath, Y) of + false -> + body_member(G, XPath, X, YPath, Ys); + true -> + true + end + end; +body_member(_G, _XPath, _X, _YPath, []) -> false. + + +is_equal(G, XPath, X, YPath, Y) -> + case {ic_forms:get_id2(X), ic_forms:get_id2(Y)} of + {ID, ID} -> + collision(G, XPath, X, YPath, Y), + true; + _ -> + false + end. + + +%% X is the new item, Y is the old one. So it is X that collides with +%% Y and Y shadows X. +collision(G, XPath, X, YPath, Y) -> + I1 = get_beef(X), + % I2 = get_beef(Y), + if is_record(I1, op) -> %%, record(I2, op) -> + ic_error:error(G, {inherit_name_collision, + {YPath, Y}, {XPath, X}}); + is_record(I1, attr) -> %%, record(I2, attr) -> + ic_error:error(G, {inherit_name_collision, + {YPath, Y}, {XPath, X}}); + true -> + ?ifopt(G, warn_name_shadow, + ic_error:warn(G, {inherit_name_shadow, + {YPath, Y}, {XPath, X}})) + end. + +has_idlist(X) when is_record(X, typedef) -> true; +has_idlist(X) when is_record(X, member) -> true; +has_idlist(X) when is_record(X, case_dcl) -> true; +has_idlist(X) when is_record(X, attr) -> true; +has_idlist(_) -> false. + +replace_idlist(X, IdList) when is_record(X, typedef) -> X#typedef{id=IdList}; +replace_idlist(X, IdList) when is_record(X, attr) -> X#attr{id=IdList}. + +get_beef(X) when is_record(X, id_of) -> X#id_of.type; +get_beef(X) -> X. + + +%% And among all elements in list +list_and(F, [X|Xs]) -> + case F(X) of + true -> list_and(F, Xs); + false -> false + end; +list_and(_F, []) -> true. + + + + + +%%-------------------------------------------------------------------- +%% +%% resolve_inherit shall return a list of resolved inheritances, +%% that is all names replaced with their global names. +%% + +inherit_resolve(G, S, N, [X|Rest], Out) -> + case scoped_lookup(G, S, N, X) of + {Name, _T, _TK, Inh} -> + case lists:member(Name, Out) of + true -> + inherit_resolve(G, S, N, Rest, Out); + false -> + case unique_append(Inh, [Name|Out]) of + error -> + ic_error:error(G, {inherit_resolve, X, Name}), + inherit_resolve(G, S, N, Rest, []); + UA -> + inherit_resolve(G, S, N, Rest, UA) + end + end; + _ -> inherit_resolve(G, S, N, Rest, Out) + end; +inherit_resolve(_G, _S, _N, [], Out) -> lists:reverse(Out). + +unique_append([X|Xs], L) -> + case lists:member(X, L) of + true -> unique_append(Xs, L); + false -> unique_append(Xs, [X|L]) + end; +unique_append([], L) -> L; +%% Error +unique_append(_, _L) -> error. + + + + +%%-------------------------------------------------------------------- +%% +%% Utilities +%% + +%% Must preserve order, therefore had to write my own (instead of lists:map) +check_list(G, S, N, [X|Xs]) -> + X1 = check(G, S, N, X), + [X1 | check_list(G, S, N, Xs)]; +check_list(_G, _S, _N, []) -> []. + + + +filter( [] ) -> + error; +filter( [I | Is ] ) -> + case I of + { _, member, { _, TKINFO }, _ } -> + fetchType( TKINFO ); + + { _, struct, _, _ } -> + struct; + + { _, typedef, TKINFO, _ } -> + fetchType( TKINFO ); + + { _, module, _, _ } -> + module; + + { _, interface, _, _ } -> + interface; + + { _, op, _, _ } -> + op; + + { _,enum, _, _ } -> + enum; + + { _, spellcheck } -> + filter( Is ); + + _ -> + error + end. + + +fetchType( { tk_sequence, _, _ } ) -> + sequence; +fetchType( { tk_array, _, _ } ) -> + array; +fetchType( { tk_struct, _, _, _} ) -> + struct; +fetchType( { tk_string, _} ) -> + string; +fetchType( { tk_wstring, _} ) -> %% WSTRING + wstring; +fetchType( { tk_fixed, _, _} ) -> + fixed; +fetchType( tk_short ) -> + short; +fetchType( tk_long ) -> + long; +fetchType( tk_longlong ) -> %% LLONG + longlong; +fetchType( tk_ushort ) -> + ushort; +fetchType( tk_ulong ) -> + ulong; +fetchType( tk_ulonglong ) -> %% ULLONG + ulonglong; +fetchType( tk_float ) -> + float; +fetchType( tk_double ) -> + double; +fetchType( tk_boolean ) -> + boolean; +fetchType( tk_char ) -> + char; +fetchType( tk_wchar ) -> %% WCHAR + wchar; +fetchType( tk_octet ) -> + octet; +fetchType( { tk_enum, _, _, _ } ) -> + enum; +fetchType( { tk_union, _, _, _, _, _ } ) -> + union; +fetchType( tk_any ) -> + any; +fetchType( _ ) -> + error. + +%% Z is a single name +to_uppercase(Z) -> + lists:map(fun(X) when X>=$a, X=<$z -> X-$a+$A; + (X) -> X end, Z). + + +%%------------------------------------------------------------ +%% +%% Always fetchs TK of a record. +%% +%%------------------------------------------------------------ +fetchTk(G,N,X) -> + case ic_forms:get_tk(X) of + undefined -> + searchTk(G,ictk:get_IR_ID(G, N, X)); + TK -> + TK + end. + + +%%------------------------------------------------------------ +%% +%% seek type code when not accessible by get_tk/1 +%% +%%------------------------------------------------------------ +searchTk(G,IR_ID) -> + S = ic_genobj:tktab(G), + case catch searchTk(S,IR_ID,typedef) of + {value,TK} -> + TK; + _ -> %% false / exit + case catch searchTk(S,IR_ID,struct) of + {value,TK} -> + TK; + _ -> %% false / exit + case catch searchTk(S,IR_ID,union) of + {value,TK} -> + TK; + _ -> + undefined + end + end + end. + + +searchTk(S,IR_ID,Type) -> + L = lists:flatten(ets:match(S,{'_',Type,'$1','_'})), + case lists:keysearch(IR_ID,2,L) of + {value,TK} -> + {value,TK}; + false -> + searchInsideTks(L,IR_ID) + end. + + +searchInsideTks([],_IR_ID) -> + false; +searchInsideTks([{tk_array,TK,_}|Xs],IR_ID) -> + case searchIncludedTk(TK,IR_ID) of + {value,TK} -> + {value,TK}; + false -> + searchInsideTks(Xs,IR_ID) + end. + + +searchIncludedTk({tk_array,TK,_},IR_ID) -> + searchIncludedTk(TK,IR_ID); +searchIncludedTk({tk_sequence,TK,_},IR_ID) -> + searchIncludedTk(TK,IR_ID); +searchIncludedTk(TK, _IR_ID) when is_atom(TK) -> + false; +searchIncludedTk(TK,IR_ID) -> + case element(2,TK) == IR_ID of + true -> + {value,TK}; + false -> + false + end. + diff --git a/lib/ic/src/icunion.erl b/lib/ic/src/icunion.erl new file mode 100644 index 0000000..38a2d14 --- /dev/null +++ b/lib/ic/src/icunion.erl @@ -0,0 +1,1490 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(icunion). + +-import(ic_codegen, [emit/2, emit/3, emit/4, emit_c_enc_rpt/4, emit_c_dec_rpt/4]). +-import(ic_cbe, [mk_c_type/3, mk_c_type/4]). + +-include("icforms.hrl"). +-include("ic.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([union_gen/4]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +union_gen(G, N, X, c) when is_record(X, union) -> + emit_c_union(G, N, X); +union_gen(_G, _N, _X, _L) -> + ok. + + +%% Emits the union +emit_c_union(G, N, X) -> + %%io:format("Rec = ~p\n",[X]), + case ic_genobj:is_hrlfile_open(G) of + true -> + + %% Sort Union Default = put it last in case list + NewX = #union{ id = X#union.id, + type = X#union.type, + body = mvDefaultToTail(X#union.body), + tk = X#union.tk }, + + UnionScope = [ic_forms:get_id2(NewX) | N], + + case ic_pragma:is_local(G,UnionScope) of + + true -> + + HFd = ic_genobj:hrlfiled(G), + emit_c_union_values(G, N, NewX, HFd), + UnionName = ic_util:to_undersc(UnionScope), + + emit(HFd, "\n#ifndef __~s__\n",[ictype:to_uppercase(UnionName)]), + emit(HFd, "#define __~s__\n",[ictype:to_uppercase(UnionName)]), + ic_codegen:mcomment_light(HFd, + [io_lib:format("Union definition: ~s", + [UnionName])], + c), + emit(HFd, "typedef struct {\n"), + emit(HFd, " ~s _d;\n", [get_c_union_discriminator(G, N, NewX)]), + emit(HFd, " union {\n"), + emit_c_union_values_decl(G, N, NewX, HFd), + emit(HFd, " } _u;\n"), + emit(HFd, "} ~s;\n\n", [UnionName]), + + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, int*, int*);\n", + [ic_util:mk_oe_name(G, "sizecalc_"), UnionName]), + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, ~s*);\n", + [ic_util:mk_oe_name(G, "encode_"), UnionName, UnionName]), + emit(HFd, "int ~s~s(CORBA_Environment *oe_env, char *, int*, ~s*);\n", + [ic_util:mk_oe_name(G, "decode_"), UnionName, UnionName]), + emit(HFd, "\n#endif\n\n"), + create_c_union_file(G, N, NewX, UnionName); + + false -> %% Do not generate included types att all. + ok + end; + false -> + ok + end. + + + +%% Loops over union members and creates members typedefs +emit_c_union_values(G, N, X, Fd) -> + emit_c_union_values_loop(G, N, X, Fd, X#union.body). + +emit_c_union_values_loop(G, N, X, Fd, [CU]) -> + case CU of + {case_dcl,_,Id,Type} -> + case Id of + {array, _AID, _SZ} -> % Check for arrays + mk_array_file(G,N,X,Id,Type,Fd); + _ -> % Elementary types or seq/struct + ok + end; + _ -> + error + end; +emit_c_union_values_loop(G, N, X, Fd, [CU |CUs]) -> + case CU of + {case_dcl,_,Id,Type} -> + case Id of + {array, _AID, _SZ} -> % Check for arrays + mk_array_file(G,N,X,Id,Type,Fd); + _ -> % Elementary types or seq/struct + emit_c_union_values_loop(G, N, X, Fd, CUs) + end; + _ -> + error + end. + + +%% Loops over union members and declares members inside union structure +emit_c_union_values_decl(G, N, X, Fd) -> + emit_c_union_values_decl_loop(G, N, X, Fd, X#union.body). + +emit_c_union_values_decl_loop(G, N, X, Fd, [CU]) -> + case CU of + {case_dcl,_,Id,Type} -> + case Id of + {array, _AID, _SZ} -> % Check for arrays + mk_array_decl(G,N,X,Id,Type,Fd); + _ -> % Elementary types or seq/struct + mk_union_member_decl(G,N,X,Id,Type,Fd), + ok + end; + _ -> + error + end; +emit_c_union_values_decl_loop(G, N, X, Fd, [CU |CUs]) -> + case CU of + {case_dcl,_,Id,Type} -> + case Id of + {array, _AID, _SZ} -> % Check for arrays + mk_array_decl(G,N,X,Id,Type,Fd), + emit_c_union_values_decl_loop(G, N, X, Fd, CUs); + _ -> % Elementary types or seq/struct + mk_union_member_decl(G,N,X,Id,Type,Fd), + emit_c_union_values_decl_loop(G, N, X, Fd, CUs) + end; + _ -> + error + end. + + +%% Makes the declaration for the array in union +mk_array_decl(G,N,X,Id,Type,Fd) -> + emit(Fd, " ~s ~s;\n", + [getCaseTypeStr(G,N,X,Id,Type), + mk_array_name(Id)]). + +mk_array_name({array,Id,D}) -> + ic_forms:get_id2(Id) ++ mk_array_dim(D). + +mk_array_dim([]) -> + ""; +mk_array_dim([{_,_,Dim}|Dims]) -> + "[" ++ Dim ++ "]" ++ mk_array_dim(Dims). + + +%% Creates the array file +mk_array_file(G,N,X,{array,AID,SZ},Type,HFd) -> + ArrayName = ic_util:to_undersc([ic_forms:get_id2(AID),ic_forms:get_id2(X) | N]), + ArrayDim = extract_array_dim(SZ), + emit(HFd, "\n#ifndef __~s__\n",[ictype:to_uppercase(ArrayName)]), + emit(HFd, "#define __~s__\n\n",[ictype:to_uppercase(ArrayName)]), + icstruct:create_c_array_coding_file(G, + N, + {ArrayName,ArrayDim}, + Type, + no_typedef), + emit(HFd, "\n#endif\n\n"). + +extract_array_dim([{_,_,Dim}]) -> + [Dim]; +extract_array_dim([{_,_,Dim}|Dims]) -> + [Dim | extract_array_dim(Dims)]. + + +%% Makes the declaration for the member in union +mk_union_member_decl(G,N,X,Id,Type,Fd) -> + emit(Fd, " ~s ~s;\n", + [getCaseTypeStr(G,N,X,Id,Type), + ic_forms:get_id2(Id)]). + + + + +%% File utilities +create_c_union_file(G, N, X, UnionName) -> + + {Fd , SName} = open_c_coding_file(G, UnionName), + _HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header + HrlFName = filename:basename(ic_genobj:include_file(G)), + ic_codegen:emit_stub_head(G, Fd, SName, c), + emit(Fd, "#include \"~s\"\n\n",[HrlFName]), + + %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Fd = ic_genobj:stubfiled(G), %% Write on stubfile + %% HFd = ic_genobj:hrlfiled(G), %% Write on stubfile header + %% HrlFName = filename:basename(ic_genobj:include_file(G)), + %% emit(Fd, "#include \"~s\"\n\n",[HrlFName]), + %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + put(op_variable_count, 0), + put(tmp_declarations, []), + + %% Write generated code on file + emit_union_sizecount(G, N, X, Fd, UnionName), + emit_union_encode(G, N, X, Fd, UnionName), + emit_union_decode(G, N, X, Fd, UnionName), + file:close(Fd). + +open_c_coding_file(G, Name) -> + SName = string:concat(ic_util:mk_oe_name(G, "code_"), Name), + FName = + ic_file:join(ic_options:get_opt(G, stubdir),ic_file:add_dot_c(SName)), + case file:open(FName, [write]) of + {ok, Fd} -> + {Fd, SName}; + Other -> + exit(Other) + end. + + + + +get_c_union_discriminator(G, N, X) -> + case getDiscrStr(G, N, X#union.type) of + error -> + ic_error:fatal_error(G, {illegal_typecode_for_c, X#union.type, N}); + DiscrStr -> + case ic_code:get_basetype(G, DiscrStr) of + {short, _} -> + "CORBA_short"; + {unsigned,{short, _}} -> + "CORBA_unsigned_short"; + {long, _} -> + "CORBA_long"; + {unsigned,{long, _}} -> + "CORBA_unsigned_long"; + {boolean,_} -> + "CORBA_boolean"; + {char,_} -> + "CORBA_char"; + {enum, EnumType} -> + EnumType; + _ -> + DiscrStr + end + end. + +getDiscrStr(G, N, S) when element(1, S) == scoped_id -> + case ic_symtab:get_full_scoped_name(G, N, S) of + {FSN, _, tk_short, _} -> + ic_util:to_undersc(FSN); + {FSN, _, tk_ushort, _} -> + ic_util:to_undersc(FSN); + {FSN, _, tk_long, _} -> + ic_util:to_undersc(FSN); + {FSN, _, tk_ulong, _} -> + ic_util:to_undersc(FSN); + {FSN, _, tk_boolean, _} -> + ic_util:to_undersc(FSN); + {FSN, _, tk_char, _} -> + ic_util:to_undersc(FSN); + {FSN, _, {tk_enum,_,_,_}, _} -> + ic_util:to_undersc(FSN); + _ -> + error + end; +getDiscrStr(_G, N, X) -> + case X of + {short,_} -> + "CORBA_short"; + {unsigned,{short,_}} -> + "CORBA_unsigned_short"; + {long, _} -> + "CORBA_long"; + {unsigned,{long,_}} -> + "CORBA_unsigned_long"; + {boolean,_} -> + "CORBA_boolean"; + {char,_} -> + "CORBA_char"; + {enum,TID,_,_} -> + ic_util:to_undersc([ic_forms:get_id2(TID) | N]); + _ -> + error + end. + + + + +getCaseTypeStr(G, N, X, I, T) when element(1, T) == scoped_id -> + case catch ic_symtab:get_full_scoped_name(G, N, T) of + {FSN, _, _, _} -> + BT = ic_code:get_basetype(G, ic_util:to_undersc(FSN)), + case isList(BT) of + true -> + BT; + false -> + case BT of + {short,_} -> + "CORBA_short"; + {unsigned,{short,_}} -> + "CORBA_unsigned_short"; + {long, _} -> + "CORBA_long"; + {unsigned,{long,_}} -> + "CORBA_unsigned_long"; + {float,_} -> + "CORBA_float"; + {double,_} -> + "CORBA_double"; + {boolean,_} -> + "CORBA_boolean"; + {char,_} -> + "CORBA_char"; + {wchar,_} -> + "CORBA_wchar"; + {octet,_} -> + "CORBA_octet"; + {string,_} -> + "CORBA_char*"; + {wstring,_} -> + "CORBA_wchar*"; + {sequence,_,_} -> + ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]); + {struct,SID,_,_} -> + ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]); + {enum,EID} -> + EID; + {any, _} -> %% Fix for any type + "CORBA_long"; + _ -> + %%io:format("BT = ~p~n",[BT]), + error + end + end + end; +getCaseTypeStr(_G, N, X, I, T) -> + case T of + {short,_} -> + "CORBA_short"; + {unsigned,{short,_}} -> + "CORBA_unsigned_short"; + {long, _} -> + "CORBA_long"; + {unsigned,{long,_}} -> + "CORBA_unsigned_long"; + {float,_} -> + "CORBA_float"; + {double,_} -> + "CORBA_double"; + {boolean,_} -> + "CORBA_boolean"; + {char,_} -> + "CORBA_char"; + {wchar,_} -> + "CORBA_wchar"; + {octet,_} -> + "CORBA_octet"; + {string,_} -> + "CORBA_char*"; + {wstring,_} -> + "CORBA_wchar*"; + {sequence,_,_} -> + ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]); + {struct,SID,_,_} -> + ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]); + {union,UID,_,_,_} -> + ic_util:to_undersc([ic_forms:get_id2(UID), ic_forms:get_id2(X) | N]); + {any, _} -> %% Fix for any type + "CORBA_long"; + _ -> + error + end. + +isList(L) when is_list(L) -> + true; +isList(_) -> + false. + +%% +%% Sizecount facilities +%% +emit_union_sizecount(G, N, X, Fd, UnionName) -> + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, int* oe_size_count_index, int* oe_size) {\n\n", + [ic_util:mk_oe_name(G, "sizecalc_"), UnionName]), + + emit(Fd, " int oe_malloc_size = 0;\n"), + emit(Fd, " int oe_error_code = 0;\n"), + emit(Fd, " int oe_type = 0;\n"), + emit(Fd, " int oe_tmp = 0;\n"), + emit_union_discr_var_decl(G, N, X, Fd), + + ic_codegen:nl(Fd), + emit(Fd, " if(*oe_size == 0)\n",[]), + AlignName = lists:concat(["*oe_size + sizeof(",UnionName,")"]), + emit(Fd, " *oe_size = ~s;\n\n", [ic_util:mk_align(AlignName)]), + + emit(Fd, " if ((oe_error_code = ei_get_type(oe_env->_inbuf, oe_size_count_index, &oe_type, &oe_tmp)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_get_type", []), + emit(Fd, " return oe_error_code;\n }\n"), + + %%emit(Fd, " if (oe_tmp != 3)\n"), + %%emit(Fd, " return -1;\n\n"), + + emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n", []), + emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit_c_union_discr_sizecount(G, N, X, Fd), + emit(Fd, " /* Calculate union size */\n"), + emit(Fd, " switch(oe_discr) {\n"), + + emit_c_union_loop(G, N, X, Fd, X#union.body, sizecalc), + emit(Fd, " }\n\n"), + + emit(Fd, " *oe_size = ~s;\n",[ic_util:mk_align("*oe_size+oe_malloc_size")]), + emit(Fd, " return 0;\n"), + emit(Fd, "}\n\n\n"). + + +emit_union_discr_var_decl(G, N, X, Fd) -> + UD = get_c_union_discriminator(G, N, X), + case UD of + "CORBA_short" -> + emit(Fd, " long oe_discr = 0;\n"); + "CORBA_unsigned_short" -> + emit(Fd, " unsigned long oe_discr = 0;\n"); + "CORBA_long" -> + emit(Fd, " long oe_discr = 0;\n"); + "CORBA_unsigned_long" -> + emit(Fd, " unsigned long oe_discr = 0;\n"); + "CORBA_boolean" -> + emit(Fd, " int oe_discr = 0;\n"), + emit(Fd, " char oe_bool[256];\n"); + "CORBA_char" -> + emit(Fd, " char oe_discr = 0;\n"); + _T -> + emit(Fd, " int oe_dummy = 0;\n"), + emit(Fd, " ~s oe_discr = 0;\n",[UD]) + end. + + +emit_c_union_discr_sizecount(G, N, X, Fd) -> + emit(Fd, " /* Calculate discriminator size */\n"), + UD = get_c_union_discriminator(G, N, X), + case UD of + "CORBA_short" -> + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_unsigned_short" -> + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_long" -> + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_unsigned_long" -> + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_boolean" -> + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, oe_bool)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"), + emit(Fd, " oe_discr = 0;\n"), + emit(Fd, " }\n"), + emit(Fd, " else if (strcmp(oe_bool, \"true\") == 0) {\n"), + emit(Fd, " oe_discr = 1;\n"), + emit(Fd, " }\n"), + emit(Fd, " else {\n"), + emit_c_dec_rpt(Fd, " ", "not boolean", []), + emit(Fd, " return -1;\n }\n"); + + "CORBA_char" -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, &oe_discr)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + T -> + emit(Fd, " oe_tmp = *oe_size_count_index;\n"), + emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n", [T]), + ?emit_c_dec_rpt(Fd, " ", "oe_size_calc_~s", [T]), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " *oe_size_count_index = oe_tmp;\n"), + emit(Fd, " oe_tmp = oe_env->_iin;\n"), + emit(Fd, " oe_env->_iin = *oe_size_count_index;\n"), + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, NULL, &oe_dummy, &oe_discr)) < 0) {\n", [T]), + ?emit_c_dec_rpt(Fd, " ", "oe_decode_~s", [T]), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " *oe_size_count_index = oe_env->_iin;\n"), + emit(Fd, " oe_env->_iin = oe_tmp;\n\n") + end. + + + +emit_c_union_loop(G, N, X, Fd, CaseList, Case) -> + emit_c_union_loop(G, N, X, Fd, CaseList, false, Case). + +emit_c_union_loop(G, N, X, Fd, [], GotDefaultCase, Case) -> + case GotDefaultCase of + false -> + emit_c_union_valueless_discriminator(G, N, X, Fd, Case) + end; +emit_c_union_loop(G, N, X, Fd, [CU|CUs], GotDefaultCase, Case) -> + case CU of + {case_dcl,CaseList,I,T} -> + GotDefaultCase = emit_c_union_case(G, N, X, Fd, I, T, CaseList, Case), + emit_c_union_loop(G, N, X, Fd, CUs, GotDefaultCase, Case); + _ -> + error + end. + +emit_c_union_valueless_discriminator(_G, _N, _X, Fd, Case) -> + emit(Fd, " default:\n"), + case Case of + sizecalc -> + emit(Fd, " {\n"), + emit(Fd, " char oe_undefined[15];\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, " + "oe_size_count_index, oe_undefined)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " }\n"); + encode -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"undefined\")) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"); + decode -> + emit(Fd, " {\n"), + emit(Fd, " char oe_undefined[15];\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, " + "oe_undefined)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if (strcmp(oe_undefined, \"undefined\") != 0) {\n"), + emit_c_dec_rpt(Fd, " ", "undefined", []), + emit(Fd, " return -1;\n }\n"), + emit(Fd, " }\n") + end. + + +emit_c_union_case(G, N, X, Fd, I, T, [{default,_}], Case) -> + emit(Fd, " default:\n"), + case Case of + sizecalc -> + getCaseTypeSizecalc(G, N, X, Fd, I, T); + encode -> + getCaseTypeEncode(G, N, X, Fd, I, T); + decode -> + getCaseTypeDecode(G, N, X, Fd, I, T) + end, + true; +emit_c_union_case(G, N, X, Fd, I, T, [{Bool,_}], Case) -> %% Boolean discriminator + case Bool of + 'TRUE' -> + emit(Fd, " case 1:\n"); + 'FALSE' -> + emit(Fd, " case 0:\n") + end, + case Case of + sizecalc -> + getCaseTypeSizecalc(G, N, X, Fd, I, T); + encode -> + getCaseTypeEncode(G, N, X, Fd, I, T); + decode -> + getCaseTypeDecode(G, N, X, Fd, I, T) + end, + emit(Fd, " break;\n\n"), + false; +emit_c_union_case(G, N, X, Fd, I, T, [{Bool,_}|Rest], Case) -> %% Boolean discriminator + case Bool of + 'TRUE' -> + emit(Fd, " case 1:\n"); + 'FALSE' -> + emit(Fd, " case 0:\n") + end, + emit_c_union_case(G, N, X, Fd, I, T, Rest, Case), + false; +emit_c_union_case(G, N, X, Fd, I, T, [{_,_,NrStr}], Case) -> %% Integer type discriminator + case get_c_union_discriminator(G, N, X) of + "CORBA_char" -> + emit(Fd, " case \'~s\':\n",[NrStr]); + _ -> + emit(Fd, " case ~s:\n",[NrStr]) + end, + case Case of + sizecalc -> + getCaseTypeSizecalc(G, N, X, Fd, I, T); + encode -> + getCaseTypeEncode(G, N, X, Fd, I, T); + decode -> + getCaseTypeDecode(G, N, X, Fd, I, T) + end, + emit(Fd, " break;\n\n"), + false; +emit_c_union_case(G, N, X, Fd, I, T, [{_,_,NrStr}|Rest], Case) -> %% Integer type discriminator + emit(Fd, " case ~s:\n",[NrStr]), + emit_c_union_case(G, N, X, Fd, I, T, Rest, Case), + false; +emit_c_union_case(G, N, X, Fd, I, T, [{scoped_id,_,_,[EID]}], Case) -> %% Enumerant type discriminator + SID = ic_util:to_undersc([EID|get_c_union_discriminator_scope(G, N, X)]), + %%io:format("SID = ~p~n",[SID]), + emit(Fd, " case ~s:\n",[SID]), + case Case of + sizecalc -> + getCaseTypeSizecalc(G, N, X, Fd, I, T); + encode -> + getCaseTypeEncode(G, N, X, Fd, I, T); + decode -> + getCaseTypeDecode(G, N, X, Fd, I, T) + end, + emit(Fd, " break;\n\n"), + false; +emit_c_union_case(G, N, X, Fd, I, T, [{scoped_id,_,_,[EID]}|Rest], Case) -> %% Enumerant type discriminator + SID = ic_util:to_undersc([EID|get_c_union_discriminator_scope(G, N, X)]), + %%io:format("SID = ~p~n",[SID]), + emit(Fd, " case ~s:\n",[SID]), + emit_c_union_case(G, N, X, Fd, I, T, Rest, Case), + false. + + +%% +%% Returns the enumerant discriminator scope +%% +get_c_union_discriminator_scope(G, N, X) -> + {FullScopedName, _, _TK, _} = ic_symtab:get_full_scoped_name(G, N, X#union.type), + BT = case ic_code:get_basetype(G, ic_util:to_undersc(FullScopedName)) of + {enum,ST} -> + ST; + Other -> + Other + end, + tl(lists:reverse(string:tokens(BT,"_"))). %% Ugly work arround + + + + + +getCaseTypeSizecalc(G, N, X, Fd, I, T) when element(1, T) == scoped_id -> + case ic_fetch:member2type(G,X,I) of + ushort -> + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ushort:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + ulong -> + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + short -> + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + long -> + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + float -> + emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "float:ei_decode_double", []), + emit(Fd, " return oe_error_code;\n }\n"); + double -> + emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "double:ei_decode_double", []), + emit(Fd, " return oe_error_code;\n }\n"); + boolean -> + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"); + char -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + octet -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "octet:ei_decode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + string -> + emit(Fd, " if ((oe_error_code = ei_get_type(oe_env->_inbuf, oe_size_count_index, &oe_type, &oe_tmp)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ei_get_type", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_malloc_size = ~s;\n",[ic_util:mk_align("oe_malloc_size+oe_tmp+1")]); + any -> %% Fix for any type + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + + _ -> + case getCaseTypeStr(G, N, X, I, T) of + "erlang_pid" -> + emit(Fd, " if ((oe_error_code = ei_decode_pid(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n", + []), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_pid", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_port" -> + emit(Fd, " if ((oe_error_code = ei_decode_port(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n", + []), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_port", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_ref" -> + emit(Fd, " if ((oe_error_code = ei_decode_ref(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n", + []), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_ref", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_term" -> + emit(Fd, " if ((oe_error_code = ei_decode_term(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n", + []), + ?emit_c_dec_rpt(Fd, " ", "ei_deoce_term", []), + emit(Fd, " return oe_error_code;\n }\n"); + + Other -> + + emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [Other]), + ?emit_c_dec_rpt(Fd, " ", "oe_sizecalc_~s", [Other]), + emit(Fd, " return oe_error_code;\n }\n") + end + end; +getCaseTypeSizecalc(G, N, X, Fd, I, T) -> + case I of + {array,_,_} -> + ArrayName = ic_util:to_undersc([ic_forms:get_id2(I),ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [ArrayName]), + ?emit_c_dec_rpt(Fd, " ", "oe_sizecalc_~s", [ArrayName]), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + case T of + {short,_} -> + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + {unsigned,{short,_}} -> + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ushort:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + {long, _} -> + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + {unsigned,{long,_}} -> + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + {float,_} -> + emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "float:ei_decode_double", []), + emit(Fd, " return oe_error_code;\n }"); + {double,_} -> + emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "double:ei_decode_double", []), + emit(Fd, " return oe_error_code;\n }\n"); + {boolean,_} -> + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"); + {char,_} -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + {octet,_} -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "octet:ei_decode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + {string,_} -> + emit(Fd, " if ((oe_error_code = ei_get_type(oe_env->_inbuf, oe_size_count_index, &oe_type, &oe_tmp)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ei_get_type", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_malloc_size = ~s;\n",[ic_util:mk_align("oe_malloc_size+oe_tmp+1")]); + {sequence,_,_} -> + SeqName = ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [SeqName]), + ?emit_c_dec_rpt(Fd, " ", "sequence:oe_sizecalc_~s", [SeqName]), + emit(Fd, " return oe_error_code;\n }\n"); + {struct,SID,_,_} -> + StructName = ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [StructName]), + ?emit_c_dec_rpt(Fd, " ", "struct:oe_sizecalc_~s", [StructName]), + emit(Fd, " return oe_error_code;\n }\n"); + {union,UID,_,_,_} -> + UnionName = ic_util:to_undersc([ic_forms:get_id2(UID), ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_sizecalc_~s(oe_env, oe_size_count_index, &oe_malloc_size)) < 0) {\n", + [UnionName]), + ?emit_c_dec_rpt(Fd, " ", "union:oe_sizecalce_~s", [UnionName]), + emit(Fd, " return oe_error_code;\n }\n"); + {any, _} -> %% Fix for any type + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, oe_size_count_index, 0)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "any:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end + end. + + + + + +%% +%% Encode facilities +%% +emit_union_encode(G, N, X, Fd, UnionName) -> + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, ~s* oe_rec) {\n\n", + [ic_util:mk_oe_name(G, "encode_"), UnionName, UnionName]), + + emit(Fd, " int oe_error_code = 0;\n\n"), + + emit(Fd, " if ((oe_error_code = oe_ei_encode_tuple_header(oe_env, 3)) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"~s\")) < 0) {\n", + [UnionName]), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit_c_union_discr_encode(G, N, X, Fd), + emit(Fd, " /* Encode union */\n"), + emit(Fd, " switch(oe_rec->_d) {\n"), + emit_c_union_loop(G, N, X, Fd, X#union.body, encode), + emit(Fd, " }\n\n"), + emit(Fd, " return 0;\n"), + emit(Fd, "}\n\n\n"). + + +emit_c_union_discr_encode(G, N, X, Fd) -> + emit(Fd, " /* Encode descriminator */\n"), + UD = get_c_union_discriminator(G, N, X), + case UD of + "CORBA_short" -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_d)) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_unsigned_short" -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_d)) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_long" -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_d)) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_unsigned_long" -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_d)) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_boolean" -> + emit(Fd, " switch(oe_rec->_d) {\n"), + emit(Fd, " case 0:\n"), + emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"false\")) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " case 1:\n"), + emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"true\")) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " default:\n"), + emit_c_enc_rpt(Fd, " ", "boolean failure", []), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n\n"); + "CORBA_char" -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_d)) < 0) {\n"), + emit_c_enc_rpt(Fd, " ", "oe_ei_encode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + T -> + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, oe_rec->_d)) < 0) {\n", [T]), + ?emit_c_enc_rpt(Fd, " ", "oe_encode_~s", [T]), + emit(Fd, " return oe_error_code;\n }\n") + end. + + +getCaseTypeEncode(G, N, X, Fd, I, T) when element(1, T) == scoped_id -> + case ic_fetch:member2type(G,X,I) of + ushort -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "ushort:oe_ei_encode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + ulong -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "ulong:oe_ei_encode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + short -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "short:oe_ei_encode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + long -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "long:oe_ei_encode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + float -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_double(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "float:oe_ei_encode_double", []), + emit(Fd, " return oe_error_code;\n }\n"); + double -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_double(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "double:oe_ei_encode_double", []), + emit(Fd, " return oe_error_code;\n }\n"); + boolean -> + emit(Fd, " switch(oe_rec->_u.~s) {\n",[ic_forms:get_id2(I)]), + emit(Fd, " case 0:\n"), + emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"false\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean:oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " case 1:\n"), + emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"true\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean:oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " default:\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean failure", []), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n"); + char -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "char:oe_ei_encode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + octet -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "octet:oe_ei_encode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + string -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_string(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_string", []), + emit(Fd, " return oe_error_code;\n }\n"); + struct -> + case ic_cbe:mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_pid(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_pid", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_port" -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_port(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_port", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_ref" -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_ref(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_ref", []), + emit(Fd, " return oe_error_code;\n }\n"); + "ETERM*" -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_term(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_term", []), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T), ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "oe_encode_~s", + [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n") + end; + sequence -> + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "sequence:oe_encode_~s", + [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n"); + array -> + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "array:oe_encode_~s", + [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n"); + union -> + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "union:oe_encode_~s", + [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n"); + enum -> + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "enum:oe_encode_~s", + [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n"); + any -> %% Fix for any type + emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "enum:oe_ei_encodelong", []), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end; +getCaseTypeEncode(G, N, X, Fd, I, T) -> + case I of + {array,AID,_} -> + ArrayName = ic_util:to_undersc([ic_forms:get_id2(AID),ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ArrayName,ic_forms:get_id2(AID)]), + ?emit_c_enc_rpt(Fd, " ", "array:oe_encode_~s", [ArrayName]), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + case T of + {short,_} -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "short:oe_ei_encode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + {unsigned,{short,_}} -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "ushort:oe_ei_encode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + {long, _} -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_long(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "long:oe_ei_encode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + {unsigned,{long,_}} -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_ulong(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "ulong:oe_ei_encode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + {float,_} -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_double(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "float:oe_ei_encode_double", []), + emit(Fd, " return oe_error_code;\n }\n"); + {double,_} -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_double(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "double:oe_ei_encode_double", []), + emit(Fd, " return oe_error_code;\n }\n"); + {boolean,_} -> + emit(Fd, " switch(oe_rec->_u.~s) {\n",[ic_forms:get_id2(I)]), + emit(Fd, " case 0:\n"), + emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"false\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean:oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " case 1:\n"), + emit(Fd, " if ((oe_error_code = oe_ei_encode_atom(oe_env, \"true\")) < 0) {\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean:oe_ei_encode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " break;\n"), + emit(Fd, " default:\n"), + ?emit_c_enc_rpt(Fd, " ", "boolean failure", []), + emit(Fd, " return -1;\n"), + emit(Fd, " }\n"); + {char,_} -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "char:oe_ei_encode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + {octet,_} -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_char(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "octet:oe_ei_encode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + {string,_} -> + emit(Fd, " if ((oe_error_code = oe_ei_encode_string(oe_env, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "oe_ei_encode_string", []), + emit(Fd, " return oe_error_code;\n }\n"); + {sequence,_,_} -> + SeqName = ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [SeqName,ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "sequence:oe_encode_~s", [SeqName]), + emit(Fd, " return oe_error_code;\n }\n"); + {struct,SID,_,_} -> + StructName = ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [StructName,ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "struct:oe_encode_~s", [StructName]), + emit(Fd, " return oe_error_code;\n }\n"); + {union,UID,_,_,_} -> + UnionName = ic_util:to_undersc([ic_forms:get_id2(UID), ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_encode_~s(oe_env, &oe_rec->_u.~s)) < 0) {\n", + [UnionName,ic_forms:get_id2(I)]), + ?emit_c_enc_rpt(Fd, " ", "union:oe_encode_~s", [UnionName]), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end + end. + + + + +%% +%% Decode facilities +%% +emit_union_decode(G, N, X, Fd, UnionName) -> + emit(Fd, "int ~s~s(CORBA_Environment *oe_env, char *oe_first, int* oe_index, ~s* oe_rec) {\n\n", + [ic_util:mk_oe_name(G, "decode_"), UnionName, UnionName]), + + emit(Fd, " int oe_error_code = 0;\n"), + emit(Fd, " int oe_tmp = 0;\n"), + emit(Fd, " char oe_union_name[256];\n\n"), + + emit(Fd, " if((char*) oe_rec == oe_first)\n",[]), + AlignName = lists:concat(["*oe_index + sizeof(",UnionName,")"]), + emit(Fd, " *oe_index = ~s;\n\n", [ic_util:mk_align(AlignName)]), + + emit(Fd, " if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, &oe_env->_iin, &oe_tmp)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_tuple_header", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_union_name)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit_c_union_discr_decode(G, N, X, Fd), + emit(Fd, " /* Decode union */\n"), + emit(Fd, " switch(oe_rec->_d) {\n"), + emit_c_union_loop(G, N, X, Fd, X#union.body, decode), + emit(Fd, " }\n\n"), + + emit(Fd, " *oe_index = ~s;\n", [ic_util:mk_align("*oe_index")]), + emit(Fd, " return 0;\n"), + emit(Fd, "}\n\n\n"). + + +emit_c_union_discr_decode(G, N, X, Fd) -> + emit(Fd, " /* Decode descriminator */\n"), + UD = get_c_union_discriminator(G, N, X), + case UD of + "CORBA_short" -> + emit(Fd, " {\n"), + emit(Fd, " long oe_long;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_long)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_rec->_d = (short) oe_long;\n\n"), + emit(Fd, " if (oe_rec->_d != oe_long)\n return -1;\n"), + emit(Fd, " }\n\n"); + "CORBA_unsigned_short" -> + emit(Fd, " {\n"), + emit(Fd, " unsigned long oe_ulong;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_ulong)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "unshort:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_rec->_d = (unsigned short) oe_ulong;\n\n"), + emit(Fd, " if (oe_rec->_d != oe_ulong)\n return -1;\n"), + emit(Fd, " }\n\n"); + "CORBA_long" -> + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_d)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_unsigned_long" -> + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_d)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + "CORBA_boolean" -> + emit(Fd, " {\n"), + emit(Fd, " char oe_bool[25];\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_bool)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"), + emit(Fd, " oe_rec->_d = 0;\n"), + emit(Fd, " }else if (strcmp(oe_bool, \"true\") == 0) {\n"), + emit(Fd, " oe_rec->_d = 1;\n"), + emit(Fd, " } else {\n"), + emit_c_dec_rpt(Fd, " ", "boolean failure", []), + emit(Fd, " return -1;\n }\n"), + emit(Fd, " }\n\n"); + "CORBA_char" -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_d)) < 0) {\n"), + emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + T -> + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_d)) < 0) {\n", + [T]), + ?emit_c_dec_rpt(Fd, " ", "oe_decode_~s", [T]), + emit(Fd, " return oe_error_code;\n }\n") + end. + + + +getCaseTypeDecode(G, N, X, Fd, I, T) when element(1, T) == scoped_id -> + case ic_fetch:member2type(G,X,I) of + ushort -> + emit(Fd, " {\n"), + emit(Fd, " unsigned long oe_ulong;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_ulong)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ushort:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_rec->_u.~s = (unsigned short) oe_ulong;\n\n",[ic_forms:get_id2(I)]), + emit(Fd, " if (oe_rec->_u.~s != oe_ulong)\n return -1;\n",[ic_forms:get_id2(I)]), + emit(Fd, " }\n"); + ulong -> + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + short -> + emit(Fd, " {\n"), + emit(Fd, " long oe_long;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_long)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_rec->_u.~s = (short) oe_long;\n\n",[ic_forms:get_id2(I)]), + emit(Fd, " if (oe_rec->_u.~s != oe_long)\n return -1;\n",[ic_forms:get_id2(I)]), + emit(Fd, " }\n"); + long -> + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + float -> + emit(Fd, " {\n"), + emit(Fd, " double oe_double;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, &oe_env->_iin, &oe_double)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "float:ei_decode_double", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_rec->_u.~s = (float) oe_double;\n",[ic_forms:get_id2(I)]), + emit(Fd, " }\n"); + double -> + emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "double:ei_decode_double", []), + emit(Fd, " return oe_error_code;\n }\n"); + boolean -> + emit(Fd, " {\n"), + emit(Fd, " char oe_bool[25];\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_bool)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"), + emit(Fd, " oe_rec->_u.~s = 0;\n",[ic_forms:get_id2(I)]), + emit(Fd, " } else if (strcmp(oe_bool, \"true\") == 0) {\n"), + emit(Fd, " oe_rec->_u.~s = 1;\n",[ic_forms:get_id2(I)]), + emit(Fd, " } else {\n"), + ?emit_c_dec_rpt(Fd, " ", "boolean failure", []), + emit(Fd, " return -1;\n }\n"), + emit(Fd, " }\n"); + char -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + octet -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "octet:ei_decode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + string -> + emit(Fd, " {\n"), + emit(Fd, " int oe_type = 0;\n"), + emit(Fd, " int oe_string_ctr = 0;\n\n"), + + emit(Fd, " (int) ei_get_type(oe_env->_inbuf, &oe_env->_iin, &oe_type, &oe_string_ctr);\n\n"), + + emit(Fd, " oe_rec->_u.~s = (void *) (oe_first + *oe_index);\n\n",[ic_forms:get_id2(I)]), + + emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->_inbuf, &oe_env->_iin, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " *oe_index = ~s;\n",[ic_util:mk_align("*oe_index+oe_string_ctr+1")]), + emit(Fd, " }\n"); + struct -> + case ic_cbe:mk_c_type(G, N, T, evaluate_not) of + "erlang_pid" -> + emit(Fd, " if ((oe_error_code = ei_decode_pid(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_pid", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_port" -> + emit(Fd, " if ((oe_error_code = ei_decode_port(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_port", []), + emit(Fd, " return oe_error_code;\n }\n"); + "erlang_ref" -> + emit(Fd, " if ((oe_error_code = ei_decode_ref(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_ref", []), + emit(Fd, " return oe_error_code;\n }\n"); + "ETERM*" -> + emit(Fd, " if ((oe_error_code = ei_decode_term(oe_env->_inbuf, &oe_env->_iin, (void **)&oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_term", []), + emit(Fd, " return oe_error_code;\n }\n"); + + _ -> + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "oe_decode_~s", + [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n") + end; + sequence -> + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "sequence:oe_decode_~s", + [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n"); + array -> + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "array:oe_decode_~s", [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n"); + union -> + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "union:oe_decode_~s", [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n"); + enum -> + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n", + [getCaseTypeStr(G, N, X, I, T),ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "enum:oe_decode_~s", [getCaseTypeStr(G, N, X, I, T)]), + emit(Fd, " return oe_error_code;\n }\n"); + any -> %% Fix for any type + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "any:ei_decodelong", []), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end; +getCaseTypeDecode(G, N, X, Fd, I, T) -> + case I of + {array,AID,_} -> + ArrayName = ic_util:to_undersc([ic_forms:get_id2(AID),ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, oe_rec->_u.~s)) < 0) {\n", + [ArrayName,ic_forms:get_id2(AID)]), + ?emit_c_dec_rpt(Fd, " ", "array:oe_decode_~s", [ArrayName]), + emit(Fd, " return oe_error_code;\n }\n"); + _ -> + case T of + {short,_} -> + emit(Fd, " {\n"), + emit(Fd, " long oe_long;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_long)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "short:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_rec->_u.~s = (short) oe_long;\n\n",[ic_forms:get_id2(I)]), + emit(Fd, " if (oe_rec->_u.~s != oe_long)\n return -1;\n",[ic_forms:get_id2(I)]), + emit(Fd, " }\n"); + {unsigned,{short,_}} -> + emit(Fd, " {\n"), + emit(Fd, " unsigned long oe_ulong;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_ulong)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "ushort:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_rec->_u.~s = (unsigned short) oe_ulong;\n\n",[ic_forms:get_id2(I)]), + emit(Fd, " if (oe_rec->_u.~s != oe_ulong)\n return -1;\n",[ic_forms:get_id2(I)]), + emit(Fd, " }\n"); + {long, _} -> + emit(Fd, " if ((oe_error_code = ei_decode_long(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "long:ei_decode_long", []), + emit(Fd, " return oe_error_code;\n }\n"); + {unsigned,{long,_}} -> + emit(Fd, " if ((oe_error_code = ei_decode_ulong(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "ulong:ei_decode_ulong", []), + emit(Fd, " return oe_error_code;\n }\n"); + {float,_} -> + emit(Fd, " {\n"), + emit(Fd, " double oe_double;\n"), + emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, &oe_env->_iin, &oe_double)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "float:ei_decode_double", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " oe_rec->_u.~s = (float) oe_double;\n",[ic_forms:get_id2(I)]), + emit(Fd, " }\n"); + {double,_} -> + emit(Fd, " if ((oe_error_code = ei_decode_double(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "dobule:ei_decode_double", []), + emit(Fd, " return oe_error_code;\n }\n"); + {boolean,_} -> + emit(Fd, " {\n"), + emit(Fd, " char oe_bool[25];\n\n"), + emit(Fd, " if ((oe_error_code = ei_decode_atom(oe_env->_inbuf, &oe_env->_iin, oe_bool)) < 0) {\n"), + ?emit_c_dec_rpt(Fd, " ", "boolean:ei_decode_atom", []), + emit(Fd, " return oe_error_code;\n }\n"), + emit(Fd, " if (strcmp(oe_bool, \"false\") == 0) {\n"), + emit(Fd, " oe_rec->_u.~s = 0;\n",[ic_forms:get_id2(I)]), + emit(Fd, " } else if (strcmp(oe_bool, \"true\") == 0) {\n"), + emit(Fd, " oe_rec->_u.~s = 1;\n",[ic_forms:get_id2(I)]), + emit(Fd, " } else {\n"), + ?emit_c_dec_rpt(Fd, " ", "boolean failure", []), + emit(Fd, " return -1;\n }\n"), + emit(Fd, " }\n"); + {char,_} -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "char:ei_decode_char", []), + emit(Fd, " return oe_error_code;\n }\n"); + {octet,_} -> + emit(Fd, " if ((oe_error_code = ei_decode_char(oe_env->_inbuf, &oe_env->_iin, &oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + emit(Fd, " return oe_error_code;\n }\n"); + {string,_} -> + emit(Fd, " {\n"), + emit(Fd, " int oe_type = 0;\n"), + emit(Fd, " int oe_string_ctr = 0;\n\n"), + + emit(Fd, " (int) ei_get_type(oe_env->_inbuf, &oe_env->_iin, &oe_type, &oe_string_ctr);\n\n"), + + emit(Fd, " oe_rec->_u.~s = (void *) (oe_first + *oe_index);\n\n",[ic_forms:get_id2(I)]), + + emit(Fd, " if ((oe_error_code = ei_decode_string(oe_env->_inbuf, &oe_env->_iin, oe_rec->_u.~s)) < 0) {\n", + [ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "ei_decode_string", []), + emit(Fd, " return oe_error_code;\n }\n"), + + emit(Fd, " *oe_index = ~s;\n",[ic_util:mk_align("*oe_index+oe_string_ctr+1")]), + emit(Fd, " }\n"); + {sequence,_,_} -> + SeqName = ic_util:to_undersc([ic_forms:get_id2(I), ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n", + [SeqName,ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "sequence:oe_decode_~s", [SeqName]), + emit(Fd, " return oe_error_code;\n }\n"); + {struct,SID,_,_} -> + StructName = ic_util:to_undersc([ic_forms:get_id2(SID), ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n", + [StructName,ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "struct:oe_decode_~s", [StructName]), + emit(Fd, " return oe_error_code;\n }\n"); + {union,UID,_,_,_} -> + UnionName = ic_util:to_undersc([ic_forms:get_id2(UID), ic_forms:get_id2(X) | N]), + emit(Fd, " if ((oe_error_code = oe_decode_~s(oe_env, oe_first, oe_index, &oe_rec->_u.~s)) < 0) {\n", + [UnionName,ic_forms:get_id2(I)]), + ?emit_c_dec_rpt(Fd, " ", "union:oe_decode_~s", [UnionName]), + emit(Fd, " return oe_error_code;\n }"); + _ -> + ic_error:fatal_error(G, {illegal_typecode_for_c, T, N}) + end + end. + +mvDefaultToTail(CDclL) -> + mvDefaultToTail(CDclL,[],[]). + + +mvDefaultToTail([], F, FD) -> + lists:reverse(F) ++ FD; +mvDefaultToTail([{case_dcl,CaseList,I,T}|Rest], Found, FoundDefault) -> + case lists:keysearch(default, 1, CaseList) of + {value,Default} -> + NewCaseList = lists:delete(Default, CaseList) ++ [Default], + mvDefaultToTail(Rest, Found, [{case_dcl,NewCaseList,I,T}|FoundDefault]); + false -> + mvDefaultToTail(Rest, [{case_dcl,CaseList,I,T}|Found], FoundDefault) + end. + + diff --git a/lib/ic/src/icyeccpre.hrl b/lib/ic/src/icyeccpre.hrl new file mode 100644 index 0000000..71b02b7 --- /dev/null +++ b/lib/ic/src/icyeccpre.hrl @@ -0,0 +1,124 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + + +-export([parse/1, parse_and_scan/1, format_error/1]). + +-import(lists, [reverse/1]). + +-ifdef(JAM). +-compile([{parse_transform,jam_yecc_pj},pj]). +-endif. + + +-include("icforms.hrl"). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% The parser generator will insert appropriate declarations before this line.% + +parse(Tokens) -> + case catch yeccpars1(Tokens, false, 0, [], []) of + error -> + Errorline = + if Tokens == [] -> 0; true -> element(2, hd(Tokens)) end, + {error, + {Errorline, ?MODULE, "syntax error at or after this line."}}; + Other -> + Other + end. + +parse_and_scan({Mod, Fun, Args}) -> + case apply(Mod, Fun, Args) of + {eof, _} -> + {ok, eof}; + {error, Descriptor, _} -> + {error, Descriptor}; + {ok, Tokens, _} -> + yeccpars1(Tokens, {Mod, Fun, Args}, 0, [], []) + end. + +format_error(Message) -> + case io_lib:deep_char_list(Message) of + true -> + Message; + _ -> + io_lib:write(Message) + end. + +% To be used in grammar files to throw an error message to the parser toplevel. +% Doesn't have to be exported! +return_error(Line, Message) -> + throw({error, {Line, ?MODULE, Message}}). + + +% Don't change yeccpars1/6 too much, it is called recursively by yeccpars2/8! +yeccpars1([Token | Tokens], Tokenizer, State, States, Vstack) -> + yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, + Tokenizer); +yeccpars1([], {M, F, A}, State, States, Vstack) -> + case catch apply(M, F, A) of + {eof, Endline} -> + {error, {Endline, ?MODULE, "end_of_file"}}; + {error, Descriptor, _Endline} -> + {error, Descriptor}; + {'EXIT', Reason} -> + {error, {0, ?MODULE, Reason}}; + {ok, Tokens, _Endline} -> + case catch yeccpars1(Tokens, {M, F, A}, State, States, Vstack) of + error -> + Errorline = element(2, hd(Tokens)), + {error, {Errorline, ?MODULE, + "syntax error at or after this line."}}; + Other -> + Other + end + end; +yeccpars1([], false, State, States, Vstack) -> + yeccpars2(State, '$end', States, Vstack, {'$end', 999999}, [], false). + +% For internal use only. +yeccerror(Token) -> + {error, + {element(2, Token), ?MODULE, + ["syntax error before: ", yecctoken2string(Token)]}}. + +yecctoken2string({atom, _, A}) -> io_lib:write(A); +yecctoken2string({integer,_,N}) -> io_lib:write(N); +yecctoken2string({float,_,F}) -> io_lib:write(F); +yecctoken2string({char,_,C}) -> io_lib:write_char(C); +yecctoken2string({var,_,V}) -> io_lib:format("~s", [V]); +yecctoken2string({string,_,S}) -> io_lib:write_string(S); +yecctoken2string({reserved_symbol, _, A}) -> io_lib:format("~w", [A]); +yecctoken2string({'dot', _}) -> "'.'"; +yecctoken2string({'$end', _}) -> + []; +yecctoken2string({Other, _}) when is_atom(Other) -> + io_lib:format("~w", [Other]); +yecctoken2string({_, _, Other}) when is_list(Other) andalso is_number(hd(Other)) -> + Other; +yecctoken2string({_, _, Other}) -> + io_lib:format("~p", [Other]); +yecctoken2string(Other) -> + io_lib:write(Other). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk new file mode 100644 index 0000000..6f973e3 --- /dev/null +++ b/lib/ic/vsn.mk @@ -0,0 +1,13 @@ +IC_VSN = 4.2.23 + +TICKETS = OTP-8201 + +TICKETS_4.2.22 = OTP-8088 + +TICKETS_4.2.21 = OTP-7982 + +TICKETS_4.2.20 = OTP-7837 + +TICKETS_4.2.19 = OTP-7595 + +TICKETS_4.2.18 = OTP-7313 diff --git a/lib/orber/AUTHORS b/lib/orber/AUTHORS new file mode 100644 index 0000000..a77bdcf --- /dev/null +++ b/lib/orber/AUTHORS @@ -0,0 +1,8 @@ +Original Authors: +Lars Thorsen +Per Danielsson +Peter Lundell +Niclas Eklund +Babbis Xagorarakis + +Contributors: diff --git a/lib/orber/COSS/CosNaming/CosNaming_BindingIterator_impl.erl b/lib/orber/COSS/CosNaming/CosNaming_BindingIterator_impl.erl new file mode 100644 index 0000000..7d1791a --- /dev/null +++ b/lib/orber/COSS/CosNaming/CosNaming_BindingIterator_impl.erl @@ -0,0 +1,93 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: CosNaming_BindingIterator_impl.erl +%% +%%----------------------------------------------------------------- +-module('CosNaming_BindingIterator_impl'). + +-include_lib("orber/include/corba.hrl"). +-include("CosNaming.hrl"). +-include("orber_cosnaming.hrl"). + + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([init/1, terminate/2, code_change/3]). +-export([next_one/1, next_n/2, destroy/1]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External interface functions +%%----------------------------------------------------------------- +%%----------------------------------------------------------------- +%% Func: init/1 +%% Args: +%% Returns: +%%----------------------------------------------------------------- +init(State) -> + {ok, State}. + +%%----------------------------------------------------------------- +%% Func: terminate/2 +%% Args: +%% Returns: +%%----------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +next_one([]) -> + NoBinding = #'CosNaming_Binding'{binding_name=[], + binding_type=nobject}, + {reply, {false, NoBinding}, []}; +next_one([Binding]) -> + {reply, {true, Binding}, []}; +next_one([Binding|Rest]) -> + {reply, {true, Binding}, Rest}. + +next_n([], _) -> + {reply, {false, []}, []}; +next_n(List, HowMany) -> + {More, Acc, NewList} = split(List, HowMany, []), + {reply, {More, Acc}, NewList}. + +split([], _, Acc) -> + {false, Acc, []}; +split(Rest, 0, Acc) -> + {true, Acc, Rest}; +split([H|T], N, Acc) -> + split(T, N-1, [H|Acc]). + + +destroy(OE_State) -> + {stop, normal, ok, OE_State}. + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- diff --git a/lib/orber/COSS/CosNaming/CosNaming_NamingContextExt_impl.erl b/lib/orber/COSS/CosNaming/CosNaming_NamingContextExt_impl.erl new file mode 100644 index 0000000..84db0b8 --- /dev/null +++ b/lib/orber/COSS/CosNaming/CosNaming_NamingContextExt_impl.erl @@ -0,0 +1,751 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: CosNaming_NamingContextExt_impl.erl +%% Modified: +%% +%%----------------------------------------------------------------- +%% README: +%% (1) +%% +%%----------------------------------------------------------------- +-module('CosNaming_NamingContextExt_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/src/orber_iiop.hrl"). +-include("CosNaming.hrl"). +-include("CosNaming_NamingContext.hrl"). +-include("CosNaming_NamingContextExt.hrl"). +-include("orber_cosnaming.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +%% Mandatory callbacks +-export([init/1, + terminate/2, + code_change/3]). + +%% Inherrit from CosNaming::NamingContext +-export([bind/4, + rebind/4, + bind_context/4, + rebind_context/4, + resolve/3, + unbind/3, + new_context/2, + bind_new_context/3, + list/3, + destroy/2]). + +%% CosNaming::NamingContextExt +-export([to_string/3, + to_name/3, + to_url/4, + resolve_str/3]). + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([dump/0, + install/2]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- +%% DEBUG INFO +-define(DEBUG_LEVEL, 5). + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : init/1 +%% Description: Initiates the server +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%%---------------------------------------------------------------------- +init([]) -> + {ok, term_to_binary('undefined')}; + +init(DBKey) -> + _F = ?write_function(#orber_CosNaming{name_context=DBKey, + nameindex=[]}), + write_result(mnesia:transaction(_F)), + {ok, DBKey}. + +%%---------------------------------------------------------------------% +%% Function : terminate +%% Description: Shutdown the server +%% Returns : any (ignored by gen_server) +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> + ok. + +%%---------------------------------------------------------------------% +%% Function : code_change +%% Description: Convert process state when code is changed +%% Returns : {ok, State} +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------% +%% Function : install +%% Arguments : Timeout - abort if timeout triggered. +%% Options - mnesia options +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +install(Timeout, Options) -> + %% Fetch a list of the defined tables to see if 'CosNaming' is defined. + AllTabs = mnesia:system_info(tables), + DB_tables_created = + case lists:member('orber_CosNaming', AllTabs) of + true -> + case lists:member({local_content, true}, + Options) of + true-> + mnesia:add_table_copy('orber_CosNaming', + node(), + ram_copies); + _-> + mnesia:create_table('orber_CosNaming',[{attributes, + record_info(fields, + 'orber_CosNaming')} + |Options]) + end; + _ -> + mnesia:create_table('orber_CosNaming',[{attributes, + record_info(fields, + 'orber_CosNaming')} + |Options]) + end, + Wait = mnesia:wait_for_tables(['orber_CosNaming'], Timeout), + %% Check if any error has occured yet. If there are errors, return them. + + if + DB_tables_created == {atomic, ok}, + Wait == ok -> + _F = ?write_function(#orber_CosNaming{name_context= + term_to_binary('undefined'), + nameindex=[]}), + write_result(mnesia:transaction(_F)); + true -> + {error, [DB_tables_created, Wait]} + end. + + +%%---------------------------------------------------------------------- +%% Interface CosNaming::NamingContext +%%---------------------------------------------------------------------- +%%---------------------------------------------------------------------- +%% Function : bind +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +bind(OE_THIS, OE_State, [N], Obj) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _BF = + fun() -> + case mnesia:wread({orber_CosNaming, SubobjKey}) of + [#orber_CosNaming{nameindex = X}] -> + case lists:keysearch(N, 1, X) of + {value, _} -> + {'EXCEPTION', #'CosNaming_NamingContext_AlreadyBound'{}}; + false -> + mnesia:write(#orber_CosNaming{name_context=SubobjKey, + nameindex=[{N, nobject, Obj} | X]}) + end; + Other -> + orber:dbg("[~p] ~p:bind(~p, ~p);~n" + "DB access returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N], + cxt=OE_THIS}} + end + end, + case mnesia:transaction(_BF) of + {atomic, {'EXCEPTION', E}} -> + corba:raise(E); + {atomic, ok} -> + {reply, ok, OE_State}; + Other -> + orber:dbg("[~p] ~p:bind(~p, ~p);~n" + "DB transaction returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +bind(OE_THIS, OE_State, [H|T], Obj) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RF = ?read_function({orber_CosNaming, SubobjKey}), + case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of + error -> + corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T], + cxt=OE_THIS}); + X -> + case lists:keysearch(H, 1, X) of + {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') -> + {reply, 'CosNaming_NamingContext':bind(NC, T, Obj), OE_State}; + {value, {H, ncontext, NC}} -> + bind(NC, OE_State, T, Obj); + _ -> + corba:raise(#'CosNaming_NamingContext_CannotProceed' + {rest_of_name=[H|T], cxt=OE_THIS}) + end + end; +bind(_OE_THIS, _OE_State, [], _Obj) -> + orber:dbg("[~p] CosNaming_NamingContextExt:bind();~n" + "Invoked this operation with an empty list", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}). + +%%---------------------------------------------------------------------- +%% Function : rebind +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +rebind(OE_THIS, OE_State, [N], Obj) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RBF = + fun() -> + case mnesia:wread({orber_CosNaming, SubobjKey}) of + [#orber_CosNaming{nameindex = X}] -> + KList = + case lists:keysearch(N, 1, X) of + {value, {N, _, _V}} -> + lists:keyreplace(N, 1, X, {N, nobject, Obj}); + false -> + [{N, nobject, Obj} | X] + end, + mnesia:write(#orber_CosNaming{name_context=SubobjKey, + nameindex=KList}); + Other -> + orber:dbg("[~p] ~p:rebind(~p, ~p);~n" + "DB access returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N], + cxt=OE_THIS}} + end + end, + case mnesia:transaction(_RBF) of + {atomic, {'EXCEPTION', E}} -> + corba:raise(E); + {atomic, ok} -> + {reply, ok, OE_State}; + Other -> + orber:dbg("[~p] ~p:rebind(~p, ~p);~n" + "DB transaction returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +rebind(OE_THIS, OE_State, [H|T], Obj) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RF = ?read_function({orber_CosNaming, SubobjKey}), + case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of + error -> + corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T], + cxt=OE_THIS}); + X -> + case lists:keysearch(H, 1, X) of + {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') -> + {reply, 'CosNaming_NamingContext':rebind(NC, T, Obj), OE_State}; + {value, {H, ncontext, NC}} -> + rebind(NC, OE_State, T, Obj); + _ -> + corba:raise(#'CosNaming_NamingContext_CannotProceed' + {rest_of_name=[H|T], cxt=OE_THIS}) + end + end; +rebind(_OE_THIS, _OE_State, [], _Obj) -> + orber:dbg("[~p] CosNaming_NamingContextExt:rebind();~n" + "Invoked this operation with an empty list", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}). + +%%---------------------------------------------------------------------- +%% Function : bind_context +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +bind_context(OE_THIS, OE_State, [N], Obj) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _BCF = + fun() -> + case mnesia:wread({orber_CosNaming, SubobjKey}) of + [#orber_CosNaming{nameindex = X}] -> + case lists:keysearch(N, 1, X) of + {value, _} -> + {'EXCEPTION', #'CosNaming_NamingContext_AlreadyBound'{}}; + false -> + mnesia:write(#orber_CosNaming{name_context=SubobjKey, + nameindex= + [{N, ncontext, Obj} | X]}) + end; + Other -> + orber:dbg("[~p] ~p:bind_context(~p, ~p);~n" + "DB access returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N], + cxt=OE_THIS}} + end + end, + case mnesia:transaction(_BCF) of + {atomic, {'EXCEPTION', E}} -> + corba:raise(E); + {atomic, ok} -> + {reply, ok, OE_State}; + Other -> + orber:dbg("[~p] ~p:bind_context(~p, ~p);~n" + "DB transaction returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +bind_context(OE_THIS, OE_State, [H|T], Obj) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RF = ?read_function({orber_CosNaming, SubobjKey}), + case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of + error -> + corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T], + cxt=OE_THIS}); + X -> + case lists:keysearch(H, 1, X) of + {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') -> + {reply, 'CosNaming_NamingContext':bind_context(NC, T, Obj), + OE_State}; + {value, {H, ncontext, NC}} -> + bind_context(NC, OE_State, T, Obj); + _ -> + corba:raise(#'CosNaming_NamingContext_CannotProceed' + {rest_of_name=[H|T], cxt=OE_THIS}) + end + end; +bind_context(_OE_THIS, _OE_State, [], _Obj) -> + orber:dbg("[~p] CosNaming_NamingContextExt:bind_context();~n" + "Invoked this operation with an empty list", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}). + +%%---------------------------------------------------------------------- +%% Function : rebind_context +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +rebind_context(OE_THIS, OE_State, [N], Obj) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RBCF = + fun() -> + case mnesia:wread({orber_CosNaming, SubobjKey}) of + [#orber_CosNaming{nameindex = X}] -> + KList = + case lists:keysearch(N, 1, X) of + {value, {N, _, _V}} -> + lists:keyreplace(N, 1, X, {N, ncontext, Obj}); + false -> + [{N, ncontext, Obj} | X] + end, + mnesia:write(#orber_CosNaming{name_context=SubobjKey, + nameindex= KList}); + Other -> + orber:dbg("[~p] ~p:rebind_context(~p, ~p);~n" + "DB access returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N], + cxt=OE_THIS}} + end + end, + case mnesia:transaction(_RBCF) of + {atomic, {'EXCEPTION', E}} -> + corba:raise(E); + {atomic, ok} -> + {reply, ok, OE_State}; + Other -> + orber:dbg("[~p] ~p:rebind_context(~p, ~p);~n" + "DB transaction returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +rebind_context(OE_THIS, OE_State, [H|T], Obj) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RF = ?read_function({orber_CosNaming, SubobjKey}), + case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of + error -> + corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T], + cxt=OE_THIS}); + X -> + case lists:keysearch(H, 1, X) of + {value, {H,ncontext, NC}} when is_record(NC, 'IOP_IOR') -> + {reply, 'CosNaming_NamingContext':rebind_context(NC, T, Obj), + OE_State}; + {value, {H,ncontext, NC}} -> + rebind_context(NC, OE_State, T, Obj); + _ -> + corba:raise(#'CosNaming_NamingContext_CannotProceed' + {rest_of_name=[H|T], cxt=OE_THIS}) + end + end; +rebind_context(_OE_THIS, _OE_State, [], _Obj) -> + orber:dbg("[~p] CosNaming_NamingContextExt:rebind_context();~n" + "Invoked this operation with an empty list", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}). + +%%---------------------------------------------------------------------- +%% Function : resolve +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +resolve(OE_THIS, OE_State, [N]) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RF = ?read_function({orber_CosNaming, SubobjKey}), + case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of + error -> + corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N], + cxt=OE_THIS}); + X -> + case lists:keysearch(N, 1, X) of + {value, {N, _, Value}} -> + {reply, Value, OE_State}; + false -> + corba:raise(#'CosNaming_NamingContext_NotFound' + {rest_of_name=[N], why='not_object'}) + end + end; +resolve(OE_THIS, OE_State, [H|T]) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RF = ?read_function({orber_CosNaming, SubobjKey}), + case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of + error -> + corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T], + cxt=OE_THIS}); + X -> + case lists:keysearch(H, 1, X) of + {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') -> + {reply, 'CosNaming_NamingContext':resolve(NC, T), OE_State}; + {value, {H, ncontext, NC}} -> + resolve(NC, OE_State, T); + _ -> + corba:raise(#'CosNaming_NamingContext_CannotProceed' + {rest_of_name=[H|T], cxt=OE_THIS}) + end + end; +resolve(_OE_THIS, _OE_State, []) -> + orber:dbg("[~p] CosNaming_NamingContextExt:resolve();~n" + "Invoked this operation with an empty list", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}). + +%%---------------------------------------------------------------------- +%% Function : unbind +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +unbind(OE_THIS, OE_State, [N]) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _UBF = + fun() -> + case mnesia:wread({orber_CosNaming, SubobjKey}) of + [#orber_CosNaming{nameindex = X}] -> + KList = lists:keydelete(N, 1, X), + mnesia:write(#orber_CosNaming{name_context=SubobjKey, + nameindex= KList}); + Other -> + orber:dbg("[~p] ~p:unbind(~p, ~p);~n" + "DB transaction returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + {'EXCEPTION', #'CosNaming_NamingContext_CannotProceed'{rest_of_name=[N], + cxt=OE_THIS}} + end + end, + case mnesia:transaction(_UBF) of + {atomic, {'EXCEPTION', E}} -> + corba:raise(E); + {atomic, ok} -> + {reply, ok, OE_State}; + Other -> + orber:dbg("[~p] ~p:unbind(~p, ~p);~n" + "DB transaction returned ~p", + [?LINE, ?MODULE, N, SubobjKey, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end; +unbind(OE_THIS, OE_State, [H|T]) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RF = ?read_function({orber_CosNaming, SubobjKey}), + case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of + error -> + corba:raise(#'CosNaming_NamingContext_CannotProceed'{rest_of_name=[H|T], + cxt=OE_THIS}); + X -> + case lists:keysearch(H, 1, X) of + {value, {H, ncontext, NC}} when is_record(NC, 'IOP_IOR') -> + {reply, 'CosNaming_NamingContext':unbind(NC, T), OE_State}; + {value, {H, ncontext, NC}} -> + unbind(NC, OE_State, T); + _ -> + corba:raise(#'CosNaming_NamingContext_CannotProceed' + {rest_of_name=[H|T], cxt=OE_THIS}) + end + end; +unbind(_OE_THIS, _OE_State, []) -> + orber:dbg("[~p] CosNaming_NamingContextExt:unbind();~n" + "Invoked this operation with an empty list", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_YES}). + + +%%---------------------------------------------------------------------- +%% Function : new_context +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +new_context(_OE_THIS, OE_State) -> + DBKey = term_to_binary({now(), node()}), + %% Create a record in the table and set the key to a newly + {reply, + 'CosNaming_NamingContextExt':oe_create(DBKey, + [{pseudo, true}|?CREATE_OPTS]), + OE_State}. + +%%---------------------------------------------------------------------- +%% Function : bind_new_context +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +bind_new_context(OE_THIS, OE_State, N) -> + DBKey = term_to_binary({now(), node()}), + %% Create a record in the table and set the key to a newly + %% generated objectkey. + %%?PRINTDEBUG("bind_new_context"), + NewCtx = 'CosNaming_NamingContextExt':oe_create(DBKey, + [{pseudo, true}|?CREATE_OPTS]), + %% Bind the created name context to a name + case catch bind_context(OE_THIS, OE_State, N, NewCtx) of + {'EXCEPTION', E} -> + 'CosNaming_NamingContextExt':destroy(NewCtx), + corba:raise(E); + {reply, ok, _} -> + {reply, NewCtx, OE_State} + end. + + +%%---------------------------------------------------------------------- +%% Function : list +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +list(OE_THIS, OE_State, HowMany) -> + SubobjKey = corba:get_subobject_key(OE_THIS), + _RF = ?read_function({orber_CosNaming, SubobjKey}), + case orber_cosnaming_utils:query_result(mnesia:transaction(_RF)) of + error -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}); + X -> + case convert_list(X, HowMany, 0, []) of + {false, List} -> + {reply, {ok, List, ?ORBER_NIL_OBJREF}, OE_State}; + {true, List, Rest} -> + %% By setting HowMany to '-1' it will never match + %% the Counter. Hence, the whole list will be transformed. + {false, List2} = convert_list(Rest, -1, 0, []), + BIterator = 'CosNaming_BindingIterator': + oe_create(List2, ?CREATE_OPTS), + {reply, {ok, List, BIterator}, OE_State} + end + end. + +convert_list([], _, _, Acc) -> + {false, Acc}; +convert_list(Rest, Counter, Counter, Acc) -> + {true, Acc, Rest}; +convert_list([{N, T, _O}|Rest], HowMany, Counter, Acc) -> + convert_list(Rest, HowMany, Counter+1, + [#'CosNaming_Binding'{binding_name=[N], + binding_type=T}|Acc]). + +%%---------------------------------------------------------------------- +%% Function : destroy +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +destroy(OE_THIS, OE_State) -> + case corba:get_subobject_key(OE_THIS) of + <<131,100,0,9,117,110,100,101,102,105,110,101,100>> -> + %% undefined binary. + corba:raise(#'NO_PERMISSION'{completion_status=?COMPLETED_NO}); + SubobjKey -> + _DF = + fun() -> + case mnesia:wread({orber_CosNaming, SubobjKey}) of + [#orber_CosNaming{nameindex = []}] -> + mnesia:delete({orber_CosNaming, SubobjKey}); + Other when is_list(Other) -> + orber:dbg("[~p] ~p:destroy(~p);~n" + "DB access returned ~p", + [?LINE, ?MODULE, SubobjKey, Other], ?DEBUG_LEVEL), + {'EXCEPTION', #'CosNaming_NamingContext_NotEmpty'{}}; + Other -> + orber:dbg("[~p] ~p:destroy(~p);~n" + "DB access returned ~p", + [?LINE, ?MODULE, SubobjKey, Other], ?DEBUG_LEVEL), + {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}} + end + end, + case mnesia:transaction(_DF) of + {atomic, {'EXCEPTION', E}} -> + corba:raise(E); + {atomic, ok} -> + {reply, ok, OE_State}; + Other -> + orber:dbg("[~p] ~p:destroy(~p);~n" + "DB transaction returned ~p", + [?LINE, ?MODULE, SubobjKey, Other], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}) + end + end. + +%%---------------------------------------------------------------------- +%% Interface CosNaming::NamingContextExt +%%---------------------------------------------------------------------- +%%---------------------------------------------------------------------- +%% Function : to_string +%% Arguments : Name +%% Description: +%% Returns : StringName | +%% {'EXCEPTION', NamingContext::InvalidName{}} +%%---------------------------------------------------------------------- +to_string(_OE_This, OE_State, Name) -> + {reply, orber_cosnaming_utils:name2string(Name), OE_State}. + + +%%---------------------------------------------------------------------- +%% Function : to_name +%% Arguments : StringName +%% Description: +%% Returns : Name | +%% {'EXCEPTION', NamingContext::InvalidName{}} +%%---------------------------------------------------------------------- +to_name(_OE_This, OE_State, StringName) -> + {reply, orber_cosnaming_utils:string2name(StringName), OE_State}. + + +%%---------------------------------------------------------------------- +%% Function : to_url +%% Arguments : Address +%% StringName +%% Description: +%% Returns : URLString | +%% {'EXCEPTION', NamingContext::InvalidName{}} +%% {'EXCEPTION', NamingContextExt::InvalidAddress{}} +%%---------------------------------------------------------------------- +to_url(_, _, "", _) -> + %% Empty address not allowed. + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}); +to_url(_OE_This, OE_State, Address, "") -> + %% Empty stringname => use corbaloc + orber_cosnaming_utils:check_addresses(Address), + {reply, "corbaloc:"++orber_cosnaming_utils:escape_string(Address), OE_State}; +to_url(_OE_This, OE_State, Address, StringName) -> + %% Non-empty stringname => use corbaname + orber_cosnaming_utils:check_addresses(Address), + orber_cosnaming_utils:check_name(StringName), + {reply, + "corbaname:"++orber_cosnaming_utils:escape_string(Address)++"#"++ + orber_cosnaming_utils:escape_string(StringName), + OE_State}. + +%%---------------------------------------------------------------------- +%% Function : resolve_str +%% Arguments : StringName +%% Description: +%% Returns : Object | +%% {'EXCEPTION', NamingContext::InvalidName{}} +%% {'EXCEPTION', NamingContext::NotFound{why, rest_of_name}} +%% {'EXCEPTION', NamingContext::CannotProceed{cxt, rest_of_name}} +%%---------------------------------------------------------------------- +resolve_str(OE_This, OE_State, StringName) -> + Name = orber_cosnaming_utils:string2name(StringName), + resolve(OE_This, OE_State, Name). + +%%====================================================================== +%% Internal functions +%%====================================================================== +%% Check a write transaction +write_result({atomic,ok}) -> ok; +write_result(_What) -> + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO}). + + +%%---------------------------------------------------------------------- +%% Debugging functions +%%---------------------------------------------------------------------- +dump() -> + case catch mnesia:dirty_first('orber_CosNaming') of + {'EXIT', R} -> + io:format("Exited with ~p\n",[R]); + Key -> + dump_print(Key), + dump_loop(Key) + end. + +dump_loop(PreviousKey) -> + case catch mnesia:dirty_next('orber_CosNaming', PreviousKey) of + {'EXIT', R} -> + io:format("Exited with ~p\n",[R]); + '$end_of_table' -> + ok; + Key -> + dump_print(Key), + dump_loop(Key) + end. + +dump_print(Key) -> + case catch mnesia:dirty_read({'orber_CosNaming', Key}) of + {'EXIT', R} -> + io:format("Exited with ~p\n",[R]); + [X] -> + io:format("name_context: ~p\n-----------------------------\n" + " nameindex structure\n-----------------------------\n~p\n\n", + [binary_to_term(X#orber_CosNaming.name_context), + X#orber_CosNaming.nameindex]); + _ -> + ok + end. + +%%-------------------------- END OF MODULE ----------------------------- diff --git a/lib/orber/COSS/CosNaming/Makefile b/lib/orber/COSS/CosNaming/Makefile new file mode 100644 index 0000000..d3deec7 --- /dev/null +++ b/lib/orber/COSS/CosNaming/Makefile @@ -0,0 +1,150 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +EBIN=../../ebin + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(ORBER_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN) +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES = \ + CosNaming_NamingContextExt_impl \ + CosNaming_BindingIterator_impl \ + lname \ + lname_component \ + orber_cosnaming_utils + +ERL_FILES = $(MODULES:%=%.erl) +HRL_FILES = lname.hrl \ + orber_cosnaming.hrl +GEN_ERL_FILES = \ + oe_cos_naming.erl \ + CosNaming_Name.erl \ + CosNaming_NamingContext.erl \ + CosNaming_BindingIterator.erl \ + CosNaming_NameComponent.erl \ + CosNaming_Binding.erl \ + CosNaming_BindingList.erl \ + CosNaming_NamingContext_NotFound.erl \ + CosNaming_NamingContext_AlreadyBound.erl \ + CosNaming_NamingContext_CannotProceed.erl \ + CosNaming_NamingContext_InvalidName.erl \ + CosNaming_NamingContext_NotEmpty.erl + +GEN_EXT_ERL_FILES = \ + oe_cos_naming_ext.erl \ + CosNaming_NamingContextExt.erl \ + CosNaming_NamingContextExt_InvalidAddress.erl + +GEN_HRL_FILES = \ + oe_cos_naming.hrl \ + CosNaming.hrl \ + CosNaming_NamingContext.hrl \ + CosNaming_BindingIterator.hrl + +GEN_EXT_HRL_FILES = \ + oe_cos_naming_ext.hrl \ + CosNaming_NamingContextExt.hrl + +GEN_FILES = $(GEN_ERL_FILES) $(GEN_HRL_FILES) \ + $(GEN_EXT_ERL_FILES) $(GEN_EXT_HRL_FILES) + +TARGET_FILES = \ + $(GEN_EXT_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +IDL_FILE = cos_naming.idl \ + cos_naming_ext.idl + +APP_FILE = +#APP_SRC = $(APP_FILE).src +#APP_TARGET = $(EBIN)/$(APP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_IDL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin +# The -pa option is just used temporary until erlc can handle +# includes from other directories than ../include . +ERL_COMPILE_FLAGS += \ + $(ERL_IDL_FLAGS) \ + -I$(ERL_TOP)/lib/orber/include \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,"orber_$(ORBER_VSN)"}' + +YRL_FLAGS = + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +opt: $(TARGET_FILES) $(APP_TARGET) + +debug: + @${MAKE} TYPE=debug + +clean: + rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) + sed -e 's;%VSN%;$(VSN);' $(APP_SRC) > $(APP_TARGET) + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- +$(GEN_FILES): cos_naming_ext.idl cos_naming.idl + erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' \ + +'{this,"CosNaming::NamingContextExt"}' cos_naming_ext.idl + erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' cos_naming.idl + +# echo "ic:gen(cos_naming, [{this, \"CosNaming::NamingContext\"}]), halt()."| $(ERL) $(ERL_IDL_FLAGS) + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/COSS/CosNaming + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(IDL_FILE) $(RELSYSDIR)/COSS/CosNaming + $(INSTALL_DATA) $(GEN_FILES) $(RELSYSDIR)/COSS/CosNaming + + +release_docs_spec: + diff --git a/lib/orber/COSS/CosNaming/cos_naming.idl b/lib/orber/COSS/CosNaming/cos_naming.idl new file mode 100644 index 0000000..3cd6c99 --- /dev/null +++ b/lib/orber/COSS/CosNaming/cos_naming.idl @@ -0,0 +1,77 @@ +// Naming Service v1.0 described in CORBAservices: +// Common Object Services Specification, chapter 3 +// OMG IDL for CosNaming Module, p 3-6 + +#pragma prefix "omg.org" + +module CosNaming +{ + typedef string Istring; + struct NameComponent { + Istring id; + Istring kind; + }; + + typedef sequence Name; + + enum BindingType {nobject, ncontext}; + + struct Binding { + Name binding_name; + BindingType binding_type; + }; + + typedef sequence BindingList; + + + interface BindingIterator; + interface NamingContext; + + interface NamingContext { + + enum NotFoundReason { missing_node, not_context, not_object}; + + exception NotFound { + NotFoundReason why; + Name rest_of_name; + }; + + exception CannotProceed { + NamingContext cxt; + Name rest_of_name; + }; + + exception InvalidName{}; + exception AlreadyBound {}; + exception NotEmpty{}; + + void bind(in Name n, in Object obj) + raises(NotFound, CannotProceed, InvalidName, AlreadyBound); + void rebind(in Name n, in Object obj) + raises(NotFound, CannotProceed, InvalidName); + void bind_context(in Name n, in NamingContext nc) + raises(NotFound, CannotProceed,InvalidName, AlreadyBound); + void rebind_context(in Name n, in NamingContext nc) + raises(NotFound, CannotProceed, InvalidName); + Object resolve (in Name n) + raises(NotFound, CannotProceed, InvalidName); + void unbind(in Name n) + raises(NotFound, CannotProceed, InvalidName); + NamingContext new_context(); + NamingContext bind_new_context(in Name n) + raises(NotFound, AlreadyBound, CannotProceed, InvalidName); + void destroy( ) + raises(NotEmpty); + void list (in unsigned long how_many, + out BindingList bl, + out BindingIterator bi); + }; + + interface BindingIterator { + boolean next_one(out Binding b); + boolean next_n(in unsigned long how_many, + out BindingList bl); + void destroy(); + }; +}; + diff --git a/lib/orber/COSS/CosNaming/cos_naming_ext.idl b/lib/orber/COSS/CosNaming/cos_naming_ext.idl new file mode 100644 index 0000000..8099a00 --- /dev/null +++ b/lib/orber/COSS/CosNaming/cos_naming_ext.idl @@ -0,0 +1,37 @@ +// Naming Service v1.0 described in CORBAservices: +// Common Object Services Specification, chapter 3 +// OMG IDL for CosNaming Module, p 3-6 + +#ifndef _COSNAMINGEXT_IDL_ +#define _COSNAMINGEXT_IDL_ + + +#include + +#pragma prefix "omg.org" + +module CosNaming +{ + interface NamingContextExt:NamingContext { + + typedef string StringName; + typedef string Address; + typedef string URLString; + + StringName to_string(in Name n) + raises(InvalidName); + + Name to_name(in StringName sn) + raises(InvalidName); + + exception InvalidAddress{}; + + URLString to_url(in Address addr,in StringName sn) + raises(InvalidAddress, InvalidName); + + Object resolve_str(in StringName n) + raises(NotFound, CannotProceed, InvalidName); + }; +}; + +#endif//_COSNAMINGEXT_IDL_ diff --git a/lib/orber/COSS/CosNaming/lname.erl b/lib/orber/COSS/CosNaming/lname.erl new file mode 100644 index 0000000..9f060d3 --- /dev/null +++ b/lib/orber/COSS/CosNaming/lname.erl @@ -0,0 +1,133 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: lname.erl +%%----------------------------------------------------------------- +-module(lname). + +-include_lib("orber/include/corba.hrl"). +-include("CosNaming.hrl"). +-include("lname.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([create/0, insert_component/3, get_component/2, delete_component/2, + num_component/1, equal/2, less_than/2, + to_idl_form/1, from_idl_form/1, check_name/1, new/1]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%% DEBUG INFO +-define(DEBUG_LEVEL, 5). + +%%----------------------------------------------------------------- +%% External interface functions +%%----------------------------------------------------------------- +create() -> + []. + +insert_component(_, I, _) when I < 1-> + corba:raise(#'LName_NoComponent'{}); +insert_component([], I, _) when I > 1-> + corba:raise(#'LName_NoComponent'{}); +insert_component(Name, 1, Component) when is_record(Component, + 'CosNaming_NameComponent') -> + [Component |Name]; +insert_component([H|T], I, Component) when is_record(Component, + 'CosNaming_NameComponent') -> + [H |insert_component(T, I-1, Component)]; +insert_component(_, _, Component) -> + orber:dbg("[~p] ~p:insert_component(~p); Not a NameComponent.~n", + [?LINE, ?MODULE, Component], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). + +get_component(_, I) when I < 1-> + corba:raise(#'LName_NoComponent'{}); +get_component([], _) -> + corba:raise(#'LName_NoComponent'{}); +get_component([H|_T], 1) -> + H; +get_component([_|T], I) -> + get_component(T, I-1). + +delete_component(_, I) when I < 1-> + corba:raise(#'LName_NoComponent'{}); +delete_component([], _) -> + corba:raise(#'LName_NoComponent'{}); +delete_component([_|T], 1) -> + T; +delete_component([H|T], I) -> + [H | delete_component(T, I-1)]. + +num_component(Name) -> + num_component(Name, 0). + +equal(Name, N) -> + N == Name. + +less_than(Name, N) -> + Name < N. + +to_idl_form(Name) -> + case check_name(Name) of + false -> + corba:raise(#'LName_InvalidName'{}); + true -> + Name + end. + +from_idl_form(Name) -> + Name. + +%%destroy() -> % not needed in erlang +%% ok. + +%%----------------------------------------------------------------- +%% External Functions not in the CosNaming standard +%%----------------------------------------------------------------- +new([]) -> + []; +new([{Id, Kind} | List]) -> + [lname_component:new(Id, Kind) | new(List)]; +new([Id |List]) when is_list(Id) -> + [lname_component:new(Id) | new(List)]. + +%%----------------------------------------------------------------- +%% Internal Functions +%%----------------------------------------------------------------- +num_component([], N) -> + N; +num_component([_|T], N) -> + num_component(T, N+1). + +check_name([]) -> + true; +check_name([H|T]) -> + case catch lname_component:get_id(H) of + {'EXCEPTION', _E} -> + false; + _ -> + check_name(T) + end. diff --git a/lib/orber/COSS/CosNaming/lname.hrl b/lib/orber/COSS/CosNaming/lname.hrl new file mode 100644 index 0000000..de78e4b --- /dev/null +++ b/lib/orber/COSS/CosNaming/lname.hrl @@ -0,0 +1,33 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: lname.hrl +%%----------------------------------------------------------------- + +%% LName interface exceptions +-record('LName_NoComponent', {'OE_ID'="PIDL:LName/NoComponent:1.0"}). +-record('LName_InvalidName', {'OE_ID'="PIDL:LName/InvalidName:1.0"}). +% This exception is not used in our implementation. +-record('LName_Overflow', {'OE_ID'="PIDL:LName/Overflow:1.0"}). + +%% LNameComponent interface exceptions +-record('LNameComponent_NotSet', + {'OE_ID'="PIDL:LNameComponent/NotSet:1.0"}). diff --git a/lib/orber/COSS/CosNaming/lname_component.erl b/lib/orber/COSS/CosNaming/lname_component.erl new file mode 100644 index 0000000..9ded1d7 --- /dev/null +++ b/lib/orber/COSS/CosNaming/lname_component.erl @@ -0,0 +1,83 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: lname_component.erl +%%----------------------------------------------------------------- +-module(lname_component). + +-include_lib("orber/include/corba.hrl"). +-include("lname.hrl"). +-include("CosNaming.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([get_id/1, set_id/2, get_kind/1, set_kind/2, create/0, new/1, new/2]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% External interface functions +%%----------------------------------------------------------------- +create() -> + #'CosNaming_NameComponent'{id="", kind=""}. + +get_id(NC) when is_record(NC, 'CosNaming_NameComponent'), + NC#'CosNaming_NameComponent'.id == undefined -> + corba:raise(#'LNameComponent_NotSet'{}); +get_id(NC) when is_record(NC, 'CosNaming_NameComponent'), + NC#'CosNaming_NameComponent'.id == "" -> + corba:raise(#'LNameComponent_NotSet'{}); +get_id(NC) when is_record(NC, 'CosNaming_NameComponent') -> + NC#'CosNaming_NameComponent'.id. + +set_id(NC, Id) when is_record(NC, 'CosNaming_NameComponent') andalso is_list(Id)-> + NC#'CosNaming_NameComponent'{id=Id}. + +get_kind(NC) when is_record(NC, 'CosNaming_NameComponent') andalso + NC#'CosNaming_NameComponent'.kind == undefined -> + corba:raise(#'LNameComponent_NotSet'{}); +get_kind(NC) when is_record(NC, 'CosNaming_NameComponent') andalso + NC#'CosNaming_NameComponent'.kind == "" -> + corba:raise(#'LNameComponent_NotSet'{}); +get_kind(NC) when is_record(NC, 'CosNaming_NameComponent') -> + NC#'CosNaming_NameComponent'.kind. + +set_kind(NC, Kind) when is_record(NC, 'CosNaming_NameComponent') andalso is_list(Kind) -> + NC#'CosNaming_NameComponent'{kind=Kind}. + +%%destroy() -> % not needed in erlang +%% true. + +%%----------------------------------------------------------------- +%% External Functions not in the CosNaming standard +%%----------------------------------------------------------------- +new(Id) when is_list(Id) -> + #'CosNaming_NameComponent'{id=Id, kind=""}. +new(Id, Kind) when is_list(Id) andalso is_list(Kind) -> + #'CosNaming_NameComponent'{id=Id, kind=Kind}. + +%%----------------------------------------------------------------- +%% Internal Functions +%%----------------------------------------------------------------- diff --git a/lib/orber/COSS/CosNaming/orber_cosnaming.hrl b/lib/orber/COSS/CosNaming/orber_cosnaming.hrl new file mode 100644 index 0000000..073158e --- /dev/null +++ b/lib/orber/COSS/CosNaming/orber_cosnaming.hrl @@ -0,0 +1,63 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%-------------------------------------------------------------------- + +-ifndef(ORBER_COSNAMING_HRL). +-define(ORBER_COSNAMING_HRL, true). + +%%----------------------------------------------------------------- +%% Mnesia Table definition record +%%----------------------------------------------------------------- +-record('orber_CosNaming', {name_context, nameindex}). + +%%----------------------------------------------------------------- +%% Macros +%%----------------------------------------------------------------- + +-define(CREATE_OPTS, [{no_security, orber:partial_security()}]). + +%%-define(dirty_query_context, true). + +%% This macro returns a read fun suitable for evaluation in a transaction +-define(read_function(Objkey), + fun() -> + mnesia:read(Objkey) + end). + +%% This macro returns a write fun suitable for evaluation in a transaction +-define(write_function(R), + fun() -> + mnesia:write(R) + end). + +%% This macro returns a delete fun suitable for evaluation in a transaction +-define(delete_function(R), + fun() -> + mnesia:delete(R) + end). + +-ifdef(dirty_query_context). +-define(query_check(Q_res), Q_res). +-else. +-define(query_check(Q_res), {atomic, Q_res}). +-endif. + +-endif. diff --git a/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl new file mode 100644 index 0000000..7792839 --- /dev/null +++ b/lib/orber/COSS/CosNaming/orber_cosnaming_utils.erl @@ -0,0 +1,750 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: orber_cosnaming_utils.erl +%% Modified: +%% +%%----------------------------------------------------------------- +-module(orber_cosnaming_utils). + +-include("orber_cosnaming.hrl"). +-include("CosNaming.hrl"). +-include("CosNaming_NamingContext.hrl"). +-include("CosNaming_NamingContextExt.hrl"). +-include_lib("orber/include/corba.hrl"). + + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([query_result/1]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([addresses/1, name/1, + check_addresses/1, check_name/1, + key/1, select_type/1, lookup/1, lookup/2, + escape_string/1, unescape_string/1, + name2string/1, string2name/1]). + +%%----------------------------------------------------------------- +%% Records +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Defines +%%----------------------------------------------------------------- +%% DEFAULT VALUES: +%% +%% IIOP: +%% - port: 2809 +%% - iiop version: 1.0 +-define(DEF_VERS, {1,0}). +-define(DEF_PORT, 2809). +-define(DEF_KEY, "NameService"). +-define(HTTP_DEF_PORT, 80). + +%% DEBUG INFO +-define(DEBUG_LEVEL, 5). + +%%----------------------------------------------------------------- +%% External interface functions +%%----------------------------------------------------------------- +%% Check a read transaction +query_result({atomic, Qres}) -> + case Qres of + [Hres] -> + Hres#orber_CosNaming.nameindex; + [Hres|Tres] -> + orber:dbg("[~p] orber_cosnaming_utils:query_result(~p);~n" + "Multiple Hits: ~p", [?LINE, Qres, [Hres|Tres]], ?DEBUG_LEVEL), + error; + [] -> + orber:dbg("[~p] orber_cosnaming_utils:query_result();~n" + "No hit", [?LINE], ?DEBUG_LEVEL), + error; + Other -> + orber:dbg("[~p] orber_cosnaming_utils:query_result(~p);~n" + "Mnesia Access Failed ~p", [?LINE, Qres, Other], ?DEBUG_LEVEL), + error + end; +query_result({aborted, Qres}) -> + orber:dbg("[~p] orber_cosnaming_utils:query_result(~p);~n" + "Mnesia Access Aborted", [?LINE, Qres], ?DEBUG_LEVEL), + error; +query_result(What) -> + orber:dbg("[~p] orber_cosnaming_utils:query_result(~p);~n" + "Mnesia Access Failed", [?LINE, What], ?DEBUG_LEVEL), + error. + + +%%---------------------------------------------------------------------- +%% Function : check_addresses +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +check_addresses(Str) -> + {_, Rest2} = addresses(Str), + case key(Rest2) of + {_, []} -> + ok; + What -> + orber:dbg("[~p] orber_cosnaming_utils:check_addresses(~p);~n" + "Key ~p", [?LINE, Str, What], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}) + end. + +%%---------------------------------------------------------------------- +%% Function : check_name +%% Arguments : +%% Description: +%% Returns : +%%---------------------------------------------------------------------- +check_name(Str) -> + name(Str). + +%%---------------------------------------------------------------------- +%% Function : select_type +%% Arguments : A corbaloc/corbaname-string. +%% Description: +%% Returns : A tuple which contain data about what connection we want to use | +%% {'EXCEPTION', #'CosNaming_NamingContextExt_InvalidAddress'{}} +%%---------------------------------------------------------------------- +select_type([$c, $o, $r, $b, $a, $l, $o, $c, $:|Rest1]) -> + {Addresses, Rest2} = addresses(Rest1), + case key(Rest2) of + {Key, []} -> + {corbaloc, Addresses, Key}; + What -> + orber:dbg("[~p] orber_cosnaming_utils:select_type(~p);~n" + "Key ~p", [?LINE, Rest1, What], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}) + end; +select_type([$c, $o, $r, $b, $a, $n, $a, $m, $e, $:|Rest1]) -> + {Addresses, Rest2} = addresses(Rest1), + {Key, Rest3} = key(Rest2), + Name = name(Rest3), + {corbaname, Addresses, Key, string2name(Name)}; + +select_type([$f, $i, $l, $e, $:, $/ |Rest]) -> + file(Rest); +select_type([$f, $t, $p, $:, $/, $/ |Rest]) -> + ftp(Rest); +select_type([$h, $t, $t, $p, $:, $/, $/ |Rest]) -> + http(Rest); + +select_type(What) -> + orber:dbg("[~p] orber_cosnaming_utils:select_type(~p);~n" + "Malformed or unsupported type.", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}). + + +%%---------------------------------------------------------------------- +%% Function : addresses +%% Arguments : A corbaloc string. +%% Description: +%% Returns : A list of addresses an the remaining part possibly containg +%% a Key and a stringified Name +%%---------------------------------------------------------------------- +addresses(Str) -> + addresses(address(protocol, Str, [], []), []). + +addresses({false, rir, Rest}, []) -> + {rir, Rest}; +addresses({false, Adr, Rest}, Addresses) -> + {lists:reverse([Adr|Addresses]), Rest}; +addresses({true, Adr, Rest}, Addresses) -> + addresses(address(protocol, Rest, [], []), [Adr|Addresses]). + +%% Which protocol. +address(protocol, [$:|T], [], []) -> + address(version, T, [], [iiop]); +address(protocol, [$i, $i, $o, $p, $:|T], [], []) -> + address(version, T, [], [iiop]); +address(protocol, [$r, $i, $r, $:|T], [], []) -> + {false, rir, T}; +address(protocol, What, _, _) -> + orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n" + "Malformed or unsupported protocol.", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}); + +%% Parsed one address, no version found or port found. +address(version, [$,|T], Acc, Previous) -> + {true, lists:reverse([?DEF_PORT, lists:reverse(Acc), ?DEF_VERS|Previous]), T}; +address(version, [$/|T], Acc, Previous) -> + {false, lists:reverse([?DEF_PORT, lists:reverse(Acc), ?DEF_VERS|Previous]), T}; +%% Found iiop version. +address(version, [$@|T], Acc, Previous) -> + case Acc of + [Minor, $., Major] -> + address(address, T, [], [{Major-$0, Minor-$0}|Previous]); + What -> + orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n" + "Malformed or unsupported version.", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}) + end; +%% Found no iiop version, switch to port. In this case Acc contains the +%% Host. +address(version, [$:|T], Acc, Previous) -> + case check_ip_version(T, [$:|Acc]) of + false -> + address(port, T, [], [lists:reverse(Acc), ?DEF_VERS|Previous]); + {ok, NewAcc, NewT, Type} -> + address(Type, NewT, [], [lists:reverse(NewAcc), ?DEF_VERS|Previous]) + end; + +%% Parsed one address, port not found. +address(address, [$,|T], [], Previous) -> + {true, lists:reverse([?DEF_PORT|Previous]), T}; +address(address, [$/|T], [], Previous) -> + {false, lists:reverse([?DEF_PORT|Previous]), T}; +address(address, [$,|T], Acc, Previous) -> + {true, lists:reverse([?DEF_PORT, lists:reverse(Acc)|Previous]), T}; +address(address, [$/|T], Acc, Previous) -> + {false, lists:reverse([?DEF_PORT, lists:reverse(Acc)|Previous]), T}; + +%% Parsed one address. +address(port, [$/|T], Acc, Previous) -> + case catch list_to_integer(lists:reverse(Acc)) of + Port when is_integer(Port) -> + {false, lists:reverse([Port|Previous]), T}; + What -> + orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n" + "Malformed port.", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}) + end; +address(port, [$,|T], Acc, Previous) -> + case catch list_to_integer(lists:reverse(Acc)) of + Port when is_integer(Port) -> + {true, lists:reverse([Port|Previous]), T}; + What -> + orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n" + "Malformed port.", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}) + end; + +%% EOS, check how far we have reached so far and add necessary default values. +address(version, [], Acc, Previous) -> + {false, lists:reverse([?DEF_PORT, lists:reverse(Acc), ?DEF_VERS|Previous]), []}; +address(port, [], [], Previous) -> + {false, lists:reverse([?DEF_PORT|Previous]), []}; +address(port, [], Acc, Previous) -> + case catch list_to_integer(lists:reverse(Acc)) of + Port when is_integer(Port) -> + {false, lists:reverse([Port|Previous]), []}; + What -> + orber:dbg("[~p] orber_cosnaming_utils:address(~p);~n" + "Malformed port.", [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}) + end; +address(address, [], [], Previous) -> + {false, lists:reverse([?DEF_PORT|Previous]), []}; +address(address, [], Acc, Previous) -> + {false, lists:reverse([?DEF_PORT, lists:reverse(Acc)|Previous]), []}; + +%% Found port +address(address, [$:|T], Acc, Previous) -> + case check_ip_version(T, [$:|Acc]) of + false -> + address(port, T, [], [lists:reverse(Acc)|Previous]); + {ok, NewAcc, NewT, Type} -> + address(Type, NewT, [], [lists:reverse(NewAcc)|Previous]) + end; + +address(Type, [H|T], Acc, Previous) -> + address(Type, T, [H|Acc], Previous). + + +check_ip_version(T, Acc) -> + case orber_env:ip_version() of + inet -> + false; + inet6 -> + case search_for_delimiter(1, T, Acc, $:) of + {ok, NewAcc, NewT, Type} -> + {ok, NewAcc, NewT, Type}; + _ -> + false + end + end. + +%% An IPv6 address may look like (x == hex, d == dec): +%% * "0:0:0:0:0:0:10.1.1.1" - x:x:x:x:x:x:d.d.d.d +%% * "0:0:0:0:8:800:200C:417A" - x:x:x:x:x:x:x:x +%% We cannot allow compressed addresses (::10.1.1.1) since we it is not +%% possible to know if the last part is a port number or part of the address. +search_for_delimiter(7, [], Acc, $:) -> + {ok, Acc, [], address}; +search_for_delimiter(9, [], Acc, $.) -> + {ok, Acc, [], address}; +search_for_delimiter(_, [], _, _) -> + false; +search_for_delimiter(7, [$/|T], Acc, $:) -> + {ok, Acc, [$/|T], address}; +search_for_delimiter(9, [$/|T], Acc, $.) -> + {ok, Acc, [$/|T], address}; +search_for_delimiter(_, [$/|_T], _Acc, _) -> + false; +search_for_delimiter(7, [$,|T], Acc, $:) -> + {ok, Acc, [$,|T], address}; +search_for_delimiter(9, [$,|T], Acc, $.) -> + {ok, Acc, [$,|T], address}; +search_for_delimiter(_, [$,|_T], _Acc, _) -> + false; +search_for_delimiter(7, [$:|T], Acc, $:) -> + {ok, Acc, T, port}; +search_for_delimiter(9, [$:|T], Acc, $.) -> + {ok, Acc, T, port}; +search_for_delimiter(N, [$:|T], Acc, $:) -> + search_for_delimiter(N+1, T, [$:|Acc], $:); +search_for_delimiter(N, [$.|T], Acc, $.) when N > 6, N < 9 -> + search_for_delimiter(N+1, T, [$.|Acc], $.); +search_for_delimiter(6, [$.|T], Acc, $:) -> + search_for_delimiter(7, T, [$.|Acc], $.); +search_for_delimiter(N, [H|T], Acc, LookingFor) -> + search_for_delimiter(N, T, [H|Acc], LookingFor). + +%%---------------------------------------------------------------------- +%% Function : key +%% Arguments : A string which contain a Key we want to use and, if defined, +%% stringified NameComponent sequence. +%% Description: +%% Returns : The Key and the remaining part, i.e., a stringified +%% NameComponent sequence. +%%---------------------------------------------------------------------- +key(Str) -> + key(Str, []). +key([], []) -> + {?DEF_KEY, []}; +key([], Acc) -> + {lists:reverse(Acc), []}; +key([$#|T], []) -> + {?DEF_KEY, T}; +key([$#|T], Acc) -> + {lists:reverse(Acc), T}; +key([$/|T], []) -> + key(T, []); +key([H|T], Acc) -> + key(T, [H|Acc]). + +%%---------------------------------------------------------------------- +%% Function : name +%% Arguments : A string describing a NameComponent sequence. +%% Description: +%% Returns : The input string | +%% {'EXCEPTION', #'CosNaming_NamingContext_InvalidName'{}} +%%---------------------------------------------------------------------- +name(Str) -> + name(Str, []). +name([], Acc) -> + lists:reverse(Acc); +name([$., $/|_T], _) -> + corba:raise(#'CosNaming_NamingContext_InvalidName'{}); +name([$/, $/|_T], _) -> + corba:raise(#'CosNaming_NamingContext_InvalidName'{}); +name([$/|T], []) -> + name(T, []); +name([H|T], Acc) -> + name(T, [H|Acc]). + + +%%---------------------------------------------------------------------- +%% Function : file +%% Arguments : A string describing connection parameters. +%% Description: +%% Returns : A tuple consisting of data extracted from the given string. +%%---------------------------------------------------------------------- +file(File) -> + {file, File}. + +%%---------------------------------------------------------------------- +%% Function : ftp +%% Arguments : A string describing connection parameters. +%% Description: +%% Returns : A tuple consisting of data extracted from the given string. +%%---------------------------------------------------------------------- +ftp(Address) -> + %% Perhaps we should run some checks here? + {ftp, Address}. + +%%---------------------------------------------------------------------- +%% Function : http +%% Arguments : A string describing connection parameters. +%% Description: +%% Returns : A tuple consisting of data extracted from the given string. +%%---------------------------------------------------------------------- +http(Address) -> + case string:tokens(Address, ":") of + [Host, Rest] -> + %% At his stage we know that address contains a Port number. + {Port, Key} = split_to_slash(Rest, []), + case catch list_to_integer(Port) of + PortInt when is_integer(PortInt) -> + {http, Host, PortInt, Key}; + _ -> + orber:dbg("[~p] orber_cosnaming_utils:http(~p);~n" + "Malformed key; should be http://Host:Port/path/name.html~n" + "or http://Host/path/name.html", + [?LINE, Address], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}) + end; + [Address] -> + %% Use default port + {Host, Key} = split_to_slash(Address, []), + {http, Host, ?HTTP_DEF_PORT, Key}; + _What -> + orber:dbg("[~p] orber_cosnaming_utils:http(~p);~n" + "Malformed key; should be http://Host:Port/path/name.html~n" + "or http://Host/path/name.html", + [?LINE, Address], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}) + end. + +split_to_slash([], _Acc) -> + orber:dbg("[~p] orber_cosnaming_utils:split_to_slash();~n" + "No Key given Host:Port/Key.html", [?LINE], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}); +split_to_slash([$/|Rest], Acc) -> + {lists:reverse(Acc), [$/|Rest]}; +split_to_slash([H|T], Acc) -> + split_to_slash(T, [H|Acc]). + +%%---------------------------------------------------------------------- +%% Function : lookup +%% Arguments : A tuple which contain data about what connection we want to use. +%% Description: +%% Returns : Object | +%% {'EXCEPTION', E} +%%---------------------------------------------------------------------- +lookup(Data) -> + lookup(Data, []). + +lookup({corbaname, rir, _Key, []}, Ctx) -> + %% If no object key supplied NameService is defined to be default. + corba:resolve_initial_references("NameService", Ctx); +lookup({corbaname, rir, Key, Name}, Ctx) -> + NS = corba:resolve_initial_references(Key, Ctx), + 'CosNaming_NamingContext':resolve(NS, Ctx, Name); + +lookup({corbaloc, rir, Key}, Ctx) -> + corba:resolve_initial_references(Key, Ctx); + +lookup({corbaname, [], _Key, _Name}, _Ctx) -> + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}); +lookup({corbaname, Addresses, Key, ""}, Ctx) -> + %% Not Name-string defined, which is the same as corbaloc. + lookup({corbaloc, Addresses, Key}, Ctx); +lookup({corbaname, [[iiop, Vers, Host, Port]|Addresses], Key, Name}, Ctx) -> + NS = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key), + case catch 'CosNaming_NamingContext':resolve(NS, Ctx, Name) of + {'EXCEPTION', _} -> + lookup({corbaname, Addresses, Key, Name}, Ctx); + Obj -> + Obj + end; +lookup({corbaname, [_|Addresses], Key, Name}, Ctx) -> + lookup({corbaname, Addresses, Key, Name}, Ctx); + +lookup({corbaloc, [], _Key}, _Ctx) -> + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}); +lookup({corbaloc, [[iiop, Vers, Host, Port]|Addresses], Key}, Ctx) -> + ObjRef = iop_ior:create_external(Vers, key2id(Key), Host, Port, Key), + OldVal = put(orber_forward_notify, true), + case catch corba_object:non_existent(ObjRef, Ctx) of + {location_forward, Result} -> + put(orber_forward_notify, OldVal), + Result; + false -> + put(orber_forward_notify, OldVal), + ObjRef; + true -> + put(orber_forward_notify, OldVal), + lookup({corbaloc, Addresses, Key}, Ctx); + _ -> + %% May be located on a version using '_not_existent' + %% see CORBA2.3.1 page 15-34 try again. + case catch corba_object:not_existent(ObjRef, Ctx) of + {location_forward, Result} -> + put(orber_forward_notify, OldVal), + Result; + false -> + put(orber_forward_notify, OldVal), + ObjRef; + _ -> + put(orber_forward_notify, OldVal), + lookup({corbaloc, Addresses, Key}, Ctx) + end + end; + +lookup({corbaloc, [_|Addresses], Key}, Ctx) -> + lookup({corbaloc, Addresses, Key}, Ctx); + + +lookup({file, File}, _Ctx) -> + case file:read_file(File) of + {ok, IOR} -> + binary_to_list(IOR); + {error, Reason} -> + orber:dbg("[~p] orber_cosnaming_utils:lookup(~p);~n" + "Failed to access file: ~p.", + [?LINE, File, Reason], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContext_InvalidName'{}) + end; +lookup({http, Host, Port, Key}, _Ctx) -> + SetupTimeout = orber:iiop_setup_connection_timeout(), + SendTimeout = orber:iiop_timeout(), + {ok, Socket} = create_connection(Host, Port, SetupTimeout), + Request = "GET " ++ Key ++ " HTTP/1.0\r\n\r\n", + case gen_tcp:send(Socket, Request) of + ok -> + receive_msg(Socket, [], SendTimeout); + {error, Reason} -> + orber:dbg("[~p] orber_cosnaming_utils:lookup();~n" + "Failed to send request: ~p.", + [?LINE, Reason], ?DEBUG_LEVEL), + corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO}) + end; +lookup({ftp, _Address}, _Ctx) -> + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}); +lookup(_, _Ctx) -> + corba:raise(#'CosNaming_NamingContextExt_InvalidAddress'{}). + + +receive_msg(Socket, Acc, Timeout) -> + receive + {tcp_closed, Socket} -> + [_Header, Body] = re:split(Acc,"\r\n\r\n",[{return,list}]), + Body; + {tcp, Socket, Response} -> + receive_msg(Socket, Acc ++ Response, Timeout); + {tcp_error, Socket, Reason} -> + orber:dbg("[~p] orber_cosnaming_utils:receive_msg();~n" + "connection failed: ~p.", + [?LINE, Reason], ?DEBUG_LEVEL), + gen_tcp:close(Socket), + corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO}) + after Timeout -> + gen_tcp:close(Socket), + corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO}) + end. + +create_connection(Host, Port, Timeout) -> + case gen_tcp:connect(Host,Port,[{packet,0},{reuseaddr,true}], Timeout) of + {ok,Socket} -> + {ok,Socket}; + Error -> + orber:dbg("[~p] orber_cosnaming_utils:create_connection(~p, ~p, ~p);~n" + "Reason: ~p", + [?LINE, Host, Port, Timeout, Error], ?DEBUG_LEVEL), + corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------- +%% Function : key2id +%% Arguments : An objectkey (e.g. NameService) +%% Description: +%% Returns : The associated IFR-id +%%---------------------------------------------------------------------- +key2id(Key) -> + %% We need this test to avoid returning an exit if an XX:typeID() + %% fails (e.g. the module doesn't exist). + case catch key2id_helper(Key) of + {ok, Id} -> + Id; + _ -> + "" + end. + + +key2id_helper("NameService") -> + {ok, 'CosNaming_NamingContext':typeID()}; +key2id_helper("RootPOA") -> + {ok, "IDL:omg.org/PortableServer/POA:1.0"}; +key2id_helper("POACurrent") -> + {ok, "IDL:omg.org/PortableServer/Current:1.0"}; +key2id_helper("InterfaceRepository") -> + {ok, "IDL:omg.org/CORBA/Repository:1.0"}; +key2id_helper("TradingService") -> + {ok, "IDL:omg.org/CosTrading/Lookup:1.0"}; +key2id_helper("TransactionCurrent") -> + {ok, "IDL:omg.org/CosTransactions/Current:1.0"}; +key2id_helper("DynAnyFactory") -> + {ok, "IDL:omg.org/DynamicAny/DynAnyFactory:1.0"}; +key2id_helper("ORBPolicyManager") -> + {ok, "IDL:omg.org/CORBA/PolicyManager:1.0"}; +key2id_helper("PolicyCurrent") -> + {ok, "IDL:omg.org/CORBA/PolicyCurrent:1.0"}; +key2id_helper("NotificationService") -> + {ok, "IDL:omg.org/CosNotifyChannelAdmin/EventChannelFactory:1.0"}; +key2id_helper("TypedNotificationService") -> + {ok, "IDL:omg.org/CosTypedNotifyChannelAdmin::TypedEventChannelFactory:1.0"}; +key2id_helper("CodecFactory") -> + {ok, "IDL:omg.org/IOP/CodecFactory:1.0"}; +key2id_helper("PICurrent") -> + {ok, "IDL:omg.org/PortableInterceptors/Current:1.0"}; +%% Should we use SecurityLevel1 instead?? This key can be either. +key2id_helper("SecurityCurrent") -> + {ok, "IDL:omg.org/SecurityLevel2/Current:1.0"}; +%% Unknown - use the empty string. Might not work for all other ORB's but it's +%% the only option we've got. +key2id_helper(_) -> + {ok, ""}. + + + +%%---------------------------------------------------------------------- +%% Function : name2string +%% Arguments : A sequence of NameComponents +%% Description: +%% Returns : A string describing the sequence. +%%---------------------------------------------------------------------- +name2string(Name) -> + name2string(lists:reverse(Name), []). +name2string([], Acc) -> + lists:flatten(Acc); +name2string([#'CosNaming_NameComponent'{id="", kind=""}], Acc) -> + name2string([], [$.|Acc]); +name2string([#'CosNaming_NameComponent'{id=ID, kind=""}], Acc) -> + name2string([], [convert_reserved(ID)|Acc]); +name2string([#'CosNaming_NameComponent'{id=ID, kind=Kind}], Acc) -> + name2string([], [convert_reserved(ID), $., convert_reserved(Kind)|Acc]); +name2string([#'CosNaming_NameComponent'{id="", kind=""}|T], Acc) -> + name2string(T, [$/, $.|Acc]); +name2string([#'CosNaming_NameComponent'{id=ID, kind=""}|T], Acc) -> + name2string(T, [$/, convert_reserved(ID)|Acc]); +name2string([#'CosNaming_NameComponent'{id=ID, kind=Kind}|T], Acc) -> + name2string(T, [$/, convert_reserved(ID), $., convert_reserved(Kind)|Acc]); +name2string(What, Acc) -> + orber:dbg("[~p] orber_cosnaming_utils:name2string(~p)~n" + "Malformed NameComponent: ~p", + [?LINE, Acc, What], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContext_InvalidName'{}). + +%% '/' and '.' are reserved as separators but can be overridden by using '\'. +convert_reserved([]) -> + []; +convert_reserved([$/|T]) -> + [$\\, $/|convert_reserved(T)]; +convert_reserved([$.|T]) -> + [$\\, $.|convert_reserved(T)]; +convert_reserved([$\\, H|T]) -> + [$\\, H|convert_reserved(T)]; +convert_reserved([H|T]) -> + [H|convert_reserved(T)]. + + +%%---------------------------------------------------------------------- +%% Function : string2name +%% Arguments : A string describing a sequence of NameComponents. +%% Description: +%% Returns : A sequence of NameComponents +%%---------------------------------------------------------------------- +string2name([]) -> + []; +string2name(Str) -> + {NC, Rest} = get_NC(id, Str, [], []), + [NC|string2name(Rest)]. + +get_NC(id, [], ID, _Kind) -> + {#'CosNaming_NameComponent'{id=lists:reverse(ID), kind=""}, []}; +get_NC(kind, [], ID, Kind) -> + {#'CosNaming_NameComponent'{id=lists:reverse(ID), kind=lists:reverse(Kind)}, []}; +%% // is not allowed; must be /./ +get_NC(id, [$/|_T], [], _) -> + orber:dbg("[~p] orber_cosnaming_utils:get_NC();~n" + "'//' not allowed, use '/./'", [?LINE], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContext_InvalidName'{}); +get_NC(id, [$., $/|T], [], _) -> + {#'CosNaming_NameComponent'{id="", kind=""}, T}; +%% End of this ID/Kind; in this case kind eq. "". +get_NC(id, [$/|T], ID, _Kind) -> + {#'CosNaming_NameComponent'{id=lists:reverse(ID), kind=""}, T}; +get_NC(kind, [$/|T], ID, Kind) -> + {#'CosNaming_NameComponent'{id=lists:reverse(ID), kind=lists:reverse(Kind)}, T}; +%% ID exist but it's not allowed to write "id1./id2.kind2". +get_NC(id, [$., $/|_T], _, _) -> + orber:dbg("[~p] orber_cosnaming_utils:get_NC();~n" + "'id1./id2.kind2' not allowed, use 'id1/id2.kind2'", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContext_InvalidName'{}); +get_NC(id, [$\\, $., H|T], ID, Kind) -> + get_NC(id, T, [H, $.|ID], Kind); +get_NC(id, [$\\, $/, H|T], ID, Kind) -> + get_NC(id, T, [H, $/|ID], Kind); +get_NC(kind, [$\\, $., H|T], ID, Kind) -> + get_NC(kind, T, ID, [H|Kind]); +get_NC(kind, [$\\, $/, H|T], ID, Kind) -> + get_NC(kind, T, ID, [H|Kind]); +get_NC(id, [$.|T], ID, Kind) -> + get_NC(kind, T, ID, Kind); +get_NC(id, [H|T], ID, Kind) -> + get_NC(id, T, [H|ID], Kind); +get_NC(kind, [H|T], ID, Kind) -> + get_NC(kind, T, ID, [H|Kind]); +get_NC(Type, Data, ID, Kind) -> + orber:dbg("[~p] orber_cosnaming_utils:get_NC(~p, ~p, ~p, ~p);~n" + "Unknown", [?LINE, Type, Data, ID, Kind], ?DEBUG_LEVEL), + corba:raise(#'CosNaming_NamingContext_InvalidName'{}). + + +%% Converts \< to '%3c' +escape_string(Str) -> + escape_string(Str, []). +escape_string([], Acc) -> + lists:reverse(Acc); +escape_string([$\\, Char |T], Acc) -> + escape_string(T, [code_character(16#0f band Char), + code_character(16#0f band (Char bsr 4)),$%|Acc]); +escape_string([Char|T], Acc) -> + escape_string(T, [Char|Acc]). + + +code_character(N) when N < 10 -> + $0 + N; +code_character(N) -> + $a + (N - 10). + +%% Converts '%3c' to \< +unescape_string(Str) -> + unescape_string(Str, []). +unescape_string([], Acc) -> + lists:reverse(Acc); +unescape_string([$%, H1, H2 |T], Acc) -> + I1 = hex2int(H1), + I2 = hex2int(H2), + I = I1 * 16 + I2, + unescape_string(T, [I, $\\|Acc]); +unescape_string([H|T], Acc) -> + unescape_string(T, [H|Acc]). + +hex2int(H) when H >= $a -> + 10 + H - $a; +hex2int(H) when H >= $A -> + 10 + H -$A; +hex2int(H) -> + H - $0. + +%%-------------------------- END OF MODULE ----------------------------- diff --git a/lib/orber/Makefile b/lib/orber/Makefile new file mode 100644 index 0000000..58a673d --- /dev/null +++ b/lib/orber/Makefile @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(ORBER_VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +SUB_DIRECTORIES = COSS/CosNaming src java_src c_src examples doc/src priv + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_subdir.mk + diff --git a/lib/orber/c_src/InitialReference.cc b/lib/orber/c_src/InitialReference.cc new file mode 100644 index 0000000..a95fa0f --- /dev/null +++ b/lib/orber/c_src/InitialReference.cc @@ -0,0 +1,205 @@ +/** + * + * 1997-2007 + * Ericsson AB, All Rights Reserved + * + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Initial Developer of the Original Code is Ericsson AB. + * + */ +/** + * InitialReference is a class which generates the INIT reference + * which can be used by the InitialReferences interface. + * + * creation date: 1997-11-04 + */ +#include "InitialReference.hh" + +InitialReference::InitialReference() +{ + host = 0; + iorString = 0; +}; + +InitialReference::~InitialReference() +{ + if(host){ + delete host; + delete iorString; + } +}; + + /** + * Returns the stringified objectreference to the initial reference server + */ +char* InitialReference::stringified_ior(char* newhost, int newport) +{ + STRINGSTREAM iorByteString; + STRINGSTREAM profileData; + + STRINGBUF *s; + STRINGBUF *profileDataBuf; + STRINGBUF *iorByteStringBuf; + long profileDataLength = 0; + char *str; + + // byte_order followed by ' {"", [{0, ' + // char iorBytesFirstPart[] = {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0}; + char iorBytesFirstPart[48] = {0,0,0,0,0,0,0,32,73,68,76,58,79,114,98,101,114,47,73,110,105,116,105,97,108,82,101,102,101,114,101,110,99,101,115,58,49,46,48,0,0,0,0,1,0,0,0,0}; + // the objectkey "INIT + char iorBytesLastPart[8] = {0,0,0,4,73,78,73,84}; + + // Fix the ProfileData struct. + char pdPrefix[4] = {0,1,0,0}; + char hsize[4]; + char profileDataLengthBytes[4]; + char portbytes[2]; + long hostLength = strlen(newhost); + + + if(host) + if(strcmp(newhost, host) == 0 && newport == port) + return iorString; + else { + delete host; + delete iorString; + } + host = new char[hostLength+1]; + memcpy(host, newhost, hostLength+1); + port = newport; + + enc_ulong(hostLength + 1, hsize); + enc_ushort(port, portbytes); + + profileDataBuf = profileData.rdbuf(); + + profileDataBuf->sputn(pdPrefix, 4); + profileDataBuf->sputn(hsize, 4); + profileDataBuf->sputn(host, hostLength); + profileDataBuf->sputc(0); + profileDataLength = 4 + 4 + hostLength + 1; + + profileDataLength = align(profileDataBuf, profileDataLength, 2); + + profileDataBuf->sputn(portbytes, 2); + profileDataLength += 2; + + profileDataLength = align(profileDataBuf, profileDataLength, 4); + + profileDataBuf->sputn(iorBytesLastPart, 8); + profileDataLength += 8; + //cout << "pd length: " << profileDataLength << "\n"; + + enc_ulong(profileDataLength, profileDataLengthBytes); + + // Fix the whole IOR + + iorByteStringBuf = iorByteString.rdbuf(); + + iorByteStringBuf->sputn(iorBytesFirstPart, 48); + iorByteStringBuf->sputn(profileDataLengthBytes, 4); +#ifdef HAVE_SSTREAM + iorByteStringBuf->sputn(profileData.str().data(), profileDataLength); +#else + str = profileData.str(); + iorByteStringBuf->sputn(str, profileDataLength); + delete str; +#endif + + createIOR(iorByteString, 48 + 4 + profileDataLength); + + return iorString; +} + + +void InitialReference::enc_ushort(int s, char *byteArray) +{ + byteArray[0] = (char) ((s >> 8) & 0xFF); + byteArray[1] = (char) ((s >> 0) & 0xFF); + + return; +} + +void InitialReference::enc_ulong(long l, char *byteArray) +{ + byteArray[0] = (char) ((l >> 24) & 0xFF); + byteArray[1] = (char) ((l >> 16) & 0xFF); + byteArray[2] = (char) ((l >> 8) & 0xFF); + byteArray[3] = (char) ((l >> 0) & 0xFF); + + return; +} + +void InitialReference::createIOR(strstream& byte, long length) +{ + STRINGBUF *stringbuf; + STRINGSTREAM string; + + int i; +#ifdef HAVE_SSTREAM + const char *c; + const char *bytestr = byte.str().c_str(); +#else + char *c; + char *bytestr = byte.str(); +#endif + int b, n1, n2, c1, c2; + + stringbuf = string.rdbuf(); + stringbuf->sputn("IOR:",4); + + for(i = 0, c = bytestr; i < length; c++, i++) + { + b = *c; + if(b<0) b+= 256; + n1 = b / 16; + n2 = b % 16; + c1 = (n1 < 10) ? ('0' + n1) : ('a' + (n1 - 10)); + c2 = (n2 < 10) ? ('0' + n2) : ('a' + (n2 - 10)); + + stringbuf->sputc(c1); + stringbuf->sputc(c2); + + } + + stringbuf->sputc(0); + + delete bytestr; + +#ifdef HAVE_SSTREAM + iorString = (char *)string.str().c_str(); +#else + iorString = string.str(); +#endif + + return; +} + +long InitialReference::align(STRINGBUF* sbuf, long currentLength, + int alignment) +{ + long length = currentLength; + + int remainder = alignment - (currentLength % alignment); + if (remainder == alignment) return length; + + for (int i = 0; i < remainder; i++) + { + sbuf->sputc(0); + length++; + } + return length; +} + + diff --git a/lib/orber/c_src/InitialReference.hh b/lib/orber/c_src/InitialReference.hh new file mode 100644 index 0000000..1c3c5c8 --- /dev/null +++ b/lib/orber/c_src/InitialReference.hh @@ -0,0 +1,59 @@ +/** + * + * 1997-2007 + * Ericsson AB, All Rights Reserved + * + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Initial Developer of the Original Code is Ericsson AB. + * + */ +/* + * InitialReference is a class for creating an external IOR for the object + * reference INIT. + */ +#ifndef _INITIALREFERENCE_HH +#define _INITIALREFERENCE_HH +#include +#include + +#if HAVE_SSTREAM +#include +typedef std::stringstream STRINGSTREAM; +typedef std::stringbuf STRINGBUF; +#else +#include +typedef strstream STRINGSTREAM; +typedef strstreambuf STRINGBUF; +#endif + +class InitialReference { +private: + char* iorString; + char* host; + int port; + + void enc_ushort(int s, char *byteArray); + void enc_ulong(long l, char *byteArray); + void createIOR(STRINGSTREAM& byte, long length); + long align(STRINGBUF* sbuf, long currentLength, int alignment); + +public: + InitialReference(); + ~InitialReference(); + + char* stringified_ior(char* host, int port); + +}; + +#endif diff --git a/lib/orber/c_src/Makefile b/lib/orber/c_src/Makefile new file mode 100644 index 0000000..73ab79d --- /dev/null +++ b/lib/orber/c_src/Makefile @@ -0,0 +1,23 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Invoke with GNU make or clearmake -C gnu. +# + +include $(ERL_TOP)/make/run_make.mk diff --git a/lib/orber/c_src/Makefile.in b/lib/orber/c_src/Makefile.in new file mode 100644 index 0000000..56f0d57 --- /dev/null +++ b/lib/orber/c_src/Makefile.in @@ -0,0 +1,113 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +CXX = @CXX@ +CC = @CC@ +LIBS = @LIBS@ + +OBJDIR = ../priv/obj/$(TARGET) + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(ORBER_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +CC_FILES = \ + InitialReference.cc + +HH_FILES = \ + InitialReference.hh + +ALL_CFLAGS = @CFLAGS@ @DEFS@ $(CFLAGS) + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(OBJDIR) orber + +ifeq ($(findstring win32,$(TARGET)),win32) +orber: + echo "Nothing to build on NT" +else +ifeq ($(findstring vxworks,$(TARGET)),vxworks) +orber: + echo "Nothing to build for VxWorks" + +else +orber: + echo "Nothing to build" +endif +endif + +clean: + +docs: + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +$(OBJDIR): + -mkdir -p $(OBJDIR) + +$(OBJDIR)/%.o: %.c + $(CC) -c -o $@ $(ALL_CFLAGS) $< + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +ifeq ($(findstring win32,$(TARGET)),win32) +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/priv/src + $(INSTALL_DIR) $(RELSYSDIR)/priv/include + $(INSTALL_PROGRAM) $(CC_FILES) $(RELSYSDIR)/priv/src + $(INSTALL_PROGRAM) $(HH_FILES) $(RELSYSDIR)/priv/include +else +ifeq ($(findstring vxworks,$(TARGET)),vxworks) +release_spec: + $(INSTALL_DIR) $(RELSYSDIR)/priv/src + $(INSTALL_DIR) $(RELSYSDIR)/priv/include + $(INSTALL_PROGRAM) $(CC_FILES) $(RELSYSDIR)/priv/src + $(INSTALL_PROGRAM) $(HH_FILES) $(RELSYSDIR)/priv/include +else +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/priv/src + $(INSTALL_DIR) $(RELSYSDIR)/priv/include + $(INSTALL_DATA) $(CC_FILES) $(RELSYSDIR)/priv/src + $(INSTALL_DATA) $(HH_FILES) $(RELSYSDIR)/priv/include +endif +endif + + +release_docs_spec: diff --git a/lib/orber/c_src/main.cc b/lib/orber/c_src/main.cc new file mode 100644 index 0000000..c1d1707 --- /dev/null +++ b/lib/orber/c_src/main.cc @@ -0,0 +1,31 @@ +/** + * + * 1997-2007 + * Ericsson AB, All Rights Reserved + * + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Initial Developer of the Original Code is Ericsson AB. + * + */ + +#include "InitialReference.hh" + +main() +{ + InitialReference ir; + + cout << ir.stringified_ior("fingolfin", 4001) << "\n"; + + +} diff --git a/lib/orber/doc/etc/.gitignore b/lib/orber/doc/etc/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/orber/doc/html/.gitignore b/lib/orber/doc/html/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/orber/doc/javadoc/.gitignore b/lib/orber/doc/javadoc/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/orber/doc/man1/.gitignore b/lib/orber/doc/man1/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/orber/doc/man3/.gitignore b/lib/orber/doc/man3/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/orber/doc/pdf/.gitignore b/lib/orber/doc/pdf/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/lib/orber/doc/src/CosNaming.xml b/lib/orber/doc/src/CosNaming.xml new file mode 100644 index 0000000..db087ae --- /dev/null +++ b/lib/orber/doc/src/CosNaming.xml @@ -0,0 +1,74 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNaming + + + + 1997-06-10 + A +
+ CosNaming + The CosNaming service is a collection of interfaces that together define the naming service. + +

The naming service provides the principal mechanism for clients to find + objects in an ORB based world. The naming service provides an initial naming + context that functions as the root context for all names. Given this context + clients can navigate in the name space.

+

Types that are declared on the CosNaming level are:

+ Name; + +enum BindingType {nobject, ncontext}; + +struct Binding { + Name binding_name; + BindingType binding_type; +}; + +typedef sequence BindingList; + ]]> +

To get access to the record definitions for the structs use: + -include_lib("orber/COSS/CosNaming.hrl")..

+

Names are not an ORB object but the can be structured in components as seen by + the definition above. There are no requirements on names so the service can support + many different conventions and standards.

+

There are two different interfaces supported in the service:

+ + NamingContext + BindingIterator + +

IDL specification for CosNaming:

+ +
+ +
+ diff --git a/lib/orber/doc/src/CosNaming_BindingIterator.xml b/lib/orber/doc/src/CosNaming_BindingIterator.xml new file mode 100644 index 0000000..83972a6 --- /dev/null +++ b/lib/orber/doc/src/CosNaming_BindingIterator.xml @@ -0,0 +1,98 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNaming_BindingIterator + + + + 1997-06-10 + A +
+ CosNaming_BindingIterator + This interface supports iteration over a name binding list. + +

This interface allows a client to iterate over the Bindinglist it has been + initiated with.

+

The type NameComponent used below is defined as:

+ + -record('CosNaming_NameComponent', {id, kind=""}). + +

id and kind are strings.

+

The type Binding used below is defined as:

+ + -record('CosNaming_Binding', {binding_name, binding_type}). + +

binding_name is a Name = [NameComponent] and + binding_type is an enum which + has the values nobject and ncontext.

+

Both these records are defined in the file CosNaming.hrl and it + is included with:

+ + -include_lib("orber/COSS/CosNaming/CosNaming.hrl"). + +
+ + + next_one(BindinIterator) -> Return + Return a binding + + BindingIterator = #objref + Return = {bool(), Binding} + + +

This operation returns the next binding and a boolean. The latter + is set to true if the binding is valid otherwise false. If the boolean + is false there are no more bindings to retrieve.

+
+
+ + next_n(BindinIterator, HowMany) -> Return + Return a binding list + + BindingIterator = #objref + HowMany = int() + BindingList = [Binding] + Return = {bool(), BindingList} + + +

This operation returns a binding list with at most HowMany bindings. + If there are no more bindings it returns false otherwise true.

+
+
+ + destroy(BindingIterator) -> Return + Destroy the iterator object + + BindingIterator = #objref + Return = ok + + +

This operation destroys the binding iterator.

+
+
+
+ +
+ diff --git a/lib/orber/doc/src/CosNaming_NamingContext.xml b/lib/orber/doc/src/CosNaming_NamingContext.xml new file mode 100644 index 0000000..7a3c7bc --- /dev/null +++ b/lib/orber/doc/src/CosNaming_NamingContext.xml @@ -0,0 +1,249 @@ + + + + +
+ + 19972009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosNaming_NamingContext + + + + 1997-06-10 + A +
+ CosNaming_NamingContext + This interface supports different bind and access functions for names in a context. + +

This is the object that defines name scopes, names must be unique within a + naming context. Objects may have multiple names and may exist in multiple + naming contexts. Name context may be named in other contexts and cycles are + permitted.

+

The type NameComponent used below is defined as:

+ + -record('CosNaming_NameComponent', {id, kind=""}). + +

where id and kind are strings.

+

The type Binding used below is defined as:

+ + -record('CosNaming_Binding', {binding_name, binding_type}). + +

where binding_name is a Name and binding_type is an enum which + has the values nobject and ncontext.

+

Both these records are defined in the file CosNaming.hrl and it + is included with:

+ + -include_lib("orber/COSS/CosNaming/CosNaming.hrl"). + +

There are a number of exceptions that can be returned from functions in this + interface.

+ + +

NotFound is defined as

+ +-record('CosNaming_NamingContext_NotFound', + {rest_of_name, why}). +
+ +

CannotProceed is defined as

+ +-record('CosNaming_NamingContext_CannotProceed', + {rest_of_name, cxt}). +
+ +

InvalidName is defined as

+ +-record('CosNaming_NamingContext_InvalidName', {}). +
+ +

NotFound is defined as

+ +-record('CosNaming_NamingContext_NotFound', {}). +
+ +

AlreadyBound is defined as

+ +-record('CosNaming_NamingContext_AlreadyBound', {}). +
+ +

NotEmpty is defined as

+ +-record('CosNaming_NamingContext_NotEmpty', {). +
+
+

These exceptions are defined in the file CosNaming_NamingContext.hrl and it + is included with:

+ + -include_lib("orber/COSS/CosNaming/CosNaming_NamingContext.hrl"). + +
+ + + bind(NamingContext, Name, Object) -> Return + Bind a Name to an Object + + NameContext = #objref + Name = [NameComponent] + Object = #objref + Return = ok + + +

Creates a binding of a name and an object in the naming context. + Naming contexts that are bound using bind() do not participate + in name resolution.

+
+
+ + rebind(NamingContext, Name, Object) -> Return + Bind an Object to the Name even if the Name already is bound + + NamingContext = #objref + Name = [NameComponent] + Object = #objref + Return = ok + + +

Creates a binding of a name and an object in the naming context even + if the name is already bound. Naming contexts that are bound using + rebind() do not participate in name resolution.

+
+
+ + bind_context(NamingContext1, Name, NamingContex2) -> Return + Bind a Name to an NamingContext + + NamingContext1 = NamingContext2 =#objref + Name = [NameComponent] + Return = ok + + +

The bind_context function creates a binding of a name and a naming context in + the current context. + Naming contexts that are bound using bind_context() participate + in name resolution.

+
+
+ + rebind_context(NamingContext1, Name, NamingContex2) -> Return + Bind an NamingContext to the Name even if the Name already is bound + + NamingContext1 = NamingContext2 =#objref + Name = [NameComponent] + Return = ok + + +

The rebind_context function creates a binding of a name and a naming context in + the current context even if the name already is bound. + Naming contexts that are bound using rebind_context() participate + in name resolution.

+
+
+ + resolve(NamingContext, Name) -> Return + Retrieve an Object bound to Name + + NamingContext = #objref + Name = [NameComponent] + Return = Object + Object = #objref + + +

The resolve function is the way to retrieve an object bound to a name in + the naming context. The given name must match exactly the bound name. The + type of the object is not returned, clients are responsible for narrowing + the object to the correct type.

+
+
+ + unbind(NamingContext, Name) -> Return + Remove the binding for a Name + + NamingContext = #objref + Name = [NameComponent] + Return = ok + + +

The unbind operation removes a name binding from the naming context.

+
+
+ + new_context(NamingContext) -> Return + Create a new NamingContext + + NamingContext = #objref + Return = #objref + + +

The new_context operation creates a new naming context.

+
+
+ + bind_new_context(NamingContext, Name) -> Return + Create a new NamingContext and bind it to a Name + + NamingContext = #objref + Name = [NameComponent] + Return = #objref + + +

The new_context operation creates a new naming context and binds it to + Name in the current context.

+
+
+ + destroy(NamingContext) -> Return + Destroy a NamingContext + + NamingContext = #objref + Return = ok + + +

The destroy operation disposes the NamingContext object and removes it from the + name server. The context must be empty e.g. not contain any bindings to be + removed.

+
+
+ + list(NamingContext, HowMany) -> Return + List returns a all bindings in the context + + NamingContext = #objref + HowMany = int() + Return = {ok, BindingList, BindingIterator} + BindingList = [Binding] + BindingIterator = #objref + + +

The list operation returns a BindingList with a number of bindings up-to + HowMany from the context. It also returns a BindinIterator which can be used to + step through the list. If the total number of existing bindings are less + than, or equal to, the HowMany parameter a NIL object reference + is returned.

+

+ +

One must destroy the BindingIterator, unless it is a NIL object + reference, by using 'BindingIterator':destroy(). Otherwise one can get + dangling objects.

+
+
+
+
+ +
+ diff --git a/lib/orber/doc/src/CosNaming_NamingContextExt.xml b/lib/orber/doc/src/CosNaming_NamingContextExt.xml new file mode 100644 index 0000000..ef091bc --- /dev/null +++ b/lib/orber/doc/src/CosNaming_NamingContextExt.xml @@ -0,0 +1,102 @@ + + + + +
+ + 2000 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + CosNaming_NamingContextExt + + + + 2000-08-16 + A +
+ CosNaming_NamingContextExt + This interface contains operation for converting a Name sequence to a string and back. + +

To get access to the record definitions for the structures use:

+

+ + -include_lib("orber/COSS/CosNaming/CosNaming.hrl"). + +

This module also exports the functions described in:

+ + +

CosNaming_NamingContext

+
+
+
+ + + to_string(NamingContext, Name) -> Return + Stringify a Namesequence to a string + + NameContext = #objref + Name = [NameComponent] + Return = string() | {'EXCEPTION', NamingContext::InvalidName{}} + + +

Stringifies a Name sequence to a string.

+
+
+ + to_name(NamingContext, NameString) -> Return + Convert a stringified Nameto a Namesequence + + NameContext = #objref + NameString = string() + Return = [NameComponent] | {'EXCEPTION', NamingContext::InvalidName{}} + + +

Converts a stringified Name to a Name sequence.

+
+
+ + to_url(NamingContext, AddressString, NameString) -> Return + Return an URL string constructed from the given Address and Name strings + + NameContext = #objref + Address = NameString = string() + Return = URLString | {'EXCEPTION', NamingContext::InvalidName{}} | {'EXCEPTION', NamingContextExt::InvalidAddress{}} + + +

This operation takes a corbaloc string and a stringified Name + sequence as input and returns a fully formed URL string.

+
+
+ + resolve_str(NamingContext, NameString) -> Return + Return the object associated, if any, with the given name string + + NameContext = #objref + NameString = string() + Return = #objref | {'EXCEPTION', NamingContext::InvalidName{}} | {'EXCEPTION', NamingContext::NotFound{why, rest_of_name}} | {'EXCEPTION', NamingContext::CannotProceed{cxt, rest_of_name}} + + +

This operation takes a stringified Name sequence as input and + returns the associated, if any, object.

+
+
+
+ +
+ diff --git a/lib/orber/doc/src/Makefile b/lib/orber/doc/src/Makefile new file mode 100644 index 0000000..40f5ef8 --- /dev/null +++ b/lib/orber/doc/src/Makefile @@ -0,0 +1,272 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(ORBER_VSN) +APPLICATION=orber + +# ---------------------------------------------------- +# Include dependency +# ---------------------------------------------------- + +ifndef DOCSUPPORT +include make.dep +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml +XML_REF3_FILES = \ + any.xml \ + corba.xml \ + corba_object.xml \ + orber.xml \ + CosNaming.xml \ + CosNaming_NamingContext.xml \ + CosNaming_NamingContextExt.xml \ + CosNaming_BindingIterator.xml \ + lname.xml \ + lname_component.xml \ + orber_ifr.xml \ + orber_tc.xml \ + Module_Interface.xml \ + interceptors.xml \ + fixed.xml \ + orber_diagnostics.xml \ + orber_acl.xml + +XML_PART_FILES = \ + part_notes_history.xml \ + part.xml \ + part_notes.xml + +XML_CHAPTER_FILES = \ + ch_contents.xml \ + ch_introduction.xml \ + ch_orber_kernel.xml \ + ch_ifr.xml \ + ch_install.xml \ + ch_idl_to_erlang_mapping.xml \ + ch_example.xml \ + ch_naming_service.xml \ + ch_stubs.xml \ + ch_security.xml \ + notes.xml \ + ch_exceptions.xml \ + ch_interceptors.xml \ + ch_orberweb.xml \ + ch_debugging.xml + +XML_HTML_FILES = \ + notes_history.xml + + +BOOK_FILES = book.xml + +XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF3_FILES) \ + $(XML_PART_FILES) $(XML_CHAPTER_FILES) + +TECHNICAL_DESCR_FILES = + +GIF_FILES = \ + book.gif \ + notes.gif \ + ref_man.gif \ + user_guide.gif \ + name.gif \ + orbs.gif \ + theORB.gif \ + iiop.gif \ + dependent.gif \ + interceptor_operations.gif \ + menuframe.gif \ + dataframe1.gif \ + dataframe2.gif \ + dataframe3.gif \ + dataframe4.gif \ + dataframe5.gif \ + dataframe6.gif \ + dataframe7.gif \ + dataframe8.gif \ + firewall_nat.gif + +# ---------------------------------------------------- + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_HTML_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +INFO_FILE = ../../info +EXTRA_FILES = summary.html.src \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) + +ifdef DOCSUPPORT + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +else + +TEX_FILES_BOOK = \ + $(BOOK_FILES:%.xml=%.tex) +TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \ + $(XML_APPLICATION_FILES:%.xml=%.tex) +TEX_FILES_USERS_GUIDE = \ + $(XML_CHAPTER_FILES:%.xml=%.tex) + +TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf +TOP_PS_FILE = $(APPLICATION)-$(VSN).ps + +$(TOP_PDF_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ + +$(TOP_PS_FILE): book.dvi ../../vsn.mk + $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ + +endif + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + + +ifdef DOCSUPPORT + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + rm -f $(JD_HTML) $(JD_PACK) + +else + +ifeq ($(DOCTYPE),pdf) +docs: pdf +else +ifeq ($(DOCTYPE),ps) +docs: ps +else +docs: html gifs man +endif +endif + +pdf: $(TOP_PDF_FILE) + +ps: $(TOP_PS_FILE) + +html: $(HTML_FILES) $(INTERNAL_HTML_FILES) + +clean clean_docs clean_tex: + rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK) + rm -f $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE) + rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN) + rm -f $(JD_HTML) $(JD_PACK) + +endif + + +man: $(MAN3_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + + +ifdef DOCSUPPORT + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 +else + +ifeq ($(DOCTYPE),pdf) +release_docs_spec: pdf + $(INSTALL_DIR) $(RELEASE_PATH)/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf +else +ifeq ($(DOCTYPE),ps) +release_docs_spec: ps + $(INSTALL_DIR) $(RELEASE_PATH)/ps + $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps +else +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + +endif +endif + +endif + +release_spec: + diff --git a/lib/orber/doc/src/Module_Interface.xml b/lib/orber/doc/src/Module_Interface.xml new file mode 100644 index 0000000..85f19cc --- /dev/null +++ b/lib/orber/doc/src/Module_Interface.xml @@ -0,0 +1,355 @@ + + + + +
+ + 1999 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + Module_Interface + + + + 1999-09-03 + A +
+ Module_Interface + Orber generated stubs/skeletons. + +

This module contains the stub/skeleton functions generated by IC.

+

Starting a Orber server can be done in three ways:

+ + Normal - when the server dies Orber forgets all knowledge of the server. + Supervisor child - adding the configuration parameter {sup_child, true} + the oe_create_link/2 function returns {ok, Pid, ObjRef} which + can be handled by the application supervisor/stdlib-1.7 or later. + Persistent object reference - adding the configuration parameters {persistent, true} + and {regname, {global, term()}} Orber will remember the object reference until the + server terminates with reason normal or shutdown. Hence, + if the server is started as a transient supervisor child we do not + receive a 'OBJECT_NOT_EXIST' exception when it has crashed and is being restarted. + +

The Orber stub can be used to start a pseudo object, which will create a non-server implementation. + A pseudo object introduce some limitations:

+ + The functions oe_create_link/2 is equal to oe_create/2, i.e., + no link can or will be created. + The BIF:s self() and process_flag(trap_exit,true) behaves incorrectly. + The IC option {{impl, "M::I"}, "other_impl"} has no effect. The call-back + functions must be implemented in a file called M_I_impl.erl + The IC option from has no effect. + The call-back functions must be implemented as if the IC option + {this, "M::I"} was used. + Server State changes have no effect. The user can provide information via + the Env start parameter and the State returned from init/2 will be the State + passed in following invocations. + If a call-back function replies with the Timeout parameter set it have no effect. + Operations defined as oneway are blocking until the operation replies. + The option {pseudo, true} overrides all other start options. + Only the functions, besides own definitions, init/2 (called via oe_create*/2) and + terminate/2 (called via corba:dispose/1) must be implemented. + +

By adopting the rules for pseudo objects described above we can use oe_create/2 + to create server or pseudo objects, by excluding or including the + option {pseudo, true}, without changing the call-back module. +

+

If you start a object without {regname, RegName} it can only be accessed through the returned object key. + Started with a {regname, RegName} the name is registered locally or globally. +

+ +

To avoid flooding Orber with old object references start erlang using the flag + -orber objectkeys_gc_time Time, which will remove all object references + related to servers being dead for Time seconds. To avoid extra overhead, i.e., performing + garbage collect if no persistent objects are started, the objectkeys_gc_time default value + is infinity. For more information, see the orber and corba documentation.

+
+
+ + + Module_Interface:typeID() -> TypeId + Return the Type ID related to this stub/skeleton + + TypeId = string(), e.g., "IDL:Module/Interface:1.0" + + +

Returns the Type ID related to this stub/skeleton

+
+
+ + Module_Interface:oe_create() -> ObjRef + Start a Orber server. + + ObjRef = #object reference + + +

Start a Orber server.

+
+
+ + Module_Interface:oe_create_link() -> ObjRef + Start a linked Orber server. + + ObjRef = #object reference + + +

Start a linked Orber server.

+
+
+ + Module_Interface:oe_create(Env) -> ObjRef + Start a Orber server. + + Env = term() + ObjRef = #object reference + + +

Start a Orber server passing Env to init/1.

+
+
+ + Module_Interface:oe_create_link(Env) -> ObjRef + Start a linked Orber server. + + Env = term() + ObjRef = #object reference + + +

Start a linked Orber server passing Env to init/1.

+
+
+ + Module_Interface:oe_create(Env, Options) -> ObjRef + Start a Orber stub/skeleton + + Env = term() + ObjRef = #object reference + Options = [{sup_child, false} | {persistent, Bool} | {regname, RegName} | {pseudo, Bool} | {local_typecheck, Bool} | {survive_exit, Bool} | {create_options, [CreateOpts]}] + Bool = true | false + RegName = {global, term()} | {local, atom()} + CreateOpts = {debug, [Dbg]} | {timeout, Time} + Dbg = trace | log | statistics | {log_to_file, FileName} + + +

Start a Orber server passing Env to init/1.

+

If the option {pseudo, true} is used, all other options are overridden. + As default, this option is set to false.

+

This function cannot be used for starting a server as supervisor child. + If started as persistent, the options [{persistent, true}, {regname, {global, term()}}] must be used and + Orber will only forget the object reference if it terminates with reason normal or shutdown.

+

The option {local_typecheck, boolean()}, which overrides the + Local Typechecking + environment flag, turns on or off typechecking. If activated, + parameters, replies and raised exceptions will be checked to ensure that + the data is correct, when invoking operations on CORBA Objects within + the same Orber domain. Due to the extra overhead, this option + MAY ONLY be used during testing and development.

+

{survive_exit, boolean()} overrides the + EXIT Tolerance + environment flag. If activated, the server will not terminate, even though + the call-back module returns EXIT.

+

Time specifies how long time, in milliseconds, the server is allowed to + spend initializing. For more information about the Dbg options, + see the sys module.

+
+
+ + Module_Interface:oe_create_link(Env, Options) -> Return + Start a Orber stub/skeleton + + Env = term() + Return = ObjRef | {ok, Pid, ObjRef} + ObjRef = #object reference + Options = [{sup_child, Bool} | {persistent, Bool} | {regname, RegName} | {pseudo, Bool} | {local_typecheck, Bool} | {survive_exit, Bool} | {create_options, [CreateOpts]}] + Bool = true | false + RegName = {global, term()} | {local, atom()} + CreateOpts = {debug, [Dbg]} | {timeout, Time} + Dbg = trace | log | statistics | {log_to_file, FileName} + + + + + +

Start a linked Orber server passing Env to init/1.

+

If the option {pseudo, true} is used, all other options are overridden and no link will be created. + As default, this option is set to false.

+

This function can be used for starting a server as persistent or supervisor child. At the moment + [{persistent, true}, {regname, {global, term()}}] must be used to start + a server as persistent, i.e., if a server died and is in the process of being restarted + a call to the server will not raise 'OBJECT_NOT_EXIST' exception. + Orber will only forget the object reference if it terminates with reason normal or shutdown, + hence, the server must be started as transient (for more information see the + supervisor documentation).

+

The options {local_typecheck, boolean()} and {survive_exit, boolean()} + behaves in the same way as for oe_create/2.

+

Time specifies how long time, in milliseconds, the server is allowed to + spend initializing. For more information about the Dbg options, + see the sys module.

+
+
+ + Module_Interface:own_functions(ObjRef, Arg1, ..., ArgN) -> Reply + Module_Interface:own_functions(ObjRef, Options, Arg1, ..., ArgN) -> Reply + User defined function which is not a part of Orber + + ObjRef = #object reference + Options = [Option] | Timeout + Option = {timeout, Timeout} | {context, [Context]} + Timeout = infinity | integer(milliseconds) + Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData} + CtxId = ?ORBER_GENERIC_CTX_ID + CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options} + Interface = string() + Options = [{Key, Value}] + Key = ssl_client_verify | ssl_client_depth | ssl_client_certfile | ssl_client_cacertfile | + ssl_client_password | ssl_client_keyfile | ssl_client_ciphers | ssl_client_cachetimeout + Value = allowed value associated with the given key + ArgX = specified in the IDL-code. + Reply = specified in the IDL-code. + + +

The default value for the Timeout option is infinity. + IPv4 or IPv6 addresses are accepted as local Interface.

+

The configuration context is used to override the global + SSL client side + configuration.

+

To gain access to #'IOP_ServiceContext'{} record and the + ?ORBER_GENERIC_CTX_ID macro, you must add + -include_lib("orber/include/corba.hrl"). to your module.

+
+
+
+ +
+ CALLBACK FUNCTIONS +

The following functions should be exported from a CORBA + callback module. Note, a complete template of the call-back module can + be generated automatically by compiling the IDL-file with the IC option + {be,erl_template}. One should also add + the same compile options, for example this or from, + used when generating the stub/skeleton modules.

+
+ + + Module_Interface_impl:init(Env) -> CallReply + User defined function which is not a part of Orber + + Env = term() + CallReply = {ok, State} | {ok, State, Timeout} | ignore | {stop, StopReason} + State = term() + Timeout = int() >= 0 | infinity + StopReason = term() + + +

Whenever a new server is started, init/1 is the first function called in the specified call-back module.

+
+
+ + Module_Interface_impl:terminate(Reason, State) -> ok + User defined function which is not a part of Orber + + Reason = term() + State = term() + + +

This call-back function is called whenever the server is about to terminate.

+
+
+ + Module_Interface_impl:code_change(OldVsn, State, Extra) -> CallReply + User defined function which is not a part of Orber + + OldVsn = undefined | term() + State = term() + Extra = term() + CallReply = {ok, NewState} + NewState = term() + + +

Update the internal State.

+
+
+ + Module_Interface_impl:handle_info(Info, State) -> CallReply + User defined function which is not a part of Orber + + Info = term() + State = term() + CallReply = {noreply, State} | {noreply, State, Timeout} | {stop, StopReason, State} + Timeout = int() >= 0 | infinity + StopReason = normal | shutdown | term() + + +

If the configuration parameter {{handle_info, "Module::Interface"}, true} + is passed to IC and process_flag(trap_exit,true) is set in the init() + call-back this function must be exported.

+ +

To be able to handle the Timeout option in CallReply in the call-back + module the configuration parameter {{handle_info, "Module::Interface"}, true} must + be passed to IC.

+
+
+
+ + Module_Interface_impl:own_functions(State, Arg1, ..., ArgN) -> CallReply + Module_Interface_impl:own_functions(This, State, Arg1, ..., ArgN) -> CallReply + Module_Interface_impl:own_functions(This, From, State, Arg1, ..., ArgN) -> ExtCallReply + Module_Interface_impl:own_functions(From, State, Arg1, ..., ArgN) -> ExtCallReply + User defined function which is not a part of Orber + + This = the servers #object reference + State = term() + ArgX = specified in the IDL-code. + CallReply = {reply, Reply, State} | {reply, Reply, State, Timeout} | {stop, StopReason, Reply, State} | {stop, StopReason, State} | corba:raise(Exception) + ExtCallReply = CallReply | corba:reply(From, Reply), {noreply, State} | corba:reply(From, Reply), {noreply, State, Timeout} + Reply = specified in the IDL-code. + Timeout = int() >= 0 | infinity + StopReason = normal | shutdown | term() + + +

All two-way functions must return one of the listed replies or raise any of + the exceptions listed in the IDL code (i.e. raises(...)). + If the IC compile options this and/or from are used, + the implementation must accept the This and/or From + parameters.

+
+
+ + Module_Interface_impl:own_functions(State, Arg1, ..., ArgN) -> CastReply + Module_Interface_impl:own_functions(This, State, Arg1, ..., ArgN) -> CastReply + User defined function which is not a part of Orber + + This = the servers #object reference + State = term() + CastReply = {noreply, State} | {noreply, State, Timeout} | {stop, StopReason, State} + ArgX = specified in the IDL-code. + Reply = specified in the IDL-code. + Timeout = int() >= 0 | infinity + StopReason = normal | shutdown | term() + + +

All one-way functions must return one of the listed replies. + If the IC compile option this is used, + the implementation must accept the This parameter.

+
+
+
+ +
+ diff --git a/lib/orber/doc/src/Orber/InitialReference.java b/lib/orber/doc/src/Orber/InitialReference.java new file mode 100644 index 0000000..300de59 --- /dev/null +++ b/lib/orber/doc/src/Orber/InitialReference.java @@ -0,0 +1,130 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/** + * InitialReference is a class which generates the INIT reference + * which can be used by the InitialReferences interface. + */ +package Orber; + +public class InitialReference +{ + + /** + * Constructor. + */ + public InitialReference(){;} + + /** + * Returns the stringified objectreference to the initial reference server + */ + public String stringified_ior(String host, int port) + { + String iorByteString; + String profileData; + String iorString; + + // byte_order followed by ' {"", [{0, ' + // char iorBytesFirstPart[] = {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0}; + char iorBytesFirstPart[] = {0,0,0,0,0,0,0,32,73,68,76,58,79,114,98,101,114,47,73,110,105,116,105,97,108,82,101,102,101,114,101,110,99,101,115,58,49,46,48,0,0,0,0,1,0,0,0,0}; + // the objectkey "INIT + char iorBytesLastPart[] = {0,0,0,4,73,78,73,84}; + + // Fix the ProfileData struct. + char pdPrefix[] = {0,1,0,0}; + char nullbyte[] = {0}; + profileData = new String(pdPrefix) + enc_ulong(host.length() + 1) + host + new String(nullbyte); + profileData = align(profileData, 2); + profileData += enc_ushort(port); + profileData = align(profileData, 4); + profileData += new String(iorBytesLastPart); + // Fix the whole IOR + iorByteString = new String(iorBytesFirstPart) + enc_ulong(profileData.length()) + + profileData; + + // System.out.print("Start[" + profileData.length() + "]"); + // System.out.print("["); + // for(int x = 0; x < iorByteString.length(); x++) + // { + // System.out.print((int) iorByteString.charAt(x) + ","); + // } + // System.out.println("]"); + + iorString = createIOR(iorByteString); + // System.out.println(iorString); + return iorString; + } + + + private String enc_ushort(int s) + { + char byteArray[] = {(char) ((s >>> 8) & 0xFF), + (char) ((s >>> 0) & 0xFF)}; + + return new String(byteArray); + } + + private String enc_ulong(int l) + { + char byteArray[] = {(char) ((l >>> 24) & 0xFF), + (char) ((l >>> 16) & 0xFF), + (char) ((l >>> 8) & 0xFF), + (char) ((l >>> 0) & 0xFF)}; + + return new String(byteArray); + + } + + private String createIOR(String bytes) + { + int i; + StringBuffer sb = new StringBuffer("IOR:"); + + for(i = 0; i < bytes.length(); i++) + { + int b = bytes.charAt(i); + if(b<0) b+= 256; + int n1 = b / 16; + int n2 = b % 16; + int c1 = (n1 < 10) ? ('0' + n1) : ('a' + (n1 - 10)); + int c2 = (n2 < 10) ? ('0' + n2) : ('a' + (n2 - 10)); + sb.append((char)c1); + sb.append((char)c2); + } + + return sb.toString(); + } + + private String align(String buffer, int alignment) + { + String s = buffer; + char nullbyte[] = {0}; + + int remainder = alignment - (buffer.length() % alignment); + if (remainder == alignment) return s; + + for (int i = 0; i < remainder; i++) + { + s += new String(nullbyte); + } + return s; + } + + +} diff --git a/lib/orber/doc/src/Orber/Makefile b/lib/orber/doc/src/Orber/Makefile new file mode 100644 index 0000000..49da975 --- /dev/null +++ b/lib/orber/doc/src/Orber/Makefile @@ -0,0 +1,70 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(ORBER_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN) + +# +# JAVA macros +# +JAVA_CLASSES = \ + InitialReference + +JAVA_FILES= $(JAVA_CLASSES:%=%.java) + +CLASSPATH = ../.. + +# ---------------------------------------------------- +# Flags +# ---------------------------------------------------- +JAVA_OPTIONS = + +# ---------------------------------------------------- +# Make Rules +# ---------------------------------------------------- + +debug opt: + +clean: + +docs: + +# ---------------------------------------------------- +# Release Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/java_src/Orber + $(INSTALL_DATA) $(JAVA_FILES) $(RELSYSDIR)/java_src/Orber + +release_docs_spec: + diff --git a/lib/orber/doc/src/Orber/ignore_config_record.inf b/lib/orber/doc/src/Orber/ignore_config_record.inf new file mode 100644 index 0000000..0a5053e --- /dev/null +++ b/lib/orber/doc/src/Orber/ignore_config_record.inf @@ -0,0 +1 @@ +This file makes clearmake use the -T switch for this subdirectory diff --git a/lib/orber/doc/src/any.xml b/lib/orber/doc/src/any.xml new file mode 100644 index 0000000..6ba1a96 --- /dev/null +++ b/lib/orber/doc/src/any.xml @@ -0,0 +1,116 @@ + + + + +
+ + 1998 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + any + + + + 1998-04-20 + A +
+ any + the corba any type + +

This module contains functions that gives an interface to the CORBA any type.

+

Note that the any interface in orber does not contain a destroy + function because the any type is represented as an Erlang record and + therefor will be removed by the garbage collector when not in use.

+

The type TC used below describes an IDL type and is a tuple according + to the to the Erlang language mapping.

+

The type Any used below is defined as:

+ + -record(any, {typecode, value}). + +

where typecode is a TC tuple and value is an Erlang term of + the type defined by the typecode field.

+
+ + + create() -> Result + create(Typecode, Value) -> Result + Create an any record + + Typecode = TC + Value = term() + Result = Any + + +

The create/0 function creates an empty any record and the create/2 + function creates an initialized record.

+
+
+ + set_typecode(A, Typecode) -> Result + Set the typecode field + + A = Any + Typecode = TC + Result = Any + + +

This function sets the typecode of A and returns a + new any record.

+
+
+ + get_typecode(A) -> Result + Fetch the typecode + + A = Any + Result = TC + + +

This function returns the typecode of A.

+
+
+ + set_value(A, Value) -> Result + Set the value field + + A = Any + Value = term() + Result = Any + + +

This function sets the value of A and returns a + new any record.

+
+
+ + get_value(A) -> Result + Fetch the value + + A = Any + Result = term() + + +

This function returns the value of A. +

+
+
+
+ +
+ diff --git a/lib/orber/doc/src/book.gif b/lib/orber/doc/src/book.gif new file mode 100644 index 0000000000000000000000000000000000000000..94b38687920c5386f0d90df2cfc962d66f52fbce GIT binary patch literal 1081 zcmV-91jhSENk%v~VJrYQ0K@U3Z&d%1>*52OU z=jZ3|@9+2b_W%F@EC2ui04xAE000I5ARvxpX`Uh%Eez$Ma2!{|XMe{g?|T;9x5JA^ zG%bL@N^vRj5RkV9bLkO4ZPIBmas5oR#mf&V1Q#(0YhcjmXe*9~d=7a)?vMy(=-KE* z8yQRzT~`AL3l4P-3kL!Lf=d(yg_TGJLq#4K5D7Jwg%4&P850c&1Y@8d0)H_S5pFPj z7ZR$K4m$^o4iXXx39coCpaZff8wUU$784g63O)Mnh1d zM*Ony;LwB#3?8W4Fn~dfDxggNp6C!kf(B*{AQb3^!o#OZ2{2Ij__0FI3O->S0!o2G zg@f-96evKTsnY>a2Pj~$%K;+++!`!k(;yCksSK!^1M@%uPY44fe1t$i?MDI+c2ZbC za|F=4KrQICaN${m0^A%h5YV8o0a~3adU`fEQr`1qssBIw;^v!UF;k;yW-v@4+eo>JYd}fHVVU z5gLf*p9x%mVi^DlSTI8WPNw|_zy%J@^^O%t7;wu6|1F@62n+%+n+O+(7C~JYKp}tz zPXIAiOdhnDfD0a6fWQkLNGO6;!$2WQfj6jx)&W2YPymny2!Ox=N)36z-FBgSXr4c6dN%+LI-06;0gjrH4CDHEr=iiO;mnh?Fk3i5Wq1C#9AnbqG>3C zxFaCoE>b2iV1odev}UfA7}V< + + + +
+ + 19972009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + orber + + + 1998-04-25 + 2.0 +
+ + + Orber + + + + + + + + + + + + + + +
+ diff --git a/lib/orber/doc/src/ch_contents.xml b/lib/orber/doc/src/ch_contents.xml new file mode 100644 index 0000000..6538380 --- /dev/null +++ b/lib/orber/doc/src/ch_contents.xml @@ -0,0 +1,172 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The Orber Application + + + 1998-05-05 + B + ch_contents.xml +
+ +
+ Content Overview +

The Orber documentation is divided into three sections: +

+ + +

PART ONE - The User's Guide +

+Description of the Orber Application including IDL-to-Erlang + language mapping, services and a small tutorial demonstrating + the development of a simple service.

+
+ +

PART TWO - Release Notes +

+A concise history of Orber.

+
+ +

PART THREE - The Reference Manual +

+ A quick reference guide, including a + brief description, to all the functions available in Orber.

+
+
+
+ +
+ Brief Description of the User's Guide +

The User's Guide contains the following parts:

+ + +

ORB kernel and IIOP support

+
+ +

Interface Repository

+
+ +

IDL to Erlang mapping

+
+ +

CosNaming Service

+
+ +

Resolving initial reference from Java or C++

+
+ +

Tutorial - creating a simple service

+
+ +

CORBA Exceptions

+
+ +

Interceptors

+
+ +

OrberWeb

+
+ +

Debugging +

+
+
+ +
+ ORB Kernel and IIOP Support +

The ORB kernel which has IIOP support will allow the creation + of persistent server objects in Erlang. These objects can also + be accessed via Erlang and Java environments. For the moment a + Java enabled ORB is needed to generate Java from IDL to use + Java server objects (this has been tested using OrbixWeb).

+
+ +
+ Interface Repository +

The IFR is an interface repository used for some type-checking + when coding/decoding IIOP. The IFR is capable of storing all + interfaces and declarations of OMG IDL.

+
+ +
+ IDL to Erlang Mapping +

The OMG IDL mapping for Erlang, which is necessary to access the + functionality of Orber, is described, The mapping structure is + included as the\011basic and the constructed OMG IDL types + references, invocations\011and Erlang characteristics. An example is + also provided.

+
+ +
+ CosNaming Service +

Orber contains a CosNaming compliant service.

+
+ +
+ Resolving Initial References from Java or C++ +

A couple of classes are added to Orber to simplify initial + reference access from Java or C++. +

+

Resolving initial reference from Java

+ A class with only one method which returns an Interoperable Object Referenceon the + external string format to the INIT object (see "Interoperable + Naming Service" specification).

+

Resolving initial reference from C++

+ + A class (and header file) with only one method which returns + an IOR on the external string format to the INIT object (see + "Interoperable Naming Service" specification).

+
+ +
+ Orber Stub/Skeleton +

An example which describes the API and behavior of Orber stubs and skeletons.

+
+ +
+ CORBA Exceptions +

A listing of all system exceptions supported by Orber and how one should + handle them. This chapter also describe how to generate user defined + exceptions.

+
+ +
+ Interceptors +

Descibes how to implement and activate interceptors.

+
+ +
+ OrberWeb +

Offers the possibility to administrate and supervise Orber via a GUI.

+
+ +
+ Debugging +

Describes how to use different tools when debugging and/or developing + new applications using Orber. Also includes a FAQ, which deal with + the most common mistakes when using Orber. +

+
+
+
+ diff --git a/lib/orber/doc/src/ch_debugging.xml b/lib/orber/doc/src/ch_debugging.xml new file mode 100644 index 0000000..8c5685b --- /dev/null +++ b/lib/orber/doc/src/ch_debugging.xml @@ -0,0 +1,209 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Debugging + + + 2001-11-29 + + ch_debugging.xml +
+ +
+ Tools and FAQ +

Persons who use Orber for the first time may find it hard to tell what goes + wrong when trying to setup communication between an Orber-ORB and ORB:s supplied + by another vendor or another Orber-ORB. The purpose of this chapter is to inform + about the most common mistakes and what tools one can use to overcome these + problems.

+ +
+ Tools +

To begin with, Orber can be configured to run in debug mode. There are four ways + to set this parameter:

+ + erl -orber orber_debug_level 10 - can be added to a start-script. + corba:orb_init([{orber_debug_level, 10}]) - this operation must + be invoked before starting Orber. + orber:configure(orber_debug_level, 10) - this operation can + be invoked at any time. + OrberWeb - via the Configuration menu one can easily change + the configuration. For more information, see the OrberWeb chapter in this + User's Guide. + +

When Orber runs i debug mode, printouts will be generated if anything abnormal occurs + (not necessarily an error). An error message typically looks like:

+ +=ERROR REPORT==== 29-Nov-2001::14:09:55 === +=================== Orber ================= +[410] corba:common_create(orber_test_server, [{pseudo,truce}]); +not a boolean(truce). +=========================================== + +

In the example above, we tried to create an object with an incorrect option (i.e. should + have been {pseudo,true}).

+

If you are not able to solve the problem, you should include all generated reports when + contacting support or using the erlang-questions mailing list.

+

It is easy to forget to, for example, set all fields in a struct, which + one may not discover when developing an application using Orber. When using + a typed language, such faults would cause a compile time error. To avoid + these mistakes, Orber allows the user to activate automatic typechecking + of all local invocations of CORBA Objects. For this feature to be really + useful, the user must create test suites which cover as much as + possible. For example, invoking an operation with invalid or incorrect + arguments should also be tested. This option can be activated for one object + or all object via:

+ + 'MyModuyle_MyInterface':oe_create(Env, [{local_typecheck, true}]) - + This approach will only activate, or deactivate, typechecking for + the returned instance. Naturally, this option can also be passed + to oe_create_link/2, corba:create/4 and + corba:create_link/4. + erl -orber flags 2 - can be added to a start-script. + All object invocations will be typechecked, unless overridden by the + previous option. + corba:orb_init([{flags, 16#0002}]) - this operation must + be invoked before starting Orber. Behaves as the previous + option. + +

If incorrect data is passed or returned, Orber uses the error_logger + to generate logs, which can look like:

+ +=ERROR REPORT==== 10-Jul-2002::12:36:09 === +========= Orber Typecheck Request ========= +Invoked......: MyModule_MyInterface:foo/1 +Typecode.....: [{tk_enum,"IDL:MyModule/enumerant:1.0", + "enumerant", + ["one","two"]}] +Arguments....: [three] +Result.......: {'EXCEPTION',{'MARSHAL',[],102,'COMPLETED_NO'}} +=========================================== + +

Note, that the arity is equivalent to the IDL-file. In the example above, + an undefined enumerant was used. In most cases, it is useful to set the + configuration parameter orber_debug_level 10 as well. Due to the + extra overhead, this option MAY ONLY be used during testing and + development. + For more information, see also + configuration settings.

+

It is also possible to trace all communication between an Orber-ORB and, for example, + a Java-ORB, communicating via IIOP. All you need to do is to activate an + interceptor. Normally, the users must + implement the interceptor themselves, but for your convenience Orber includes three + pre-compiled interceptors called orber_iiop_tracer, + orber_iiop_tracer_silent and orber_iiop_tracer_stealth.

+ +

Logging all traffic is expensive. Hence, only use the supplied + interceptors during test and development.

+
+

The orber_iiop_tracer and orber_iiop_tracer_silent interceptors + uses the error_logger module to generate the logs. If the traffic + is intense you probably want to write the reports to a log-file. + This is done by, for example, invoking:

+ +erl> error_logger:tty(false). +erl> error_logger:logfile({open, "/tmp/IIOPTrace"}). + +

The IIOPTrace file will contain, if you use the orber_iiop_tracer + interceptor, reports which looks like:

+ +=INFO REPORT==== 13-Jul-2005::18:22:39 === +=============== new_out_connection ======= +Node : myNode@myHost +From : 192.0.0.10:47987 +To : 192.0.0.20:4001 +========================================== + +=INFO REPORT==== 29-Nov-2001::15:26:28 === +=============== out_request ============== +Connection: {"192.0.0.20",4001,"192.0.0.10",47987} +Operation : resolve +Parameters: [[{'CosNaming_NameComponent', + "AIK","SwedishIcehockeyChampions"}]] +Context : [{'IOP_ServiceContext',1, + {'CONV_FRAME_CodeSetContext',65537,65801}}] +========================================== + +

The orber_iiop_tracer_silent will not log GIOP encoded data. To activate + one the interceptors, you have two options:

+ + erl -orber interceptors "{native,[orber_iiop_tracer]}" - can be added to a start-script. + corba:orb_init([{interceptors, {native, [orber_iiop_tracer_silent]}}]) - this operation must + be invoked before starting Orber. + +

It is also possible to active and deactivate an interceptor during + run-time, but this will only affect currently existing connections. + For more information, consult Orber's Reference Manual regarding the + operations orber:activate_audit_trail/0/1 and + orber:activate_audit_trail/0/1.

+
+ +
+ FAQ +

Q: When my client, typically written in C++ or Java, invoke narrow on an Orber object reference it fails?

+

A: You must register your application in the IFR by invoking oe_register(). + If the object was created by a COS-application, you must run install + (e.g. cosEventApp:install()).

+

A: Confirm, by consulting the IDL specifications, that the received object reference really + inherit from the interface you are trying to narrow it to.

+

+

Q: I am trying to register my application in the IFR but it fails. Why?

+

A: If one, or more, interface in your IDL-specification inherits from + other interface(s), you must register them before registering your + application. Note, this also apply when you inherit interfaces + supported by a COS-application. Hence, they must be installed prior to + registration of your application.

+

+

Q: I have a Orber client and server residing on two different Orber instances but I only get the 'OBJECT_NOT_EXIST' exception, even though I am sure that the object is still alive?

+

A: If the two Orber-ORB's are not intended to be a part of multi-node ORB, make sure that the + two Orber-ORB's have different domain names set (see + configuration settings). The easiest way + to confirm this is to invoke orber:info() on each node.

+

+

Q: When I'm trying to install and/or start Orber it fails?

+

A: Make sure that no other Orber-ORB is already running on the same node. If so, + change the iiop_port configuration parameter (see + configuration settings).

+

+

Q: My Orber server is invoked via IIOP but Orber cannot marshal the reply?

+

A: Consult your IDL file to confirm that your replies are of the correct + type. If it is correct and the return type is, for example, + a struct, make sure you have set every field in the struct. If + you do not do that it will be set to the atom 'undefined', which + most certainly is not correct.

+

+

A: Check that you handle inout and out parameters correctly + (see the IDL specification). For example, a function which have one + out-parameter and should return void, then your call-back module + should return {reply, {ok, OutParam}, State}. Note, even though + the return value is void (IDL) you must reply with ok.

+

+

Q: I cannot run Orber as a multi-node ORB?

+

A: Make sure that the Erlang distribution have been started for each + node and the cookies are correct. For more information, + consult the System Documentation

+

+
+
+
+ diff --git a/lib/orber/doc/src/ch_example.xml b/lib/orber/doc/src/ch_example.xml new file mode 100644 index 0000000..d4cc5ce --- /dev/null +++ b/lib/orber/doc/src/ch_example.xml @@ -0,0 +1,170 @@ + + + + +
+ + 19972009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Orber Examples + + + 1997-05-20 + A + ch_example.xml +
+ +
+ A Tutorial on How to Create a Simple Service + +
+ Interface Design +

This example uses a very simple stack server. The specification + contains two interfaces: the first is the Stack itself and the + other is the StackFactory which is used to create new stacks. + The specification is in the file stack.idl.

+ +
+ +
+ Generating Erlang Code +

Run the IDL compiler on this file by calling the ic:gen/1 function

+ +\0111> ic:gen("stack"). + +

This will produce the client stub and server skeleton. Among other files a stack API module named StackModule_Stack.erl + will be produced. + This will produce among other files a stack API module called + StackModule_Stack.erl which contains the client stub and + the server skeleton.

+
+ +
+ Implementation of Interface +

After generating the API stubs and the server skeletons it is time to + implement the servers and if no special options are sent + to the IDL compiler the file name should be + _impl.erl]]>, in our case + StackModule_Stack_impl.erl.

+ +

We also have the factory interface which is used to create new stacks + and that implementation is in the file + StackModule_StackFactory_impl.erl.

+ +

To start the factory server one executes the function + StackModule_StackFactory:oe_create/0 which in this + example is done in the module stack_factory.erl where + the started service is also registered in the name service.

+ +
+ +
+ Writing a Client in Erlang +

At last we will write a client to access our service.

+ +
+ +
+ Writing a Client in Java +

To write a Java client for Orber you must have another + ORB that uses IIOP for client-server communication and supports a + Java language mapping. It must also have support for + IDL:CosNaming/NamingContext or IDL:CosNaming/NamingContextExt. + If the client ORB support Interoperable Naming Service the Java Client + can look like:

+ + +

If an ORB does not support CosNaming at all the cos_naming.idl + file must be compiled and imported.

+
+
+ +
+ Building the Example +

To build the example for access from a Java client you need a Java + enabled ORB (e.g. JavaIDL). The example below is based on JDK-1.4.

+ +fingolfin 127> erl +Erlang (BEAM) emulator version 5.5.4.3 [async-threads:0] [hipe] [kernel-poll:false] + +Eshell V5.5.4.3 (abort with ^G) +1> ic:gen(stack). +Erlang IDL compiler version 4.2.12 +ok +2> make:all(). +Recompile: StackModule_EmptyStack +Recompile: StackModule_Stack +Recompile: StackModule_StackFactory +Recompile: StackModule_StackFactory_impl +Recompile: StackModule_Stack_impl +Recompile: oe_stack +Recompile: stack_client +Recompile: stack_factory +up_to_date +3> +BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded + (v)ersion (k)ill (D)b-tables (d)istribution +a +fingolfin 128> idlj stack.idl +fingolfin 129> javac StackModule/*.java +fingolfin 130> javac *.java +fingolfin 131> cp StackClient.class StackModule/ + +
+ +
+ How to Run Everything +

Below is a short transcript on how to run Orber.

+ + +fingolfin 143> erl +Erlang (BEAM) emulator version 5.5.4.3 [async-threads:0] [hipe] [kernel-poll:false] + +Eshell V5.5.4.3 (abort with ^G) +1> orber:jump_start([{interceptors, {native, [orber_iiop_tracer_silent]}}]). +ok +2> oe_stack:oe_register(). +ok +3> stack_factory:start(). +ok +4> stack_client:run(). +1 +1 +7 +4 +ok +5> + +

Before testing the Java part of this example generate and compile Java classes for + orber/examples/stack.idl as seen in the build example. + To run the Java client use the following command:

+ + +fingolfin 38> java StackModule.StackClient "corbaname::localhost:4001#StackFactory" +1 +1 +7 +4 +Empty stack +fingolfin 39> + +
+
+ +
+ diff --git a/lib/orber/doc/src/ch_exceptions.xml b/lib/orber/doc/src/ch_exceptions.xml new file mode 100644 index 0000000..a8fb98f --- /dev/null +++ b/lib/orber/doc/src/ch_exceptions.xml @@ -0,0 +1,237 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CORBA System and User Defined Exceptions + + + 2000-12-19 + + ch_exceptions.xml +
+ +
+ System Exceptions +

Orber, or any other ORB, may raise a System Exceptions. + These exceptions contain status- and minor-fields and may not appear in the + operations raises exception IDL-definition.

+ +
+ Status Field +

The status field indicates if the request was completed or not and will be + assigned one of the following Erlang atoms:

+ + + Status + Description + + + 'COMPLETED_YES' + The operation was invoked on the target object but an error occurred after the object replied. This occur, for example, if a server replies but Orber is not able to marshal and send the reply to the client ORB. + + + 'COMPLETED_NO' + Orber failed to invoke the operation on the target object. This occur, for example, if the object no longer exists. + + + 'COMPLETED_MAYBE' + Orber invoked the operation on the target object but an error occurred and it is impossible to decide if the request really reached the object or not. + + System Exceptions Status +
+
+ +
+ Minor Field +

The minor field contains an integer (VMCID), which is related to a more + specific reason why an invocation failed. The function + orber:exception_info/1 can be used to map the minor code to a string. + Note, for VMCID:s not assigned by the OMG or Orber, the documentation + for that particular ORB must be consulted.

+
+ +
+ Supported System Exceptions +

The OMG CORBA specification defines the following exceptions:

+ + 'BAD_CONTEXT' - if a request does not contain a correct + context this exception is raised. + 'BAD_INV_ORDER' - this exception indicates that operations + has been invoked operations in the wrong order, which would cause, + for example, a dead-lock. + 'BAD_OPERATION' - raised if the target object exists, but + that the invoked operation is not supported. + 'BAD_PARAM' - is thrown if, for example, a parameter is out + of range or otherwise considered illegal. + 'BAD_TYPECODE' - if illegal type code is passed, for example, + encapsulated in an any data type the 'BAD_TYPECODE' exception + will be raised. + 'BAD_QOS' - raised whenever an object cannot support the + required quality of service. + 'CODESET_INCOMPATIBLE' - raised if two ORB's cannot + communicate due to different representation of, for example, + char and/or wchar. + 'COMM_FAILURE' - raised if an ORB is unable to setup + communication or it is lost while an operation is in progress. + 'DATA_CONVERSION' - raised if an ORB cannot convert data + received to the native representation. See also the + 'CODESET_INCOMPATIBLE' exception. + 'FREE_MEM' - the ORB failed to free dynamic memory and + failed. + 'IMP_LIMIT' - an implementation limit was exceeded in the + ORB at run time. A object factory may, for example, limit the + number of object clients are allowed to create. + 'INTERNAL' - an internal failure occurred in an ORB, which + is unrecognized. You may consider contacting the ORB providers + support. + 'INTF_REPOS' - the ORB was not able to reach the interface + repository, or some other failure relating to the interface + repository is detected. + 'INITIALIZE' - the ORB initialization failed due to, for + example, network or configuration error. + 'INVALID_TRANSACTION' - is raised if the request carried an + invalid transaction context. + 'INV_FLAG' - an invalid flag was passed to an operation, + which caused, for example, a connection to be closed. + 'INV_IDENT' - this exception indicates that an IDL + identifier is incorrect. + 'INV_OBJREF' - this exception is raised if an object + reference is malformed or a nil reference (see + also corba:create_nil_objref/0). + 'INV_POLICY' - the invocation cannot be made due to an + incompatibility between policy overrides that apply to the + particular invocation. + 'MARSHAL' - this exception may be raised by the client- or + server-side when either ORB is unable to marshal/unmarshal requests or + replies. + 'NO_IMPLEMENT' - if the operation exists but no implementation + exists, this exception is raised. + 'NO_MEMORY' - the ORB has run out of memory. + 'NO_PERMISSION' - the caller has insufficient privileges, + such as, for example, bad SSL certificate. + 'NO_RESOURCES' - a general platform resource limit + exceeded. + 'NO_RESPONSE' - no response available of a deferred + synchronous request. + 'OBJ_ADAPTER' - indicates administrative mismatch; the object + adapter is not able to associate an object with the implementation + repository. + 'OBJECT_NOT_EXIST' - the object have been disposed or + terminated; clients should remove all copies of the object reference + and initiate desired recovery process. + 'PERSIST_STORE' - the ORB was not able to establish a + connection to its persistent storage or data contained in the + the storage is corrupted. + 'REBIND' - a request resulted in, for example, a + 'LOCATION_FORWARD' message; if the policies are incompatible + this exception is raised. + 'TIMEOUT' - raised if a request fail to complete within the + given time-limit. + 'TRANSACTION_MODE' - a transaction policy mismatch detected. + 'TRANSACTION_REQUIRED' - a transaction is required for the + invoked operation but the request contained no transaction context. + 'TRANSACTION_ROLLEDBACK' - the transaction associated with + the request has already been rolled back or will be. + 'TRANSACTION_UNAVAILABLE' - no transaction context can be + supplied since the ORB is unable to contact the Transaction + Service. + 'TRANSIENT' - the ORB could not determine the current status + of an object since it could not be reached. The error may be + temporary. + 'UNKNOWN' - is thrown if an implementation throws a + non-CORBA, or unrecognized, exception. + +
+
+ +
+ User Defined Exceptions +

User exceptions is defined in IDL-files and is listed in operations raises + exception listing. For example, if we have the following IDL code:

+ +module MyModule { + + exception MyException {}; + exception MyExceptionMsg { string ExtraInfo; }; + + interface MyInterface { + + void foo() + raises(MyException); + + void bar() + raises(MyException, MyExceptionMsg); + + void baz(); + }; +}; + +
+ +
+ Throwing Exceptions +

To be able to raise MyException or MyExceptionMsg exceptions, + the generated MyModule.hrl must be included, and typical usage is:

+ +-module('MyModule_MyInterface_impl'). +-include("MyModule.hrl"). + +bar(State) -> + case TestingSomething of + ok -> + {reply, ok, State}; + {error, Reason} when list(Reason) -> + corba:raise(#'MyModule_MyExceptionMsg'{'ExtraInfo' = Reason}); + error -> + corba:raise(#'MyModule_MyException'{}) + end. + +
+ +
+ Catching Exceptions +

Depending on which operation we invoke we must be able to handle:

+ + foo - MyException or a system exception. + bar - MyException, MyExceptionMsg or a system + exception. + baz - a system exception. + +

Catching and matching exceptions can bee done in different ways:

+ + case catch 'MyModule_MyInterface':bar(MIReference) of + ok -> + %% The operation raised no exception. + ok; + {'EXCEPTION', #'MyModule_MyExceptionMsg'{'ExtraInfo' = Reason}} -> + %% If we want to log the Reason we must extract 'ExtraInfo'. + error_logger:error_msg("Operation 'bar' raised: ~p~n", [Reason]), + ... do something ...; + {'EXCEPTION', E} when record(E, 'OBJECT_NOT_EXIST') -> + ... do something ...; + {'EXCEPTION', E} -> + ... do something ... + end. + +
+
+ diff --git a/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml b/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml new file mode 100644 index 0000000..0e2b049 --- /dev/null +++ b/lib/orber/doc/src/ch_idl_to_erlang_mapping.xml @@ -0,0 +1,1471 @@ + + + + +
+ + 19972009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + OMG IDL to Erlang Mapping + + + 1998-10-10 + + ch_idl_to_erlang_mapping.xml +
+ +
+ OMG IDL to Erlang Mapping - Overview +

The purpose of OMG IDL, Interface Definition Language, mapping + is to act as translator between platforms and languages. An IDL + specification is supposed to describe data types, object types etc.

+

CORBA is independent of the programming language used to construct + clients or implementations. In order to use the ORB, it is + necessary for programmers to know how to access ORB functionality + from their programming languages. It translates different IDL constructs + to a specific programming language. This chapter + describes the mapping of OMG IDL constructs to the Erlang programming + language.

+
+ +
+ OMG IDL Mapping Elements +

A complete language mapping will allow the programmer to have + access to all ORB functionality in a way that is convenient for + a specified programming language. +

+

All mapping must define the following elements: +

+ + All OMG IDL basic and constructed types + References to constants defined in OMG IDL + References to objects defined in OMG IDL + Invocations of operations, including passing of + parameters and receiving of results + Exceptions, including what happens when an operation + raises an exception and how the exception parameters are + accessed + Access to attributes + Signatures for operations defined by the ORB, such as + dynamic invocation interface, the object adapters etc. + Scopes; + OMG IDL has several levels of scopes, which are mapped to Erlang's + two scopes. + +
+ +
+ Getting Started +

To begin with, we should decide which type of objects (i.e. servers) we + need and if two, or more, should export the same functionality. Let us + assume that we want to create a system for DB (database) access for different + kind of users. For example, anyone with a valid password may extract + data, but only a few may update the DB. Usually, an application + is defined within a module, and all global datatypes are defined + on the top-level. To begin with we create a module and the interfaces we + need:

+ +// DB IDL +#ifndef _DB_IDL_ +#define _DB_IDL_ +// A module is simply a container +module DB { + + // An interface maps to a CORBA::Object. + interface CommonUser { + + }; + + // Inherit the Consumer interface + interface Administrator : CommonUser { + + }; + + interface Access { + + }; + +}; +#endif +

Since the Administrator should be able to do the same things as the + CommonUser, the previous inherits from the latter. The Access + interface will grant access to the DB. + Now we are ready to define the functionality and data types we need. But, this + requires that we know a little bit more about the OMG IDL.

+ +

The OMG defines a set of reserved case insensitive key-words, which may + NOT be used as identifiers (e.g. module name). For more + information, see + Reserved Compiler Names and Keywords

+
+
+ +
+ Basic OMG IDL Types +

The OMG IDL mapping is strongly typed and, even if you have a good knowledge + of CORBA types, it is essential to read carefully the following mapping to + Erlang types.

+

The mapping of basic types is straightforward. Note that the + OMG IDL double type is mapped to an Erlang float which does not + support the full double value range.

+ + + OMG IDL type + Erlang type + Note + + + float + Erlang float + + + + double + Erlang float + value range not supported + + + short + Erlang integer + -2^15 .. 2^15-1 + + + unsigned short + Erlang integer + 0 .. 2^16-1 + + + long + Erlang integer + -2^31 .. 2^31-1 + + + unsigned long + Erlang integer + 0 .. 2^32-1 + + + long long + Erlang integer + -2^63 .. 2^63-1 + + + unsigned long long + Erlang integer + 0 .. 2^64-1 + + + char + Erlang integer + ISO-8859-1 + + + wchar + Erlang integer + UTF-16 (ISO-10646-1:1993) + + + boolean + Erlang atom + true/false + + + octet + Erlang integer + + + + any + Erlang record + #any{typecode, value} + + + long double + Not supported + + + + Object + Orber object reference + Internal Representation + + + void + Erlang atom + ok + + OMG IDL basic types +
+

The any value is written as a record with the field typecode which + contains the Type Code is a full definition of a type representation, + see also the Type Code table, + and the value field itself.

+

Functions with return type void will return the atom ok.

+
+ +
+ Template OMG IDL Types and Complex Declarators +

Constructed types all have native mappings as shown in the table + below.

+ + + Type + IDL code + Maps to + Erlang code + + + string + typedef string S;

+void op(in S a);
+ Erlang string + ok = op(Obj, "Hello World"), +
+ + wstring + typedef wstring S;

+void op(in S a);
+ Erlang list of Integers + ok = op(Obj, "Hello World"), +
+ + sequence + typedef sequence <long, 3> S;

+void op(in S a);
+ Erlang list + ok = op(Obj, [1, 2, 3]), +
+ + array + typedef string S[2];

+void op(in S a);
+ Erlang tuple + ok = op(Obj, {"one", "two"}), +
+ + fixed + typedef fixed<3,2> myFixed;

+void op(in myFixed a);
+ Erlang tuple + MF = fixed:create(3, 2, 314),

+ok = op(Obj, MF),
+
+ OMG IDL Template and Complex Declarators +
+ +
+ String/WString Data Types +

A string consists of all possible 8-bit quantities except null. + Most ORB:s uses, including Orber, the character set Latin-1 (ISO-8859-1). + The wstring type is represented as a list of integers, where + each integer represents a wide character. In this case Orber uses, as + most other ORB:s, the UTF-16 (ISO-10646-1:1993) character set.

+

When defining a a string or wstring they can be of limited length or + null terminated:

+ myString10; +typedef wstring<10> myWString10; + ]]> +

If we want to define a char/string or wchar/wstring constant, we can + use octal (\\OOO - one, two or three octal digits), + hexadecimal (\\xHH - one or two hexadecimal digits) and unicode (\\uHHHH - + one, two, three or four hexadecimal digits.) representation as well. + For example:

+ +const string SwedensBestSoccerTeam = "\\101" "\\x49" "\\u004B"; +const wstring SwedensBestHockeyTeam = L"\\101\\x49\\u004B"; +const char aChar = '\\u004B'; +const wchar aWchar = L'\\u004C'; + +

Naturally, we can use "Erlang", L"Rocks", 'A' + and L'A' as well.

+
+ +
+ Sequence Data Type +

A sequence can be defined to be of a maximum length or unbounded, and may + contain Basic and Template types and scoped names:

+ aShortSequence; +typedef sequence aLongSequence; +typedef sequence anEvenLongerSequence; + ]]> +
+ +
+ Array Data Type +

Arrays are multidimensional, fixed-size arrays. The indices is language + mapping specific, which is why one should not pass them as arguments + to another ORB.

+ +typedef long myMatrix[2][3]; + +
+ +
+ Fixed Data Type +

A Fixed Point literal consists of an integer part (decimal digits), + decimal point and a fraction part (decimal digits), + followed by a D or d. Either the integer part or the + fraction part may be missing; the decimal point may be missing, + but not d/D. The integer part must be a positive integer less than 32. + The Fraction part must be a positive integer less than or equal to + the Integer part.

+ +const fixed myFixed1 = 3.14D; +const fixed myFixed2 = .14D; +const fixed myFixed3 = 0.14D; +const fixed myFixed4 = 3.D; +const fixed myFixed5 = 3D; + +

It is also possible to use unary (+-) and binary (+-*/) operators:

+ +const fixed myFixed6 = 3D + 0.14D; +const fixed myFixed7 = -3.14D; + +

The Fixed Point examples above are, so called, anonymous + definitions. In later CORBA specifications these have been deprecated + as function parameters or return values. Hence, we strongly recommend that + you do not use them. Instead, you should use:

+ myFixed53; +const myFixed53 myFixed53constant = 03.140d; +typedef fixed<3,2> myFixed32; +const myFixed32 myFixed32constant = 3.14d; + +myFixed53 foo(in myFixed32 MF); // OK +void bar(in fixed<5,3> MF); // Illegal + ]]> +
+

For more information, see Fixed in + Orber's Reference Manual.

+

Now we continue to work on our IDL specification. To begin with, we want + to limit the size of the logon parameters (Id and password). Since the + UserID and Password parameters, only will be used when + invoking operations on the Access interface, we may choose to define + them within the scope that interface. To keep it simple our DB will contain + employee information. Hence, as the DB key we choose an integer + (EmployeeNo).

+ UserID; + typedef string<10> Password; + + CommonUser logon(in UserID ID, in Password PW); + + }; + +}; +#endif ]]> +

But what should, for example, the lookup operation return? One option + is to use the any data type. But, depending on what kind of data it + encapsulates, this datatype can be rather expensive to use. We might find a + solution to our problems among the Constructed IDL types.

+
+ +
+ Constructed OMG IDL Types +

Constructed types all have native mappings as shown in the table + below.

+ + + Type + IDL code + Maps to + Erlang code + + + struct + struct myStruct {

+long a;

+short b;

+};

+void op(in myStruct a);
+ Erlang record + ok = op(Obj, #'myStruct'{a=300, b=127}), +
+ + union + union myUnion switch(long) {

+case 1: long a;

+};

+void op(in myUnion a);
+ Erlang record + ok = op(Obj, #'myUnion'{label=1, value=66}), +
+ + enum + enum myEnum {one, two};

+void op(in myEnum a);
+ Erlang atom + ok = op(Obj, one), +
+ OMG IDL constructed types +
+ +
+ Struct Data Type +

A struct may have Basic, Template, Scoped Names and Constructed + types as members.

+
+ +
+ Enum Data Type +

The maximum number of identifiers which may defined in an enumeration + is 2³². The order in which the identifiers are named in the + specification of an enumeration defines the relative order of the + identifiers.

+
+ +
+ Union Data Type +

A union may consist of:

+ + Identifier + Switch - may be an integer, char, boolean, enum or scoped name. + Body - with or without a default case; may appear at + most once. + +

A case label must match the defined type of the discriminator, and may only + contain a default case if the values given in the non-default labels do + not cover the entire range of the union's discriminant type. For example:

+ +// Illegal default; all cases covered by +// non-default cases. +union BooleanUnion switch(boolean) { + case TRUE: long TrueValue; + case FALSE: long FalseValue; + default: long DefaultValue; +}; +// OK +union BooleanUnion2 switch(boolean) { + case TRUE: long TrueValue; + default: long DefaultValue; +}; + +

It is not necessary to list all possible values of the union discriminator + in the body. Hence, the value of a union is the value of the discriminator + and, in given order, one of the following:

+ + If the discriminator match a label, explicitly listed in a + case statement, the value must be of the same type. + If the union contains a default label, the value must match the + type of the default label. + No value. Orber then inserts the Erlang atom undefined + in the value field when receiving a union from an external + ORB. + +

The above can be summed up to:

+ +// If the discriminator equals 1 or 2 the value +// is a long. Otherwise, the atom undefined. +union LongUnion switch(long) { + case 1: + case 2: long TrueValue; +}; +// If the discriminator equals 1 or 2 the value +// is a long. Otherwise, a boolean. +union LongUnion2 switch(long) { + case 1: + case 2: long TrueValue; + default: boolean DefaultValue; +}; + +
+ +

Every field in, for example, a struct must be initiated. Otherwise + it will be set to the atom undefined, which Orber cannot + encode when communicating via IIOP. In the example above, invoking + the operation with #'myStruct'{a=300} will fail (equal to + #'myStruct'{a=300, b=undefined})

+
+

Now we can continue to work on our IDL specification. To begin with, we should + determine the return value of the lookup operation. Since the any + type can be rather expensive we can use a struct or a union instead. + If we intend to return the same information about a employee every time we can + use a struct. Let us assume that the DB contains the name, address, employee + number and department.

+ UserID; + typedef string<10> Password; + + // Since Administrator inherits from CommonUser + // the returned Object can be of either type. + CommonUser logon(in UserID ID, in Password PW); + + }; + +}; +#endif ]]> +

We can also define exceptions (i.e. not system exception) thrown by + each interface. Since exceptions are thoroughly described in the chapter + System and User Defined Exceptions, + we choose not to. Hence, we are now ready to compile our IDL-file by + invoking:

+
+$ erlc DB.idl
+    
+

or:

+
+$ erl
+Erlang (BEAM) emulator version 5.1.1 [threads:0]
+
+Eshell V5.1.1  (abort with ^G)
+1> ic:gen('DB').
+ok
+2> halt().
+    
+

The next step is to implement our servers. But, to be able to do that, + we need to know how we can access data type definitions. For example, + since a struct is mapped to an Erlang record we must include an hrl-file + in our callback module.

+
+ +
+ Scoped Names and Generated Files + +
+ Scoped Names +

Within a scope all identifiers must be unique. The following kinds of + definitions form scopes in the OMG IDL:

+ + module + interface + operation + valuetype + struct + union + exception + +

For example, since enumerants do not form a scope, the following IDL code + is not valid:

+ +module MyModule { + // 'two' is not unique + enum MyEnum {one, two}; + enum MyOtherEnum {two, three}; +}; + +

But, since Erlang only has two levels of scope, module and + function, the OMG IDL scope is mapped as follows:

+ + Function Scope - used for constants, operations and attributes. + Erlang Module Scope - the Erlang module scope + handles the remaining OMG IDL scopes. + +

An Erlang module, corresponding to an IDL global name, is derived by + converting occurrences of "::" to underscore, and eliminating + the leading "::". Hence, accessing MyEnum from another module, one + use MyModule::MyEnum

+

For example, an operation foo defined in interface I, which + is defined in module M, would be written in IDL as M::I::foo + and as 'M_I':foo in Erlang - foo is the function + name and 'M_I' is the name of the Erlang module. Applying this + knowledge to a stripped version of the DB.idl gives:

+ UserID; + typedef string<10> Password; + + // Since Administrator inherits from CommonUser + // the returned Object can be of either type. + // This operation is exported from: + // DB_Access.erl + CommonUser logon(in UserID ID, in Password PW); + + }; + +}; +#endif ]]> +

Using underscores in IDL names can lead to ambiguities + due to the name mapping described above. It is advisable to + avoid the use of underscores in identifiers. For example, the following + definition would generate two structures named x_y_z.

+ +module x { + + struct y_z { +\011... + }; + + interface y { + +\011struct z { +\011 ... +\011}; + }; +}; + +
+ +
+ Generated Files +

Several files can be generated for each scope.

+ + An Erlang source code file (.erl) is generated + for top level scope as well as the Erlang header file. + An Erlang header file (.hrl) will be generated for + each scope. The header file will contain record definitions + for all struct, union and exception + types in that scope. + Modules that contain at least one constant definition, + will produce Erlang source code files (.erl). + That Erlang file will contain constant functions for + that scope. + Modules that contain no constant definitions are considered + empty and no code will be produced for them, but only for + their included modules/interfaces. + Interfaces will produce Erlang source code files (.erl), + this code will contain all operation stub code and implementation + functions. + In addition to the scope-related files, an Erlang source file will + be generated for each definition of the types struct, + union and exception (these are the types that + will be represented in Erlang as records). + This file will contain special access functions for that record. + The top level scope will produce two files, one header file + (.hrl) and one Erlang source file (.erl). + These files are named as the IDL file, prefixed with oe_. + +

After compiling DB.idl, the following files have been generated:

+ + oe_DB.hrl and oe_DB.erl for the top scope level. + DB.hrl for the module DB. + DB_Access.hrl and DB_Access.erl for the interface + DB_Access. + DB_CommonUser.hrl and DB_CommonUser.erl for the interface + DB_CommonUser. + DB_Administrator.hrl and DB_Administrator.erl for the interface + DB_Administrator. + DB_employee.erl for the structure employee in module + DB. + +

Since the employee struct is defined in the top level scope, + the Erlang record definition is found in DB.hrl. IC also generates + stubs/skeletons (e.g. DB_CommonUser.erl) and access functions for + some datatypes (e.g. DB_employee.erl). How the stubs/skeletons are + used is thoroughly described in + Stubs/Skeletons and + Module_Interface.

+
+
+ +
+ Typecode, Identity and Name Access Functions +

As mentioned in a previous section, struct, union and + exception types yield record definitions and access code + for that record. + For struct, union, exception, array and + sequence types, a special file is generated that holds access + functions for TypeCode, Identity and Name. + These functions are put in the file corresponding to the scope where + they are defined. For example, the module DB_employee.erl, + representing the employee struct, exports the following functions:

+ + tc/0 - returns the type code for the struct. + id/0 - returns the IFR identity of the struct. In this case + the returned value is "IDL:DB/employee:1.0", but + if the struct was defined in the scope of CommonUser, + the result would be "IDL:DB/CommonUser/employee:1.0". + However, the user usually do not need to know the Id, just + which Erlang module contains the correct Id. + name/0 - returns the scoped name of the struct. The employee + struct name is "DB_employee". + +

Type codes give a complete description of the type including all its components and structure.are, for example, used in Any values. + Hence, we can encapsulate the employee struct in an any + type by:

+ +%% Erlang code +.... +AnEmployee = #'DB_employee'{'No' = 1, + 'Name' = "Adam Ivan Kendall", + 'Address' = "Rasunda, Solna", + 'Dpt' = 'Department1'}, +EmployeeTC = 'DB_employee':tc(), +EmployeeAny = any:create(EmployeeTC, AnEmployee), +.... + +

For more information, see the + Type Code listing.

+
+ +
+ References to Constants +

Constants are generated as Erlang functions, and are accessed by a + single function call. The functions are put in the file + corresponding to the scope where they are defined. There is no + need for an object to be started to access a constant.

+

Example:

+ +// m.idl +module m { + const float pi = 3.14; + + interface i { +\011const float pi = 3.1415; + }; +}; + +

Since the two constants are defined in different scopes, the IDL code + above is valid, but not necessarily a good approach. After compiling + m.idl, the constant definitions can be extracted by invoking:

+
+$ erlc m.idl
+$ erlc m.erl
+$ erl
+Erlang (BEAM) emulator version 5.1.1 [threads:0]
+
+Eshell V5.1.1  (abort with ^G)
+1> m:pi().
+3.14
+2> m_i:pi().
+3.1415
+3> halt().
+    
+
+ +
+ References to Objects Defined in OMG IDL +

Objects are accessed by object references. An object reference + is an opaque Erlang term created and maintained by the ORB.

+

Objects are implemented by providing implementations for all + operations and attributes of the Object, see operation implementation.

+
+ +
+ Exceptions +

Exceptions are handled as Erlang catch and throws. Exceptions + are translated to messages over an IIOP bridge but converted + back to a throw on the receiving side. Object implementations + that invoke operations on other objects must be aware of the + possibility of a non-local return. This includes invocation of + ORB and IFR services. See also the + Exceptions section.

+

Exception parameters are mapped as an Erlang record and accessed + as such.

+

An object implementation that raises an exception will use the + corba:raise/1 function, passing the exception record as + parameter.

+
+ +
+ Access to Attributes +

Attributes are accessed through their access functions. An + attribute implicitly defines the _get and _set + operations. These operations are handled in the same way as + normal operations. The _get operation is defined as a readonly + attribute.

+ +readonly attribute long RAttribute; +attribute long RWAttribute; + +

The RAttribute requires that you implement, in your call-back module, + _get_RAttribute. For the RWAttribute it is necessary to implement + _get_RWAttribute and _set_RWAttribute.

+
+ +
+ Invocations of Operations + +

A standard Erlang gen_server behavior is used for + object implementation. The gen_server state is then + used as the object internal state. Implementation of the object + function is achieved by implementing its methods and attribute operations. + These functions will usually have the internal state as their first parameter, + followed by any in and inout parameters.

+

Do not confuse the + object internal state with its object reference. The object internal state is + an Erlang term which has a format defined by the user.

+ +

It is is not always the case that the internal state will be the first parameter, as stubs can use their own object reference as the first parameter (see the IC documentation).

+
+

A function call will invoke an operation. The first + parameter of the function should be the object reference and then + all in and inout parameters follow in the same + order as specified in the IDL specification. The result will be a return value + unless the function has inout or out parameters specified; + in which case, a tuple of the return value, followed by the parameters will + be returned.

+

Example:

+ +// IDL +module m { + interface i { + readonly attribute long RAttribute; + attribute long RWAttribute; + long foo(in short a); + long bar(in char c, inout string s, out long count); + void baz(out long Id); + }; +}; + +

Is used in Erlang as :

+ +%% Erlang code +.... +Obj = ... %% get object reference +RAttr = m_i:'_get_RAttribute'(Obj), +RWAttr = m_i:'_get_RWAttribute'(Obj), +ok = m_i:'_set_RWAttribute'(Obj, Long), +R1 = m_i:foo(Obj, 55), +{R2, S, Count} = m_i:bar(Obj, $a, "hello"), +.... + +

Note how the inout parameter is passed and + returned. There is no way to use a single occurrence of a + variable for this in Erlang. Also note, that ok, Orber's + representation of the IDL-type void, must be returned by + baz and '_set_RWAttribute'. + These operations can be implemented in the call-back module as:

+ +'_set_RWAttribute'(State, Long) -> + {reply, ok, State}. + +'_get_RWAttribute'(State) -> + {reply, Long, State}. + +'_get_RAttribute'(State) -> + {reply, Long, State}. + +foo(State, AShort) -> + {reply, ALong, State}. + +bar(State, AShort, AString) -> + {reply, {ALong, "MyString", ALong}, State}. + +baz(State) -> + {reply, {ok, AId}, State}. + +

The operations may require more arguments (depends on IC options used). For + more information, see Stubs/Skeletons + and Module_Interface.

+ +

A function can also be defined to be oneway, i.e. + asynchronous. But, since the behavior of a oneway operation is not + defined in the OMG specifications (i.e. the behavior can differ depending on + which other ORB Orber is communicating with), one should avoid using it.

+
+
+ +
+ Implementing the DB Application +

Now we are ready to implement the call-back modules. There are three modules + we must create:

+ + DB_Access_impl.erl + DB_CommonUser_impl.erl + DB_Administrator_impl.erl + +

An easy way to accomplish that, is to use the IC backend erl_template, + which will generate a complete call-back module. One should also add + the same compile options, for example this or from, + used when generating the stub/skeleton modules:

+ +$> erlc +"{be,erl_template}" DB.idl + +

We begin with implementing the DB_Access_impl.erl module, which, + if we used erl_template, will look like the following. All we need + to do is to add the logic to the logon operation.

+ +%% +%% $Id$ +%% +%%---------------------------------------------------------------------- +%% Module : DB_Access_impl.erl +%% +%% Source : /home/user/example/DB.idl +%% +%% Description : +%% +%% Creation date: 2005-05-20 +%% +%%---------------------------------------------------------------------- +-module('DB_Access_impl'). + +-export([logon/3]). + +%%---------------------------------------------------------------------- +%% Internal Exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%%---------------------------------------------------------------------- +%% Include Files +%%---------------------------------------------------------------------- + + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {}). + +%%====================================================================== +%% API Functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : logon/3 +%% Arguments : State - term() +%% ID = String() +%% PW = String() +%% Returns : ReturnValue = OE_Reply +%% OE_Reply = Object_Ref() +%% Raises : +%% Description: +%%---------------------------------------------------------------------- +logon(State, ID, PW) -> +\011%% Check if the ID/PW is valid and what +\011%% type of user it is (Common or Administrator). +\011OE_Reply + = case check_user(ID, PW) of +\011 {ok, administrator} -> +\011 'DB_Administrator':oe_create(); +\011 {ok, common} -> +\011 'DB_CommonUser':oe_create(); +\011 error -> +\011 %% Here we should throw an exception + \011 corba:raise(....) + end, +\011{reply, OE_Reply, State}. + +%%====================================================================== +%% Internal Functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Arguments : Env = term() +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Raises : - +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init(_Env) -> +\011{ok, #state{}}. + + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Arguments : Reason = normal | shutdown | term() +%% State = term() +%% Returns : ok +%% Raises : - +%% Description: Invoked when the object is terminating. +%%---------------------------------------------------------------------- +terminate(_Reason, _State) -> +\011ok. + + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Arguments : OldVsn = undefined | term() +%% State = NewState = term() +%% Extra = term() +%% Returns : {ok, NewState} +%% Raises : - +%% Description: Invoked when the object should update its internal state +%% due to code replacement. +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> +\011{ok, State}. + + +%%---------------------------------------------------------------------- +%% Function : handle_info/2 +%% Arguments : Info = normal | shutdown | term() +%% State = NewState = term() +%% Returns : {noreply, NewState} | +%% {noreply, NewState, Timeout} | +%% {stop, Reason, NewState} +%% Raises : - +%% Description: Invoked when, for example, the server traps exits. +%%---------------------------------------------------------------------- +handle_info(_Info, State) -> +\011{noreply, State}. + ]]> +

Since DB_Administrator inherits from DB_CommonUser, + we must implement delete in the DB_Administrator_impl.erl + module, and lookup in DB_Administrator_impl.erlandDB_CommonUser_impl.erl. But wait, is that really necessary? Actually, + it is not. We simple use the IC compile option impl:

+
+$ erlc +'{{impl, "DB::CommonUser"}, "DBUser_impl"}'  +'{{impl, "DB::Administrator"}, "DBUser_impl"}' DB.idl
+$ erlc *.erl
+    
+

Instead of creating, and not the least, maintaining two call-back modules, + we only have to deal with DBUser_impl.erl. If we generated the + templates, we simply rename DB_Administrator_impl.erl to + DBUser_impl.erl. See also the + Exceptions chapter. + In the following example, only the implementation of the API functions + are shown:

+ +%%====================================================================== +%% API Functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : delete/2 +%% Arguments : State - term() +%% ENo = unsigned_Long() +%% Returns : ReturnValue = ok +%% Raises : +%% Description: +%%---------------------------------------------------------------------- +delete(State, ENo) -> + %% How we access the DB, for example mnesia, is not shown here. + case delete_employee(No) of + ok -> + {reply, ok, State}; + error -> + %% Here we should throw an exception if + %% there is no match. + corba:raise(....) + end. + +%%---------------------------------------------------------------------- +%% Function : lookup/2 +%% Arguments : State - term() +%% ENo = unsigned_Long() +%% Returns : ReturnValue = OE_Reply +%% OE_Reply = #'DB_employee'{No,Name,Address,Dpt} +%% No = unsigned_Long() +%% Name = String() +%% Address = String() +%% Dpt = Department +%% Department = 'Department1' | 'Department2' +%% Raises : +%% Description: +%%---------------------------------------------------------------------- +lookup(State, ENo) -> + %% How we access the DB, for example mnesia, is not shown here. + case lookup_employee(ENo) of + %% We assume that we receive a 'DB_employee' struct + {ok, Employee} -> + OE_Reply = Employee, + {reply, OE_Reply, State}; + error -> + %% Here we should throw an exception if + %% there is no match. + corba:raise(....) + end. + +

After you have compiled both call-back modules, and implemented the missing + functionality (e.g. lookup_employee/1), we can test our application:

+ +%% Erlang code +.... +%% Create an Access object +Acc = 'DB_Access':oe_create(), + +%% Login is Common user and Administrator +Adm = 'DB_Access':logon(A, "admin", "pw"), +Com = 'DB_Access':logon(A, "comm", "pw"), + +%% Lookup existing employee +Employee = 'DB_Administrator':lookup(Adm, 1), +Employee = 'DB_CommonUser':lookup(Adm, 1), + +%% If we try the same using the DB_CommonUser interface +%% it result in an exit since that operation is not exported. +{'EXIT', _} = (catch 'DB_CommonUser':delete(Adm, 1)), + +%% Try to delete the employee via the CommonUser Object +{'EXCEPTION', _} = (catch 'DB_Administrator':delete(Com, 1)), + +%% Invoke delete operation on the Administrator object +ok = 'DB_Administrator':delete(Adm, 1), +.... + +
+ +
+ Reserved Compiler Names and Keywords + +

The use of some names is strongly discouraged due to + ambiguities. However, the use of some names is prohibited + when using the Erlang mapping , as they are strictly reserved for IC.

+

IC reserves all identifiers starting with OE_ and oe_ + for internal use.

+

Note also, that an identifier in IDL can contain alphabetic, + digits and underscore characters, but the first character + must be alphabetic. +

+

The OMG defines a set of reserved words, shown below, for use as keywords. + These may not be used as, for example, identifiers. The keywords + which are not in bold face was introduced in the OMG CORBA-3.0 + specification.

+ + + abstract + exception + inout + provides + truncatable + + + any + emits + interface + public + typedef + + + attribute + enum + local + publishes + typeid + + + boolean + eventtype + long + raises + typeprefix + + + case + factory + module + readonly + unsigned + + + char + FALSE + multiple + setraises + union + + + component + finder + native + sequence + uses + + + const + fixed + Object + short + ValueBase + + + consumes + float + octet + string + valuetype + + + context + getraises + oneway + struct + void + + + custom + home + out + supports + wchar + + + default + import + primarykey + switch + wstring + + + double + in + private + TRUE + + + OMG IDL keywords +
+

The keywords listed above must be written exactly as shown. Any usage + of identifiers that collide with a keyword is illegal. For example, + long is a valid keyword; Long and LONG are + illegal as keywords and identifiers. But, since the OMG must be able + to expand the IDL grammar, it is possible to use Escaped Identifiers. For example, it is not unlikely that native + have been used in IDL-specifications as identifiers. One option is to + change all occurrences to myNative. Usually, it is necessary + to change programming language code that depends upon that IDL as well. + Since Escaped Identifiers just disable type checking (i.e. if it is a reserved + word or not) and leaves everything else unchanged, it is only necessary to + update the IDL-specification. To escape an identifier, simply prefix it + with _. The following IDL-code is illegal:

+ +typedef string native; +interface i { + void foo(in native Arg); + }; +}; + +

With Escaped Identifiers the code will look like:

+ +typedef string _native; +interface i { + void foo(in _native Arg); + }; +}; + +
+ +
+ Type Code Representation + +

Type Codes are used in any values. To avoid mistakes, you should + use access functions exported by the Data Types modules + (e.g. struct, union etc) or the orber_tc + module.

+ + + Type Code + Example + + + tk_null + + + + tk_void + + + + tk_short + + + + tk_long + + + + tk_longlong + + + + tk_ushort + + + + tk_ulong + + + + tk_ulonglong + + + + tk_float + + + + tk_double + + + + tk_boolean + + + + tk_char + + + + tk_wchar + + + + tk_octet + + + + tk_any + + + + tk_TypeCode + + + + tk_Principal + + + + {tk_objref, IFRId, Name} + {tk_objref, "IDL:M1\\I1:1.0", "I1"} + + + {tk_struct, IFRId, Name, [{ElemName, ElemTC}]} + {tk_struct, "IDL:M1\\S1:1.0", "S1", [{"a", tk_long}, {"b", tk_char}]} + + + {tk_union, IFRId, Name, DiscrTC, DefaultNr, [{Label, ElemName, ElemTC}]}

+Note: DefaultNr tells which of tuples in the case list that is default, or -1 if no default
+ {tk_union, "IDL:U1:1.0", "U1", tk_long, 1, [{1, "a", tk_long}, {default, "b", tk_char}]} +
+ + {tk_enum, IFRId, Name, [ElemName]} + {tk_enum, "IDL:E1:1.0", "E1", ["a1", "a2"]} + + + {tk_string, Length} + {tk_string, 5} + + + {tk_wstring, Length} + {tk_wstring, 7} + + + {tk_fixed, Digits, Scale} + {tk_fixed, 3, 2} + + + {tk_sequence, ElemTC, Length} + {tk_sequence, tk_long, 4} + + + {tk_array, ElemTC, Length} + {tk_array, tk_char, 9} + + + {tk_alias, IFRId, Name, TC} + {tk_alias, "IDL:T1:1.0", "T1", tk_short} + + + {tk_except, IFRId, Name, [{ElemName, ElemTC}]} + {tk_except, "IDL:Exc1:1.0", "Exc1", [{"a", tk_long}, {"b", {tk_string, 0}}]} + + Type Code tuples +
+
+
+ diff --git a/lib/orber/doc/src/ch_ifr.xml b/lib/orber/doc/src/ch_ifr.xml new file mode 100644 index 0000000..690a816 --- /dev/null +++ b/lib/orber/doc/src/ch_ifr.xml @@ -0,0 +1,49 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Interface Repository + + + 1998-10-10 + + ch_ifr.xml +
+ +
+ Interface Repository(IFR) +

The IFR is an interface repository built on the Mnesia + application. Orber uses the IFR for some type-checking + when coding/decoding IIOP. The IFR is capable of storing all + interfaces and declarations of OMG IDL. +

+

The interface repository is mainly used for dynamical + interfaces, and as none are currently supported this function + is only really used for retrieving information about interfaces.

+

Functions relating to the manipulation of the IFR including, + initialization of the IFR, as well as, locating, creating and + destroying initial references are detailed further in the Manual + Pages. +

+
+
+ diff --git a/lib/orber/doc/src/ch_install.xml b/lib/orber/doc/src/ch_install.xml new file mode 100644 index 0000000..eee2b99 --- /dev/null +++ b/lib/orber/doc/src/ch_install.xml @@ -0,0 +1,1071 @@ + + + + +
+ + 19972009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Installing Orber + + + + + + 1998-09-28 + + ch_install.xml +
+ +
+ Installation Process +

This chapter describes how to install Orber in an Erlang + Environment.

+ +
+ Preparation +

To begin with, you must decide if you want to run Orber as a:

+ + Single node (non-distributed) - all communication with other + Orber instances and ORB's supplied by other vendors use the OMG + GIOP protocol. + Multi node (distributed) - all Orber nodes, within the same + domain, communicate via the Erlang distribution protocol. + For all other Orber instances, i.e. not part of the same domain, + and ORB's supplied by other vendors, the OMG GIOP protocol + is used. + +

Which approach to use is highly implementation specific, but a few + things you should consider:

+ + All nodes within an Orber domain should have the same + security level. + If the capacity is greater than load (volume of traffic) + a single-node Orber might be a good solution. + In some cases the distributed system architecture requires a + single-node is the structure of the ORB or ORBs as defined during the install process is called the "installation".. + A multi-node Orber makes it possible to load balance + and create a more fault tolerant system. The Objects + can also have a uniform view if you use distributed + Mnesia tables. + Since the GIOP protocol creates a larger overhead than the + Erlang distribution protocol, the performance will be better + when communicating with Objects within the same Orber domain + compared with inter ORB communication (GIOP). + +

You also have to decide if you want Orber to store internal data using + disc_copies and/or ram_copies. Which storage type you should + depends if/how you intend to use Mnesia in your application. If you + intend to use disc_copies you must start with creating a Mnesia + schema, which contain information about the location of the Erlang nodes + where Orber is planned to be run. For more background information, + see the Mnesia documentation.

+

In some cases it is absolutely necessary to change the default configuration + of Orber. For example, if two Orber-ORB's shall be able to communicate + via GIOP, they must have a unique domain domain. Consult the + configuration settings + section. If you encounter any problems; see the chapter about + Debugging in this User's Guide.

+
+ +
+ Jump Start Orber +

The easiest way to start Orber is to use orber:jump_start(Port), + which start a single-node ORB with (most likely) a unique + domain (i.e. "IP-number:Port"). This function may only be used + during development and testing. For any other situation, install and + start Orber as described in the following sections. + The listen port, i.e. iiop_port configuration parameter, is set to + the supplied Port.

+ +

How Orber is configured when using orber:jump_start(Port) + may change at any time without warning. Hence, this operation must + not be used in systems delivered to a customer.

+
+
+ +
+ Install Single Node Orber +

Since a single node Orber communicate via the OMG GIOP protocol it is not + necessary to start the Erlang distribution (i.e. using -name/-sname).

+

If we use ram_copies there is no need for creating a disk based + schema. Simply use:

+ +erl> mnesia:start(). +erl> corba:orb_init([{domain, "MyRAMSingleNodeORB"}]). +erl> orber:install([node()], [{ifr_storage_type, ram_copies}]). +erl> orber:start(). + +

If you installation requires disc_copies you must begin with + creating a Mnesia schema. Otherwise, the installation is similar + to a RAM installation:

+ +erl> mnesia:create_schema([node()]). +erl> mnesia:start(). +erl> corba:orb_init([{domain, "MyDiskSingleNodeORB"}]). +erl> orber:install([node()], [{ifr_storage_type, disc_copies}, + {nameservice_storage_type, disc_copies}]). +erl> orber:start(). + +

You can still choose to store the IFR data as ram_copies, but then + the data must be re-installed (i.e. invoke orber:install/2) + if the node is restarted. Hence, since the IFR data is rather static + you should use disc_copies. For more information see the + orber section in the reference manual.

+

If you do not need to change Orber's configuration you can skip + orb_init/1. + But, you should at least set the IIOP timeout parameters.

+
+ +
+ Install RAM Based Multi Node Orber +

Within a domain Orber uses the Erlang distribution protocol. Hence, you + must start it first by, for example, using:

+ +hostA> erl -sname nodeA + +

In this example, we assume that we want to use two nodes; nodeA and + nodeB. Since Mnesia must know which other nodes should a part + of the distribution we either need to add the Mnesia configuration + parameter extra_db_nodes or use mnesia:change_config/2. To + begin with, Mnesia must be started on all nodes before we can install + Orber:

+ +nodeA@hostA> mnesia:start(). +nodeA@hostA> mnesia:change_config(extra_db_nodes, + [nodeA@hostA, nodeB@hostB]). + +

After that the above have been repeated on nodeB we must + first make sure that both nodes will use the same domain name, then + we can install Orber:

+ +nodeA@hostA> corba:orb_init([{domain, "MyRAMMultiNodeORB"}]). +nodeA@hostA> orber:install([nodeA@hostA, nodeB@hostB], + [{ifr_storage_type, ram_copies}]). +nodeA@hostA> orber:start(). + +

Note that you can only invoke orber:install/1/2 on one of the + nodes. Now we can start Orber on the other node:

+ +nodeB@hostB> corba:orb_init([{domain, "MyRAMMultiNodeORB"}]). +nodeB@hostB> orber:start(). + +
+ +
+ Install Disk Based Multi Node Orber +

As for RAM based multi-node Orber installations, the Erlang distribution + must be started (e.g. erl -sname nodeA). The major difference is that + when it is disk based a Mnesia schema must be created:

+ +nodeA@hostA> mnesia:create_schema([nodeA@hostA, nodeB@hostB]). +nodeA@hostA> mnesia:start(). + +

In this example, we assume that we want to use two nodes; nodeA and + nodeB. Since it is not possible to create a schema on more than + one node. Hence, all we have to do is to start Mnesia (i.e. invoke + mnesia:start()) on nodeB.

+

After Mnesia have been started on all nodes, you must confirm that all + nodes have the same domain name, then Orber is ready to be installed:

+ +nodeA@hostA> corba:orb_init([{domain, "MyDiskMultiNodeORB"}]). +nodeA@hostA> orber:install([nodeA@hostA, nodeB@hostB], + [{ifr_storage_type, disc_copies}]). +nodeA@hostA> orber:start(). + +

Note that you can only invoke orber:install/1/2 on one of the + nodes. Now we can start Orber on the other node:

+ +nodeB@hostB> corba:orb_init([{domain, "MyDiskMultiNodeORB"}]). +nodeB@hostB> orber:start(). + +
+ +
+ +
+ Configuration + +

It is essential that one configure Orber properly, to avoid, for example, + malicious attacks and automatically terminate IIOP connections no longer + in use. An easy way to extract information about Orber's configuration + parameters is to invoke the operation + orber:info/1/2. + Orber offer the following configuration parameters:

+ + + Key + Range + Default + + + domain + string() + "ORBER" + + + iiop_port + integer() >= 0 + 4001 + + + nat_iiop_port + integer() > 0 | {local, integer(), [{integer(), integer()}]} + The same as iiop_port + + + iiop_out_ports + 0 | {integer(),integer()} + 0 + + + iiop_max_fragments + integer() > 0 | infinity + infinity + + + iiop_max_in_requests + integer() > 0 | infinity + infinity + + + iiop_max_in_connections + integer() > 0 + infinity + + + iiop_backlog + integer() > 0 + 5 + + + iiop_packet_size + integer() > 0 | infinity + infinity + + + ip_address + string() | {multiple, [string()]} + All interfaces + + + ip_address_local + string() + Defined by the underlying system + + + nat_ip_address + string() | {multiple, [string()]} | {local, string(), [{string(), string()}]} + The same as ip_address + + + objectkeys_gc_time + integer() > 0 | infinity + infinity + + + giop_version + {1,0} | {1,1} | {1,2} + {1,1} + + + iiop_setup_connection_timeout + integer() > 0 | infinity + infinity + + + iiop_connection_timeout + integer() > 0 | infinity + infinity + + + iiop_in_connection_timeout + integer() > 0 | infinity + infinity + + + iiop_out_keepalive + true | false + false + + + iiop_in_keepalive + true | false + false + + + iiop_timeout + integer() > 0 | infinity + infinity + + + interceptors + {native, [atom()]} + - + + + local_interceptors + {native, [atom()]} + - + + + orbInitRef + [string()] | undefined + undefined + + + orbDefaultInitRef + string() | undefined + undefined + + + orber_debug_level + 0 - 10 + 0 + + + flags + integer() >= 0 + 0 + + + iiop_acl + [{atom(), string()}] | [{atom(), string(), [string()]}] + [] + + + secure + no | ssl + no + + + ssl_generation + 2 | 3 + 2 + + + iiop_ssl_port + integer() >= 0 + 4002 + + + iiop_ssl_accept_timeout + integer() > 0 | infinity + infinity + + + iiop_ssl_backlog + integer() > 0 + 5 + + + iiop_ssl_ip_address_local + string() + Defined by the underlying system + + + nat_iiop_ssl_port + integer() > 0 | {local, integer(), [{integer(), integer()}]} + The same as iiop_ssl_port + + + ssl_server_cacertfile + string() + - + + + ssl_server_certfile + string() + - + + + ssl_server_verify + 0 | 1 | 2 + - + + + ssl_server_depth + integer() + - + + + ssl_server_password + string() + - + + + ssl_server_keyfile + string() + - + + + ssl_server_ciphers + string() + - + + + ssl_server_cachetimeout + integer() | infinity + infinity + + + ssl_client_cacertfile + string() + - + + + ssl_client_certfile + string() + - + + + ssl_client_verify + 0 | 1 | 2 + - + + + ssl_client_depth + integer() + - + + + ssl_client_password + string() + - + + + ssl_client_keyfile + string() + - + + + ssl_client_ciphers + string() + - + + + ssl_client_cachetimeout + integer() | infinity + infinity + + + iiop_ssl_out_keepalive + true | false + false + + + iiop_ssl_in_keepalive + true | false + false + + Orber Configuration Parameters +
+

+

+

Comments on the table 'Orber Configuration Parameters':

+ + domain + Since Orber domains, they are supposed to communicate via IIOP, + MUST have unique names, communication will + fail if two domains have the same name. The domain name MAY NOT + contain ^G (i.e. \\007). + iiop_port + If set to 0 the OS will pick any vacant port. +

+Note:On a UNIX system it is preferable to + have a IIOP port higher than 1023, since it is not recommended to + run Erlang as a root user.
+ nat_iiop_port + The value is either an integer or {local, DefaultNATPort, [{Port, NATPort}]}. See also + Firewall Configuration. + iiop_out_ports + When set to 0 any available port will be used. + If a range is specified, Orber will only + use the local ports within the interval when trying to connect to + another ORB (Orber acts as a client ORB). If all ports are in use + communication will fail. Hence, it is absolutely necessary to + set iiop_connection_timeout as well. Otherwise, connections + no longer in use will block further communication. If one use, for + example, erl -orber iiop_out_ports "{5000,5020}", Orber + will only use port 5000 to 5020 when connecting. + If communicating via SSL, make sure you use a version that supports + the local {port, Port} option. See also + Firewall Configuration. + iiop_max_fragments + Limits the number of IIOP fragments allowed per request. + iiop_max_in_requests + Limits the number of concurrent incoming requests per incoming connection. + iiop_max_in_connections + Limits the number of concurrent incoming connections. + iiop_backlog + Defines the maximum length the queue of pending incoming + connections may grow to. + iiop_packet_size + Defines the maximum size of incoming requests. + If this limit is exceeded, the connection is closed. + ip_address + This option is used if orber only should + listen on a specific ip interface on a multi-interface host or if + exported IOR:s should contain multiple components. The value is + the IPv4 or IPv6 address as a string or {multiple, IPList}. + The latter requires that the object is available via the all IP addresses + found in the list. + ip_address_local + This option defines the default local interface Orber will + use when connecting to another ORB via IIOP, i.e., Orber act as the + client side ORB. The value is a IPv4 or IPv6 address as a string. + It is possible to override ip_address_local by defining + iiop_acl or passing the Orber generic interface Context. + If this option is not used, the underlying OS will choose which interface to + use. For more information, see the + Interface Configuration + section. + nat_ip_address + The value is the ip address as + a string (IPv4 or IPv6), {multiple, IPList} or + {local, DefaultNATIPAddress, [{IPAddress, NATIPAddress}]}. See also + Firewall Configuration. + objectkeys_gc_time + This option should be set if objects are started + using the option {persistent, true}. + The value is integer() seconds. + giop_version + Defines the default GIOP protocol version. + iiop_setup_connection_timeout + The value is an integer (seconds) or the atom infinity. + This option is only valid for client-side + connections. If this option is set, attempts to connect to other ORB's + will timeout after the given time limit. Note, if the time limit is large + the TCP protocol may timeout before the supplied value. + iiop_connection_timeout + The value is an integer (timeout in seconds between 0 and 1000000) + or the atom infinity. This option is only valid for client object + connections, i.e., will have no effect on server connections. Setting this + option will cause client connections to be terminated, if and only if, + there are no pending requests. If there are a client still waiting for + a reply, Orber will try again after the given seconds have passed. The main + purpose for this option is to reduce the number of open connections; it is, + for example, not necessary to keep a connection, only used once a day, + open at all time. + iiop_in_connection_timeout + The same as for iiop_connection_timeout. The only difference is + that this option only affects incoming connections (i.e. Orber act as + server-side ORB). + iiop_out_keepalive + Enables periodic transmission on a connected socket, when no other + data is being exchanged. If the other end does not respond, the + connection is considered broken and will be terminated. + When enabled the SO_KEEPALIVE socket level option is set. + iiop_in_keepalive + The same as for iiop_out_keepalive. The only difference is + that this option only affects incoming connections. + iiop_timeout + The value is an integer (timeout in seconds between 0 and 1000000) + or the atom infinity. This option is only valid on the client side. + Setting this option, cause all intra-ORB requests to timeout and + raise a system exception, e.g. TIMEOUT, if no replies are delivered + within the given time limit. + interceptors + If one set this parameter, e.g., + erl -orber interceptors "{native, ['myInterceptor']}", + Orber will use the supplied interceptor(s) for all inter-ORB + communication. 'myInterceptor' is the module name of the + interceptor. For more information, see the interceptor chapter + in the User's Guide and the Reference Manual. + local_interceptors + If defined, its value will be + used when activating local interceptors via + Orber Environment Flags. + If not defined, but the flag is set, Orber will use the value of + the interceptors parameter. + orbInitRef + Setting this option, e.g., + erl -orber orbInitRef [\\"NameService=corbaloc::host.com/NameService\\"], + will alter the location from where corba:resolve_initial_references(Key) + tries to find an object matching the given Key. The keys will also appear when + invoking corba:list_initial_services(). This variable overrides + orbDefaultInitRef + orbDefaultInitRef + If a matching Key for orbInitRef is not + found, and this variable is set, it determines the location from where + orber:resolve_initial_references(Key) tries to find an object + matching the given Key. Usage: + erl -orber orbDefaultInitRef \\"corbaloc::host.com\\". + orber_debug_level + The range is 0 to 10. + Using level 10 is the most verbose configuration. + This option will generate reports, using the error_logger, + for abnormal situations. It is not recommended to use this option + for delivered systems since some of the reports is not to be considered + as errors. The main purpose is to assist during development. + flags + No flags are activated in the default case. + The available configuration settings are described in + Orber Environment Flags. + iiop_acl + This option must be activated by setting + Orber Environment Flags parameter. + The value of this parameter shall be a list of [{Direction, Filter}] + and/or [{Direction, Filter, [Interfaces]}]. The Direction, + tcp_in, ssl_in, tcp_out or ssl_out, determines if + the Access Control List (ACL) applies to incoming or outgoing connections + and IIOP or IIOP over SSL. The Filter uses a extended format of + Classless Inter Domain Routing (CIDR). For example, "123.123.123.10" limits + the connection to that particular host, while "123.123.123.10/17" allows + connections to or from any host equal to the 17 most significant bits. Orber + also allow the user to specify a certain port or port range, for example, + "123.123.123.10/17#4001" and "123.123.123.10/17#4001/5001" + respectively. IPv4 or none compressed IPv6 strings are accepted.

+ + The list of Interfaces, IPv4 or IPv6 strings, may only contain + one address for outgoing connections. For incoming connections, + the Interfaces list may contain several IP strings. If set for + outgoing connections, and access is granted, Orber will use that local + interface when connecting to the server-side ORB. For incoming connections, + the client-side ORB is required to use one of the listed interfaces locally. + If it fail to do so, access will be denied. The module + orber_acl provides operations for + evaluating the access control for filters and addresses. See also the + Interface Configuration + and + Firewall Configuration + chapters.
+ secure + Determines the security mode Orber will use, which is either + no if it is an insecure domain or the type of security + mechanism used. Currently, per default, Orber is compliant with + CSIv1 level 0, which means IIOP via SSL/TLS. + The security chapter later in this manual describes how to get security + in Orber and how the options are used. + ssl_generation + Defines which SSL version, i.e. available API, is installed. The + default value, 2, refers to SSL-3.1 or later, but earlier than SSL-4.0. + If set to 3 SSL-4.0, or later, must be available. Currently it not possible + to use 1, it is only reserved for future use. + iiop_ssl_port + If set, the value must be an + integer greater than zero and not equal to iiop_port. + iiop_ssl_accept_timeout + The value is an integer (timeout in seconds) or the atom infinity and + determine how long the SSL handshake may take. This option should + be set to avoid if a client never initiate the handshake. + iiop_ssl_backlog + Defines the maximum length the queue of pending incoming + connections may grow to. + iiop_ssl_ip_address_local + This option defines the default local interface Orber will + use when connecting to another ORB via IIOP SSL, i.e., Orber act as the + client side ORB. The value is a IPv4 or IPv6 address as a string. + It is possible to override iiop_ssl_ip_address_local by defining + iiop_acl or passing the Orber generic interface Context. + If this option is not used, the underlying OS will choose which interface to + use. For more information, see the + Interface Configuration + section. + nat_iiop_ssl_port + If set, the value must be an integer greater than zero or + {local, DefaultNATPort, [{Port, NATPort}]}. See also + Firewall Configuration. + ssl_server_cacertfile + the file path to a server side CA certificate. + ssl_server_certfile + The path to a file containing a chain of PEM encoded certificates. + ssl_server_verify + The type of verification used by SSL during authentication of the + other peer for incoming calls. + ssl_server_depth + The SSL verification depth for outgoing calls. + ssl_server_password + The server side key string. + ssl_server_keyfile + The file path to a server side key. + ssl_server_ciphers + The server side cipher string. + ssl_server_cachetimeout + The server side cache timeout. + ssl_client_cacertfile + The file path to a client side CA certificate. + ssl_client_certfile + The path to a file containing a chain of PEM encoded certificates. + ssl_client_verify + The type of verification used by SSL during authentication of the + other peer for outgoing calls. + ssl_client_depth + The SSL verification depth for incoming calls. + ssl_client_password + The client side key string. + ssl_client_keyfile + The file path to a client side key. + ssl_client_ciphers + The client side cipher string. + ssl_client_cachetimeout + The client side cache timeout. + iiop_ssl_out_keepalive + Enables periodic transmission on a connected socket, when no other + data is being exchanged. If the other end does not respond, the + connection is considered broken and will be terminated. + When enabled the SO_KEEPALIVE socket level option is set. Requires that + the installed SSL version support the keepalive option + and that the ssl_generation points to this version. + iiop_ssl_in_keepalive + The same as for iiop_ssl_out_keepalive. The only difference is + that this option only affects incoming connections. +
+

It is possible to invoke operations using the extra timeout parameter:

+
+erl> module_interface:function(ObjRef, Timeout, ..Arguments..).
+erl> module_interface:function(ObjRef, [{timeout, Timeout}], ..Arguments..).
+erl> module_interface:function(ObjRef, ..Arguments..).    
+

The extra Timeout argument will override the configuration parameter + iiop_timeout. It is, however, not possible to use infinity + to override the Timeout parameter. The Timeout option is also valid for + objects which resides within the same A domain containing several Erlang nodes, which are communicating by using the Erlang internal format. An Orber domain looks as one ORB from the environment..

+

The iiop_setup_connection_timeout, iiop_timeout, + iiop_connection_timeout and iiop_in_connection_timeout + variables should be used. The specified values is implementation specific, + i.e., WAN or LAN, but they should range from + iiop_setup_connection_timeout to iiop_connection_timeout.

+

To change these settings in the configuration file, the + -config flag must be added to the erl command. See the + Reference Manual + config(4) for further information. The values can also + be sent separately as + options to the Erlang node when it is started, see the Reference + Manual + erl(1) for further information.

+ +
+ + Orber Environment Flags +

The Environment Flags allows the user to activate debugging + facilities or change Orber's behavior. The latter may result in that + Orber is no longer compliant with the OMG standard, which may be necessary + when communicating with a non-compliant ORB.

+ + + Hexadecimal Value + OMG Compliant + Description + + + 0001 + no + Exclude CodeSet Component + + + 0002 + yes + Local Typechecking + + + 0004 + yes + Use Host Name in IOR + + + 0008 + yes + Enable NAT + + + 0020 + yes + Local Interceptors + + + 0080 + yes + Light IFR + + + 0100 + yes + Use IPv6 + + + 0200 + yes + EXIT Tolerance + + + 0400 + yes + Enable Incoming ACL + + + 0800 + yes + Enable Outgoing ACL + + + 1000 + yes + Use Current Interface in IOR + + Orber Environment Flags +
+

Any combination of the flags above may be used and changes the + behavior as follows:

+ + Exclude CodeSet Component - instruct Orber to exclude + the CodeSet component in exported IOR:s. When activated, no + negotiating regarding character and wide character conversions + between the client and the server will occur. This flag will, + most likely, cause problems if your IDL specification contains + the data types wchar and/or wstring. + Local Typechecking - + If activated, parameters, replies and raised exceptions + will be checked to ensure that the data is correct. If an error + occurs, the error_logger is used to generate reports. + One MAY NOT use this option for delivered systems due + to the extra overhead. Since this option activates typechecking + for all objects generated on the target node, it is also possible + to use the option {local_typecheck, boolean()}, when + invoking oe_create/2, oe_create_link/2, + corba:create/4 or corba:create_link/4, to override + the configuration parameter. + Use Host Name in IOR - normally Orber inserts the IP-number + in IOR:s when they are exported. In some cases, this will cause + the clients to open two connections instead of one. + Enable NAT - if this flag is set, it is possible to use + the NAT (Network Address Translation) configuration parameters + (nat_iiop_port, nat_iiop_ssl_port and + nat_ip_address). + Local Interceptors - use interceptors for local + invocations. + Light IFR - if the IFR is not explicitly used and this + flag is set, Orber will use a minimal IFR to reduce memory usage + and installation time. + Use IPv6 - when this option is activated, Orber will use + IPv6 for inter-ORB communication. + EXIT Tolerance - servers will survive even though the + call-back module caused an EXIT. + Enable Incoming ACL - activates access control for incoming + connections. + Enable Outgoing ACL - activates access control for outgoing + connections. + Use Current Interface in IOR - when set, Orber will add + the interface the request came via to exported local IOR:s. + +

Invoking the operation + orber:info/1/2 will display the currently + set flags in a readable way.

+
+
+ +
+ Firewall Configuration + +

Firewalls are used to protect objects from clients in other networks or + sub-networks, but also to restrict which hosts internal objects may connect to + (i.e. inbound protection and outbound protection). A firewall + can limit access based on:

+ + Transport Level - performs access control decisions based on + address information in TCP headers. + Application Level - understands GIOP messages and the specific + transport level inter-ORB Protocol supported e.g. IIOP. + +

This section describes how to configure a Transport Level firewall. It + must have prior knowledge of the source to destination mappings, and + conceptually has a configuration table containing tuples of the form: + ({inhost:inport}, {outhost:outport}). If there are no port restrictions + it is rather easy to configure the firewall. Otherwise, we must consider the + following alternatives:

+ + Incoming Requests - Orber only uses the port-numbers specified + by the configuration parameters iiop_port and + iiop_ssl_port. Other ORB's may use several ports but it should + be possible to change this behavior. Consult the other ORBs + documentation. + Outgoing Requests - Most ORB's, Orber included, + ask the OS to supply a vacant local port when connecting to the + server-side ORB. It is possible to change this behavior when using + Orber (i.e. set the configuration parameter iiop_out_ports). + + +

Using the option iiop_out_ports may result in that Orber runs out of + valid ports numbers. For example, other applications may steal some of the + ports or the number of concurrent outgoing connections to other ORBs may be + higher than expected. To reduce, but not eliminate, the risk you should use + iiop_connection_timeout.

+
+

Firewall configuration example:

+
+# "Plain" IIOP
+To: Orber-IPNo:(iiop_port)     From: ORB-IPNo:X
+To: ORB-IPNo:Z                 From: Orber-IPNo:(iiop_out_ports | Any Port)
+
+# IIOP via SSL
+To: Orber-IPNo:(iiop_port)     From: ORB-IPNo:X
+To: Orber-IPNo:(iiop_ssl_port) From: ORB-IPNo:Y
+To: ORB-IPNo:Z                 From: Orber-IPNo:(iiop_out_ports | Any Port)
+    
+

If the communication take place via a + TCP Firewall with NAT + (Network Address Translation), we must activate this behavior and define + the external address and/or ports.

+ + + +TCP Firewall With NAT + +

Using NAT makes it possible to use different host data for different network + domains. This way we can share Internet Protocol address resources or + obscure resources. To enable this feature the + Enable NAT flag must be set and + nat_iiop_port, nat_iiop_ssl_port and nat_ip_address + configured, which maps to iiop_port, iiop_ssl_port and + ip_address respectively. Hence, the firewall must be configured to + translate the external to the internal representation correctly. If these NAT parameters + are assigned a single port number or IP address, only those will be used when + an IOR is exported to another ORB. When ip_address is set to + {multiple, [IPAddress]}, nat_ip_address should be configured in the same + way, so that each NAT IP address can be translated to a valid address by the firewall. + If objects are supposed to be accessible via different interfaces and port, see also + Interface Configuration, + the options {local, DefaultNATIPAddress, [{IPAddress, NATIPAddress}]} and/or + {local, DefaultNATPort, [{Port, NATPort}]} shall be used. The default NAT IP address + and port, should be translated to the value of ip_address_local and the default + listen port by the firewall. If the IP address and/or port is not found in the list, + the default values will be inserted in the IOR. The firewall must be able to translate + these correctly.

+

If it is necessary to limit the access to an ORB within a secure network, + but other applications running on the same host may not be blocked out, + one can use a Application Level firewall or Orber Access Control + List (ACL). The latter makes it possible for the user to define which hosts + may communicate, either as server or client, with Orber. This is achieved by + defining the configuration parameter + iiop_acl. The Classless Inter + Domain Routing (CIDR) Filter determines which peer interfaces and + ports the other ORB may use.

+ + + Filter + Peer Interface(s) + Peer Port(s) + + + "10.1.1.1" + 10.1.1.1 + any + + + "10.1.1.1/8" + 10.0.0.0-10.255.255.255 + any + + + "10.1.1.1/8#4001" + 10.0.0.0-10.255.255.255 + 4001 + + + "10.1.1.1/8#4001/5001" + 10.0.0.0-10.255.255.255 + 4001-5001 + + Orber ACL Filters +
+

Orber ACL, also allows the user to define which local interface(s) may be used, + but will not detect spoofing. The operation + orber_acl:match/2/3 makes it easy to + verify whether access would be granted or not. For example, if Orber would + be started with the ACL [{tcp_out, "10.1.1.1/8#4001/5001"}], then + orber_acl:match/2 would behave as follows:

+ +erl> orber_acl:match({11,1,1,1}, tcp_out). +false + +erl> orber_acl:match({10,1,1,1}, tcp_out). +true + +erl> orber_acl:match({11,1,1,1}, tcp_out, true). +{false,[],0} + +erl> orber_acl:match({10,1,1,1}, tcp_out, true). +{true,[],{4001,5001}} + +

Only if the returned boolean is true the extra return values makes a + difference. In the example above, {true,[],{4001,5001}} means that + Orber may connect to "10.1.1.1", using any local interface, + if the server-side ORB listens for incoming connect requests on a port + within the range 4001-5001. Note, invoking the orber_acl:match/2/3 + operation, will not result in a connect attempt by Orber. The reason for + this, is that this function may be used on a live node as well as in test + environment. Hence, if a local interface is currently not available or no + server-side ORB available via the given host/port(s), will not be detected + by Orber.

+
+ +
+ Interface Configuration + +

In many cases it is sufficient to simply configure the underlying OS which + local interfaces shall be used for all applications. But, in some cases + it is required, due to, for example, the firewall configuration, that different + local interfaces are used for different applications. Some times, it is even + necessary to use a specific interface for a single CORBA object. This section + describe how one can alter this in different ways.

+

The default behavior is that Orber lets the OS configuration decide which interface + will be added in IOR:s exported to another ORB and the local interface used + when connecting to another ORB (Orber act as client side ORB). The latter can be + overridden by setting the configuration parameters iiop_ssl_ip_address_local + and/or ip_address_local, which will affect IIOP via SSL and IIOP + respectively. These parameters can be overridden by using the Orber generic + interface Context or defining an ACL (Access Control List). The latter + always takes precedence if a local interface is included (e.g. + [{tcp_out, "10.0.0.0/8", ["10.0.0.1"]}]). If the interface is excluded + (e.g. [{tcp_out, "10.0.0.0/8"}]), the interface chosen will, in the following + order, be determined by + #'IOP_ServiceContext'{}, ip_address_local/iiop_ssl_ip_address_local or + the configuration of the underlying system.

+

Adding the interface context, for generated stubs/skeletons, is done in the + following way:

+ +Ctx = #'IOP_ServiceContext'{context_id = ?ORBER_GENERIC_CTX_ID, + context_data = {interface, "10.0.0.1"}}, +'CosNaming_NamingContext':resolve(NS, [{context, [Ctx]}], Name), + +

It is also possible to add the context to + corba:string_to_object/2, corba:resolve_initial_references/2, corba:resolve_initial_references_remote/3, corba:list_initial_services_remote/2, corba_object:not_existent/2, corba_object:non_existent/2 and corba_object:is_a/3. + The operations exported by corba_object are affected + if the supplied IOR is external. The function corba:string_to_object/2 + might require the interface context if a corbaloc or a corbaloc + string is passed (See the + INS chapter), + while corba:resolve_initial_references_remote/3 and + corba:list_initial_services_remote/2 always connect to another ORB and + it might be necessary to add the context. + The remaining corba operations are affected if calls are re-directed + by setting the orbInitRef and/or orbDefaultInitRef configuration + parameters. For more information, see the Reference Manual for each module.

+

Configuring which interface(s) that shall be used when exporting an IOR to + another ORB, is determined by nat_ip_address, setting the flag + 16#1000 + and ip_address, in that order. Orber listens for incoming connections + either via all interfaces or the interface defined by ip_address. It is + also possible to add and remove extra listen interfaces by using + orber:add_listen_interface/2/3 and orber:remove_listen_interface/1. + In this case one should set the 16#1000 flag and, if necessary, set the + configuration parameters + {local, DefaultNATIPAddress, [{IPAddress, NATIPAddress}]} and/or + {local, DefaultNATPort, [{Port, NATPort}]}.

+
+
+ diff --git a/lib/orber/doc/src/ch_interceptors.xml b/lib/orber/doc/src/ch_interceptors.xml new file mode 100644 index 0000000..27b254c --- /dev/null +++ b/lib/orber/doc/src/ch_interceptors.xml @@ -0,0 +1,278 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Orber Interceptors + Nick + + 2001-08-16 + + ch_interceptors.xml +
+ +
+ Using Interceptors +

For Inter-ORB communication, e.g., via IIOP, it is possible + to intercept requests and replies. To be able to use Interceptors + Orber the configuration parameter interceptors must be defined.

+ +
+ Configure Orber to Use Interceptors +

The configuration parameter interceptors must be defined, e.g., + as command line option:

+ +erl -orber interceptors "{native, ['myInterceptor']}" + +

It is possible to use more than one interceptor; simply add them to the + list and they will be invoked in the same order as they appear in the list.

+

One can also active and deactivate an interceptor during + run-time, but this will only affect currently existing connections. + For more information, consult Orber's Reference Manual regarding the + operations orber:activate_audit_trail/0/1 and + orber:activate_audit_trail/0/1.

+
+ +
+ Creating Interceptors +

Each supplied interceptor must export the following functions:

+ + new_out_connection/3/5 - one of these operations is called when + a client application calls an object residing on remote ORB. + If an interceptor exports both versions, arity 3 and 5, which + operation that will be invoked is Orber internal. + new_in_connection/3/5 - one of these operations is invoked + when a client side ORB tries to set up a connection to the target ORB. + If an interceptor exports both versions, arity 3 and 5, which + operation that will be invoked is Orber internal. + out_request/6 - supplies all request data on the client side + ORB. + out_request_encoded/6 - similar to out_request + but the request body is encode. + in_request_encoded/6 - after a new request arrives at the + target ORB the request data is passed to the interceptor in + encoded format. + in_request/6 - prior to invoking the operation on the + target object, the interceptor in_request is called. + out_reply/6 - after the target object replied the + out_reply operation is called with the result of the object + invocation. + out_reply_encoded/6 - before sending a reply back to the + client side ORB this operation is called with the result in + encoded format. + in_reply_encoded/6 - after the client side ORB receives + a reply this function is called with the reply in encoded + format. + in_reply/6 - before delivering the reply to the client + this operation is invoked. + closed_in_connection/1 - when a connection is terminated + on the client side this function is called. + closed_out_connection/1 - if an outgoing connection is + terminated this operation will be invoked. + +

The operations new_out_connection, new_in_connection, + closed_in_connection and closed_out_connection operations + are only invoked once per connection. The remaining operations + are called, as shown below, for every Request/Reply to/from remote + CORBA Objects.

+ + + +The Invocation Order of Interceptor Functions. + +
+
+ +
+ Interceptor Example +

Assume we want to create a simple access service which purpose is to:

+ + Only allow incoming request from ORB's residing on a certain set of + nodes. + Restrict the objects any client may invoke operations on. + Only allow outgoing requests to call a limited set of external + ORB's. + Add a checksum to each binary request/reply body. + +

To restricts the access we use a protected and named ets-table + holding all information. How the ets-table is initiated and maintained + is implementation specific, but it contain + {Node, ObjectTable, ChecksumModule} where Node is used as + ets-key, ObjectTable is a reference to another ets-table in which + we store which objects the clients are allowed to invoke operations on + and ChecksumModule determines which module we should use to handle + the checksums.

+ +new_in_connection(Arg, Host, Port) -> + %% Since we only use one interceptor we do not care about the + %% input Arg since it is set do undefined by Orber. + case ets:lookup(in_access_table, Host) of + [] -> + %% We may want to log the Host/Port to see if someone tried + %% to hack in to our system. + exit("Access not granted"); + [{Host, ObjTable, ChecksumModule}] -> + {ObjTable, ChecksumModule} + end. + +

The returned tuple, i.e., {ObjTable, ChecksumModule}, will be passed + as the first argument whenever invoking one of the interceptor functions. + Unless the connection attempt did not fail we are now ready for receiving + requests from the client side ORB.

+

When a new request comes in the first interceptor function to be invoked is + in_request_encoded. We will remove the checksum from the coded + request body in the following way:

+ +in_request_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:remove_checksum(Bin), + {NewBin, Extra}. + +

If the checksum check fails the ChecksumModule should invoke exit/1. + But if the check succeeded we are now ready to check if the client-ORB + objects are allowed to invoke operations on the target object. Please note, + it is possible to run both checks in in_request_encoded. Please + note, the checksum calculation must be relatively fast to ensure a + good throughput.

+

If we want to we can restrict any clients to only use a subset of operations + exported by a server:

+ +in_request({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Params, Extra) -> + case ets:lookup(ObjTable, {ObjKey, Op}) of + [] -> + exit("Client tried to invoke illegal operation"); + [SomeData] -> + {Params, Extra} + end. + +

At this point Orber are now ready to invoke the operation on the target + object. Since we do not care about what the reply is the out_reply + function do nothing, i.e.:

+ +out_reply(_, _, _, _, Reply, Extra) -> + {Reply, Extra}. + +

If the client side ORB expects a checksum to be added to the reply we + add it by using:

+ +out_reply_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:add_checksum(Bin), + {NewBin, Extra}. + + +

If we manipulate the binary as above the behavior must + be Bin == remove_checksum(add_checksum(Bin)).

+
+

For outgoing requests the principle is the same. Hence, it is not further + described here. The complete interceptor module would look like:

+ + +-module(myInterceptor). + +%% Interceptor functions. +-export([new_out_connection/3, +\011 new_in_connection/3, +\011 closed_in_connection/1, +\011 closed_out_connection/1, +\011 in_request_encoded/6, +\011 in_reply_encoded/6, +\011 out_reply_encoded/6, +\011 out_request_encoded/6, +\011 in_request/6, +\011 in_reply/6, +\011 out_reply/6, +\011 out_request/6]). + +new_in_connection(Arg, Host, Port) -> + %% Since we only use one interceptor we do not care about the + %% input Arg since it is set do undefined by Orber. + case ets:lookup(in_access_table, Host) of + [] -> + %% We may want to log the Host/Port to see if someone tried + %% to hack in to our system. + exit("Access not granted"); + [{Host, ObjTable, ChecksumModule}] -> + {ObjTable, ChecksumModule} + end. + +new_out_connection(Arg, Host, Port) -> + case ets:lookup(out_access_table, Host) of + [] -> + exit("Access not granted"); + [{Host, ObjTable, ChecksumModule}] -> + {ObjTable, ChecksumModule} + end. + +in_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:remove_checksum(Bin), + {NewBin, Extra}. + +in_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) -> + case ets:lookup(ObjTable, {ObjKey, Op}) of + [] -> + exit("Client tried to invoke illegal operation"); + [SomeData] -> + {Params, Extra} + end. + +out_reply(_, _, _, _, Reply, Extra) -> + {Reply, Extra}. + +out_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:add_checksum(Bin), + {NewBin, Extra}. + +out_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) -> + case ets:lookup(ObjTable, {ObjKey, Op}) of + [] -> + exit("Client tried to invoke illegal operation"); + [SomeData] -> + {Params, Extra} + end. + +out_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:add_checksum(Bin), + {NewBin, Extra}. + +in_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) -> + NewBin = ChecksumModule:remove_checksum(Bin), + {NewBin, Extra}. + +in_reply(_, _, _, _, Reply, Extra) -> + {Reply, Extra}. + +closed_in_connection(Arg) -> + %% Nothing to clean up. + Arg. + +closed_out_connection(Arg) -> + %% Nothing to clean up. + Arg. + + +

One can also use interceptors for debugging purposes, e.g., + print which objects and operations are invoked with which arguments + and the outcome of the operation. In conjunction with the configuration + parameter orber_debug_level it is rather easy to find out what + went wrong or just to log the traffic.

+
+
+
+ diff --git a/lib/orber/doc/src/ch_introduction.xml b/lib/orber/doc/src/ch_introduction.xml new file mode 100644 index 0000000..16240e1 --- /dev/null +++ b/lib/orber/doc/src/ch_introduction.xml @@ -0,0 +1,144 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Introduction to Orber + Megan Lynch + + 1998-09-21 + + ch_introduction.xml +
+ +
+ Overview +

The Orber application is a CORBA compliant Object Request Brokers + (ORB), which provides CORBA functionality in an Erlang + environment. Essentially, the ORB channels communication or + transactions between nodes in a + heterogeneous environment. +

+

Common Object Request Broker Architecture is a common communication standard developed by the OMG (Object Management Group)(Common Object Request Broker + Architecture) provides an interface definition language allowing + efficient system integration and also supplies standard + specifications for some services. +

+

The Orber application contains the following parts:

+ + +

ORB kernel and IIOP support

+
+ +

Interface Repository

+
+ +

Interface Definition Language Mapping for Erlang

+
+ +

CosNaming Service

+
+
+ +
+ Benefits +

Orber provides CORBA functionality in an Erlang environment that enables: +

+ + +

Platform interoperability and transparency

+

Orber enables communication between + OTP applications or Erlang environment applications and + other platforms; for example, Windows NT, Solaris + etc, allowing platform transparency. This is especially helpful in situations where there + are many users with different platforms. For example, + booking airline tickets would require the airline database + and hundreds of travel agents (who may not have the same + platform) to book seats on flights.

+
+ +

Application level interoperability and transparency

+

As Orber is a CORBA compliant application, its purpose is + to provide interoperability and transparency on the application + level. + Orber simplifies the distributed system software by defining the + environment as objects, which in effect, views + everything as identical regardless of programming + languages.

+ Previously, time-consuming programming was + required to facilitate communication between different languages. + However, with CORBA compliant Orber the Application + Programmer is relieved of this task. This makes + communication on an application level relatively transparent to the user.

+
+
+
+ +
+ Purpose and Dependencies +

The system architecture and OTP dependencies of Orber are illustrated in figure 1 below:

+ + + +Figure 1: Orber Dependencies and Structure. + +

Orber is dependent on Mnesia (see the Mnesia + documentation) - an Erlang database management application + used to store object information.

+ +

Although Orber does not have a run-time + application dependency to IC (an Interface Definition Language - IDL is the OMG specified interface definition language, used to define the CORBA object interfaces.compiler for + Erlang), it is necessary when building + services and applications. See the IC documentation for + further details.

+
+ + + +Figure 2: ORB interface between Java and Erlang Environment Nodes. + +

This simplified illustration in figure 2 demonstrates how Orber can facilitate communication in a heterogeneous environment. The Erlang Nodes running + OTP and the other Node running applications written in Java can + communicate via an Object Request Broker - ORB open software bus architecture specified by the OMG which allows object components to communicate in a heterogeneous environment.(Object Request Broker). Using + Orber means that CORBA functions can be used to achieve this + communication. +

+

For example, if one of the above nodes requests an object, it does not + need to know if that object is located on the same, or + different, Erlang or Java nodes. The ORB will channel the + information creating platform and application transparency for + the user. +

+
+ +
+ Prerequisites +

To fully understand the concepts presented in the + documentation, it is recommended that the user is familiar + with distributed programming and CORBA (Common Object Request + Broker Architecture). +

+

Recommended reading includes Open Telecom Platform Documentation Set and Concurrent Programming in Erlang. +

+
+
+
+ diff --git a/lib/orber/doc/src/ch_naming_service.xml b/lib/orber/doc/src/ch_naming_service.xml new file mode 100644 index 0000000..510ccf2 --- /dev/null +++ b/lib/orber/doc/src/ch_naming_service.xml @@ -0,0 +1,461 @@ + + + + +
+ + 19972009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + CosNaming Service + + + 1998-10-10 + + ch_naming_service.xml +
+ +
+ Overview of the CosNaming Service +

The CosNaming Service is a service developed to help users and + programmers identify objects by human readable names rather than by a + reference. By binding a name to a naming context (another object), a + contextual reference is formed. This is helpful when navigating in the + object space. In addition, identifying objects by name allows you to evolve + and/or relocate objects without client code modification.

+

The CosNaming service has some concepts that are important:

+ + +

name binding - a name to object association.

+
+ +

naming context - is an object that contains a set of + name bindings in which each name is unique. Different names can be + bound to the same object. +

+
+ +

to bind a name - is to create a name binding in a given + context.

+
+ +

to resolve a name - is to determine the object associated + with the name in a given context.

+
+
+

A name is always resolved in a context, there no absolute names exist. + Because a context is like any other object, it can also be bound to + a name + in a naming context. + This will result in a naming graph (a directed graph with notes and + labeled edges). The graph allows more complex names to refer to an + object. Given a context, you can use a sequence to reference an object. + This sequence is henceforth referred to as name and the + individual + elements in the sequence as name components. All but the + last name component are bound to naming contexts. +

+

The diagram in figure 1 illustrates how the Naming Service provides a + contextual relationship between objects, NamingContexts and + NameBindings to create an object locality, as the + object itself, has no name. +

+ + + +Figure 1: Contextual object relationships using the Naming Service. + +

The naming contexts provide a directory of contextual + reference and naming for objects (an object can appear to + have more than one name). +

+

In figure 1 the object to the right can either be + called alpha from one context or gamma from another. +

+

The Naming Service has an initial naming context, which is shown + in the diagram as the top-most object in the naming graph. + It has two names beta and epsilon, which are bound to other + naming contexts. The initial naming context is a well known location + used to share a common name space between multiple programs. + You can traverse the naming graph until you reach a name, which is + bound to an object, which is not a naming context. +

+

We recommend reading chapter 12, CORBA Fundamentals and Programming, for detailed information regarding the + Naming Service.

+
+ +
+ The Basic Use-cases of the Naming Service +

The basic use-cases of the Naming Service are: +

+ + Fetch initial reference to the naming service. + Creating a naming context. + Binding and unbinding names to objects. + Resolving a name to an object. + Listing the bindings of a naming context. + Destroying a naming context. + + +
+ Fetch Initial Reference to the Naming Service +

In order to use the naming service you have to fetch an + initial reference to it. This is done with:

+ +\011NS = corba:resolve_initial_references("NameService"). + + +

NS in the other use-cases refers to this initial reference.

+
+
+ +
+ Creating a Naming Context +

There are two functions for creating a naming context. + The first function, which only creates a naming context object is:

+ +NC = 'CosNaming_NamingContext':new_context(NS). + +

The other function creates a naming context and binds it to a name in + an already existing naming context (the initial context in this + example): +

+ +NC = 'CosNaming_NamingContext':bind_new_context(NS, lname:new(["new"])). + +
+ +
+ Binding and Unbinding Names to Objects +

The following steps illustrate how to bind/unbind an object reference + to/from a name. For the example below, assume that the NamingContexts + in the path are already bound to the name /workgroup/services, + and that reference to the services context are in the variable + Sc.

+ + +

Use the naming library functions to create a name

+ +Name = lname:new(["object"]). + +
+ +

Use CosNaming::NamingContext::bind() to bind a name to an object

+ +'CosNaming_NamingContext':bind(Sc, Name, Object). + +
+ +

Use CosNaming::NamingContext::unbind() to remove the NameBinding from an object

+ +'CosNaming_NamingContext':unbind(Sc, Name). + +
+
+ +

Objects can have more than one name, to indicate different paths to + the same object.

+
+
+ +
+ Resolving a Name to an Object +

The following steps show how to retrieve the object reference to the service context + above (/workgroup/services).

+ + +

Use the naming library functions to create a name path:

+ +Name = lname:new(["workgroup", "services"]). + +
+ +

Use CosNaming::NamingContext::resolve() to to resolve the name to an object

+ +Sc = 'CosNaming_NamingContext':resolve(NS, Name). + +
+
+

An alternative is to use:

+ +Sc = corba:string_to_object("corbaname:rir:/NameService#workgroup/services/"). + +

The corbaname schema is described further in the Interoperable + Naming Service section.

+
+ +
+ Listing the Bindings in a NamingContext + + +

Use CosNaming::NamingContext::list() to list all the bindings in a context

+

The following code retrieves and lists up to 10 bindings from a context.

+ +{BList, BIterator} = 'CosNaming_NamingContext':list(Sc, 10). + +lists:foreach(fun({{Id, Kind},BindingType}) -> case BindingType of +\011nobject -> +\011\011io:format("id: %s, kind: %s, type: object~n", [Id, Kind]); +\011 _ -> +\011\011io:format("id: %s, kind: %s, type: ncontext~n", [Id, Kind]) +\011end end, +\011Blist). + +
+
+ +

Normally a The binding iterator (Like a book mark) indicates which objects have been read from the list.is helpful in situations where you have a large\011number of objects + in a list, as the programmer then can traverse it more easily. + In Erlang it is not needed, because lists are easily handled in the + language itself.

+
+ +

Remember that the BindingIterator (BIterator in the example) is an object and therefore + must be removed otherwise dangling processes will occur. + Use CosNaming::BindingIterator::destroy() to remove it.

+
+ + 'CosNaming_NamingContext':destroy(BIterator). + +
+ +
+ Destroying a Naming Context +

The naming contexts are persistent and must be explicitly removed. + (they are also removed if all Orber nodes in the domain are stopped).

+ + +

Use CosNaming::NamingContext::destroy() to remove a NamingContext

+ +'CosNaming_NamingContext':destroy(Sc). + +
+
+
+
+ +
+ Interoperable Naming Service + +

The OMG specifies URL schemes, which represent a CORBA object and a CORBA object + bound in a NamingContext, for resolving references from other ORB:s. As of today, + three schemes are defined:

+ + IOR + corbaloc + corbaname + + +
+ IOR +

A stringified IOR is a valid URL format but difficult for humans to handle + through non-electronic means. This URL format does not depend on a specific + Name Service and, thus, is robust and insulates the client from the encapsulated + transport information and object key used to reference the object.

+
+ +
+ corbaloc +

The notation of this scheme is similar to the more well known URL HTTP, and + the full corbaloc BNF is:

+ = "corbaloc:"["/"] + = [","]* + = | + = | + = ":" + = rir + = + = ":" + = + = | ":" + = ":" + = "iiop" + = [":"] + = DNS-style Host Name | ip_address + = ".""@" | empty_string + = number + = number + = number + = for example NameService + ]]> +

The corbaloc scheme consists of 3 parts:

+ + Protocol - as of today iiop or rir is supported. + Using rir means that we will resolve the given Key locally, i.e., + the same as using corba:resolve_initial_references("NameService"). + IIOP address - this address can be divided into Version, Host + and Port. If the version or port are left out they will be set to the default + values 1.0 and 2809 respectively. + KeyString - an object key, e.g., "NameService". If no Key is + supplied the default value "NameService" will be used. + +

A corbaloc can be passed used together with + corba:string_to_object("corbaloc::1.0@erlang.org:4001/NameService") or set as the + configuration variables orbInitilRef or orbDefaultInitilRef and calling + corba:resolve_initial_references("NameService"). For more information see the Orber + installation chapter. corbaloc can also be used together with corbaname + to gain an easy access to a Name Service.

+

Currently, the OMG defines a set of reserved keys and the type of object, + listed below, they should be associated with. The NameService + key may not be changed in Orber. If you want to add one of the + reserved keys as an initial service, simply use:

+ +1> Factory = cosNotificationApp:start_global_factory(). +2> corba:add_initial_service("NotificationService", Factory). + +

This object can then be easily resolved by any other ORB, supporting + the Interoperable Naming Service, by using:

+ +3> NF = corba:string_to_object("corbaloc::1.0@erlang.org:4001/NotificationService"). + + + + String Name + Object Type + + + RootPOA + PortableServer::POA + + + POACurrent + PortableServer::Current + + + InterfaceRepository + CORBA::Repository + + + NameService + CosNaming::NamingContext + + + TradingService + CosTrading::Lookup + + + SecurityCurrent + SecurityLevel1::Current/SecurityLevel2::Current + + + TransactionCurrent + CosTransaction::Current + + + DynAnyFactory + DynamicAny::DynAnyFactory + + + ORBPolicyManager + CORBA::PolicyManager + + + PolicyCurrent + CORBA::PolicyCurrent + + + NotificationService + CosNotifyChannelAdmin::EventChannelFactory + + + TypedNotificationService + CosTypedNotifyChannelAdmin::TypedEventChannelFactory + + + CodecFactory + IOP::CodecFactory + + + PICurrent + PortableInterceptors::Current + + Currently reserved key strings +
+
+ +
+ corbaname +

The corbaname URL scheme is an extension of the corbaloc scheme, and + the full corbaname BNF is:

+ = "corbaname:"["/"]["#"] + = as described above. + = as described above. + ]]> +

The string_name, concatenated to the corbaloc string, identifies + a binding in a naming context. A name component consists of two parts, i.e., + id and kind, which is represented as follows:

+ + + String Name + Name Sequence + Comment + + + "id1/./id3.kind3" + [{"id1",""},{"",""},{"id3","kind3"}] + The first component has no kind defined while the second component's both fields are empty. + + + "id1//id3.kind3" + ERROR + Not allowed, must insert a '.' between the '//'. + + + "id1.kind1/." + [{"id1","kind1"},{"",""}] + The first component's fields are both set while the second component's both fields are empty. + + + "id1.kind1/id2." + ERROR + An Id with a trailing '.' is not allowed. + + + "i\\\\/d1/i\\\\.d2" + [{"i/d1",""},{"i.d2",""}] + Since '.' and '/' are used to separate the components, these tokens must be escaped to be correctly converted. + + Stringified Name representation +
+

After creating a stringified Name we can either use:

+ +NameStr = "org.erlang", +NS = corba:resolve_initial_references("NameService"), +Obj = 'CosNaming_NamingContextExt':resolve_str(NS, NameStr), + +

or concatenate the Name String using:

+ +NameStr = "Swedish/Soccer/Champions", +Address = "corbaname:iiop:1.0@www.aik.se:2000/NameService", +NS = corba:resolve_initial_references("NameService"), +URLStr = 'CosNaming_NamingContextExt':to_url(NS, Address, NameStr), +Obj = corba:string_to_object(URLStr), + +

Using the first alternative, the configuration variables orbInitilRef and + orbDefaultInitilRef, will determine which other ORB's or the local + Name Service Orber will try to resolve the given string from. The second + alternative allows us to override any settings of the configuration variables.

+

The function to_url/3 will perform any necessary escapes compliant with + IETF/RFC 2396. US-ASCII alphanumeric characters and + + are not escaped.

+
+
+
+ diff --git a/lib/orber/doc/src/ch_orber_kernel.xml b/lib/orber/doc/src/ch_orber_kernel.xml new file mode 100644 index 0000000..6669641 --- /dev/null +++ b/lib/orber/doc/src/ch_orber_kernel.xml @@ -0,0 +1,102 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + The Orber Application + + + 1998-10-05 + + ch_orber_kernel.xml +
+ +
+ ORB Kernel and IIOP +

This chapter gives a brief overview of the ORB and its relation + to objects in a distributed environment and the usage of Domains + in Orber. + Also Internet-Inter ORB Protocol (Internet-Inter ORB Protocol) is discussed and how this + protocol facilitates communication between ORBs to + allow the accessory of persistent server objects in Erlang.

+
+ +
+ The Object Request Broker (ORB) +

An ORB kernel can be best described as the middle-ware, which + creates relationships between clients and servers, but is + defined by its interfaces. This allows transparency for the + user, as they do not have to be aware of where the requested + object is located. Thus, the programmer can work with any other + platform provided that an IDL mapping and interfaces exist. +

+

The IDL mapping which is described in a later chapter is the + translator between other platforms, and languages. However, it + is the ORB, which provides objects with a structure by which + they can communicate with other objects. +

+

ORBs intercept and direct messages from one object, pass this + message using IIOP to another ORB, which then directs the + message to the indicated object. +

+

An ORB is the base on which interfaces, communication stubs + and mapping can be built to enable communication between + objects. Orber uses A domain allows a more efficient communication protocol to be used between objects not on the same node without the need of an ORBto group objects of different nodes +

+

How the ORB provides communication is shown very simply in figure 1 below:

+ + + +Figure 1: How the Object Request Broker works. + +

The domain in Orber gives an extra aspect to the distributed object + environment as each domain has one ORB, but it is distributed over + a number of object in different nodes. The domain binds objects on + nodes more closely than distributed objects in different domains. The + advantage of a domain is that a faster communication exists between + nodes and objects of the same domain. An internal communication protocol + (other than IIOP) allows a + more efficient communication between these objects.

+ +

Unlike objects, domains can only have one name + so that no communication ambiguities exist between domains.

+
+
+ +
+ Internet Inter-Object Protocol (IIOP) +

IIOP is a communication protocol developed by the OMG to + facilitate communication in a distributed object-oriented + environment. +

+

Figure 2 below demonstrates how IIOP works between objects:

+ + + +Figure 2: IIOP communication between domains and objects. + + +

Within the Orber domains the objects communicate without + using the IIOP. However, the user is unaware of the difference in protocols, as this difference is not visible.

+
+
+
+ diff --git a/lib/orber/doc/src/ch_orberweb.xml b/lib/orber/doc/src/ch_orberweb.xml new file mode 100644 index 0000000..30513ba --- /dev/null +++ b/lib/orber/doc/src/ch_orberweb.xml @@ -0,0 +1,221 @@ + + + + +
+ + 20012009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + OrberWeb + Nick + + 2001-11-22 + + ch_orberweb.xml +
+ +
+ Using OrberWeb +

OrberWeb is intended to make things easier when developing and + testing applications using Orber. The user is able to interact + with Orber via a GUI by using a web browser.

+

OrberWeb requires that the application WebTool is available and + started on at least one node; if so OrberWeb can usually be used to + to access Orber nodes supporting the Interoperable Naming + Service. How to start OrberWeb is described in + Starting OrberWeb

+

The OrberWeb GUI consists of a Menu Frame and a + Data Frames.

+ +
+ The Menu Frame +

The menu frame consists of:

+ + Node List - which node to access. + Configuration - see how Orber on the current node is configured. + Name Service - browse the NameService and add/remove a Context/Object. + IFR Types - see which types are registered in IFR. + Create Object - create a new object and, possibly, store it in the NameService. + +

+ + + The Menu Frame. + +

Which nodes we can access is determined by what is returned when invoking [node()|nodes()]. + If you cannot see a desired node in the list, you have to call net_adm:ping(Node). + But this requires that the node is started with the distribution switched on + (e.g. erl -sname myNode); this also goes for the node OrberWeb is running on.

+
+ +
+ The Configuration Data Frame +

When accessing the Configuration page OrberWeb presents a table containing the + configuration settings for the target node.

+

+ + + Configuration Settings. + +

It is also possible to change those configuration parameters which can be changed when Orber + is already started. The Key-Value pairs is given as a list of tuples, e.g., + [{orber_debug_level, 5}, {iiop_timeout, 60}, {giop_version, {1,2}}]. If one tries to update a parameter + which may not be changed an error message will be displayed.

+
+ +
+ The IFR Data Frame +

All types registered in the IFR (Interface Repository) which have an associated IFR-id + can be viewed via the IFR Data Frame. This gives the user an easy way to confirm that + all necessary IDL-specifications have been properly registered. All available types are + listed when choosing IFR Types in the menu frame:

+

+ + + Select Type. + +

After selecting a type all definitions of that particular type will be displayed. If no such + bindings exists the table will be empty.

+

Since Orber adds definitions to the IFR when it is installed (e.g. CosNaming), not only + types defined by the user will show up in the table. In the figure below you find the + the NameService exceptions listed.

+

+ + + List Registered Exceptions. + +
+ +
+ The NameService Data Frame +

The NameService main purpose is to make possible to bind object references, which + can client applications can resolve and invoke operations on. Initially, the NameService + is empty. The most common scenario, is that user applications create Contexts and add objects + in the NameService. OrberWeb allows the user to do the very same thing.

+

When referencing an object or context you must use stringified NameComponents. + For more information see the Interoperable Naming Service. + In the following example we will use the string org/erlang/TheObjectName, where + org and erlang will be contexts and TheObjectName + the name the object will be bound to.

+

Since the NameService is empty in the beginning, the only thing we can do is creating + a new context. Simply write org in the input field and press New Context. + If OrberWeb was able to create the context or not, is shown in the completion message. + If successful, just press the Go Back button. Now, a link named org should + be listed in the table. In the right column the context type is displayed. Contexts are + associated with ncontext and objects with nobject.

+

+ + + Add a New Context. + +

To create the next level context (i.e. erlang), simply follow the link and repeat the procedure. + If done correctly, a table containing the same data as the following figure should be the result + if you follow the erlang link. Note, that the path is displayed in the yellow + field.

+

+

If a context does not contain any sub-contexts or object bindings, it is possible to + delete the context. If these requirements are met, a Delete Context button will appear. + A completion status message will be displayed after deleting the context.

+

+ + + Delete Context. + +

Now it is possible to bind an object using the complete name string. To find out how this is + done using OrberWeb see Object Creation. + For now, we will just assume that an object have been created and bound as TheObjectName.

+

+ + + Object Stored in the NameService. + +

If you follow the TheObjectName link, data about the bound object will be + presented. Note, depending on which type of object it is, the information given differs. + It would, for example, not be possible to display a Pid for all types of objects since + it might reside on a Java-ORB. In the figure below a CosNotification FilterFactory have + been bound under the name org/erlang/TheObjectName.

+

+ + + Object Data. + +

OrberWeb also makes it possible to remove a binding and dispose the associated object. + Pressing Unbind the binding will be removed but the object will still exist. + But, if the Unbind and Dispose button is pressed, the binding will be removed + and the object terminated.

+
+ +
+ The Object Creation Data Frame + +

This part makes it possible to create a new object and, if wanted, store it the + NameService.

+

+ + + Create a New Object. + + + Module - simply type the name of the module of the object type + you want to create. If the module begins with a capital letter, we normally must + write 'Module_Interface'. But, when using OrberWeb, you shall NOT. + Since we cannot create linked objects this is not an option. + Arguments - the supplied arguments must be written as a single Erlang term. + That is, as a list or tuple containing other Erlang terms. The arguments will be + passed to the init function of the object. It is, however, not possible + to use Erlang records. If OrberWeb is not able to parse the arguments, an error message + will be displayed. If left empty, an empty list will be passed. + Options - the options can be the ones listed under + Module_Interface in Orber's Reference manual. + Hence, they are not further described here. But, as an example, in the figure above + we started the object as globally registered. If no options supplied the object + will be started as default. + Name String - if left empty the object will not be registered in the + NameService. Hence, it is important that you can access the object in another way, + otherwise a zombie process is created. In the previous section we used the name string + org/erlang/TheObjectName. If we choose the same name here, the listed contexts + (i.e. org and erlang) must be created before we can create + and bind the object to TheObjectName. If this requirement is not met, OrberWeb + cannot bind the object. Hence, the object will be terminated and an error message + displayed. + Operation to use - which option choosed will determine the behavior of OrberWeb. + If you choose bind and a binding already exists an error message will be + displayed and the newly started object terminated. But if you choose rebind + any existing binding will over-written. + +
+
+ +
+ Starting OrberWeb + +

You may choose to start OrberWeb on node, on which Orber is running or not. But + the Erlang distribution must be started (e.g. by using -sname aNodeName). Now, all + you have to do is to invoke:

+ + +erl> webtool:start(). +WebTool is available at http://localhost:8888/ +Or http://127.0.0.1:8888/ + +

Type one of the URL:s in your web-browser. If you want to access the WebTool application + from different machine, just replace localhost with its name. For more information, + see the WebTool documentation.

+
+
+ diff --git a/lib/orber/doc/src/ch_security.xml b/lib/orber/doc/src/ch_security.xml new file mode 100644 index 0000000..938025a --- /dev/null +++ b/lib/orber/doc/src/ch_security.xml @@ -0,0 +1,148 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + How to use security in Orber + + + 1999-09-01 + + ch_security.xml +
+ +
+ Security in Orber + +
+ Introduction +

Orber SSL provides authentication, privacy and integrity for your + Erlang applications. Based on the Secure Sockets Layer protocol, the + Orber SSL ensures that your Orber clients and servers can + communicate securely over any network. + This is done by tunneling IIOP through an SSL connection. To get + the node secure you will also need to have a firewall which + only lets through connections to certain ports.

+
+ +
+ Enable Usage of Secure Connections +

To enable a secure Orber domain you have to set the configuration variable + secure which currently only can have one of two values; + no if no security for IIOP should be used and ssl if + secure connections is needed (ssl is currently the only supported + security mechanism).

+

The default is no security.

+
+ +
+ Configurations when Orber is Used on the Server Side +

The following three configuration variables can be used to configure Orber's SSL + behavior on the server side.

+ + ssl_server_certfile - which is a path to a file containing a + chain of PEM encoded certificates for the Orber domain as server. + ssl_server_cacertfile - which is a path to a file containing + a chain of PEM encoded certificates for the Orber domain as server. + ssl_server_verify - which specifies type of verification: + 0 = do not verify peer; 1 = verify peer, verify client once, + 2 = verify peer, verify client once, fail if no peer certificate. + The default value is 0. + ssl_server_depth - which specifies verification depth, i.e. + how far in a chain of certificates the verification process shall + proceed before the verification is considered successful. The default + value is 1. + ssl_server_keyfile - which is a path to a file containing a + PEM encoded key for the Orber domain as server. + ssl_server_password - only used if the private keyfile is + password protected. + ssl_server_ciphers - which is string of ciphers as a colon + separated list of ciphers. + ssl_server_cachetimeout - which is the session cache timeout + in seconds. + +

There also exist a number of API functions for accessing the values of these variables:

+ + orber:ssl_server_certfile/0 + orber:ssl_server_cacertfile/0 + orber:ssl_server_verify/0 + orber:ssl_server_depth/0 + orber:ssl_server_keyfile/0 + orber:ssl_server_password/0 + orber:ssl_server_ciphers/0 + orber:ssl_server_cachetimeout/0 + +
+ +
+ Configurations when Orber is Used on the Client Side +

When the Orber enabled application is the client side in the secure connection the + different configurations can be set per client process instead and not for the whole domain + as for incoming calls.

+

One can use configuration variables to set default values for the domain but they can be changed + per client process. Below is the list of client configuration variables.

+ + ssl_client_certfile - which is a path to a file containing a + chain of PEM encoded certificates used in outgoing calls in the current + process. + ssl_client_cacertfile - which is a path to a file containing a + chain of PEM encoded CA certificates used in outgoing calls in the + current process. + ssl_client_verify - which specifies type of verification: + 0 = do not verify peer; 1 = verify peer, verify client once, + 2 = verify peer, verify client once, fail if no peer certificate. + The default value is 0. + ssl_client_depth - which specifies verification depth, i.e. + how far in a chain of certificates the verification process shall proceed + before the verification is considered successful. The default value is 1. + ssl_client_keyfile - which is a path to a file containing a + PEM encoded key when Orber act as client side ORB. + ssl_client_password - only used if the private keyfile is + password protected. + ssl_client_ciphers - which is string of ciphers as a colon + separated list of ciphers. + ssl_client_cachetimeout - which is the session cache timeout + in seconds. + +

There also exist a number of API functions for accessing and changing the values of this + variables in the client processes.

+

Access functions:

+ + orber:ssl_client_certfile/0 + orber:ssl_client_cacertfile/0 + orber:ssl_client_verify/0 + orber:ssl_client_depth/0 + orber:ssl_client_keyfile/0 + orber:ssl_client_password/0 + orber:ssl_client_ciphers/0 + orber:ssl_client_cachetimeout/0 + +

Modify functions:

+ + orber:set_ssl_client_certfile/1 + orber:set_ssl_client_cacertfile/1 + orber:set_ssl_client_verify/1 + orber:set_ssl_client_depth/1 + +
+
+
+ diff --git a/lib/orber/doc/src/ch_stubs.xml b/lib/orber/doc/src/ch_stubs.xml new file mode 100644 index 0000000..785805a --- /dev/null +++ b/lib/orber/doc/src/ch_stubs.xml @@ -0,0 +1,283 @@ + + + + +
+ + 19992009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + Orber Stubs/Skeletons + + + 1999-09-03 + A + ch_stubs.xml +
+ +
+ Orber Stubs and Skeletons Description +

This example describes the API and behavior of Orber stubs and skeletons. +

+ +
+ Server Start +

Orber servers can be started in several ways. The chosen start functions determines + how the server can be accessed and its behavior. +

+

Using Module_Interface:oe_create() or oe_create_link(): +

+ + No initial data can be passed. + Cannot be used as a supervisor child start function. + Only accessible through the object reference returned by the start function. + The object reference is no longer valid if the server dies and is restarted. + +

Using Module_Interface:oe_create(Env) or oe_create_link(Env):

+ + Initial data can be passed using Env. + Cannot be used as a supervisor child start function. + Only accessible through the object reference returned by the start function. + The object reference is no longer valid if the server dies and is restarted. + +

Using Module_Interface:oe_create(Env, Options):

+ + Initial data can be passed using Env. + Cannot be used as a supervisor child start function. + Accessible through the object reference returned by the start function. If the option + {regname, RegName} is used the object reference stays valid even if the + server has been restarted. + If the options {persistent, true} and {regname, {global, Name}} is used, + the result from an object invocation will be the exception 'OBJECT_NOT_EXIST' + only if the object has terminated with reason + normal or shutdown. If the object is in the process of restarting, the result + will be {error, Reason} or a system exception is raised. + The option {pseudo, true} makes it possible to start create non-server objects. + There are, however, some limitations, which are further described in the + Pseudo objects section. + +

Using Module_Interface:oe_create_link(Env, Options):

+ + Initial data can be passed using Env. + Can be used as a supervisor child start function if the option {sup_child, true} used. + Accessible through the object reference returned by the start function. If the option + {regname, RegName} is used the object reference stays valid even if the + server has been restarted. + If the options {persistent, true} and {regname, {global, Name}} is used, + the result from an object invocation will be the exception 'OBJECT_NOT_EXIST' + only if the object has terminated with reason + normal or shutdown. If the object is in the process of restarting, the result + will be {error, Reason} or a system exception is raised. + For starting a server as a supervisor child you should use the options + [{persistent, true}, {regname, {global, Name}}, {sup_child, true}] and of type transient. + This configuration allows you to delegate restarts to the supervisor and still be able to + use the same object reference and be able to see if the server is permanently terminated. + Please note you must use supervisor/stdlib-1.7 or later and that the it returns + {ok, Pid, Object} instead of just Object. + Using the option {pseudo, true} have the same effect as using + oe_create/2. + + +

To avoid flooding Orber with old object references start erlang using the flag + -orber objectkeys_gc_time Time, which will remove all object references + related to servers being dead for Time seconds. To avoid extra overhead, i.e., performing + garbage collect if no persistent objects are started, the objectkeys_gc_time default value + is infinity. For more information, see the orber and corba documentation.

+
+ +

Orber still allow oe_create(Env, {Type,RegName}) and oe_create_link(Env, {Type,RegName}) to be used, + but may not in future releases.

+
+
+ +
+ Pseudo Objects +

This section describes Orber pseudo objects. +

+

The Orber stub can be used to start a pseudo object, which will create a non-server implementation. + A pseudo object introduce some limitations:

+ + The functions oe_create_link/2 is equal to oe_create/2, i.e., + no link can or will be created. + The BIF:s self() and process_flag(trap_exit,true) behaves incorrectly. + The IC option {{impl, "M::I"}, "other_impl"} has no effect. The call-back + functions must be implemented in a file called M_I_impl.erl + The call-back functions must be implemented as if the IC option + {this, "M::I"} was used. + The gen_server State changes have no effect. The user can provide information via + the Env start parameter and the State returned from init/2 will be the State + passed in following invocations. + The server reply Timeout has no effect. + The compile option from has no effect. + The option {pseudo, true} overrides all other start options. + Only the functions, besides own definitions, init/2 (called via oe_create*/2) and + terminate/2 (called via corba:dispose/1) must be implemented. + +

By adopting the rules for pseudo objects described above we can use oe_create/2 + to create server or pseudo objects, by excluding or including the + option {pseudo, true}, without changing the call-back module.

+

To create a pseudo object do the following:

+ +fingolfin 127> erl +Erlang (BEAM) emulator version 4.9 + +Eshell V4.9 (abort with ^G) +1> ic:gen(myDefinition, [{this, "MyModule::MyInterface"}]). +Erlang IDL compiler version 20 +ok +2> make:all(). +Recompile: oe_MyDefinition +Recompile: MyModule_MyInterface +Recompile: MyModule_MyInterface_impl +up_to_date +3> PseudoObj = MyModule_MyInterface:oe_create(Env, [{pseudo, true}]). + +

The call-back functions must be implemented as MyFunction(OE_THIS, State, Args), + and called by MyModule_MyInterface:MyFunction(PseudoObj, Args).

+
+ +
+ Call-back Module +

This section provides an example of how a call-back module may be implemented.

+ +

Arguments and Replies are determined by the IDL-code and, hence, not + further described here.

+
+ +%%%----------------------------------------------------------- +%%% File : Module_Interface_impl.erl +%%% Author : +%%% Purpose : +%%% Created : +%%%----------------------------------------------------------- + +-module('Module_Interface_impl'). + +%%--------------- INCLUDES ----------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib(".. .."). + +%%--------------- EXPORTS------------------------------------- +%% Arity depends on IC configuration parameters and the IDL +%% specification. +-export([own_function/X]). + + +%%--------------- gen_server specific ------------------------ +-export([init/1, terminate/2, code_change/3, handle_info/2]). + +%%------------------------------------------------------------ +%% function : server specific +%%------------------------------------------------------------ +init(InitialData) -> + %% 'trap_exit' optional (have no effect if pseudo object). + process_flag(trap_exit,true), + + %%--- Possible replies --- + %% Reply and await next request + {ok, State}. + + %% Reply and if no more requests within Time the special + %% timeout message should be handled in the + %% Module_Interface_impl:handle_info/2 call-back function (use the + %% IC option {{handle_info, "Module::Interface"}, true}). + {ok, State, Timeout} + + %% Return ignore in order to inform the parent, especially if it is a + %% supervisor, that the server, as an example, did not start in + %% accordance with the configuration data. + ignore + %% If the initializing procedure fails, the reason + %% is supplied as StopReason. + {stop, StopReason} + +terminate(Reason, State) -> + ok. + +code_change(OldVsn, State, Extra) -> + {ok, NewState}. + +%% If use IC option {{handle_info, "Module::Interface"}, true}. +%% (have no effect if pseudo object). +handle_info(Info, State) -> + %%--- Possible replies --- + %% Await the next invocation. + {noreply, State}. + %% Stop with Reason. + {stop, Reason, State}. + +%%--- two-way ------------------------------------------------ +%% If use IC option {this, "Module:Interface"} +%% (Required for pseudo objects) +own_function(This, State, .. Arguments ..) -> +%% IC options this and from +own_function(This, From, State, .. Arguments ..) -> +%% IC option from +own_function(From, State, .. Arguments ..) -> + %% Send explicit reply to client. + corba:reply(From, Reply), + %%--- Possible replies --- + {noreply, State} + {noreply, State, Timeout} + + +%% If not use IC option {this, "Module:Interface"} +own_function(State, .. Arguments ..) -> + %%--- Possible replies --- + %% Reply and await next request + {reply, Reply, State} + + %% Reply and if no more requests within Time the special + %% timeout message should be handled in the + %% Module_Interface_impl:handle_info/2 call-back function (use the + %% IC option {{handle_info, "Module::Interface"}, true}). + {reply, Reply, State, Timeout} + + %% Stop the server and send Reply to invoking object. + {stop, StopReason, Reply, State} + + %% Stop the server and send no reply to invoking object. + {stop, StopReason, State} + + %% Raise exception. Any changes to the internal State is lost. + corba:raise(Exception). + +%%--- one-way ------------------------------------------------ +%% If use IC option {this, "Module:Interface"} +%% (Required for pseudo objects) +own_function(This, State, .. Arguments ..) -> + +%% If not use IC option {this, "Module:Interface"} +own_function(State, .. Arguments ..) -> + %%--- Possible results --- + {noreply, State} + + %% Release and if no more requests within Time the special + %% timeout message should be handled in the + %% Module_Interface_impl:handle_info/2 call-back function (use the + %% IC option {{handle_info, "Module::Interface"}, true}). + {noreply, State, Timeout} + + %% Stop the server with StopReason. + {stop, StopReason, State} + +%%--------------- END OF MODULE ------------------------------ + +
+
+
+ diff --git a/lib/orber/doc/src/corba.xml b/lib/orber/doc/src/corba.xml new file mode 100644 index 0000000..6c89279 --- /dev/null +++ b/lib/orber/doc/src/corba.xml @@ -0,0 +1,451 @@ + + + + +
+ + 19972009 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + corba + + + + + + 1997-06-10 + A +
+ corba + The functions on CORBA module level + +

This module contains functions that are specified on the CORBA module + level. It also contains some functions for creating and disposing + objects.

+
+ + + create(Module, TypeID) -> Object + create(Module, TypeID, Env) -> Object + create(Module, TypeID, Env, Optons1) -> Object + create_link(Module, TypeID) -> Object + create_link(Module, TypeID, Env) -> Object + create_link(Module, TypeID, Env, Options2) -> Reply + Create and start a new server object + + Module = atom() + TypeID = string() + Env = term() + Options1 = [{persistent, Bool} | {regname, RegName} | {local_typecheck, Bool}] + Options2 = [{sup_child, Bool} | {persistent, Bool} | {regname, RegName} | {pseudo, Bool} | {local_typecheck, Bool}] + RegName = {local, atom()} | {global, term()} + Reply = #objref | {ok, Pid, #objref} + Bool = true | false + Object = #objref + + +

These functions start a new server object. If you start it + without RegName it can only be accessed through the + returned object key. Started with a RegName the name is + registered locally or globally.

+

TypeID is the repository ID of the server object type and + could for example look like "IDL:StackModule/Stack:1.0".

+

Module is the name of the interface API module.

+

Env is the arguments passed which will be passed to the + implementations init call-back function.

+

A server started with create/2, create/3 or create/4 does not care + about the parent, which means that the parent is not handled + explicitly in the generic process part.

+

A server started with create_link2, create_link/3 or create_link/4 + is initially linked to the caller, the parent, and it will + terminate whenever the parent process terminates, and with the same + reason as the parent. If the server traps exits, the terminate/2 + call-back function is called in order to clean up before the + termination. These functions should be used if the server is a + worker in a supervision tree.

+

If you use the option {sup_child, true} create_link/4 will return + {ok, Pid, #objref}, otherwise #objref, and make it possible + to start a server as a supervisor child (stdlib-1.7 or later).

+

If you use the option {persistent, true} you also must use the option + {regname, {global, Name}}. This combination makes it possible to tell + the difference between a server permanently terminated or in the process of restarting.

+

The option {pseudo, true}, allow us to create an object which is not a + server. Using {pseudo, true} overrides all other start options. + For more information see section Module_Interface.

+

If a server is started using the option {persistent, true} the object key + will not be removed unless it terminates with reason normal or shutdown. + Hence, if persistent servers is used as supervisor children they should be transient + and the objectkeys_gc_time should be modified (default equals infinity).

+

The option {local_typecheck, boolean()}, which overrides the + Local Typechecking + environment flag, turns on or off typechecking. If activated, + parameters, replies and raised exceptions will be checked to ensure that + the data is correct, when invoking operations on CORBA Objects within + the same Orber domain. Due to the extra overhead, this option + MAY ONLY be used during testing and development.

+ +Example: +\011 + corba:create('StackModule_Stack', "IDL:StackModule/Stack:1.0", +\011 {10, test}) + +
+
+ + dispose(Object) -> ok + Stop a server object + + Object = #objref + + +

This function is used for terminating the execution of a + server object. Invoking this operation on a NIL object reference, + e.g., the return value of corba:create_nil_objref/0, always + return ok. For valid object references, invoking this operation + more than once, will result in a system exception.

+
+
+ + create_nil_objref() -> Object + Stop a server object + + Object = #objref representing NIL. + + +

Creates an object reference that represents the NIL value. + Attempts to invoke operations using the returned object reference + will return a system exception.

+
+
+ + create_subobject_key(Object, Key) -> Result + Add an Erlang term to a private key field + + Object = #objref + Key = term() + Result = #objref + + +

This function is used to create a subobject in a server object. + It can for example be useful when one wants unique access to + separate rows in a mnesia or an ETS table. The Result is + an object reference that will be seen as a unique reference to + the outside world but will access the same server object where one + can use the get_subobject_key/1 function to get the private + key value.

+

Key is stored in the object reference Object. + If it is a binary it will be stored as is and otherwise it is + converted to a binary before storage.

+
+
+ + get_subobject_key(Object) -> Result + Fetch the contents of the private key field + + Object = #objref + Result = #binary + + +

This function is used to fetch a subobject key from the object + reference Object. The result is a always a binary, if it + was an Erlang term that was stored with create_subobject_key/2 + one can to do binary_to_term/1 to get the real value.

+
+
+ + get_pid(Object) -> Result + Get the process id from an object key + + Object = #objref + Result = #pid | {error, Reason} | {'EXCEPTION',E} + + +

This function is to get the process id from an object, which is a + must when CORBA objects is started/handled in a supervisor tree. + The function will throw exceptions if the key is not found or + some other error occurs.

+
+
+ + raise(Exception) + Generate an Erlang throw + + Exception = record() + + +

This function is used for raising corba exceptions as an + Erlang user generated exit signal. It will throw the tuple + {'EXCEPTION', Exception}.

+
+
+ + reply(To, Reply) -> true + Send explicit reply to client + + To = client reference + Reply = IDL type + + +

This function can be used by a CORBA object to explicitly send + a reply to a client that invoked a two-way operation. If this operation + is used, it is not possible to return a reply in the call-back + module. +

+To must be the From argument provided to the + callback function, which requires that the IC option from + was used when compiling the IDL-file.

+
+
+ + resolve_initial_references(ObjectId) -> Object + resolve_initial_references(ObjectId, Contexts) -> Object + Return the object reference for the given object id + + ObjectId = string() + Contexts = [Context] + Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData} + CtxId = ?ORBER_GENERIC_CTX_ID + CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options} + Interface = string() + Options = [{Key, Value}] + Key = ssl_client_verify | ssl_client_depth | ssl_client_certfile | ssl_client_cacertfile | + ssl_client_password | ssl_client_keyfile | ssl_client_ciphers | ssl_client_cachetimeout + Value = allowed value associated with the given key + Object = #objref + + +

This function returns the object reference associated with the given + object id. Initially, only "NameService" is available. To add or remove + services use add_initial_service/2 or remove_initial_service/1.

+

The configuration context is used to override the global + SSL client side + configuration.

+
+
+ + add_initial_service(ObjectId, Object) -> boolean() + Add a new initial service and associate it with the given id + + ObjectId = string() + Object = #objref + + +

This operation allows us to add initial services, which can be accessed by + using resolve_initial_references/1 or the corbaloc schema. + If using an Id defined by the OMG, the given object must be of the + correct type; for more information see the + Interoperable Naming Service. + Returns false if the given id already exists.

+
+
+ + remove_initial_service(ObjectId) -> boolean() + Remove association between the given id and service + + ObjectId = string() + + +

If we don not want a certain service to be accessible, invoking this function + will remove the association. Returns true if able to terminate the + binding. If no such binding existed false is returned.

+
+
+ + list_initial_services() -> [ObjectId] + Return a list of supported object id's + + ObjectId = string() + + +

This function returns a list of allowed object id's.

+
+
+ + resolve_initial_references_remote(ObjectId, Address) -> Object + resolve_initial_references_remote(ObjectId, Address, Contexts) -> Object + Return the object reference for the given object id + + ObjectId = string() + Address = [RemoteModifier] + RemoteModifier = string() + Contexts = [Context] + Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData} + CtxId = ?ORBER_GENERIC_CTX_ID + CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options} + Interface = string() + Options = [{Key, Value}] + Key = ssl_client_verify | ssl_client_depth | ssl_client_certfile | ssl_client_cacertfile | + ssl_client_password | ssl_client_keyfile | ssl_client_ciphers | ssl_client_cachetimeout + Value = allowed value associated with the given key + Object = #objref + + +

This function returns the object reference for the object id asked + for. + The remote modifier string has the following format: + "iiop://host:port".

+

The configuration context is used to override the global + SSL client side + configuration.

+ +

This operation is not supported by most ORB's. Hence, use + corba:string_to_object/1 instead.

+
+
+
+ + list_initial_services_remote(Address) -> [ObjectId] + list_initial_services_remote(Address, Contexts) -> [ObjectId] + Return a list of supported object id's + + Address = [RemoteModifier] + RemoteModifier = string() + Contexts = [Context] + Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData} + CtxId = ?ORBER_GENERIC_CTX_ID + CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options} + Interface = string() + Options = [{Key, Value}] + Key = ssl_client_verify | ssl_client_depth | ssl_client_certfile | ssl_client_cacertfile | + ssl_client_password | ssl_client_keyfile | ssl_client_ciphers | ssl_client_cachetimeout + Value = allowed value associated with the given key + ObjectId = string() + + +

This function returns a list of allowed object id's. The remote modifier + string has the following format: "iiop://host:port".

+

The configuration context is used to override the global + SSL client side + configuration.

+ +

This operation is not supported by most ORB's. Hence, avoid + using it.

+
+
+
+ + object_to_string(Object) -> IOR_string + Convert the object reference to the external string representation + + Object = #objref + IOR_string = string() + + +

This function returns the object reference as the external string + representation of an IOR.

+
+
+ + string_to_object(IOR_string) -> Object + string_to_object(IOR_string, Contexts) -> Object + Convert the external string representation to an object reference + + IOR_string = string() + Contexts = [Context] + Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData} + CtxId = ?ORBER_GENERIC_CTX_ID + CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options} + Interface = string() + Options = [{Key, Value}] + Key = ssl_client_verify | ssl_client_depth | ssl_client_certfile | ssl_client_cacertfile | + ssl_client_password | ssl_client_keyfile | ssl_client_ciphers | ssl_client_cachetimeout + Value = allowed value associated with the given key + Object = #objref + + +

This function takes a corbaname, corbaloc or an IOR on the + external string representation and returns the object reference.

+

To lookup the NameService reference, simply use + "corbaloc:iiop:1.2@123.0.0.012:4001/NameService"

+

We can also resolve an object from the NameService by using + "corbaname:iiop:1.2@123.0.0.012:4001/NameService#org/Erlang/MyObj"

+

For more information about corbaname and corbaloc, see + the User's Guide (Interoperable Naming Service).

+

The configuration context is used to override the global + SSL client side + configuration.

+

How to handle the interface context is further described in the User's Guide.

+
+
+ + print_object(Data [, Type]) -> ok | {'EXCEPTION', E} | {'EXIT', R} | string() + Print the supplied object + + Data = IOR_string | #objref (local or external) | corbaloc/corbaname string + Type = IoDevice | error_report | {error_report, Reason} | info_msg | {info_msg, Comment} | string + IoDevice = see the io-module + Reason = Comment = string() + + +

The object represented by the supplied data is dissected and presented + in a more readable form. The Type parameter is optional; if not supplied + standard output is used. For error_report and info_msg + the error_logger module is used, with or without Reason or Comment. + If the atom string is supplied this function will return a flat + list. The IoDevice is passed to the operation io:format/2.

+

If the supplied object is a local reference, the output is equivalent + to an object exported from the node this function is invoked on.

+
+
+ + add_alternate_iiop_address(Object, Host, Port) -> NewObject | {'EXCEPTION', E} + Add ALTERNATE_IIOP_ADDRESS component to the supplied local object + + Object = NewObject = local #objref + Host = string() + Port = integer() + + +

This operation creates a new instance of the supplied object + containing an ALTERNATE_IIOP_ADDRESS component. Only the new instance + contains the new component. When this object is passed to another + ORB, which supports the ALTERNATE_IIOP_ADDRESS, requests will be routed + to the alternate address if it is not possible to communicate with + the main address.

+

The ALTERNATE_IIOP_ADDRESS component requires that IIOP-1.2 is used. + Hence, make sure both Orber and the other ORB is correctly configured.

+

+ +

Make sure that the given Object is accessible via the + alternate Host/port. For example, if the object is correctly started as + local or pseudo, the object should be available on all + nodes within a multi-node Orber installation. Since only one instance + exists for other object types, it will not be possible to access it + if the node it was started on terminates.

+
+
+
+ + orb_init(KeyValueList) -> ok | {'EXIT', Reason} + Configure Orber before starting it + + KeyValueList = [{Key, Value}] + Key = any key listed in the configuration chapter + Value = allowed value associated with the given key + + +

This function allows the user to configure Orber in, for example, + an Erlang shell. Orber may NOT be started prior to invoking + this operation. For more information, see + configuration settings + in the User's Guide.

+
+
+
+ +
+ diff --git a/lib/orber/doc/src/corba_object.xml b/lib/orber/doc/src/corba_object.xml new file mode 100644 index 0000000..810f06d --- /dev/null +++ b/lib/orber/doc/src/corba_object.xml @@ -0,0 +1,196 @@ + + + + +
+ + 1997 + 2007 + Ericsson AB, All Rights Reserved + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + + corba_object + + + + + + 1997-11-10 + A +
+ corba_object + The CORBA Object interface functions + +

This module contains the CORBA Object interface functions that can be + called for all objects.

+
+ + + get_interface(Object) -> InterfaceDef + Fetch the interface description + + Object = #objref + InterfaceDef = term() + + +

This function returns the full interface description for an object.

+
+
+ + is_nil(Object) -> boolean() + Return true, if the given object is a NIL object reference, otherwise false + + Object = #objref + + +

This function checks if the object reference has a nil object value, + which denotes no object. It is the reference that is tested and no + object implementation is involved in the test.

+
+
+ + is_a(Object, Logical_type_id) -> Return + is_a(Object, Logical_type_id, Contexts) -> Return + Return true if the target object is an, or inherit from, object of the given type + + Object = #objref + Logical_type_id = string() + Contexts = [Context] + Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData} + CtxId = ?ORBER_GENERIC_CTX_ID + CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options} + Interface = string() + Options = [{Key, Value}] + Key = ssl_client_verify | ssl_client_depth | ssl_client_certfile | ssl_client_cacertfile | + ssl_client_password | ssl_client_keyfile | ssl_client_ciphers | ssl_client_cachetimeout + Value = allowed value associated with the given key + Return = boolean() | {'EXCEPTION', E} + + +

The Logical_type_id is a string that is a share type + identifier (repository id). The function returns true if the object + is an instance of that type or an ancestor of the "most derived" + type of that object.

+

The configuration context is used to override the global + SSL client side + configuration.

+

Note: Other ORB suppliers may not support this function completely + according to the OMG specification. Thus, a is_a call may + raise an exception or respond unpredictable if the Object is + located on a remote node.

+
+
+ + is_remote(Object) -> boolean() + Determine whether or not an object reference is remote + + Object = #objref + + +

This function returns true if an object reference is remote + otherwise false.

+
+
+ + non_existent(Object) -> Return + non_existent(Object, Contexts) -> Return + Return false if the target object do not exist, otherwise true + + Object = #objref + Contexts = [Context] + Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData} + CtxId = ?ORBER_GENERIC_CTX_ID + CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options} + Interface = string() + Options = [{Key, Value}] + Key = ssl_client_verify | ssl_client_depth | ssl_client_certfile | ssl_client_cacertfile | + ssl_client_password | ssl_client_keyfile | ssl_client_ciphers | ssl_client_cachetimeout + Value = allowed value associated with the given key + Return = boolean() | {'EXCEPTION', E} + + +

This function can be used to test if the object has been destroyed. + It does this without invoking any application level code. The ORB + returns true if it knows that the object is destroyed otherwise + false.

+

The configuration context is used to override the global + SSL client side + configuration.

+

Note: The OMG have specified two different operators, _not_existent (CORBA version 2.0 and 2.2) and + _non_existent (CORBA version 2.3), to be used for this function. It is not mandatory to support + both versions. Thus, a non_existent call may raise an exception or respond unpredictable + if the Object is located on a remote node. Depending on which version, ORB:s you intend to + communicate with supports, you can either use this function or not_existent/1.

+
+
+ + not_existent(Object) -> Return + not_existent(Object, Contexts) -> Return + Return false if the target object do not exist, otherwise true + + Object = #objref + Contexts = [Context] + Context = #'IOP_ServiceContext'{context_id = CtxId, context_data = CtxData} + CtxId = ?ORBER_GENERIC_CTX_ID + CtxData = {interface, Interface} | {userspecific, term()} | {configuration, Options} + Interface = string() + Options = [{Key, Value}] + Key = ssl_client_verify | ssl_client_depth | ssl_client_certfile | ssl_client_cacertfile | + ssl_client_password | ssl_client_keyfile | ssl_client_ciphers | ssl_client_cachetimeout + Value = allowed value associated with the given key + Return = boolean() | {'EXCEPTION', E} + + +

This function is implemented due to Interoperable purposes. Behaves as + non_existent except the operator _not_existent is used when + communicating with other ORB:s.

+

The configuration context is used to override the global + SSL client side + configuration.

+
+
+ + is_equivalent(Object, OtherObject) -> boolean() + Return true if the target object and the supplied object easily can be determined to be equal, otherwise false + + Object = #objref + OtherObject = #objref + + +

This function is used to determine if two object references are + equivalent so far the ORB easily can determine. It returns + true if the target object reference is equal to the + other object reference and false otherwise.

+
+
+ + hash(Object, Maximum) -> int() + Return a hash value based on the target object + + Object = #objref + Maximum = int() + + +

This function returns a hash value based on the object reference + that not will change during the lifetime of the object. + The Maximum parameter denotes the upper bound of the value.

+
+
+
+ +
+ diff --git a/lib/orber/doc/src/dataframe1.gif b/lib/orber/doc/src/dataframe1.gif new file mode 100644 index 0000000000000000000000000000000000000000..21bd0afbc5999b053e06ffd52069d8248bd1c029 GIT binary patch literal 21074 zcmWh!c{tSH_kYj6GZ@<#8A}YIu{N?aV;v%6D-{|lF;SyM@{wlDVr(_Gl9aJjNHrwU zI@TyO6AOT40zi3<1nbTvn$`$I`&R~y)#vW)k_)}n3!33`|7_1C|LI8<9jG1b!O-n zN&hCvh(xfAu`sxR(X_F3-1_3h!qC(Ce}2BTuxv6i34m&({QUi%0L>xj)sDUy#cE(I z3{wfHz{UUm!5CPRP#1`rH=QYR+qK6n9G%f~YpyZbO-FyrdQYyMHIt;pBf(R2 zG*6NY_P+Y>=gSwrjPZ4SUBBGcH4Z&(bD_50c{t>3RpD$l&tMeOeWPcd&)ZTPKD_%z z_f45!81%It8XZxQOlnEmDFiLJg?5*RtMBNuA!ll(1?7~5;bW2|*VeL^fKORxHRxzXt`OCx01A^9dgOH1D^?0re-Vhh7!0_=~$wng<%Tk1&*=U{?XG|6BK$v`^4@RMNRM$jf$SXo(E z2}Wn0d#sQA@_yc9J>S_n#)Dc&FyLSzwOH6*3;j-#)plFMYG>z|(Xnw`N;6h-FG;_4 z=IuC%%o!S3wk6k-D8BPA#|ikFq0t`}|Y^m*&Y$j^o8EC0{aFXnkzgXe$YM_)7(G)ZIw07_mb?3t>)PYxYp=<^1z$E61>I;G<7{f#_Tpi=4b~;FD`9Nv#$x!Du>*QT z$n=KEo7`6q&utvHoxJAz@wr`rE>Cv{cn6quePi;(UG4)j&q9Nyx#k3;2gXKjpLPz0 zmH&u}Zj*1`$RQH!gUh}oHP`2DHj1r0@OG5FQf(BPJeHI1{dCMn7w(c zjib8F%iU~ew74+Sk!SPv*2c>RD63OK?#IUB2yg1kS4u--vt0I1T)*sK%ein@q5b#i zh?g#rM1^e3gy@GCTv}*%>gK@XnHImkE>$^z`%cl-br$#J~SLX{H0;lPJUx=Q=eQpHp z4nx{A%g}dBzec5P?0;@dXvMynX7w7M9xZ7{J&4bb?5=1yLojP2@YlW!Ae_}7@t<(C zp{yft;>C^POWc=RLb9fniGJ~7qG3WxL`J*n(2CK;<=D%aLHZ_uX2zBY9CWKzA_qr5 z^Y|EcuR!iF=hk5d!1cL(vErBMm3_w`);?96TaUZrz_&&IH-lHqiheZ>=I z@uuvteJ;Nm;$c;{Z4#GaDkC15@@iE@Y^ z+jVG^CHg8Um-s#D_>b^Bd&>;#-2rT1awyTSV!J8w^nMOQBf9bui#2)e)QELdO42s# zoUvmAmD~5Fcsl0R+~`jpdv$Sp|6hww?hPgpx>uJCz8KM21Bse=5+udeG9iXdgP?oSBRq_4rR+kdzG``!V2ucK7_?+MA{?Hx8_pW*Kth zW}V_2W5(?tHawIQ`}|FY9apZYz5}ou z<_K5Z_da{5zi;kB*O%Se{Xua^@uzdOFD`L{rb%HFwU=bhyKPqcmcLJU<_AEnk01Vg zIb!>^rtuR#xqpQx1RH?}+U*0i+UL1G$zE zcxcuI?;ueUd-pAv4gaDnn0PjYCN(fjHk&a8??+Jw;HIZj*HhMZBMW#owOwiZWD0(T zrL~_=&4A?%=7z7UOMXABJudIoi>$$O&pyHaliq{ByNq!KTNj(dK9v(z|CerIc0OsL zu4N_*c02)+pmg*mUJWTu_FplLOB`^vK5p8Ym;Yr?i*lL5__4RpvUd2(#f3}hqGa0> zGds$EeXo9UVQ;cU#0lL~H6|3f#tCtZ#M16{(D<1(t~(}by=hIAMHe~S!h+G9H(}Cn zzx@KzUH;OlCM91QN`B_EExP39xhHA42ljrq-aW%4@@kaQOMgP_K3gZAh@vrSf=}Kl zbAQw8Uwyf=%L?Q>l(rZgrwmjngKb7WohkFo4&Q{*%hXf(s$;D3pT8645q<0rZ2=b( zRz5lPRgZn%dUadjA@Yra47XNL@1yut1)pI0-}_h})9Nz4f*dTLut~>BFWfNKar2Fq z{6}u+)q5fghF`Mjg29z>agfTNLcrObnGZ|ZqqFHs_S%cLAI45CylM^CpoXzxH$ig1 z7Iny6yKktsGh)G1i${ZV+*A>#d+-Kmh0APxQG(lRKm@4fI|Y;eM~)aN&Jw8k`Sn&| zDVg>QSY)c-6V>6nP||$^)}}q-$he87ve58nS1zw62AD?5ZlR!TA*d)Y?Z`;$3##?L z(SMIfI*0!)e6xufUP*l>p89WM>974kQIit}kDD5=ox0-CXllJQ@<|lw(s{dUo{%ZH z=38+70*7b5o8vR&XM6LPFNWjueY=ZNfu2E6a3-S9b?(OYUw?Ovk^A)0J9dL-?B}UQZR?RoNzal)ZN_Aevuj<~ zq2gYBla*EhH^Z}0D5Gq7Sg;19xTRe2KA8jYD z>B!J`iV-&q>|MJ{t2dVW`^vU8er0JwS?BrA;~)4&!^3a;jB=)@^&b4K4}Er9 z36QAp8)ca*=L^>{&3DyKv%?#|Oc`zL%pdpZKAH90uX=%Udfer|;I;&FjygKmT2vGE z;LgLE`j9pdj#LD@0d|Z#yKIlTJAAP%y!z##5*NtI!;fVNgL=pEj-Ix7hdYyW&e!Dz zmHXwhh!|_Ow>Wrx6ye&I9rvovA*g;++k+a-PAfA{So+zOT<<+xC$|lfNU*1fUd^wk>1&}*_f0n4-hH6){qli}P*rWlGq0;%AqvGag2-ui zz@_1;%?2x4H}B_K#_~+&9dOql{SUC(+dlc-_n%jKMtR2H*w*1|)`_iZ*`^1ZbDx;i z$zmM>v#b+yC?N^)=Pt#zc2lxRO+4FeCi-S_N{)R*_x~^9==fOBs@k0JsLUN^?ssR8 ztgmxi_d1vn!9qKP1-!OvJxy7iaQxIKU3t9w4M%=vn88*jqb(HoRD@aG+r#&s@P*?9 zsE@(@1N%1v{;>k*KpkC%6M;P*gf20BvQDJ8*_ifaHT@92otJyGhOd{D$e~jG)6i6& zK6$fbh022+1?dtch9^37yT&CaX?c+?czqe~YMA7lGkZsleonMx1d$(5CdsRa-3ZDr zq4CS2^|O-5mzO1Xwj4vpW6tv>k_O^UiC#2M?=Fw1!Gq^#pgqMB^a8Lj%D)+{`*Jk@ z+C<^Vf&?4Cv7LsEc!Hr)u|0Sr(K1>hgxxj(2ZLQXJXmFi!HzInCdfg=ENWaX{CD}p ze-(l0j@bDI*yMzY?I_x%pwvnyCH73~w6DJ5q zOKDs4;PDuEjpT}eU@I#&-io_R(H*B@KZNJ+NJFzfB0|-;X`tj%6ix%b&Q*?JDm?}> z^8HQoFC~?_8JT7jCCp1QjLe@sW9@TJl0!f3w6yskz_o~ADEv@M+w zoR@x$ZZL`0tN|SA9UNYSuemc@o@;paV*`G(^7O0{(N6|1%5m8;cs2_$$%aEp37I-* zRG#hS7F;12rKdoydWV?hLh>if03Gx=7Z)ib;#VLJQQguPUFSsBXXoCX=)8a~7$LWNH4EI6+`4L|+%R3DUg2`Ao z$aM_ldr1P~?5nLcCkODWtfiT1gdZ8WtU_cuMHw(HLuXSF z$LNHo3aBB=;J6gM@$3AMRC4sNT9r*? z+#(BiT!A1fkac8SwG5I-m+p}vP&T-yT=0?-ZVhNws~cw(8pqU#Y$fI~8}xY)d5jL+ z-HPjHW0SXO9@%OU7-<9K9 zn=l+Hx=MQK^E>Eo8RjP)bm%=|Oa-rLy4t8f)UdYgp(3W`uv=_U!ZzF?7PLx%+Q&s4 zGJ*rZN9bTO4>haOTvDx6-(rFE z$T$x5&kdj>D#RUm{VW+b&C=9US4?x8xk0chE__UdXi^{=$+&DbC`*p}F2lHA#$@B6 zsq)qi1!@^zK3>sC`gx-@1K$`CxQ~8ACIc4n8n;-uL>VMij!Wf17uATTT&$TKcO8%G zV8b2Bkgl!J+jxy>1!|lM-GqlQS(@S|cp?D4t3r@?m?%ZtiX3Mq!yJ%do=P>Rx$pyY zX*)82?S6~JI0f!PUns|fDiNtH+z}PnDiEY(Yo@6X+j*KKKqHY1c(At3lEMFD!$%ZI zA2z5;-cZN}B?8DoGW@apMz{(KX0>mZ0q7Na%MlekRtZ1C(_EI_ptCxs)u8Qxx84}F zC;arh0NY!rZV$hVDFo0m8Rlrvefh2GX*DYR9|T{4+^f7_sM6%HYq97W$alnbdBck8 z$}J^)|C)|Fw{T`_q-EP|n$)`2R5#who?cmzrT4I6?6 zlQkZyz%ErFZ(Hme8N8W`j_>Gtd-h)K1!P);4Htds@*kk-IUDd(cWK+|LgnRv0z$?h zQtqm^isx9DRwCbAy#mT~|7VS4Du+m1(@#3P{cfpgU%ch2Nwi5IA*E5*MCMp?#%7E) z*rJ7Q*DAGWl-4+$6KcsUD_2Rf9`3TmU#L14r%y?GP-5YSo zh{`UEm<4(igOm9hU)_#f%o=)QRFuFtu^^@WBN?tSXm$K9z1CSihA*vpN7@lj8I&|e zBp;t=)+~D5!Y~SMhe;M>l7AM;MG}C`D7vAL=6+NLJ?Z1fu5#2MCvruirSj5Pu1#GR zBDN+!c*WsvZe!YHt}XYkP?}yvrb!{o=86oHy!Das?@-9GeE-3xmdBp9z8lfVCoDa+ zZyyaj`VmxjhBO&iSYWFAOsjNS4$$P9@0-xt%JPW#Q?V248w^IhQ!D;yF({Otn`tzt zL_+Q|4IYZqzjW9#!wfWdFspaBvgMk0=w-i?PB`v95mwxi>+#&jE}Z=l(je0aP?ew! z$9g+3P^F6%WGr8oDqBD#s4BX6V|({ZzU(j{$2}*6ApyqByimG87q^)o9J%>Zm(b#Rp4ndl%qtCv7lGiD;AZ|NQLYI9fh(1H}X!e zHqyAwhF_k-NQdfgO96c4<=20RAgugN%_w$5@u!OWg9_B$Ciqtw0PV!l0aZahv=O*; zT`FhNZ!kY%J|9K&NiS`W#r=z4;@~xw)z~vdI0PFG4o3VdgRYvy%&~A)N@#%cEL;XZ zqJ-}zcexipnJj}7ilXDAUpB1`hYntXN`Wyo#!QJ&lX2Ek%mD>v)jPNc9rxGWKd_Gr zeTY#@VJlMXK4}BH215X#`=r2K83rZAE|U?0X_!4;V`eWRU4?nhg3l_D`{_7q6}U?c zos;9{R;1uLCE}n8_i?Y;vT^Z={}rOnRozx2k~!BRvG7y-+ioQ4cREr#)$H@V9P*2MBBL!= zXNnJlqCryiWBYp=M;xa5ndoJEs;&*P_*Y}0#A5UP%+qtuxCZzekX;#z+&RvcZ{A!13Qtz4l|MlZyK7Ue4 zV7VL&B;nn&<|{iM{QKnU3kmA_{VOX=t%ndgJ;wv8SAHzrHXF;hPy2N+S^U*1e4X8k znnS-kL*Aa&sE_q7PSVc@N3LbS!glVj$2YJ(c%W8$t7|_mJUV$rLhSY~f@^r}XJ`eC zHZZ<9{yOOmm?ot8=+?QX-pXBmwblu{rfn^qXl)zXgQxTs`z0HrDSzWs}gNt6e zNM|)T(fqv#<`PY(Z?xXh=Q=HYpJ_ML_eJ@jFbmrA;Orv{QyI-aOBBBf;`hp`ELLui zSh0m!`t9z9%CJ4B<3Z*(BK7J8VDUnm-vn!^yG^v#e-rhUV{+ujIt?5Dfj5lxU zxTCDy`T_%fEs=$s*VVRZzz@x{ek9FlE&!i!1BE*85%fASymkmA6`trg3Qq zOOGs8Sx5}SUZbaJ$?&$^VM=fb8XeS+(6`^)f3_!XOdv=kP!?YG90=IpIo=OdkV197 z)fL6%Q(uX~&Vd5T?J_6LbpQIL6cH;e5g85f$2W5Q*RCjJfCIfr{}zw&>*=gUoP!yu zN|B3P(JF`SVTr?1Y+hrRxcnsn&-p6I>6L$D}ywRf62WA5H zUgP@I4)X}6|IQ*eu}om>ML}3LfqZw?=jhNU{5-==bG#N3FjgNSCT|9icy-Om*$h6I zpa5wQR62zVK90QB0wP-q9BA+{YFY`SM7lk#SiNn+`Atj3_I`ie)McUbJ{a0RYfkgH z!E@L5qwv&!%_?txnsBY3MetMVvI;9;t~j&dR0BueY!a{|D?KV zAli3=bxIgTyM}5u+gH%xC)ffE#T-W&@HWg(6DAB4EOL>Xy zE)dKf316ENk4W@|V)~l*1Q(2w*UTu`CYMi|n!-dqGcw{j?hYU1PT3>+dq-JV58>%3 z9_eS{%1nLa>VLz?g_00=votxlNO)1>1)Dt0Ehoz5Rx7kQUFK^{^p(REvCIcrNsdZf z+(*%d58ki~X)xa`zm=-yrNd@do<bEZt)2}@!hVN6bA`hpdO}rJ zcHd$<@rzU=6$RQ;E(xh&Ikwcs(=J*^9b0-6O*!+xd6!*jm*d$@EZa{LJQE(T2K8yTqc=ns;<4roua-WoaI;y;Hk>S{{<-+FEbC`bfL~fq!q; zK075;t}#=lj`}Dv4VuB$%$K6IY!~x5#)=>A1`oM?V?>c_3SB#VTS>{MQ)WLE-)>tz z3~_m`kP3&sX{H@`vL~`DZ*(kaQ)uRYGOuTGkOJ1dt;inD3YlR-eT~6==_YTlva@j= z-nc5dw@d%6_!SM40YA!nwZlzfaq2G>vN90qQX$6~kY%Qj&xE^o07yoasab^TpX63w zlPBs+am){?Cl3EwC;nv$>09m%tPd-Mez6RZ=9dv;X7l5)^~4=i{P~vxtH*a9&}XF_ z-+EXzcCVZ8isKY11-3bs;Da55<{&N7pm9U9*aLXkA8mV5D13#4R`}?Z)o64DlTjrV zfT5$T$h@kaNKy%n4ip!dG?+$bzdRsV->V7(Oi+Dhsbtc^?pYfnkN|Dtsb z-|daEubidQd+Y8ER|x2;7HBKVQvYJIO|uayPMlJwIkgNqe%TbU{rgURD?C5}mqL%M zFn3~R7anNCpSH*LUL;l}dD9HK5L%=+ng^vmDepmGHcx?-;V1KN+)afZIkV7--3?&Df2h}7Z4{6n1a?7zJc zlnlzwHa9$0A@EwrNn`?XWU-ZmXU>Ehsm1#n_z7g*{tCco05CmEi3Gs=|CAIe1PRE- zDk2cVw;Ml*SiG|#On#9Zr!)Rux0fVU7Kl<@GZ3fQTwg8x3AzB_?=peX+ra^k@< zL$EAx;T3WfUel7I2b~@WUhC_Gr#8c zS=0579xhCqR_H@Lifj2KJp!T{kgw3{dhv8^J3hY-&EF!iGkm4_sJqn}bY`IgQ6Jv( z=JJMsJNIwlON)7ujh%$goMMIcG-)2sL;lmG5hK)~Gi;&;jMgS$xV9$^7{wa1y{^tWUY(kLDg7t# z#I4PmxeH~htnn^ok{O~8gb%i01RPt5gn*MJYe3q`jXM1~ppYSaaNxkxq&3d+*04hl zjtC!!%{7)MV2?P!vKrsA9%n0W+|Z&YnJ9~;iKgO(CP#0418VJf$Vdfo)Axapc;EA2 zU1z!=p395pF#~G`)^IvL$DjFdkh$sT6>Db6ukJGEK!4m(7=p*&rf$5n9u*~DRXkW? zMD625OZpnR)jfpP9R8;7fzN@qQJpq4O>kHWjg)GR5Fhs*ssnaJ9;pncUZ!WdWVmwUGdU24^gj#C)bCRd!iZ`S8bb z#p4VZl?RHFlk41(E0FIwoFw2;9_|PkW|4yQltEZhWH-g<(PVkM^x}6%X}oFEv-eH| z%>%*_>?O%JO!q_$MNEKHpMfhI&pYA=4nTZMuy z-=!LcP8QIvJC%l=V+|nOdmQEphlW29{1tgQ68Pdy@O~+DlS0>CEIkHfmN=fj&7n)wY7Ry0r9e1H+^G{{G#e7cK69+0DAfS8iJilp;FFfc4`x?{ z?y@t7X^^-ygl9)b>asWm5b_7aI!T!OuY_p1sXxyZV*`n!UgF?^of9xkwoqrr0xjdE zR=`p#As?zjNnVfe`hJkDRaI_?b2MeS~CO!8{L>HmYEFW_$Pb=nyX=HeloiCiykt~fd;(g68T z1@WA~IV~U(SC{KVgFUVTT;OsXOJvDZa^$(h1C@#Nock**Q4BICi~?TYkQ){++QPF> z_#Lq%&%ra1ECnf<+R5zz?^+O9CFP_ib!fGZIS_6j^ps>iiJF$%+j z;ege2&gz9+vnjC|9yt11XqI#-y(u@7YVlWej>7^hnUWhxmF!U5+bT2N#1iF*KqK^t zlNH{arvi&4LoG@!M+WFfE%8c_lREk@uK3#L=nxhR)R2?@BF9w;TQ^bdM-^0lglu$N z?IHz%D7qJ0B2VHFS`@&iJJ(5mCKV4D$_!$Yz+SSPP${JEJA@_AwP%U`qUfE-nktf6 zzuSq#j0xOi)Tw5K1{1KV%}posR}!TcGr1775~`u*J0NqxlpHe_c%2lY1ITQs5EwEi z6VDIts?nz)G~}^hl{m8l0yGISGeBA@-ugd%U#?&yi??10%i`unD%|3v0(S~{Cmu9D zIOx(mGnd5x8elF12%8Q|flS9=PC7Xz+FJs@7&e_=BEIM2;jvfn7AE^=FGxE{@Eca! z@{g!v5`J7>^Q~xy2L>@dQzykCK+i2dU54)s8s^^CV;TPaTwdUI=wvJlZb@lzR-yFC z@M;;5kReD=(J?95nhIJcf#EYitGI&OErL~Ka2gZX z|HsB|1;UXc^gHrOOCTmv!G1d5AD@dV67NqECoF^XW#aj^gjds*IPtcEJB6>MgxqDD zFsz}Wj!mw*sP|nFmzP_1hn>5pNJE8MKYHE~b=lq8KGgzzbpIwGECuyC{pQB%OZ!2|b zLFyIv^GWcQnST7Nc0~K7DdLIVTC>0rG_9)-xco-tJY!!Q7e>X`1%;sB&5ZuebOHc=+zxyHB@12+(4O+uHKE z-0FgjrJONIh8-&LY|(>} z&L;nha0lCDJcv7Ro92`=W-Dp$xU4Z*lQY_l$&ZwBW?7adMZcqvLPr#&@)BcSH`&kf8Hvd?|JuZu9smM*MeIKyy^`{#! zg7n^6xnV4x&+HI<4}y5OLp(D``U`^XldvOl9%rKZ&x?hg0;7P*IGLdSnJ8tfC}zRp z2yMnpQj|)E9kkZfA`5}^j|<-cJu3JiO_j+;_Ta2hb4VJ#5qRzQ_!4 z+61ZjGDshvYxzP9U4Ve42$v498-;U5zMD{jKvGJGOGSvjC}TF zc!j%D2*BMw{}f20HdquEJ$ZKVi#zhLyQ(0<%%AFg5`{b4-?5ctmQ1H5<8w0i7D$7C z?ERPhEeWufLo|#5G({YP6bOR^<_&;_TKorP|9mZ89OQlY01oUB|}2;^fb;%kV6w5xD{|kpK<@KpInEwcMHw&auD?h_syRfMm_|Xr!Q~UsfqZ z>pP|_s7-q%+E(GsNgoru0iw&c$)wf7%GBv!4IgE1G&w|$$SHwqqF zojqP3h0#Cpr2W)v`uCYW%BZXV@opIIL21~-ESpBwmi18PiCx z-MeHv)t0=j^+i%7E@Fd)VO~+-x5)1Ehl;dC?(IZ&2geIX07K+kM4O|YT!9DSUR)V# znBg^BmIcc>M8(8vr&ezPa;(HY^~a&!_LS7dF0;+*_(PSKaYkax>u-eTab}iAr^s7W zoJeC!N|sX>ey5JBn&gpkV@prr{qzt$m!-w2;iklbKDP22>WL!bYyO(T_-*2}7nOMU zsb$3JwTqrh>TklPmCQ|>^x*puA^I_yH|~C#I*i(PlPtid?X&m2mc*|iJuh%n zIWTkjH%PLpWa}sY`O?*u5^2)TE6G-eH{KIZ9ME0S3W~->M(>RK?dd#qruh9rUFDT1 zF+KI0(ERxhXi@u2ag5gY^Oyd56J4}d-Id$7=KGC?zAFCf-BRax5$x$-!7KjN^>-@+ zt%0kiV!z#t_`%symsOM7lVH1#zPDHB4cHVv(QDwO9kl*&GGJ&tZSGk=i z=cT?1aT?qu-DuLN)C$VGYrNT9FD}yZY8u-nWA}OUTYA+ijepyrWciPdwHSs%dDh#S zUwsOC)2VwfpmC2)=PQkUbS~O;<#*XY@wR} z%LGTd{ET{55dAZ@lhvtbbWBUGa0usHJk4^f2zA+SQxuiG_;!5D%)`iGlMkYD?JdU( zbvILNVwcK;VsGE%K5*EbNJw;iSKE&+oR=2u@-du#v;|3m#-0ekoN&It44*x*%J+9I z+<>EaG`Q|a)$qqx9=uJ#@#J?`z*bxEG!=V-=6M1Y`U z>Q6-z`lHG|!-Lo@!&<{+ExzVUmMqwa!!7aA7`|h=(vJKWPw&#XUvcPhQG~`lPv3Xo zC4}+6geMQY*mCwJmx=mMsPSdVtAOFj`qoC1Q4cMRz{k#75n7qTh!AY0@;XOSW8m4? z4<7*xLyqj~FP>g~sr98bV{)y zc_{_J%oCAo(p6t6DC$Wft;ZR*@`yYOc$@UT$&DKVKzDim?)5bVTs04XG|suJt%|(l zbwv4s$dk#|{p*eoF`EY`ch{h`lr=}5WaNN*Sw*g2d=O7rqA^=G-wA(V)j?T;%Mkly zOM^G|NK%glj9qB1k!!3<$^qx&p-~wCJllMmneLz`y9I#XU54OiWCgAZwfZl}DCbQ; zn=7{#c$ySr<2zfrp|Ez7a?s)l%z9adiEcB6$(HkA`7&M{4@5VW1P=8!MzH@N&)0>X zp!P7R)3dOi5L8o`Ws5Bo+yfRLc;{_gxxPXCL@TlGtRK1=Zn! z^q1JVp$mY9gThB+pQ_jOeHb)d3B%RMrK_IaHPPvDq3W~d#B;V zHA7BI!LWa2+q6c9G?CwnOpPxy$LLIR%e=bKdaWH5%UxCn($LxG%y7xJe#DhX<+bC- z<_P}1rxnnZyihDwr-FJxfz?y-y7(`-X(hDjEhg04}-CO^D18paN)V zdT~Qgz0l77be3b$ZjasWcP3zS6)m(@@(JoeJ}QPfLZA)Bn;f2p(9pq`*7sQ_hF#i? z*D6h0{3Eyfj`|*L4?X{2zTLNRvL%(#<)5U!zWP+kh$Ben9C;YO;W1iF`!p)Xq4s#5 zT-*Z%ZIgXV(Xr9pcK5|czY7+vZ#Q25;XLax9OoGOKJAADPF-P(vU(3x{FQcLd?YaZ znw8~0tnsZuk6W4NDHo00%-@b(_d3mKrbCJr-mOocQXUicr^HvU7Eggl%&Olh2g4qs zIT?M|<&kG`o{MpZR~0o<;QJ3;IQ=r~hvvQ1HY=mqCYM*IOyzR9=}YArD9rmv$*L&AY|<`?Uj1)LHxvUk{G!oFY*z`_Wlms7P=Q|$Ep$btxkFF8W8tv834 zZ+ih>&VX-ux#Tvndd?haJxC5>_&MR9sdQ*NOKx#j7|u+vvw>|e^AsrN*uK|B_vY_x z=$K2NfQ0t6xNr2US@71OF@RXC@cyJ6LG4l(K&jbAaJRmz_tc`)8TJm-4p8qJCzwGB zWbKacCJc2rsq6Z^zcgF>j$LiVXc<6A9p_LCz!d0Di_(QoM!wqJYCSW5fykoj{Y17F z=?eWUpx?cBZ(DmTx6pWL*LQ*G7a-q;LMHj$^tQ!R= zRB!000@>iJQ^nun+~cIyXJtXmS9oBn3>Dmr;YsZ#jrs&Bpe_o{I=b)yj;y%R=bX|@ zjfo+BSJ*ELz`fu!{kd8&6)2BfRXh%S;phZVO=IXunBP5 z2&vGn;5+>4+Vsm0H^r{G0Ta%X0W1VV^*2%Y*i%4Wl0ORBe@z2Jqpc*0CBOhWUg~n2 zHioUzXDvN!!-S7JuLm>Q<66ZtR0%Y{Fm!hHUwjOO-59$jDTZAEs&vEA20Wy#t z4Q3VTbF9(Zw#~;gB}f+s`nlkZXDM78yzMCplX-zN2{7Sz887?L7IKW_5SS1`P63-+ zgrY=(l?|*oqZEj?ga3z^!=TaHJw zAYKCuBPhg0(PONF7&bE8_+~!YRjy(KoY2=r=shlhj{BB5lbCT$=C`m2x2%K0ANYo#!LqFP8Tf8$AQEEe__Bfd`z5uaAkZ<4Bat?w{D2w!$n<*#~hAIxe}?o;COW%-icN<0k?1Ry?`}8jv%O+GHxsTGe}x`j*kb zO7eK*{r>G^#wm@d!PY_~FCTsVaQ}X1x?PHYdtkxM731I&i`zKf3z;=mB1>$hZ(()s z1DEHR=v^pgF#kYgkM$Rnk7BwCD$6@X3^mj)7zxg$QL4$lkVrTo(%-HZdXvU$Cxo0D z4Q%_e!1=+9o{$)dC3(PLo;px$i=gbH6Ay*BRCTSNk4Y6kps!_g`^61imRLYP)kLvEqf{p{{3b{*3vU^Ddjh3y0-5 zID$Lp?V<}H27OMu1Wr|a6DGiBfoMqJmm*ZFqRT!;7CsU}$}2)|g^}BOHm1F=<9k2E zR)#I|fYIPxzus(F3}4%j^LQX`_~_mrR!p$TPpZY!nZnSx=0P5Z`{m8%$xi zr*`RV7C@J~>=)OBW#k||ik;aCovd!lD`5L&pNw0IVXqJuJmA&Fz(YX@m0%UVqUZqg z^?Her(_6MrKx+2(JjbvdP(+#K8xANo9Oaor@;zsKnG*tLOVlS8uvS?{q(SVP$G8;? z+wUNQCbL5?Ku(>T=ffbh7{R(lf#xX4gBs^F$~PL|0aab}Bt`td;Mc@lVk@kIDOk5c z>)XZ$kY!K92Iv@UwG9DeU(X`tfsw*X(=7rN>w<|zEdys}r|xn?5EtCTjJ~}Coqcalw z(hf0L3evCtlWZ<* z09imMwN#+B3Ll4G-MaM(n9Kym1lj!Jt)Gd8@9NU*pc{I8fFT9O^9*oS&mZc>Pbjo@ z0cb7=ErGbj@G%w&qlqsh8Qrjq0iO2;TkuYs-oU7ONOufeB%9_VHP>>zO;`fQXvDd& zwsrSyn(YIEQ-Zd56i;UmcQkaFndhP{R-h3J{u?KPh9{-}iG*2A-YqHlLxrN3?9e06 zu}+hPX5@fJ!Oqc6Q2C5vJNBR2q>8GMOYinw_a^yy$5idhf?*3^Qtxy>rx~x2=I)I| zzKxyQzbp3Ya$NJ+%oZ!xZS1sw4!F634k1?&k*KSAB9pd3J~n`&EMWNl9llBk`Ql0d zP+5f`T!SHMp`S<^F!n^$buLE^4G?*}u#ZG09=g1DXYcC+z8#HSB{C!F50^BnBi=Hf zdx!e#wif8o0H)Ar>=vRg70&zRU&v06uFsGE@8)yVqk%&=U+bMnn@}R80mFXP`|F!{ zr0sdghy5XyBgrHY@$8Z^7q{}^VQJDy-WI4l=A91ebs0UGhm@ROG^(cu6_XL00uPkldT@2SA;2Toka51#|)-;S>=y7QIpe5$mxGPfC# zFrMMB-t(M@z{qp3HonMRFS57DuZ^Md|9;T*e+}FFKhujF0PyWIX2v#`Fmu}wOLC@0 zJ1E-}I>Ka=e5tvFJ(5@`x*3A($mylFTa&#(Zo4b?3p@dFzi6uF!I7zkh^&dPx zJkRrbUeEJ>l#|&44n$WzNQXFN@&Bm%-`&Cd%klmE#?HOb40EpwHSDH4$JTFGjMPu!o4>f5bwe#-hD zLfP#^FF*m&1R-ojrIvKgIC?$1crb5y@&#yLtm9ICxX^Wl656LZkkomqu;Ja|#S=t~ z?odITQb&WS_& z_6}y`q(2vFq*HyGZwHhqG9Mc%9z#GJ7{fs!&w1VUdWeS>bXo}Pc2`m?JiJV3WbM>{ z3`P7+bPmCeY{=fXgdErDg#Ob??;lP0@_)tBrDp6)#!7lg)~kPCIvO|Bik1OXl%%t10{H$^104eQ?@huo&4@mTt+XO2n#R-YtRqM+ zovqB9A^!e>*FCvVBe#q3LA5@mc8su1b;AK;i!zgWpykf-74qSL^+OKXN|41n(B25t#&BrN$xx1uKIiWKcfdT zG{Rj7XP+r_Ufw!n*1n{yjHG|a#h~4<)Q3E&IQf1oFcLC;Goi2yo1CEzTJT1oA(M+2 zzs;^5Bo;VJeqeM;U$!OrR@Biy`y6S5uTE{I$m5f)$GKAS-yKN3TKw}9_N9mS{f%sN zp3`qeZa5I)Syi8WFK-T~z8KLMp+l2`wPPGy8`1$U#1+Lp(50xHl6jOd)&Oi4JHJ}g68+)MptR=G$jnVjeAf>3W{#Q&E&88AV%AA3FE{Zy}tlJu)*H6#4 zM_HLPedKT0$W$3B^TfH?b4iWd1>~0eeH?w7Bm6C~0InPS)cKN|9;LtMQzyzBUCncE zYm1x{q?5rn1|N8g-|%-xzZZ;g1>cS>H%s3DN!qu*&K4)M#n@IRsmJRP4Ejf}3QwCP z$Kj;(SMwM4oT{$5*EIoKxJzqk5!qksOB`byjP8_e`TD6(ju z3OdIv!gQ!jIk27c?XyKG;-l8!6jt^Nq`UY-ZLv1%N3M42T)E<^y8(J9_}Cw%kg)g& z7H*3DE9}Z-^4kpSEAip&GhpA4?6Egzbp(T#>(L-4+yy&qNOLv2U#cGs(wCOo0gXL$ z7x>%J+A6n`Meg1&Vq&h8?wj9ayKA5Kp;^+y|GkQKV5SqzOHPFy-{yKI%1BX_8Ssmu zz8NIuUQG|bLsXt;l#dtRfBkH|w%*6sz2lm?Cp7Li{giJD_3^=|rO>e0;$!z!AZ_(Jxfl5N zC+f>B3wqE%`05bjNL9wvne9J_j-kWapQMLUCQ@JBTzK_#VuKE6JUS#RPxelF8T@%B z6UZK$*|1vKvw>cotA7pTnIonmVb$y3jy$pCJiuzbULLjj^yHd3BD3dD)4*Kt!{@J) z8L^+Mf`%I00E4?ZVjZqhb%o;m?jL)jLnW_ie4)++iZQk^ZW_dUz7`vma zbN>I>lfq?UoaeV6G22kGag+2?L7b{94@0zWzH{aN1CJ(qHO_YmUjd|By zD=+2fe7DvyC3jm;UV^AHB=iBPJS$6i9j2NyBH-!zPZ|&>iFQQ^qQJKjrkhBND`E#j zLa;UPV_guS8VJ_-g7zB=e-4j1hH_t5Y5dI2*YD5hGog!JT}G*h2IU;pvF4s_7hiuT zNr*8Ow*I$YiZl;1H2Qh(Z>WqG`x~+W#6_rqks#V679`k`eV}8qzpTo4*h=_sI`oup z6yZM#*rpD*8(I3<(zVHZcTwAoItJe$c8zZz*JIawlNwZTnyz-Ki@g7b00OmK;cH38xXG24G=-JQcAplQI&S!j~d-{Uy!BkUr-MkAM*{% zL7rgIPEI7(C0Pu(KN-o}3{#*A(Un`B(sFglY-Htlu9JKkDa)c_P7Uo(VY4_7R%T58 zDCwznisasWC_`>}1wE4fDKCn~+?FFHpO=3;7i-I@Tq@@~z#*b^y4R`VwD-r~gdIRP zZYX7z))wm~sIdfeViVpc8p}Xs`POT1>{pZ2RW8O6Y(T^5-N3;)T5;kYVDnfz#KqR; zydjKibl@RBuyZJo8fr4bPKVZd%gl(^+%Bq`#X&T zE2|@(QAIl5qJj3Zs|6-2z}+81l$7t-JnKTL(eDH=&o;#+K%*MLq-nweu;+i5L|Ywi z;ee#6T0cuSu6vESpr?|8!8Nc()!LMiNqfgyK0B3i^-X+5YOYCW{ni7tPKU$f(!;G> z)H7@Wdaa~2NyM@EU8#w_39p!%C0_%K44<88uI4@!Jm9Kbhvbk`{b`q}G!4(QDWDdj+RQqx}>tsLkIs z{PeXOh&nu#R5z@n_uXc65>Is(2Z7QZWv1J-eRe4c1y3xz51bWy?NVbAIQ@7k&}xE8)PD;=G8pX|oS3 zV0T*(O0$Hj+qBl@`K+pd#erblNqnL-ND!0Ahj>Up7HkSQfG9Il-ss!`*Ay9+%rs^* zdtJ$3cb2(J-O=VBRy)g{9djLso~fp`Ddf0E|LD|z8FN({<;ZJ>V@mK(|FLYmeD)T z9~(_JiRtsQEHBZd>)AlMSQN}i3D=!44L`~Wac;z+TK<@Zb(dVW7@+9_?PPPOj2AoS zlJgwvxR{ncGJ?Ya+*^OZ$K7}cd5NZ7V=WZ(I~i_(MILU)VjjYvF1EOH+TjY`kCBgK zwLdO$U&)OR5^nVDY9N%5o33U~b|WMz;bva%js9?*ytZNQzVoprcK`G442&Z(QdK|~4UU0K=R`QQ%r6J1ze~J`qg2xX{*t0$2fa$#d zvUoAM^|R~32XH+LiSH?bD2>U{L=rAG$DvDRbX5#0`>f$#cg1eX8@?Q@6?czPbABW7D+NxoBw z)|ePv7Y8}nv%=v4cU9Uul$urxM$JEI(3M#waTx+2dv^o-yS8;bS@SMRh>;jSgOz!E zU#ui#^8oM|A=Q|0vXzk2jD+Ay;f#i}>;^sT%unB0fElZ;N&Nw}wBU&(RLOhv4E5i~ zFPwKno(|W6IQK1TBpFcRuC{T2znMCE9G(IGB3__hK{1p5a+(G+_*$>$7sNL%4KntQ zQP27T+YrxL27mRRWswaVn-QZ5cRx+UM_?za_u*DJpj#_6mj4!6ja-^U#lv0=pVaSn8EXpIV)OuB3zIy z*TQ(Od9pX+FwTV0o5zBsg$f<Hn+(vmc?@8uI&=hsSYV>Bc@ z*fP6XJvPzW{O{6aIu5+?da(l1Iz5f7kgeL04HB@XIUID96i{(%ys0jDQ=!vi6-WQ6Lc?vdIWTP%kF)w)@z{Y1 zTf~|A&cNEIQ7;r~6d9~dnnq1!ft#;`&D&&_@8z1b&p{<( z9qYZQ3Jzv;PtUr-aD;2PB1N!{d3x09Y9uE#akVQURxExc(HiJ&^}f(}oJQ z+G8?B0p%Rm$@ml1b;}YjMy@mIa;`I%18~HqL+7VBpS5joYp+Z1%qd{y(xrB>ZX4w> zo&$*HpZKO8_+}ViAvdYNeGDWF^zMu@wx(Vmv1+2|N-441d%V>(cgWMU7uGL5g#Lg` zDJb(gu{9E#5YyM6XMG_wLeI4sn>@;dU#1whFac{U(7{D_RHLGpFc3v!5esgVX^!KJ zauuLTscxAVb)p&_t^h_rMhQ&h)6V65u;mk(*}527bd%sOe%0kr1htZ#+S74Pxc`d*=p{VsLAM z7&Yh6P3)#UcH#`{NS5Si@bmo=WoBJSOnnHx7z!0Llc~bDqY0#LAI7MZJ)@D{1m3!5 z9vaHEr&b@CioxGLfw!Wj&Fde3ZRZ-#4C#4MHu@s3Bd?5l%q=4dzZH)^_!e40&{&8| zZdMvzLg8c5O}bR@?$MOnz1~TYNsy!%^t525SfGUd2=klW9S4o*XVH4&(Xt$D95ncg zQEQ+5VVU0$?)XaaNspIDQ89^u6hY1m&(RlAmwx<^2$=>2WPzDC^4Qb?kVON=2^PKB zYfYAj(reE0uHY{CMjYuU&e5tywNI}9n~QhbSts8)H#5J5XZPbydbT?)@x{R{OG9ai zlI%BM7#RSl8Ow^EJt^X)eEM=W?o%QxG-q{zizD$iXYjVP^R}(=oJo9_cAob55OOYJ zCrPk3L$I%1;J+q_tmT@GbA#H25o^LoQf>q(=V*KGhMG<#3670#NhjrHujO&kqBA5c H2;}~MOhLDp literal 0 HcmV?d00001 diff --git a/lib/orber/doc/src/dataframe1.ps b/lib/orber/doc/src/dataframe1.ps new file mode 100644 index 0000000000000000000000000000000000000000..a07a64adba197d196325214966b98d95af6b4f45 GIT binary patch literal 423743 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 b`?F8`wQu{kkNdf=`@7Hkz3=;x9}oaLaAoF> literal 0 HcmV?d00001 diff --git a/lib/orber/doc/src/dataframe2.ps b/lib/orber/doc/src/dataframe2.ps new file mode 100644 index 0000000000000000000000000000000000000000..31ef4f1f908e2efb23261ebcd450d84464b9a7f5 GIT binary patch literal 618198 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νv61IQPq@`d3&6=#)On9F~`NMlZn;~T;PCF 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�()S%Q4$LEG!plK{l`OW!H|5cf{!q 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 literal 0 HcmV?d00001 diff --git a/lib/orber/doc/src/dataframe3.ps b/lib/orber/doc/src/dataframe3.ps new file mode 100644 index 0000000000000000000000000000000000000000..4f0e6f18658bb55928e7f4d31ddcf9965af11967 GIT binary patch literal 1060785 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