VisiTime Guide : Using the VisiTime Service

Using the VisiTime Service
This section describes the VisiTime Service, a complete implementation of the OMG Time Service Specification, Version 1.1. The OMG Time Service specification defines two types of service which are implemented in VisiBroker:
Basic Time Service: provides an interface to create objects representing time (a time stamp, for example) and intervals of time.
Timer Event Service: provides an interface to manage Timer Event Handler objects. These objects are used to generate time based events based on user defined time settings.
Time Service overview
According to the OMG Time Service Specification, the OMG Time Service was created to allow a user to obtain the current time as well as an error estimate associated with it. Additionally, the Time Service was to provide a means of tracking events by ascertaining the order in which events occur, generate time-based event triggers or “alarms”, and compute the interval between two events.
How the Time Service defines time
The OMG Time Service Specification defines time using the Universal Time Coordinated (UTC) representation. The UTC representation uses hundreds of nanoseconds (10-7 seconds) as its basic unit of time, with its base time set at 15 October 1582 00:00:00 GMT. A range of approximately 30,000 years A.D. is supported by the UTC representation.
Similarly, the UTC representation defines a intervals of time or “relative time”. Like regular time, the basic unit of a relative time is 10-7 seconds. Ranges can span approximately plus-or-minus 30,000 years.
The Time Service relies on the presence of an underlying time source that provides the time and performs any necessary time synchronization. If the underlying time source meets the security criteria set out in Appendix A of the OMG Time Service Specification, then the Time Service is able to provide secure time as well.
Time Service components
The Time Service defines two types of CORBA objects that can be used by applications. These objects are the Universal Time Object (UTO), and the Time Interval Object (TIO). Using these two objects, a CORBA Time Service must provide for the ability to:
Create a TIO from the new_interval operation.
Universal Time Object
The UTO interface corresponds to an object that contains UTC time and provides means to manipulate time in that object. UTO is an immutable object; it does not allow modifying the value of time contained in it. A UTO also provides for operations to be performed on basic time, such as comparing UTOs, comparing a UTO to a TIO interval, and getting the constituent parts of the UTO object.
Time Interval Object
Like a UTO, a TIO is an immutable object that represents a time interval and provides operations on time intervals. Methods are provided to get the interval value stored in the TIO object, determine overlapping between a TIO and one or more UTOs, and convert a TIO into a UTO.
Time Service services
In addition to providing time objects that can be manipulated and used by applications, the Time Service specifies a Timer Event Service and a Secure Time Service. The Timer Event Service provides a means for timer alarms to trigger events, which can be responded to using callback objects. The Secure Time Service allows only specified users of the system to set the time and/or specify the source of time.
Timer Event Service
The Timer Event Service provides a mechanism by which you can receive notifications when an event gets triggered. In other words, Timer Event Service provides a kind of alarm service. Your programs can register a CosEventComm::PushConsumer callback object with the Timer Event Service and obtain a special event handler object that provides operations to set and cancel alarms. When an alarm goes off, the Timer Event Service sends a notification to the callback object.
A Timer Event Handler object holds information about an event that is to be triggered at a specific time and the action to be taken when the event is triggered. The action taken is basically a call on the push method on the CosEventComm::PushConsumer object registered as the event handler. This method takes a CORBA::Any which contains the data to be pushed (the data is also specified when the event handler is registered with the event service).
The following operations are provided by the Timer Event Handler interface:
Alarms can be set using absolute or relative time definitions. They can also be set to occur periodically. The Timer Event Service interface provides operations for the complete lifecycle for the Timer Event Handler. The following operations are provided by the Timer Event Service interface:
Secure Time Service
Only administrators authorized by the system security policy may set the time and specify the source of time. Once this is guaranteed the administrator can configure the Time Service to return secured time. With this in place it can be safely assumed that the underlying time source is secured and calling a secure_universal_time operation on the Time Service interface will return a secured time. If the underlying time source is not secured, a CosTime::TimeUnavailable exception will be raised upon invocation of the secure_universal_time operation on the Time Service interface.
VisiTime Service
The VisiTime Service is a factory for creating Universal Time Objects and Time Interval Objects.
Starting the VisiTime Service
The VisiTime Service can be started by using the timeserv launcher located in the bin directory of your VisiBroker installation. Running this command starts both the VisiTime Service and “Timer Event Service”. The command syntax is:
Unix
timeserv [driver_options] [timeserv_options] &
Windows
timeserv [driver_options] [timeserv_options]
You can also start the Time Service using the VBJ launcher:
vbj [driver_options] com.borland.vbroker.CosTime.TimeServer
The following driver options are available:
The general driver options are also available for both UNIX and Windows. See the VisiBroker for C++ Developer’s Guide or VisiBroker for Java Developer’s Guide for more information.
The following VisiTime Service options are available:
Starting Secure VisiTime Service
When the underlying time source is secure and follows the guidelines given in Appendix A of the OMG Time Service specification, then the VisiTime Service can be started as a secure Time Service. Calls to TimeService::secure_universal_time would succeed in this case. Note that here security only refers to the security of the underlying time source. To start a secured VisiTime Service:
Unix
timeserv -J-Dvbroker.time.source.secured=true &
Windows
start timeserv -J-Dvbroker.time.source.secured=true
Bootstrapping the VisiTime Service
There are three ways to start a client application to get the initial reference to the VisiTime Service. These are:
Using the ORBInitRef command-line option.
Using the ORBDefaultInitRef command-line option.
When using either of the command-line options, client applications can make use of the ORB's resolve_initial_references method to obtain the Time Service or the Timer Event Service. For example:
C++
...
CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);

