Solved

Callback

Posted on 2003-11-03
21
937 Views
Last Modified: 2008-03-10
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.
 
0
Comment
Question by:lwinkenb
  • 9
  • 5
  • 4
  • +2
21 Comments
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
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
 
LVL 92

Expert Comment

by:objects
Comment Utility
> 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
 
LVL 6

Expert Comment

by:kotan
Comment Utility
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
 
LVL 92

Expert Comment

by:objects
Comment Utility
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
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
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
 
LVL 92

Accepted Solution

by:
objects earned 500 total points
Comment Utility
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
 
LVL 92

Expert Comment

by:objects
Comment Utility
Observer/Observable classes are really not designed for implementing callbacks.
0
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
So what do think is going on when notifyObservers() or notifyObservers(Object o) gets called?
0
 
LVL 5

Author Comment

by:lwinkenb
Comment Utility
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
 
LVL 92

Expert Comment

by:objects
Comment Utility
> 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
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
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
 
LVL 15

Expert Comment

by:jimmack
Comment Utility
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
 
LVL 92

Expert Comment

by:objects
Comment Utility
> 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
 
LVL 5

Author Comment

by:lwinkenb
Comment Utility
>>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
 
LVL 5

Author Comment

by:lwinkenb
Comment Utility
Objects >> I like the idea of using reflection, but what if the method takes arguments?  Would it still work?
0
 
LVL 15

Expert Comment

by:jimmack
Comment Utility
>> 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
 
LVL 92

Expert Comment

by:objects
Comment Utility
> 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
 
LVL 92

Expert Comment

by:objects
Comment Utility
> Why does the use of Runnable make a difference?

It doesn't.
0
 
LVL 5

Author Comment

by:lwinkenb
Comment Utility
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
 
LVL 92

Expert Comment

by:objects
Comment Utility
0
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
>>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

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

For beginner Java programmers or at least those new to the Eclipse IDE, the following tutorial will show some (four) ways in which you can import your Java projects to your Eclipse workbench. Introduction While learning Java can be done with…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
Viewers will learn about arithmetic and Boolean expressions in Java and the logical operators used to create Boolean expressions. We will cover the symbols used for arithmetic expressions and define each logical operator and how to use them in Boole…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now