I've looked at the java tutorials online and they all seem concerned with catching ActionEvents given out by other components that are already written. Is it possible to write your own objects that have there own set of criteria that trigger actionEvents that can then be caught by other classes that have registered as listeners?
So for example: If I wanted an object that was counting sheep to send out an actionEvent when 100 sheep had been counted to all the sleeper objects that had registered as listeners.
Is there a way to do this are there any tutorials online?
Any help is greatly appreciated.
Yes, it's pretty straightforward, once someone shows you how to create your own listeners.
First, you create your own EventObject. Here's an example from one of my projects.
import gov.bop.rabid.datahandler.bean.InmateDataBean;
import java.util.EventObject;
public class InmatePhotoEventObject extends EventObject {
private static final long serialVersionUID = 1L;
protected InmateDataBean inmate;
public InmatePhotoEventObject(Object source) {
super(source);
}
public InmateDataBean getInmate() {
return inmate;
}
public void setInmate(InmateDataBean inmate) {
this.inmate = inmate;
}
}
There's nothing special about this class, other than it extends EventObject. Your constructor is defined by EventObject, but you can create any methods you want.
Second, you define an EventListener interface.
public interface EventListener {
public void handleEvent(InmatePhotoEventObject eo);
}
You would use the EventObject you created. You can use any method name or names that you want. This is the interface for the code that will be written as a response to the listener.
Third, you write a ListenerHandler. Here's mine from the same project.
import gov.bop.rabid.datahandler.bean.InmateDataBean;
import gov.bop.rabid.datahandler.main.EventListener;
import gov.bop.rabid.datahandler.main.InmatePhotoEventListener;
import gov.bop.rabid.datahandler.main.InmatePhotoEventObject;
import java.util.ArrayList;
import java.util.List;
public class InmatePhotoListenerHandler {
protected List<EventListener> listeners;
public InmatePhotoListenerHandler() {
listeners = new ArrayList<EventListener>();
}
public void addListener(EventListener listener) {
listeners.add(listener);
}
public void removeListener(EventListener listener) {
for (int i = listeners.size() - 1; i >= 0; i--) {
EventListener instance = listeners.get(i);
if (instance.equals(listener)) {
listeners.remove(i);
}
}
}
public void fireEvent(final InmatePhotoEventObject eo,
final InmateDataBean inmate) {
for (int i = 0; i < listeners.size(); i++) {
final EventListener instance = listeners.get(i);
Runnable runnable = new Runnable() {
public void run() {
eo.setInmate(inmate);
instance.handleEvent(eo);
}
};
new Thread(runnable).start();
}
}
public static void main(String[] args) {
System.out.println("This line goes in your DataHandlerMain class "
+ "constructor.");
InmatePhotoListenerHandler handler = new InmatePhotoListenerHandler();
System.out.println("I need you to put the commented method in "
+ "DataHandlerMain so I can use the handler instance.");
// public InmatePhotoListenerHandler getInmatePhotoListenerHandler() {
// return handler;
// }
System.out.println("This line goes in the GUI code.");
handler.addListener(new InmatePhotoEventListener());
System.out.println("Later, when you've received the response from "
+ "the web service...");
InmateDataBean inmate = new InmateDataBean();
inmate.setIntKey(23);
handler.fireEvent(new InmatePhotoEventObject(handler), inmate);
}
}
The main method in this class shows you how you use a ListenerHandler. The rest of the methods in the class are standard. You would use your own EventObject and EventListener.
Yes.
I suggest you look at the java API documentation for ActionEvent and EventListenerList.
I also suggest that you read about the Listener (also called Observer) pattern.
Related
This question already has answers here:
Create a custom event in Java
(6 answers)
Closed 5 years ago.
I want to write a simple event handling solution in Java with custom events. I've only find GUI based examples, using ActionListeners so far. I've included a code, that I wrote in C#.
I want to create something like this in Java:
using System;
using System.Threading;
namespace EventHandlingPractice
{
class Program
{
static void Main(string[] args)
{
MusicServer mServer = new MusicServer();
Sub subber = new Sub();
mServer.SongPlayed += subber.SubHandlerMethod;
mServer.PlaySong();
Console.ReadKey();
}
}
// this class will notify any subscribers if the song was played
public class MusicServer
{
public event EventHandler SongPlayed;
public void PlaySong()
{
Console.WriteLine("The song is playing");
Thread.Sleep(5000);
OnSongPlayed();
}
protected virtual void OnSongPlayed()
{
if (SongPlayed != null)
SongPlayed(this, EventArgs.Empty);
}
}
// this class is class is the subscriber
public class Sub
{
public void SubHandlerMethod(object sender, EventArgs e)
{
Console.WriteLine("Notification from: " + sender.ToString() + " the song was played");
}
}
}
In Java you generally create an class for the event itself, extending from EventObject. The events of interest are defined in an interface ending with the name Listener, extending the interface EventListener.
The class which is able to broadcast events has a add/remove listener methods, where the interested party can register themselves.
Your code will work without following these conventions though, but they are (were?) meant for tools to understand names of the classes and methods.
Here a sample pseudo implementation for your domain:
public class Song {
}
public class SongEvent extends EventObject {
private final Song song;
public SongEvent(Object source, Song song) {
super(source);
this.song = Objects.requireNonNull(song);
}
public Song getSong() {
return song;
}
}
public interface SongListener extends EventListener {
default void songStarted(SongEvent event) { }
default void songPaused(SongEvent event) { }
}
public class SongServer {
private List<SongListener> listeners = new ArrayList<>();
public void addSongListener(SongListener listener) {
listeners.add(listener);
}
public void removeSongListener(SongListener listener) {
listeners.remove(listener);
}
public void playSong(Song song) {
// ....
SongEvent event = new SongEvent(this, song);
listeners.forEach(l -> l.songStarted(event));
}
}
public class MyEventHandler implements SongListener {
#Override
public void songStarted(SongEvent e) {
System.out.printf("Now listening to %s%n", e.getSong().getName());
}
}
In previous versions of Java it was standard to include an Adapter (SongAdapter) which would implement the listener interface as no-op operations. The reason for that was that if you would add events classes that extended from the adapter didn't need to add code. With Java 8 you can include default methods, so the Event Adapter pattern is not needed anymore.
I'm a Java student and this is my attempt of implementing a StackExchange (there's a pusher thread and a popper thread, a single stack resource and two controlling Threads for the stack content and time passing).
I was hoping if someone could comment my code for improvements or errors\bad practices, even if the code seems to work.
The main reason of this program was to figure out how to control resource access in a multithreading environment.
I have concerns about the use of the ScheduledThreadPoolExecutor rather than locking(the stack), and my usage of synchronized in the StackExchange class methods(for accessing the stack), I would like to spawn free threads working on a dynamically locked resource. Any advice?
NB:"Format of magic numbers and syso's may be awful for testing porpuses
code here:
package examples;
import java.util.Random;
import java.util.Stack;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.JOptionPane;
public class StackExchange {
/*
* Two Threads playing with a stack, a timer and a controller for the stack that permits to exit
* */
public class Popper implements Runnable
{
StackExchange sEx;
public Popper(StackExchange sex)
{
this.sEx=sex;
}
#Override
public void run() {
System.out.println("Popper: popping!\t"+sEx.getPeek());
sEx.callTheStack(this, null);
}
}
public class Pusher implements Runnable
{
StackExchange sEx;
public Pusher(StackExchange sex)
{
sEx=sex;
}
#Override
public void run() {
System.out.println("Pusher: pushing!\t");
sEx.callTheStack(this, "Hi!");
}
}
public class StackController implements Runnable
{
private Stack<String> theStack;
public int waiting=5;
public StackController(Stack<String> theStack, String name) {
this.theStack = theStack;
Thread.currentThread().setName(name);
}
#Override
public void run()
{
Random rand = new Random();
waiting = rand.nextInt(10);
StringBuilder buffer = new StringBuilder();
int i=0;
for(String string: theStack)
{
buffer.append(string+"\n");
i++;
}
buffer.append("\nFound "+i+" elements\nIWillWait4:\t"+waiting);
System.out.println("\t\t\t\t\t\t\t\t"+Thread.currentThread().getName().toString()+" Says:" + buffer.toString());
if(i>1)
{
System.out.println("ERRER");
System.exit(0);
}
if(i==1 && JOptionPane.showConfirmDialog(null, "found 1 element\nWannaStop?")==0)
System.exit(0);
}
}
public class Timer implements Runnable{
#Override
public void run() {
StackExchange.time++;
System.out.println("Time Passed:\t"+StackExchange.time+" seconds");
}
}
/*
* implementation of the StackExchange class
* */
private Popper popper;
private Pusher pusher;
private StackController stackController;
private StackController secondSC;
private Timer timer;
static int time=0;
private Stack<String> stack;
public StackExchange()
{
timer = new Timer();
stack = new Stack<String>();
pusher = new Pusher(this);
popper = new Popper(this);
stackController = new StackController(this.getStack(), "FirstStackController");
}
public static void main(String[] args) {
StackExchange sex = new StackExchange();
sex.start();
System.out.println("Num of Threads:"+Thread.activeCount());
}
public void start()
{
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(5);
exec.scheduleAtFixedRate(timer, 0, 1, TimeUnit.SECONDS);
exec.scheduleAtFixedRate(pusher, 0, 2, TimeUnit.SECONDS);
exec.scheduleAtFixedRate(popper, 1, 2, TimeUnit.SECONDS);
exec.scheduleAtFixedRate(stackController, 0, stackController.waiting, TimeUnit.SECONDS);
}
public Stack<String >getStack()
{
return this.stack;
}
public void callTheStack(Object caller, String pushedString)
{
synchronized(this)
{
if(caller instanceof Popper)
stack.pop();
else if(caller instanceof Pusher)
stack.push(pushedString);
}
}
public String getPeek()
{
synchronized(this)
{
return stack.peek();
}
}
}
Things that might help:
Don't use java.util.Stack.
A more complete and consistent set of LIFO stack operations is
provided by the Deque interface and its implementations, which should
be used in preference to this class.
http://docs.oracle.com/javase/8/docs/api/java/util/Stack.html
Your nested subclasses of StackExchange are all inner classes so
that means they already have a reference to the containing
StackExchange instance
and its member stack instance, which should be final.
So don't pass them as parameters. This simplifies logic, maintenance,
and GC.
caller instanceof Popper this type of reflection is utterly
unnecessary and breaks object orientation.
You know that Object is too broad a type for callTheStack (weak
name). In fact, you know that the object will be a Runnable, but
more importantly, the Runnable should know what to do already.
Synchronization should be kept minimal to just the critical section that shares data and no more, shown below using the synchronized keyword
or to just the memory boundary, shown below using the volatile keyword
and member variables of a containing class are a great way to share data between threads within the class.
Example
public class StackExchange {
private final Deque<String> stack = new ArrayDeque<>();
private volatile boolean running;
private void consume(String item) {
// ...
}
private String obtain() {
// ...
}
private boolean getPermission() {
// ...
}
// getters, setters, ...
private final Runnable consumer = new Runnable() {
#Override
public void run() {
while (running) {
final String popped;
synchronized(stack) {
popped = stack.pollFirst();
}
consume(popped);
}
}
};
private final Runnable producer = new Runnable() {
#Override
public void run() {
while (running) {
final String pushing = obtain();
synchronized(stack) {
stack.offerFirst(pushing);
}
}
}
};
public static void main(String ... args) {
StackExchange exchange = new StackExchange();
exchange.setRunning(true);
new Thread(exchange.getConsumer()).start();
new Thread(exchange.getProducer()).start();
do {
} while (exchange.getPermission());
exchange.setRunning(false);
}
}
It's a good idea to declare member variables prior to member methods.
I put the Runnable code in anonymous classes to leave the code at the very edge of using lambdas.
The idea behind consume, obtain, and getPermission is to hint at how the code would interact with the business logic that doesn't know about threading. These could be implemented as callbacks or abstract methods.
One good thing about Deque is that it can easily be set up for a FIFO queue.
Just for fun, convert those Runnable instances into lambdas, and make the StackExchange class generic.
Hot question: what other subtypes of Deque<E> might suit, and what advantages or disadvantages would they have? What code changes might need to happen to accommodate them?
I've adapted the Quote Of The Moment (QOTM) a bit and would like to build a GUI front-end. It's simple enough to pass objects from the DatagramClientHandler to the GUI. However, it seems intractable for the GUI to reference the handler.
The QuotesGUI class extends JFrame to take advantage of the Netbeans drag-and-drop palette to add Swing components easily. It's quite verbose.
Apparently, the solution is to:
Well It depends as there are more then one solution. One could be to
inject a listener to the ChannelHandler which then will get notified
once the message was received. An other solution could be to send
events to a topic once a message was received and register the
interested swing parts on the topic, so they get notified.
https://stackoverflow.com/a/8780410/262852
DatagramClientHandler:
package net.bounceme.dur.netty;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.util.CharsetUtil;
import java.net.InetSocketAddress;
import java.util.logging.Logger;
import net.bounceme.dur.client.gui.QuotesGUI;
public class DatagramClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
private static final Logger log = Logger.getLogger(DatagramClientHandler.class.getName());
private final QuotesGUI gui = new QuotesGUI();
private volatile Channel channel = null;
DatagramClientHandler() {
log.info("starting..");
gui.setVisible(true);
}
private DatagramPacket getNext() {
DatagramPacket packet = new DatagramPacket(
Unpooled.copiedBuffer("QOTM?", CharsetUtil.UTF_8),
new InetSocketAddress("localhost", 4454));
return packet;
}
#Override
public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
String response = msg.content().toString(CharsetUtil.UTF_8);
log.info(response);
gui.setQuote(response);
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.severe(cause.toString());
ctx.close();
}
}
sample method from the GUI.
public void setQuote(String packet) {
text.setText(packet);
}
Start by separating your layers of responsibilities...
I would probably start by defining some kind of listener interface which can registered with an instance of DatagramClientHandler. This interface would allow interested parties to be notified of changes or events within DatagramClientHandler and deal with those events as they see fit...
public interface MessageListener {
public void quoteRecieved(SimpleChannelInboundHandler source, String quote);
public void errorOccured(SimpleChannelInboundHandler source, Throwable cause);
}
Then you would need to provide support for the listener...
public class DatagramClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
private static final Logger log = Logger.getLogger(DatagramClientHandler.class.getName());
//private final QuotesGUI gui = new QuotesGUI();
private volatile Channel channel = null;
private List<MessageListener> listeners;
DatagramClientHandler() {
listeners = new ArrayList<MessageListener>(25);
//...
}
public synchronized void addMessageListener(MessageListener listener) {
listeners.add(listener);
}
public synchronized void removeMessageListener(MessageListener listener) {
listeners.remove(listener);
}
protected synchronized void fireQuoteRecieved(String quote) {
for (MessageListener listener : listeners) {
listener.quoteRecieved(this, quote);
}
}
#Override
public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
String response = msg.content().toString(CharsetUtil.UTF_8);
log.info(response);
fireQuoteRecieved(response);
}
//...etc...
Now, when you want to receive notifications, you would register an instance of MessageListener with an instance of DatagramClientHandler...
The problem you will have, is ensuring that any updates you make to the UI are carried out in the EDT correctly...
//...
public void quoteRecieved(SimpleChannelInboundHandler source, final String quote) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
text.setText(packet);
}
});
}
Now, if you really wanted to, you could further decouple the code with another interface...
public interface QuoteFactory {
public synchronized void addMessageListener(MessageListener listener);
public synchronized void removeMessageListener(MessageListener listener);
}
This would then be implemented by DatagramClientHandler and you UI would require an instance of QuoteFactory to be passed to it so that it could register interest in been notified when something happens...
I have used listeners with Android and never had any problems, however today when it tried to create a simple listener in Java I am getting NullPointerException, what is the cause of this and how can I fix it?
this includes 3 classes, ListenerMainStart.java, SendMessageClass.java, and ReceiveMessageClass.java
ListenerMainStart.java
public class ListenerMainStart {
public static void main(String[] args) {
new SendMessageClass();
}
}
SendMessageClass.java
public class SendMessageClass {
public OnStringRequestedListener onStringListener;
public Timer timer;
public SendMessageClass() {
timer = new Timer();
timer.schedule(new TimerAction(), 3000);
}
public void SetOnStringRequestedListener(OnStringRequestedListener listener) {
System.out.println("value of onStringListener " + onStringListener.toString());
onStringListener = listener;
}
public interface OnStringRequestedListener {
public void passString(String sendString);
}
public class TimerAction extends TimerTask {
#Override
public void run() {
if (onStringListener!=null){
// pass string to other class, ONSTRINGLISTENER IS ALWASY NULL
onStringListener.passString("string sent from SendMessageclass");
} else {
System.out.println("onStringListener is null");
}
}
}
}
ReceiveMessageClass.java
public class ReceiveMessageClass implements SendMessageClass.OnStringRequestedListener {
SendMessageClass senderClass;
public ReceiveMessageClass() {
// instantiate class
senderClass = new SendMessageClass();
// set the listener to the class
senderClass.SetOnStringRequestedListener(this);
}
#Override
public void passString(String sendString) {
// do action when string is sent from other class
System.out.println("message recevied from other class is " + sendString);
}
}
It looks like you need to call "SetOnStringRequestedListener" before you turn on your timers. As it is, that method never gets called and onStringListener never gets set. You do call that line of code in the receiver, but of course its far too late there. Your main should instantantiate both the receiver and the sender, SetOnStringRequestedListener, and then set off the timers.
SendMessageClass send = new SendMessageClass();
ReceiveMessageClass recv = new ReceiveMessageClass()
send.SetOnStringRequestedListener(recv)
EDIT: Then take out any code in the receiver that references the sender. The idea behind using the listener is that the two classes don't know directly about each other.
For school I need to learn Java and since I'm used to C++ (like Cocoa/Objective-C) based languages, I get really frustrated on Java.
I've made a super-class (that can also be used as a base-class):
public class CellView {
public CellViewHelper helper; // CellViewHelper is just an example
public CellView() {
this.helper = new CellViewHelper();
this.helper.someVariable = <anything>;
System.out.println("CellView_constructor");
}
public void draw() {
System.out.println("CellView_draw");
}
public void needsRedraw() {
this.draw();
}
}
public class ImageCellView extends CellView {
public Image someImage;
public ImageCellView() {
super();
this.someImage = new Image();
System.out.println("ImageCellView_constructor");
}
public void setSomeParam() {
this.needsRedraw(); // cannot be replaced by this.draw(); since it's some more complicated.
}
#Override public void draw() {
super.draw();
System.out.println("ImageCellView_draw");
}
}
Now, when I call it like this:
ImageCellView imageCellView = new ImageCellView();
imageCellView.setSomeParam();
I get this:
CellView_constructor
ImageCellView_constructor
CellView_draw
However, I want it to be:
CellView_constructor
ImageCellView_constructor
CellView_draw
ImageCellView_draw
How can I do this?
Thanks in advance,
Tim
EDIT:
I also implemented this method to CellView:
public void needsRedraw() {
this.draw();
}
And this to ImageCellView:
public void setSomeParam() {
this.needsRedraw(); // cannot be replaced by this.draw(); since it's some more complicated.
}
And I've been calling this:
ImageCellView imageCellView = new ImageCellView();
imageCellView.setSomeParam();
Does this causes the problem (when I call a function from the super it calls to the super only)? How can I solve this... (without having to redefine/override the needsRedraw()-method in every subclass?)
You should get proper output.
I tried you example just commented unrelated things:
import java.awt.Image;
public class CellView {
//public CellViewHelper helper; // CellViewHelper is just an example
public CellView() {
//this.helper = new CellViewHelper();
//this.helper.someVariable = <anything>;
System.out.println("CellView_constructor");
}
public void draw() {
System.out.println("CellView_draw");
}
public static void main(String[] args) {
ImageCellView imageCellView = new ImageCellView();
imageCellView.draw();
}
}
class ImageCellView extends CellView {
public Image someImage;
public ImageCellView() {
super();
//this.someImage = new Image();
System.out.println("ImageCellView_constructor");
}
#Override public void draw() {
super.draw();
System.out.println("ImageCellView_draw");
}
}
and I get following output:
CellView_constructor
ImageCellView_constructor
CellView_draw
ImageCellView_draw
This is exactly what you want, and this is what your code print's.
The short answer is "you can't."
Objects are constructed from the bottom up, calling base class initializers before subclass initializers and base class consrtuctors before subclass constructors.
EDIT:
The code you have looks good, based on your edit. I would go through the mundane tasks like ensuring that you have compiled your code after you've added you System.out.println calls to your subclass