Monday, August 24, 2009

The making of an OSGI based IRC Bot

I've released the source code of JerkBot, an IRC bot based on Jerklib and OSGI. JerkBot source code is a multi-module maven project. It's not some OSGI/Java blueprints as I'm no OSGI expert, plus JerkBot is basically a 24 hours effort without bug fixes.

The library itself is distributed under BSD license, but the bot provides plugins such as SVN for example using SVNKit , which is subject to other licensing terms.

The bot uses Declarative Services for OSGI and Java technologies such as :

  • Apache Lucene for Javadoc Search
  • Quartz for job scheduling(session tracking, pending registrations, etc.)
  • Javamail to send emails for user registration
  • EclipseLink for persistence
  • A subset of JAAS for security
  • JMX for administrative commands (accessible through JConsole or through the bot jmx command)
  • The usual Jakarta libraries and couple of other libraries

I didn't provide scripting languages to the bot for security reasons, there's only JMX. I would prefer to offer scripting languages in a secure way with a custom SecurityManager to prevent drama from happening :-).
Let's say scripting is enabled, and someone accidently tries one or all the following instructions in a scripting language.

  • File("/somepath").delete()
  • System.exit(0)
  • Download("http://website/hugefile.iso").saveToDisk();

JerkBot was roughly a one day effort with 4 rewrites(1 full day each), and of course bug fixes time to time:
  • The first version was using traditional OSGI, well not so traditional :-), with BundleActivators service trackers and listeners, etc.
  • The second rewrite used Declarative Services with manually written XML descriptors
  • The third rewrite was based on Felix IPOJO. I would have preferred to use IPOJO, but found some annoyances(abstract based classes, JMX flexibility, etc.).
  • The last rewrite is using Felix SCR but with annotations to generate XML descriptors for components. Simplify code, remove unnecessary abstractions, consistent logic, etc.

I'll be providing the binary distribution soon. The binary distribution contains everything necessary to run the bot : OSGI configuration files, Bot configuration, jars, a user/developer guide, etc.

What the bot doesn't provide is a logging mechanism, for IRC channel logs. To do it right, I think it would be better to create a new project. In my opinion, when a bot logs channel it should have, if possible, the following features:

  • Configurable tasks to schedule flexible timed delivery of existing logs(local filesystem, ftp, samba share, ssh, http put, etc.)
  • Configurable log format(HTML, CSV, TXT) with optional generation of html logs or text logs.
  • Database storage or any other persistence mechanism(Apache Lucene Index vs flat text files, database logs, etc.)
  • Ability to stop/start logging for every channel
  • Optional Web front-end to publish logs(Could be a static HTML pages with Javascript search, JSF, Wicket, GWT, Rest interface + Apache Lucene or a DB for search).
Providing a quick and dirty plugin for channel logs would be trivial but not flexible :-). I started implementing it, but I decided to stop there.

The first draft of the bot manual can be found in the svn repository. Please bear with me for grammar and spelling mistakes, it was a written very quickly at early AM :-)

In JerkBot plugins are provided by OSGI bundles. I learned a lot from my previous experience with JPF when writing XPontus.

For now the bot is sitting on irc.freenode.net in the ##swing channel, running on an old laptop(FreeBSD-CURRENT).


6 comments:

MaZe said...

Good job

Clement said...

Hi,
I say that you have some issues with iPOJO. Can you give more details about that?
If I understand correctly, you was looking for abstract classes support (iPOJO support method-based injection inside abstract classes, but not field injection), and JMX support.

Yves Zoundi said...

Instance annotation for components
I'm not sure how complicated it would be. I don't mind XML, I've worked a lot with it and wrote an XML editor.

However, I would've liked to be able to specify an @Instance annotation to prevent me from writing XML code, as I was planning to use annotations only. I was expecting IPOJO to be able to take care of it by itself :-).

Abstract services definitions
I was looking for abstract services definition using abstract classes and found a post in the mailing list. I am using the trunk version of Felix, but couldn't define abstract classes as services.

In SCR there's a definition/annotation attribute : @Service(componentAbstract=true). I tried specifying the 'target' attribute in the @Provide annotation in vain. If only the @Component annotation supported something like 'componentAbstract', as a helper. Whatever I tried didn't work, and believe me I tried but didn't ask for help on the mailing lists.

JMX
1 - Injection in JMX POJO
In SCR, I'm using services injection inside MBeans interface implementations. Using IPojo, I had issues getting it to work, components were not getting injected in the exposed POJO.

2 - Annotation retention
Another nice feature to have in IPOJO would be being able to extend an abstract class and have some runtime retention for the @Config annotation.

// annotations here
public class Test extends BaseJMXComponent implements MBeanRegistration{

... void postRegister{
Class config = class.findAnnotation(config.class)
// kind of interceptor to make the bot aware of the bean
doCustomThingsWithObjectNameOrName(config.name(), config.objectname());
}

}


3 - optional binding wrapper in JMX POJO
What I have right now, is my own MBeanServer service and some interceptors, instead of implementing a NotificationListener and looking for a custom property in the object name definition.
Basically, I wanted to be able to register MBeans using a base class, and intercept the registration without coding. I'm not sure that I'm giving enough details here, see below, my current implementation:

BotJMXRegistryService{
addBotManagedBean(MBeanWithObjectNameAlias); // equivalent to the bind annotation in IPojo
// This registers the MBean to the MBean server and put an alias to the objectname in a hashmap.
// when the component is removed, I unbind/remove from the hashmap

// not what I have, but to give you an idea
JMXUtil.beforeMethodCall(OjbectNameNick, MBean, operationName, ...)
}


In the bot, I can do something like :
jmx mbeanObjectNameAlias.sayHello()

My interceptors can prevent the sayHello method from being called, if for example, the admin isn't a member of a given group.

Yves Zoundi said...

Just a note, I did browse your blog, while coding with IPOJO too.

Thanks for your comments and publishing some news about IPOJO.

Clement said...

Hi, thanks for the feedbacks. Just a some comments:

The instance annotation will break the separation between component type and instance. At the beginning it was considered. Allowing this is just like creating a Java class declaring the instance of this class inside the class itself. We are working on a better File Install support, and a Web Console plugin to create instances.

Abstract Classes would be great and is under consideration since a couple of month. It might be developed in the next version. These is two things. One is to define abstract component type declaration extended by the 'concrete' component type declaration. It is mostly a copy - paste. The second things (really more complex), is to define a component type with an abstract class and to 'extend' it. The issue is not about method injection (already supported), but about field injection and the meaning of the inheritance in such case (the parent class declares a field for a service dependency overridden by the concrete class). So the semantic is not clear, and not supporting such case is just too limited. Last issue, what happens when the abstract type is not in the bundle, and so does not have the same bundle context...

Finally about JMX, everything is fixed by the JMX handler (http://felix.apache.org/site/ipojo-jmx-handler.html). We managed mostly everything with JMX. In fact, managing the JMX exposition yourself is generally a bad pattern as you: mix some technical code with your business code and do not necessary know which MBean Server to use (JVM, MOSGi, one exposed as a service...). The handler manages the exposition for you as well as the callbacks (that you need), the notifications, the reconfiguration... Did you try it? If so, if you had issue with that one, fell free to send me those issues, we will fix it ASAP.

Clement

Yves Zoundi said...

Hello Clement,

Thanks, I'll give IPojo another try soon.