// Get reference to Time Service
CORBA::Object_var obj_t = orb->resolve_initial_references("CosTimeService");
CosTime::TimeService_var time_svc = CosTime::TimeService::_narrow (obj_t.in());

// Get reference to Timer Event Service
CORBA::Object_var obj_te = orb->resolve_initial_references("CosTimerEventService");
CosTimerEvent::TimerEventService_var timer_svc =
CosTimerEvent::TimerEventService::_narrow (obj_te.in());
...
Java
// Get reference to Time Service
org.omg.CosTime.TimeService timeSvc = org.omg.CosTime.TimeServiceHelper.narrow(
orb.resolve_initial_references("CosTimeService"));

// Get reference to Timer Event Service
org.omg.CosTimerEvent.TimerEventService timerSvc =
org.omg.CosTimerEvent.TimerEventServiceHelper.narrow(
orb.resolve_initial_references("CosTimerEventService"));
...
Bootstrapping using ORBInitRef
The most common usage scenario for ORBInitRef is to use a corbaloc URL to specify the initial reference. Other URL schemes are also possible. For example, using the IOR string or the file URL (Java only) to specify the name of the file containing Time Service IOR. The following commands bootstrap the Time Service and Timer Event Service running on port 5566 to the client application:
C++
<client_application> -ORBInitRef CosTimeService=corbaloc::<host>:5566/CosTimeService

<client_application> -ORBInitRef CosTimerEventService=corbaloc::<host>:5566/CosTimerEventService
Java
vbj <client_application> -ORBInitRef CosTimeService=corbaloc::<host>:5566/CosTimeService

vbj <client_application> -ORBInitRef CosTimerEventService=corbaloc::<host>:5566/CosTimerEventService
Bootstrapping Using ORBDefaultInitRef
Like ORBInitRef, ORBDefaultInitRef commonly uses corbaloc URLs to specify initial references. Other URL schemes are valid as well, depending on your implementation. The following command bootstraps both the Time Service and the Timer Event Service to the client application, using ORBDefaultInitRef:
C++
<client_application> -ORBDefaultInitRef corbaloc::<host>:5566
Java
vbj <client_application> -ORBDefaultInitRef corbaloc::<host>:5566
You can also specify the ORBDefaultInitRef as a property with the vbj command starting the client application. The following command also bootstraps the Time Service, but specifies ORBDefaultInitRef as a property:
vbj -DORBDefaultInitRef=corbaloc::<host>:5566 <client_application>
Bootstrapping Using the SmartAgent
Client applications can also make use of the VisiBroker bind method to get the initial reference to the Time Service and the Timer Event Service from the SmartAgent. In Java the TimeServiceHelper and TimerEventServiceHelper classes are used to perform the bind. When executing the method, you specify the name of the Time Service and Timer Event Service to which you're connecting (and in Java, the ORB hosting them). For example:
C++
CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);

// Get reference to Time Service
CosTime::TimeService_var time_svc =
CosTime::TimeService::_bind("VBTimeService");

// Get reference to Timer Event Service
CosTimerEvent::TimerEventService_var timer_svc =
CosTimerEvent::TimerEventService::_bind
("VBTimerEventService");
Java
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);

// Get reference to Time Service
org.omg.CosTime.TimeService timeSvc =

org.omg.CosTime.TimeServiceHelper.bind(orb,
"VBTimeService");

