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:
PulsingComponentMonitorComponentListeningComponent(optional)
The explanation of these components are given on the Monido github page:
A
PulsatingComponentis something that wakes the MonitorComponent to do something. APulsatingComponentcould wake it at set intervals, once a day, manually, etc. TheMonitorComponentwill simply monitor whatever it was told to monitor (TheFileMonidoreference 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