Skip to content

Commit

Permalink
timer and scheduler interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
LisiLisenok committed Apr 23, 2017
1 parent 2baca91 commit 0c69d8f
Show file tree
Hide file tree
Showing 11 changed files with 931 additions and 19 deletions.
77 changes: 77 additions & 0 deletions source/herd/schedule/chime/Scheduler.ceylon
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import ceylon.time {
DateTime
}


"Wraps event bus to provide exchanging messages with previously created scheduler.
The object implementing interface is returned by [[connectToScheduler]]."
see( `interface Timer`, `function connectToScheduler` )
since( "0.2.0" ) by( "Lis" )
shared interface Scheduler {

"Name of the scheduler."
shared formal String name;

"Removes this scheduler."
shared formal void delete();

"Pauses this scheduler."
see( `function resume` )
shared formal void pause();

"Resumes this scheduler after pausing."
see( `function pause` )
shared formal void resume();

"Requests scheduler info."
shared formal void info( "Info handler." Anything(Throwable|SchedulerInfo) info );

"Creates interval timer."
shared formal void createIntervalTimer (
"Callback when timer created."
Anything(Timer|Throwable) handler,
"Interval timer delay in seconds."
Integer delay,
"Timer name. Timer address is timer full name, i.e. \"scheduler name:timer name\"."
String? timerName = null,
"`True` if timer is paused at initial and `false` if running."
Boolean paused = false,
"`True` if timer has to publish event and `false` if sends."
Boolean publish = false,
"Maximum number of fires or null if unlimited."
Integer? maxCount = null,
"Timer start date."
DateTime? startDate = null,
"Timer end date."
DateTime? endDate = null,
"Time zone."
String? timeZone = null
);

"Creates cron timer."
shared formal void createCronTimer (
"Callback when timer created." Anything(Timer|Throwable) handler,
"Seconds." String seconds,
"Minutes." String minutes,
"Hours." String hours,
"Days of month." String daysOfMonth,
"Months." String months,
"Optional days of week." String? daysOfWeek = null,
"Optional years." String? years = null,
"Timer name. Timer address is timer full name, i.e. \"scheduler name:timer name\"."
String? timerName = null,
"`True` if timer is paused at initial and `false` if running."
Boolean paused = false,
"`True` if timer has to publish event and `false` if sends."
Boolean publish = false,
"Maximum number of fires or null if unlimited."
Integer? maxCount = null,
"Timer start date."
DateTime? startDate = null,
"Timer end date."
DateTime? endDate = null,
"Time zone."
String? timeZone = null
);

}
196 changes: 196 additions & 0 deletions source/herd/schedule/chime/SchedulerImpl.ceylon
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import ceylon.time {
DateTime
}
import io.vertx.ceylon.core.eventbus {
EventBus,
Message
}
import ceylon.json {
JSON=Object
}