// Get reference to Timer Event Service
org.omg.CosTimerEvent.TimerEventService timerSvc =
org.omg.CosTimerEvent.TimerEventServiceHelper.bind(orb,
"VBTimerEventService");
Running the Time Service in-process
The VisiTime service has the ability to run in-process or co-located with Java applications. You need not make any application code changes when switching from out-of-process to in-process mode. Enabling the in-process Time Service is controlled through the VisiBroker property vbroker.time.enableInProc.
Regardless of whether the Time Service is using in-process or out-of-process execution mode, user applications will use orb.resolve_initial_references("CosTimeService") and orb.resolve_initial_references("CosTimerEventService") to obtain initial references to the Time Service and Timer Event Service respectively. There would be a difference in the bootstrapping mechanism for in-process and remote Time Service respectively. User applications should not specify the ORBInitRef property with in-process Time Service. Instead, they must enable the VisiBroker property vbroker.time.enableInProc=true. If ORBInitRef is used together with vbroker.time.enableInProc=true, only ORBInitRef will take effect.
NTP server support for Time Source
By default, the VisiTime Service implementation uses the System Time as the Time Source. Alternatively it can be configured to use a NTP Server as a Time Source. This is controlled through the VisiBroker property vbroker.time.ntp.addr.
Specifying NTP server addresses and failover
The value for the vbroker.time.ntp.addr can be one or a sequence of comma-separated strings representing the NTP Server addresses. Both IPv4 and IPv6 format addresses can be specified as well. For example, consider three NTP server addresses given here:
vbroker.time.ntp.addr=foo.com,[fe220::103:baaa:fbbb:fedf]:123,101.121.145.100:124
The first address, foo.com, relies on the internal DNS lookup. Since no port is specified, the default NTP port 123 is used. The second entry, [fe220::103:baaa:fbbb:fedf]:123, is an IPv6 format address enclosed in square brackets. Here, the port is defined specifically as 123. The final entry, 101.121.145.100:124 is the familiar IPv4 format, with the port number 124 specified as well.
The VisiTime Service will first try to contact the first NTP Server in the sequence. If the address is valid and the server is available, the time of the NTP Server will be returned to the caller. Assuming that the first server in the list was not available, the implementation will transparently fail over to the second in the list and so on until it retrieves the required time value from one of the Server in the list. If all of the Servers are unreachable, VisiTime Service will throw an exception to the caller. Depending on the method called, the exception can be either CosTime::TimeUnavailable or a CORBA system exception such as COMM_FAILURE.
Configuring the VisiTime Service
The VisiTime Service can be configured using the VisiBroker Console, using properties specified on the command line, or using properties specified in a properties file. The following properties are provided for the VisiTime Service.
Tells the Time Service that the Time Source is a secured one. When this property is true, a call to secure_universal_time will always succeed. Otherwise, it throws the TimeUnavailable exception.
Where addr is the host name such as myhost.com or an IP address. Both IPv4 and IPv6 addresses are supported. IPv6 addresses must be enclosed in square brackets. The port is optional. If not specified, the default Time Service port 123 is used. When multiple addresses are specified, then NTP server failover happens if communication with one of the servers fails. The Time Service will try all the servers before throwing a TimeUnavailable exception.
Creating Time Service Objects with the TimeService interface
The VisiTime Service interface TimeService provides methods for creating UTOs and TIOs, but doesn't provide any methods to deactivate/destroy these Objects. VisiBroker's TimeService implementation uses the default servant-based dispatch mechanism limiting the number of these objects, meaning that for any number of these references the real servant processing the request is only one. You will not, therefore, need to be concerned with a large number of Time Service objects--UTOs and TIOs--being created. You use the TimeService interface to create UTOs and TIOs. Before creating these objects, you must resolve to the Time Service and narrow it (using the TimeServiceHelper in Java). The following code samples explain how to do this:
C++
//Initialize the ORB
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

//Resolve the TimeService interface
CORBA::Object_var obj_t = orb->resolve_initial_references("CosTimeService");

//Narrow the TimeService interface
CosTime::TimeService_var time_svc = CosTime::TimeService::_narrow (obj_t.in());
Java
import org.omg.CORBA.ORB;
import org.omg.CosTime.*;
...
//Initialize the ORB
ORB orb = ORB.init(args, null);

//Resolve the TimeService interface
org.omg.CORBA.Object obj = orb.resolve_initial_references("CosTimeService");

