Click here to Skip to main content
15,888,803 members
Articles / Web Development / HTML

LinkSet – An Alternative Approach to Events Java

Rate me:
Please Sign up or sign in to vote.
4.00/5 (9 votes)
4 Aug 2015LGPL33 min read 33.4K   295   8   9
LinkSet is a tiny library created in order to relieve programmers from declaring listener interfaces.

Introduction

LinkSet is a tiny library created in order to relieve programmers from declaring listener interfaces. It utilizes Java 5 features and was designed to be a drop in replacement for a conventional “listener interface + anonymous class” solution.

Java is a great language, much cleaner than C#. But it lags behind in the area of listeners. Every time I did some programming in C#, I thought: "I wish Java had delegates." I also liked the Qt’s signal/slot approach. Some time ago, I thought: "Can I create something cleaner and easier to use than those syntactically horrible anonymous classes?" This way LinkSet (github.com/lbownik/linkset) was born. LinkSet is a little library that utilizes Java 5 features to provide a simple to use mechanism of listeners that doesn't require either listener interfaces, or anonymous classes.

Features of LinkSet

When I was designing LinkSet, I wanted it to be:

  1. Simple to use - the usage of a library should impose as little programming effort as possible. This means: no listener interfaces required and no special build steps needed.
  2. Flexible - both instance and static methods can be event handlers.
  3. Noninvasive – it does not require an event handling object to implement any particular interface and the event handling method can be private.
  4. Easy to learn – it consists of only a few intuitive classes to use
  5. Small and reasonably fast
  6. Free - LGPL license

I hope that I met those requirements.

Working with LinkSet

To get started with LinkSet, you need to go to the project’s website (github.com/lbownik/linkset) and download the jar file. Then it is enough to include it into your project’s class path.

Event Source

LinkSet was designed to simplify the development of both event source and event handler classes. The following code presents a class that is a source of events.

This code shows how to implement a class that can be observed by listeners.

Java
package com.mycompany.project1;

import org.linkset.DefaultListenerManager;
import org.linkset.ListenerManager;
import org.linkset.MethodPointer;

public class EventSource {

    // a multi-listener manager
    private final DefaultListenerManager clickListeners = 
       new DefaultListenerManager();
    // a single listener pointer - useful when a return value is
    // needed
    private MethodPointer vetoableListener;

    // some constants
    public final static int LeftButton = 0;
    public final static int RightButton = 1;

    public ListenerManager clickdListeners() {
        
        return this.clickListeners;
    }

    public void setVetoableListener(MethodPointer pointer) {

        this.vetoableListener = pointer;
    }

    public void doStuff() throws Exception {

        //fire click event
        this.clickListeners.invokeAll(LeftButton);

        // check if we can change state if we want to
        final boolean canChangeState
           (Boolean)this.vetoableListener.invoke();
        if(canChangeState == true) {

        }
    }
}

The class declares two private fields. The clickListeners is an object of a class DefaultListenerManager. This class is a collection of event handlers that should be invoked when an event occurs. The method clickListeners() allows clients to connect its handlers via add(…) method defined in ListenerManager interface. This way a client can easily connect to an event source using the code like:

Java
Source.clickListeners().add(….);

The second field called vetoableListener is an object of a MethodPointer class. This class implements an events handler method pointer that can be used when exactly one listener is required and its return value is necessary in following computations (like in a vetoable observer pattern). The method setVetoableListener(...) allows a client to set the pointer reference. The method doStuff() contains code that invokes all listeners with appropriate invokeAll(…) and invoke(…) methods.

Event Handler

The following code shows how to implement a class that provides methods that listen to events.

Java
package com.mycompany.project1;

import org.linkset.HandlerMethod;
import org.linkset.MethodPointer;

public class EventHandler {

    private EventSource provider = new EventSource();
    public EventHandler() {

        // we set a reference to an object and handler method id
        this.provider.clickdListeners().add(this, "clickListener");

	// in case of static methods we need to pass a Class object
	// reference
	this.provider.setVetoablePointer(new
		MethodPointer(this.getClass(), "canChange"));
    }