"Internal implementation of [[Scheduler]]."
see( `function connectToScheduler` )
since( "0.2.0" ) by( "Lis" )
class SchedulerImpl (
shared actual String name,
EventBus eventBus
)
satisfies Scheduler
{

variable Boolean alive = true;


"Fills timer general description by data."
JSON timerGeneral (
String? name, Boolean paused, Boolean publish, Integer? maxCount,
DateTime? startDate, DateTime? endDate, String? timeZone
) {
JSON timer = JSON {
Chime.key.operation -> Chime.operation.create,
Chime.key.publish -> publish
};
if ( exists n = name ) {
timer.put( Chime.key.name, n );
}
if ( paused ) {
timer.put( Chime.key.state, Chime.state.paused );
}
if ( exists n = maxCount ) {
timer.put( Chime.key.maxCount, n );
}
if ( exists n = startDate ) {
timer.put (
Chime.key.startTime,
JSON {
Chime.date.seconds -> n.seconds,
Chime.date.minutes -> n.minutes,
Chime.date.hours -> n.hours,
Chime.date.dayOfMonth -> n.day,
Chime.date.month -> n.month.integer,
Chime.date.year -> n.year
}
);
}
if ( exists n = endDate ) {
timer.put (
Chime.key.endTime,
JSON {
Chime.date.seconds -> n.seconds,
Chime.date.minutes -> n.minutes,
Chime.date.hours -> n.hours,
Chime.date.dayOfMonth -> n.day,
Chime.date.month -> n.month.integer,
Chime.date.year -> n.year
}
);
}
if ( exists n = timeZone ) {
timer.put( Chime.key.timeZone, n );
}
return timer;
}

"Sends timer create request and responds to handler."
void sendTimerCreateRequest( JSON timer, Anything(Timer|Throwable) handler ) {
eventBus.send<JSON>(
name, timer,
( Throwable | Message<JSON?> msg ) {
if ( is Throwable msg ) {
handler( msg );
}
else {
"Timer create request has to respond with body."
assert( exists rep = msg.body() );
handler( TimerImpl( rep.getString( Chime.key.name ), name, eventBus ) );
}
}
);

}


shared actual void createIntervalTimer (
Anything(Timer|Throwable) handler, Integer delay, String? timerName,
Boolean paused, Boolean publish, Integer? maxCount, DateTime? startDate, DateTime? endDate, String? timeZone
) {
JSON timer = timerGeneral( timerName, paused, publish, maxCount, startDate, endDate, timeZone );
timer.put (
Chime.key.description,
JSON {
Chime.key.type -> Chime.type.interval,
Chime.key.delay -> delay
}
);
sendTimerCreateRequest( timer, handler );
}

shared actual void createCronTimer (
Anything(Timer|Throwable) handler, String seconds, String minutes, String hours, String daysOfMonth,
String months, String? daysOfWeek, String? years,
String? timerName, Boolean paused, Boolean publish, Integer? maxCount,
DateTime? startDate, DateTime? endDate, String? timeZone
) {
JSON timer = timerGeneral( timerName, paused, publish, maxCount, startDate, endDate, timeZone );
JSON descr = JSON {
Chime.key.type -> Chime.type.cron,
Chime.date.seconds -> seconds,
Chime.date.minutes -> minutes,
Chime.date.hours -> hours,
Chime.date.daysOfMonth -> daysOfMonth,
Chime.date.months -> months,
Chime.date.daysOfWeek -> "*",
Chime.date.years -> "2015-2019"
};
if ( exists d = daysOfWeek, !d.empty ) {
descr.put( Chime.date.daysOfWeek, d );
}
if ( exists d = years, !d.empty ) {
descr.put( Chime.date.years, d );
}
timer.put( Chime.key.description, descr );
sendTimerCreateRequest( timer, handler );
}


shared actual void delete() {
if ( alive ) {
alive = false;
eventBus.send (
name,
JSON {
Chime.key.operation -> Chime.operation.delete,
Chime.key.name -> name
}
);
}
}

shared actual void pause() {
if ( alive ) {
eventBus.send (
name,
JSON {
Chime.key.operation -> Chime.operation.state,
Chime.key.name -> name,
Chime.key.state -> Chime.state.paused
}
);
}
}

shared actual void resume() {
if ( alive ) {
eventBus.send (
name,
JSON {
Chime.key.operation -> Chime.operation.state,
Chime.key.name -> name,
Chime.key.state -> Chime.state.running
}
);
}
}

shared actual void info( Anything(Throwable|SchedulerInfo) info ) {
eventBus.send (
name,
JSON {
Chime.key.operation -> Chime.operation.info
},
( Throwable|Message<JSON?> msg ) {
if ( is Message<JSON?> msg ) {
"Reply from scheduler request has not to be null."
assert( exists ret = msg.body() );
info( SchedulerInfo.fromJSON( ret ) );
}
else {
info( msg );
}
}
);
}

}
42 changes: 42 additions & 0 deletions source/herd/schedule/chime/SchedulerInfo.ceylon
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import ceylon.json {
JSON=Object
}


"Info on the scheduler."
see( `interface Scheduler`, `class TimerInfo`, `function schedulerInfo` )
since( "0.2.0" ) by( "Lis" )
shared final class SchedulerInfo {

"Scheduler name." shared String name;
"Scheduler state at the request moment." shared State state;
"List of the timers. Actual at the request moment." shared TimerInfo[] timers;

"Instantiates `SchedulerInfo` with the given parameters."
shared new (
"Scheduler name." String name,
"Scheduler state at the request moment." State state,
"List of the timers. Actual at the request moment." TimerInfo[] timers
) {
this.name = name;
this.state = state;
this.timers = timers;
}

"Instantiates `SchedulerInfo` from JSON description as send by _Chime_."
shared new fromJSON( "Scheduler info received from _Chime_." JSON schedulerInfo ) {
this.name = schedulerInfo.getString( Chime.key.name );
"Scheduler info replied from _Chime_ has to contain state field."
assert( exists state = stateByName( schedulerInfo.getString( Chime.key.state ) ) );
this.state = state;
if ( exists arr = schedulerInfo.getArrayOrNull( Chime.key.timers ) ) {
timers = arr.narrow<JSON>().map( TimerInfo.fromJSON ).sequence();
}
else {
timers = [];
}
}

shared actual String string => "Scheduler ``name``, ``state``";

}
39 changes: 39 additions & 0 deletions source/herd/schedule/chime/Timer.ceylon
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@


"Wraps event bus to provide exchanging messages with previously created timer.
The object implementing interface is returned by [[Scheduler.createIntervalTimer]]
and [[Scheduler.createCronTimer]].
Timer is sent timer fire or complete events with [[TimerEvent]].
To set timer event handler call [[handler]].
> Complete event is always published.
"
see( `interface Scheduler` )
since( "0.2.0" ) by( "Lis" )
shared interface Timer {

"Full name of the timer, i.e. \"scheduler name:timer name\"."
shared formal String name;

"Stops and removes this timer."
shared formal void delete();

"Pauses this timer."
see( `function resume` )
shared formal void pause();

"Resumes this timer after pausing."
see( `function pause` )
shared formal void resume();

"Requests timer info."
shared formal void info( "Info handler." Anything(Throwable|TimerInfo) info );

"Sets the handler for the timer events. Replaces previous one if has been set."
shared formal void handler( Anything(TimerEvent) handler );

"Unregister the handler from the event bus, while keep timer alive."
shared formal void unregister();

}
Loading

0 comments on commit 0c69d8f

Please sign in to comment.