//Narrow it properly using the Helper
TimeService timeService = TimeServiceHelper.narrow(obj);
Once you have resolved to and narrowed the TimeService interface, you can use it to create UTOs and TIOs.
Creating UTOs using the TimeService interface
Use the TimeService method universal_time() to create a Universal Time Object containing the current time. For example,
C++
CosTime::UTO_var uto = time_svc-> universal_time();
Java
UTO uto = timeService.universal_time();
creates a Universal Time Object uto whose time value is the current time at the execution of the method.
You can also create a UTO containing a relative time of your choosing (not obtained using a Time Source) using the new_universal_time method. You provide three arguments to this method:
For example:
C++
CosTime::UTO_var uto = time_svc-> new_universal_time
((CORBA::ULongLong)10000000,0,(CORBA::Short)0);
Java
UTO uto = timeService.new_universal_time
(10000000L,0,(short)0);
Creating TIOs using the TimeService interface
You can create TIOs using the TimeService interface. The new_interval method takes two arguments of type CORBA::ULongLong (C++) or long (Java), which are the bounds of the time interval expressed as hundreds of nanoseconds since base time. For example:
C++
//Create a TIO that represents a specific interval
CosTime::TIO_var tio =
time_svc->new_interval((CORBA::ULongLong)10000000,
(CORBA::ULongLong)20000000);
Java
//Create a TIO that represents a interval TIO tio
= _timeService.new_interval(10000000L, 20000000L);
Using the Timer Event Service
This section explains how to resolve to a Timer Event Service, obtain TimerEventHandlers, set alarms using the TimerEventHandlers, cancel an alarm that was previously set, and unregister a TimerEventHandler.
Before creating and utilizing TimerEventHandlers, you must resolve to the Timer Event Service itself, as well as the ORB's standard Event Service providing the PushConsumer object. For example:
C++
//Initialize the ORB
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

//Resolve the TimerEventService
CORBA::Object_var obj_t = orb->resolve_initial_references("CosTimerEventService");
CosTime::TimerEventService_var time_evsvc =
CosTime:: TimerEventService::_narrow (obj_t.in());

//Resolve to the EventService
CORBA::Object_var obj_ev = orb->resolve_initial_references("EventService");
CosEventChannelAdmin::EventChannel_var channel =
CosEventChannelAdmin::EventChannel::_narrow(obj_ev.in());
Java
import org.omg.CORBA.*;
import org.omg.CosEventComm.*;
import org.omg.CosEventChannelAdmin.*;
import org.omg.CosTime.*;
import org.omg.CosTimerEvent.*;
import org.omg.TimeBase.*;
...

//Initialize the ORB
ORB orb = ORB.init(args, null);

//Resolve the TimerEventService
TimerEventService timerEventService=TimerEventServiceHelper.narrow(
_orb.resolve_initial_references("CosTimerEventService"));

//Resolve to the EventService
EventChannel channel =
EventChannelHelper.narrow(_orb.resolve_initial_references("EventService"));
Creating TimerEventHandlers
The Timer Event Service provides an operation to register a CosEventComm::PushConsumer together with a CORBA::Any that provides event data. Internally, an instance of TimerEventHandler is created, with which the event data and PushConsumer are associated. You can at any point change the event data, but the PushConsumer is immutably associated with the TimerEventHandler and cannot be changed.
Once you have resolved the Timer Event Service and Event Service, and you have obtained a channel from the latter, you can create the Event Handler implementation. To do so, you must follow these six steps:
1
Create a ProxyPushSupplier object to push the event data to the consumer.
2
Create a PushConsumer object to receive the event data.
3
Associate the ProxyPushSupplier with its PushConsumer.
4
Obtain a ProxyPushConsumer object from the event channel. This is the object that will be registered with the Timer Event Service.
5
6
Create the event handler by executing the Timer Event Service's register method, using the ProxyPushConsumer and the CORBA::Any objects as arguments.
The following tables show source code used to execute each of the steps above:
C++
Java
Setting Alarms for TimerEventHandlers
In order to use your newly-created TimerEventHandler, you set alarms using the EventTimer interface. The set_timer method is used to set an alarm. It takes two arguments: the type of alarm and a UTO object. Three types of alarms are available:
TTAbsolute: the alarm is triggered at an absolute time specified by the UTO.
TTRelative: the alarm is triggered at the UTO relative to the current time (the UTO represents time from the current absolute time, not the time base).
TTPeriodic: the alarm occurs periodically, repeating at each relative time specified by the UTO.
To set an alarm, you must:
1
Create a TimerEventHandlers object (see “Creating TimerEventHandlers”).
2
3
Use the Event Handler's set_timer method to set the alarm.
For example, the following code sets an alarm for a TimerEventHandler object called eventHandler:
C++
//Create an UTO that represents relative time
CosTime::UTO_var uto = time_svc->new_universal_time
((CORBA::ULongLong)10000000,0,(CORBA::Short)0);

