Callback

I'm trying to implement a callback in Java (like in C++), and wondering what the best way of doing this is.

Let's say I have a class called CallBack, and a main class called Test.

class Test {
  CallBack callback;
  public static void main(String[] args) throws Exception{
    Test test = new Test();
    test.initCallback();
    Thread.sleep();
  }

  void initCallback() {
    callback = new Callback();
    callback.start();
  }

  void callbackMethod() {
    System.out.println("called from callback");
  }
}

Class CallBack extends Thread {
  public void run() {
    while(true) {
      sleep(10000);
      //call the callback method in Test
    }
  }
}

Now I realize the easiest way to do this is to pass a reference to the Test class to the CallBack class.  I was CallBack to be completely encapsulated though, so it can work as a callback to any class.

Now I was thinking to maybe have the Test class implement some interface that defined in it a callback method.  Anyways, Im looking for ideas that I havnt thought of yet, or if there is some accepted way of doing this that I havn't heard of.
 
LVL 5
lwinkenbAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

CEHJCommented:
This is a variant on the Observer pattern, which of course already exists in the API:

http://java.sun.com/j2se/1.4.2/docs/api/java/util/Observer.html

and

http://java.sun.com/j2se/1.4.2/docs/api/java/util/Observable.html

but you're using a Runnable. Is that always going to be the case?
0
objectsCommented:
> Now I was thinking to maybe have the Test class implement some interface
> that defined in it a callback method.

Yes thats the general way to handle it.
You just define some interface with your callback method, and pass implementations of that to any class that needs to make callback.

0
kotanCommented:
Pass the Test object into CallBack class. Then, callbackMethod() can be called by Test object reference in CallBack class.

class Test {
  CallBack callback;
  public static void main(String[] args) throws Exception{
    Test test = new Test();
    test.initCallback();
    Thread.sleep();
  }

  void initCallback() {
    callback = new Callback(this);
    callback.start();
  }

  void callbackMethod() {
    System.out.println("called from callback");
  }
}

Class CallBack extends Thread {
  Test test;
  public CallBack(Test test) {
     this.test = test;
  }

  public void run() {
    while(true) {
      sleep(10000);
      //call the callback method in Test
      test.callbackMethod();
    }
  }
}
0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

objectsCommented:
interface MyCallback
{
   public void callbackMethod();
}

class Test implements MyCallback {
  CallBack callback;
  public static void main(String[] args) throws Exception{
    Test test = new Test();
    test.initCallback();
    Thread.sleep();
  }

  void initCallback() {
    callback = new Callback(this);
    callback.start();
  }

  void callbackMethod() {
    System.out.println("called from callback");
  }
}

Class CallBack extends Thread {
  private MyCallback cb;
  public CallBack(MyCallback cb) {
    this.cb = cb;
  }

  public void run() {
    while(true) {
      sleep(10000);
      cb.callbackMethod();
    }
  }
}

0
CEHJCommented:
Of course, if you use the API and don't reinvent the wheel, you can simply get your class to implement the Observer interface, and then you do not need to limit the type of what you want called back.
0
objectsCommented:
If you wanted something more generic you could also use reflection and just pass the name of the method you wanted to execute.
eg. to callback any method that takes no args you'd do something like:

class Test {
  CallBack callback;
  public static void main(String[] args) throws Exception{
    Test test = new Test();
    test.initCallback();
    Thread.sleep();
  }

  void initCallback() {
    callback = new Callback(this, "callbackMethod");
    callback.start();
  }

  void callbackMethod() {
    System.out.println("called from callback");
  }
}

Class CallBack extends Thread {
  private Object tocb;
  private Method cb;
  public CallBack(Object tocallback, String methodname) throws Exception {
    tocb = tocallback;
    this.cb = tocb.getMethod(methodname, null);
  }

  public void run() {
    while(true) {
      sleep(10000);
      cb.invoke(tocb, null);
    }
  }
}
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
objectsCommented:
Observer/Observable classes are really not designed for implementing callbacks.
0
CEHJCommented:
So what do think is going on when notifyObservers() or notifyObservers(Object o) gets called?
0
lwinkenbAuthor Commented:
Thanks for the fast replies guys, looking over the responses now.  I'll answer the quick questions first though:

>>but you're using a Runnable. Is that always going to be the case?
Not always.  Actually what I want is for the CallBack class to load a JNI class which will provide it's own callback to the CallBack class.  Then CallBack will call the Test class.  In this case it would not use Runnable.  I just used Runnable to make my example a bit simpler.

>>Pass the Test object into CallBack class.
That would defeat the whole encapsulation idea.  In my origonal post I stated why this wouldn't work.

CEHJ and Object >> Going to look over your idea's now.
0
objectsCommented:
> So what do think is going on when notifyObservers() or notifyObservers(Object o) gets called?

Well you can call any method call a callback using that logic :-D

From the Observer javadoc:

"A class can implement the Observer interface when it wants to be informed of changes in observable objects."

a. we are not necessarily interested in changes in objects
b. we are not dealing with observable objects

You could certainly shoehorn the Observer/Observable classes to perform the callbacks but it would certainly not be an optimal solution and would be unnecessarily limiting.

0
CEHJCommented:
You should also be careful about tight coupling/circular references. At the moment you have

a. a reference to a Callback in Test
b. an implied reference to Test in Callback (the latter needs to call a method in the former)
0
jimmackCommented:
I'm late to the game on this one, but on balance, I think I side with CEHJ.

I'm not sure why you qualified your initial comment with regards to the Runnable interface.

>> b. an implied reference to Test in Callback (the latter needs to call a method in the former)

Surely all implementations of callbacks will rely on this to some extent.  Even with the Observer/Observable, the update method has to be called.

However, it is more general than using the specific interface.
0
objectsCommented:
> However, it is more general than using the specific interface.

Surely an approach that allows you to define the exact callback that you want to use would be preferable to using a generic interface that may not meet your needs. And what if you had different methods that needed to be called depending on circumstance.
Using Observer would also require any class that wants to use it to extend Observable which is another unnecesary limitation, which may in fact preclude it's use in some cases.

0
lwinkenbAuthor Commented:
>>You should also be careful about tight coupling/circular references.
This is exactly what I am trying to avoid.  This is why I dont want to have any sort of reference to the Test class in my CallBack class.

>> an implied reference to Test in Callback
I'm not sure exactly what you mean by implied reference.  
>> (the latter needs to call a method in the former)
Isnt this exactly what a callback is in the first place?

Maybe I need to clarify a little bit here.

In c++ you would accomplish this task by doing something like:

//this code is in the test class
Callback callback = new Callback("myMethodInTest");

Then in your test class you would have the method myMethodInTest declared.

Another way is you could pass Callback a pointer to the function in test.

0
lwinkenbAuthor Commented:
Objects >> I like the idea of using reflection, but what if the method takes arguments?  Would it still work?
0
jimmackCommented:
>> And what if you had different methods that needed to be called depending on circumstance.

Isn't this why the update method can take an object as a parameter.  (Bit of a stretch, less efficient, but more general ;-))

Can anyone clarify why CEHJ qualified the first comment?  Why does the use of Runnable make a difference?
0
objectsCommented:
> Another way is you could pass Callback a pointer to the function in test.

Thats basically what my first example does.

> but what if the method takes arguments?

Then you need to also pass any array specifying the parameter types.
0
objectsCommented:
> Why does the use of Runnable make a difference?

It doesn't.
0
lwinkenbAuthor Commented:
Thanks for the comments everyone.  I think Reflection is the way I'm going to go with this, because it provides the most flexibility.

Thanks for all the help.
0
objectsCommented:
0
CEHJCommented:
>>Can anyone clarify why CEHJ qualified the first comment?

Well, it's not that it would make any difference if it were a Runnable or not. I just thought the final form might be different and was trying to get a bit closer to that.
A false emphasis ;-)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.