3

I know it's not directly possible to serialize a function/anonymous class to the database but what are the alternatives? Do you know any useful approach to this?

To present my situation: I want to award a user "badges" based on his scores. So I have different types of badges that can be easily defined by extending this class:

class BadgeType(id:Long, name:String, detector:Function1[List[UserScore],Boolean])

The detector member is a function that walks the list of scores and return true if the User qualifies for a badge of this type.

The problem is that each time I want to add/edit/modify a badge type I need to edit the source code, recompile the whole thing and re-deploy the server. It would be much more useful if I could persist all BadgeType instances to a database. But how to do that?

The only thing that comes to mind is to have the body of the function as a script (ex: Groovy) that is evaluated at runtime.

Another approach (that does not involve a database) might be to have each badge type into a jar that I can somehow hot-deploy at runtime, which I guess is how a plugin-system might work.

What do you think?

Cristian Vrabie
  • 3,972
  • 5
  • 30
  • 49
  • 3
    What do I think? I think you should ask a more specific question than "what do you think?" – Michael Lorton Jan 12 '12 at 18:43
  • @Malvolio I thought it was clear that the final line was just an accentuation of the actual questions that I posted clearly enough at the beginning: "what are the alternatives? Do you know any useful approach to this?" It's a common idiom in communication not to repeat oneself. It seems other people did read the question more carefully because I did got some great answers so far that were spot on. – Cristian Vrabie Jan 13 '12 at 09:14

3 Answers3

3

My very brief advice is that if you want this to be truly data-driven, you need to implement a rules DSL and an interpreter. The rules are what get saved to the database, and the interpreter takes a rule instance and evaluates it against some context.

But that's overkill most of the time. You're better off having a little snippet of actual Scala code that implements the rule for each badge, give them unique IDs, then store the IDs in the database.

e.g.:

trait BadgeEval extends Function1[User,Boolean] {
  def badgeId: Int
}

object Badge1234 extends BadgeEval {
  def badgeId = 1234
  def apply(user: User) = {
    user.isSufficientlyAwesome // && ...
  }
}

You can either have a big whitelist of BadgeEval instances:

val weDontNeedNoStinkingBadges = Map(
  1234 -> Badge1234,
  5678 -> Badge5678,
  // ...
}

def evaluator(id: Int): Option[BadgeEval] = weDontNeedNoStinkingBadges.get(id)

def doesUserGetBadge(user: User, id: Int) = evaluator(id).map(_(user)).getOrElse(false)

... or if you want to keep them decoupled, use reflection:

def badgeEvalClass(id: Int) = Class.forName("com.example.badge.Badge" + id + "$").asInstanceOf[Class[BadgeEval]] 

... and if you're interested in runtime pluggability, try the service provider pattern.

Alex Cruise
  • 7,939
  • 1
  • 27
  • 40
  • Thanks for the great response! The first part is just what I have now but it does not solve the fact that when I want a new badge type I need to recompile the whole thing. Service Provider is the thing that I was looking for. I guess that on the same line of thought a custom ClassLoader would suffice, in case it's simpler to implement. – Cristian Vrabie Jan 13 '12 at 10:07
1

You can try and use Scala Continuations - they can give you the ability to serialize the computation and run it at later time or even on another machine.

Some links:

Continuations

What are Scala continuations and why use them?

Swarm - Concurrency with Scala Continuations

Community
  • 1
  • 1
Rogach
  • 26,050
  • 21
  • 93
  • 172
0

Serialization relates to data rather than methods. You cannot serialize functionality because it is a class file which is designed to serialize that and object serialization serializes the fields of an object.

So like Alex says, you need a rule engine.

Try this one if you want something fairly simple, which is string based, so you can serialize the rules as strings in a database or file:

http://blog.maxant.co.uk/pebble/2011/11/12/1321129560000.html

Using a DSL has the same problems unless you interpret or compile the code at runtime.

Ant Kutschera
  • 6,257
  • 4
  • 29
  • 40