    @HandlerMethod(id = "clickListener")
    private void clickListener(int button) {

        System.out.println("Button click=" + button);
    }

    @HandlerMethod(id = "canChange")
    private static boolean canChange() {

        System.out.println("Can change?");
        return false;
    }
    public static void main(String[] args) throws Exception {

        EventHandler handler = new EventHandler();
        handler.provider.doStuff();
    }
}

The class declares two methods. A private instance method clickListener(…) is a method that is called when a click event occurs. It is annotated with a HandlerMethod annotation with a unique id. This id is used by:

Java
this.provider.clickdListeners().add(this, "clickListener");

to point to a right method in a supplied object. The supplied identifier must be unique within a class scope, but can be reused in separate classes.

The private static method canChange() is called when a vetoableListener is called. The code:

Java
this.provider.setVetoableListener(new MethodPointer(this.getClass(),"canChange"));

set the pointer required by source object. It is notable that LinkSet requires a Class object as an event target when a static method’s id is supplied.

Summary

LinkSet library is a little Perl that was formed through a constant irritation caused by Java’s default way of handling events. It is small, simple and easy to use. It is a drop in replacement that does not require any new syntax constructs like closures.

History

  • 19th February, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Architect
Poland Poland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralHandling JButton Pin
Sonny Benavides19-Mar-10 10:22
Sonny Benavides19-Mar-10 10:22 
GeneralRe: Handling JButton Pin
Łukasz Bownik21-Mar-10 20:50
Łukasz Bownik21-Mar-10 20:50 
GeneralRe: Handling JButton Pin
Sonny Benavides23-Mar-10 5:28
Sonny Benavides23-Mar-10 5:28 
GeneralRe: Handling JButton Pin
Łukasz Bownik24-Mar-10 22:54
Łukasz Bownik24-Mar-10 22:54 
Generalcareful Pin
Stephen Swensen20-Feb-10 13:34
Stephen Swensen20-Feb-10 13:34 
GeneralRe: careful Pin
Łukasz Bownik22-Feb-10 8:54
Łukasz Bownik22-Feb-10 8:54 
) MethodPointer.equals does not guard against null obj argument.
Fixed in svn.

2) Why not use varargs for MethodPointer.invoke?
Fixed in svn.

3) In a lot of ways I like how you use the HandlerMethod annotation, but it rules out creating MethodPointers for 3rd party methods.
Good point. I'll think about that Smile | :)

4) LinkSet is a tantalizing name (I looked at this article because it caught my eye), but I can't figure out what it has to do with dynamic delegates / event listeners.

Well naming is always a problem. I thought aboud ListenerSet but it doesn't sound good so I shortened to LinkSet. The problem is that I don't own a linkset.org domain, so org.linket part of package name will have to be changed (well as open source guys say "release early, release broken" Wink | ;-)

5) C# is vastly superior to Java, and because of Java's shoddy generics implementation (erasure) and non-unified type system (primitives), it will always, always, always be a lot less "clean" than C# (not to mention Java's lack of support for first-class functions, operator overloading, explicit and implicit conversion operators, and dynamic expressions).

Well thay say that "one man's feature is another man's bloat". I came from Java to C# ans it feels a little too wity to me. I prefer languagles with less "behind the scenes" stuff. An Java 5 is less "behind the scenes" than c# 3.5 so It's cleaner to me.

As for primitives in Java- I think that c#'s value types make the same mess but the other way round Smile | :)

6) I too am horrified by Java's lack of support for first-class functions, and while I considered a dynamic approach as you have, I opted to develop a unified generic set of functors instead: Functional Java[^]

Thanks. I'll read it.
GeneralRe: careful Pin
CurtainDog22-Feb-10 15:30
CurtainDog22-Feb-10 15:30 
QuestionHow dare you? Pin
César de Souza20-Feb-10 3:17
professionalCésar de Souza20-Feb-10 3:17 
GeneralMy vote of 1 Pin
Alexander Müller20-Feb-10 0:11
Alexander Müller20-Feb-10 0:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.