//set a periodic timer on the TimerEventHandler, this
// alarm would trigger after every 1 second
// (10000000/10000) second has elapsed and the event data
// will be pushed to the PushConsumer that was previously
// registered
eventHandler->set_timer(CosTimerEvent::TTPeriodic,uto);
Java
//Create an UTO that represents a relative time
UTO uto = timeService.new_universal_time
(10000000L,0,(short)0);

//set a periodic timer on the TimerEventHandler, this
// alarm would trigger after every 1 second
// (10000000/10000) second has elapsed and the event data
// will be pushed to the PushConsumer that was previously
// registered
eventHandler.set_timer(TimeType.TTPeriodic,uto);
Note
The Timer Event Service minimum relative interval for which an alarm can be set is 1 millisecond. Any value less than 1 millisecond will be transparently converted to 1 ms.
Canceling a timer and unregistering a TimerEventHandler
To cancel an event handler's timer, simply execute the handler's cancel_timer method:
C++
eventHandler->cancel_timer();
Java
eventHandler.cancel_timer();
To unregister an event handler entirely, call the event service's unregister method:
C++
eventService->unregister(eventHandler);
Java
eventService.unregister(eventHandler);
Friendly Time Object
This is an object with a friendly interface to convert the 64-bit time representation to human readable components like year, month, day etc and vice versa: the TimeI object. The TimeI object can be viewed as a representation conversion object. The general technique for using it is to create one using the operation FriendlyTime::TimeService::time(). This creates a TimeI object with time set to zero in it. Then the _set operations can be used to set the values of the various attributes. Finally, the attribute time can be used to get the corresponding TimeT value.
Conversely, one can set any TimeT value in the time attribute and then get the year, month, and so forth. from the appropriate attributes.
The IDL for the friendly time object is as follows:
module FriendlyTime {
interface TimeI {
attribute YearT year;
attribute MonthT month;
attribute DayT day;
attribute HourT hour;
attribute MinuteT minute;
attribute SecondT second;
attribute MicrosecondT microsecond;
attribute TimeBase::TimeT time;
void reset(); // set all attributes to zero
};
The following code sample illustrates the usage of the friendly time object:
C++
//Initialize the ORB
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

//Resolve the FriendlyTimeService
CORBA::Object_var obj_t = orb->resolve_initial_references
("CosTimeService");
FriendlyTime::TimeService_var time_svc = FriendlyTime::TimeService::_narrow (obj_t.in());

//Get a TimeI object from the FriendlyTime
FriendlyTime::TimeI_var timeI = time_svc->time();

//Get the current time in a UTO
CosTime::UTO_var uto = time_svc-> universal_time();

//Set the current time in the TimeI object
timeI->time(uto->time());

//Get the various attributes from TimeI Object in a human
//readable format and print to the standard output
cout << " Year is :" << timeI->year() << endl;
cout << " Month is :" << timeI->month() << endl;
cout << " Day is :" << timeI->day() << endl;
cout << " Hour is :" << timeI->hour() << endl;
cout << " Minute is :" << timeI->minute() << endl;
cout << " Second is :" << timeI->second() << endl;
cout << " MicroSecond is :" << timeI->microsecond() << endl;
Java
import org.omg.CORBA.ORB;
import org.omg.CosTime.*;
...
//Initialize the ORB
ORB orb = ORB.init(args, null);

//Resolve the FriendlyTimeService
org.omg.FriendlyTime.TimeService friendlyTs =
org.omg.FriendlyTime.TimeServiceHelper.narrow(
_orb.resolve_initial_references("CosTimeService"));

//Get a TimeI object from the FriendlyTime
org.omg.FriendlyTime.TimeI timeI = friendlyTs.time();

//Get the current time in a UTO
UTO uto = friendlyTs.universal_time();

//Set the current time in the TimeI Object
timeI.time(uto.time());

//Get the various attributes from TimeI Object in a human
//readable format and print to //the standard output
System.out.println("Year is :"+ timeI.year());
System.out.println("Month is :"+ timeI.month());
System.out.println("Day is :"+ timeI.day());
System.out.println("Hour is :"+ timeI.hour());
System.out.println("Minute is :"+ timeI.minute());
System.out.println("Second is :"+ timeI.second());
System.out.println("MicroSecond is :"+ timeI.microsecond());