I've been working on a little project called Monido, which is simply a monitoring service for Scala. It can monitor anything from a file, a directory, a DB table, or web page. I think you get the picture.
The project, however, only ships with a single reference implementation to monitor the file system for changes. I'm using it for this very post at this moment. More on that later.
The Program
I explained in an earlier post that I write my blog entries in markdown,
and store them in a git repo. I have since modified that BloggerBot
script
to only inject the html source in my clipboard when it runs. The command looks like:
java -jar blogbot.jar ~/notes/posts/24.md
Monido can automate this procedure:
monido ~/notes/posts -e java -jar blogbot.jar
Every time I save this post, I get:
Writing conversion to your clipboard .... Done.
This saves me a few key strokes!
The -e
argument for monido is essentially like using the pipe
for a Unix system.
The full file path of the changed file is passed to the terminal argument, and immediately
run. Monido defines itself as a pure JVM, cross-platform solution to file monitoring.
monido ~/some/other/thing -e ls -l
Monido can spawn recursive monitors, although this practice is discouraged on using a large directory tree. Your operating system does this for you, so you should use that instead. Jnotify is a good Java wrapper around these OS events.
Monido is not just a file monitoring service, though! This is where the good part begins.
The Library
Monido's infrastructure is very flexible, being that it's comprised of two (optionally three), components. These components are:
PulsingComponent
MonitorComponent
ListeningComponent
(optional)
The explanation of these components are given on the Monido github page:
A
PulsatingComponent
is something that wakes the MonitorComponent to do something. APulsatingComponent
could wake it at set intervals, once a day, manually, etc. TheMonitorComponent
will simply monitor whatever it was told to monitor (TheFileMonido
reference implementation monitors the file system.) Optionally, the Monitor can notify a client of a change (or anything else really) by making use of theListeningComponent
.Lots of moving parts that have arbitrary dependencies make it a great candidate for some DI.
Now, I will show you how to do a DBMonido
, just for fun.
import com.github.philcali.monido._ // First we need to define the DBMonitor by extending the // MonitorComponent. trait DBMonitorComponent extends MonitorComponent { this: ListeningComponent[Adapter] => // Let is connect via a db string class DBMonitor(db: String) extends SimpleMonitorDevice{ def connect: Adapter = // connect to db def pulsed { // Making a fictional query val results = connect.query("SELECT COUNT(id) as count from entries") if(results("count") >= 9000) listener.changed(connect) } } } // Define Monido now object DBMonido extends Monido with ListeningComponent[Adapter] with DBMonitorComponent with PulsatingComponentImpl { // This object will NOT compile until dependencies are met val listener = new MonidoListener { def changed(db: Adapter) { // Clear records db.query("TRUNCATE entries") } } // the MonitorComponent expects a monitor value to be defined val monitor = new DBMonitor("jdbc:sqlite:test.db") // Next the PulsatingComponent expects a pulsar value to be defined // Sneal peak at 0.2 Scalendar syntax import com.github.philcali.scalendar._ val pulsar = new Pulsar(1.day.inMillis) } DBMonido.start // And we're off!
This is a pretty silly example of checking a record once a day for the change you're
looking for, but now I'll show you how easy it is to configure the Monido. Say now
I wanted to use a different pulsating implementation. I'll use a fictitious
CronPulsing
implementation that uses a cron string for its configuration.
// Re-define the DB monido object DBMonido extends Monido with ListeningComponent[Adapter] with DBMonitorComponent with CronPulsing { ... // same as before. The monitoring component worked great, so // leave it alone. // Sneak peak at the cron project import com.github.philcali.cron._ val pulsar = new CronPulsar("every Sunday at midnight".cron) } DBMonido.start // And we're off!
So there's your Monido
. I don't know how useful it could be to everyone
else, but I find myself in need of Monido
's pretty often.
-- Philip
smells like the cake pattern to me
ReplyDeleteGot a Scala question for you. In this line:
def connect: Adapter = // connect to db
The capital A in adapter is throwing me off. What does this line do?
Oh this wasn't meant to be confusing, but I see how it was...
ReplyDeleteI was making up a fake db adapter code that I was too lazy to come up with fake implementation for or say that it's fake.
So in the above context, the method "connect" would return a db adapter defined by the db string. This fictional db Adapter object has the "query" method that interacts with a relational database.
I wrote this post on little sleep... I should probably never do that :P