I'm new with akka, so want to ask how to add event to event bus and catch it called. There is code sample.
localEventBus = new com.google.common.eventbus.EventBus(new ExceptionHandler());
Object listener = new Object()
{
#Subscribe
public void witingCommand(SomeCommand cmd)
{
//Here I want to catch call
}
};
...
localEventBus.register(listener);
...
client = system.actorOf(Props.create(ClientActor.class, localEventBus, receptionists));
...
client.tell(new Publish(Constants.COMMAND, someCommand), noSender());
Types:
private final ActorSystem system;
private ActorRef client;
ClientActor.java
final class ClientActor extends UntypedActor
{
ClientActor(final EventBus eventBus, final List<ActorSelection> receptionists)
{
localEventBus = eventBus;
clusterReceptionists.addAll(receptionists);
}
#Override
public void preStart()
{...}
#Override
public void postStop()
{...}
#Override
public void onReceive(final Object msg)
{...}
}
Problem is that 'witingCommand' is not being called, maybe someone can tell me what I do wrong?
Related
I was looking at how to create and fire events using Bukkit API.
public class PlayerDisconnect implements Listener {
#EventHandler
public void onQuit(PlayerQuitEvent event){
//code
}
}
I mean, doesn't matter the name of the method (in this case onQuit, I can use onDisconnect, onLeave, etc. and it will still be called by PlayerQuitEvent), it calls every method using PlayerQuitEvent as a parameter. I want to be able to replicate that behaviour.
You can create and call your own custom events using the Bukkit Event API. Spigot has a good starting tutorial on the Event API.
A simple example of a Cancellable event that takes a Player:
...
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class MyCustomEvent extends Event implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private final Player player;
private boolean cancelled;
public MyCustomEvent(Player player)
{
this.player = player;
}
public static HandlerList getHandlerList()
{
return handlers;
}
public Player getPlayer()
{
return this.player;
}
public HandlerList getHandlers()
{
return handlers;
}
#Override
public boolean isCancelled()
{
return cancelled;
}
#Override
public void setCancelled(boolean cancelled)
{
this.cancelled = cancelled;
}
}
Which you can then call elsewhere in your custom event like so
...
MyCustomEvent event = new MyCustomEvent(player);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return;
...
Finally, you would listen for the event like you would any other event:
...
#EventHandler
public void onMyCustomEvent(MyCustomEvent event){
Player player = event.getPlayer();
...
}
You should use PluginManager#callEvent(Event).
public class CustomEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final String a;
private final int b;
private boolean cancelled;
public CustomEvent(String a, int b) {
this.a = a;
this.b = b;
}
public String getA() {
return a;
}
public int getB() {
return b;
}
#Override
public boolean isCancelled() {
return cancelled;
}
#Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
#Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
CustomEvent event = new CustomEvent("some data", 5);
Server server = ...
server.getPluginManager().callEvent(event);
if (event.isCancelled()) return;
// Do event
See the official tutorial and this community tutorial.
If you want to use the Bukkit event system in a non-Bukkit plugin project, you can add the Bukkit API as dependency (just the API, not the server implementing it).
I'm creating an user event system using JDK 9 Flow API, so I have a room (which extends the UserSubscriver class above), it may have many users and each user can offer (dispatch) updates at any time.
public abstract class UserSubscriver implements Flow.Subscriber<Notification> {
private Flow.Subscription subscription;
#Override
public void onSubscribe(final Flow.Subscription subscription) {
this.subscription = subscription;
subscription.request(1);
}
#Override
public void onError(final Throwable throwable) {
// ...
}
#Override
public void onNext(final Notification notification) {
// ...
subscription.request(1);
}
#Override
public void onComplete() {
// How can I know who was the publisher of this?
}
}
User class:
public class User extends SubmissionPublisher<Notification> {
....
public int offer(Notification item) {
return super.offer(item, (sub, msg) -> false);
}
}
On the onUpdate I can receive any args, so I can receive the publisher of the update, but there are no args on onComplete.
How can I know who was the publisher of an onComplete event?
I thought of creating a separate class for all of the smack's basic methods like connecting, login, sending message, receiving messages.
So, there's a listener method which receives messages.
static ChatManagerListener chatManagerListener = new ChatManagerListener() {
#Override
public void chatCreated(Chat chat, boolean createdLocally) {
chat.addMessageListener(
new ChatMessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
System.out.println("MESSAGE RECEIVED: "+message.toString());
messageReceived(message);
}
});
}
};
Message is received and passed to messageReceived() method.
SITUATION:
Now, when I import this class into other, I would like to extend the functionality of this messageReceived() method, so the whole process remains abstract and the developer only deals with incoming messages. Or, somehow this messageReceived() method push the message to that other class.
Basically you need to define another listner to manage the message.
This is a working snippet example (of a prototype, so it's ugly and without any pattern) to update the GUI of reciver user.
If you'll need something else keep in mind that you'll need plugins (PacketInterceptor) on server side.
/*MessageGuiUpdate.java*/
public interface MessageGuiUpdate {
public void displayMessage(String body);
}
/*XmppManager.java*/
public void init() throws XMPPException, SmackException, IOException {
private MessageGuiUpdate guiUpdate;
//FOO
//BAR
/* init() */
this.chatManager = ChatManager.getInstanceFor(connection);
this.chatManager.addChatListener(
new ChatManagerListener() {
#Override
public void chatCreated(Chat chat, boolean createdLocally)
{
if (!createdLocally)
{
chat.addMessageListener(new IncomingMessageListener());;
}
}
});
}
/*nested class*/
class IncomingMessageListener implements ChatMessageListener {
#Override
public void processMessage(Chat arg0, Message message) {
String from = message.getFrom();
String body = message.getBody();
if (body != null)
{
System.out.println(String.format("============ Received message '%1$s' from %2$s\n============", body, from));
guiUpdate.displayMessage(body);
}
}
}
/*CustomGui.java*/
public class CustomGui implements MessageGuiUpdate {
//foo
#Override
public void displayMessage(String message) {
System.out.println("I've just recived: "+message);
}
}
I use Grizzly to setup websocket server in java. My problem is that I can't set broadcaster to websocket to use optimized one by overriding WebSocketApplication. I followed the way the documentation describe. But I got that error.
The method setBroadcaster(Broadcaster) from the type SimpleWebSocket
is not visible.
Here is my code
public class BroadcastApplication extends WebSocketApplication {
private final Broadcaster broadcaster;
public BroadcastApplication(Broadcaster broadcaster) {
this.broadcaster = broadcaster;
}
#Override public WebSocket createSocket(ProtocolHandler handler,
HttpRequestPacket requestPacket, WebSocketListener... listeners) {
final DefaultWebSocket ws = (DefaultWebSocket) super.createSocket(handler, requestPacket, listeners);
ws.setBroadcaster(broadcaster); // Got error here
return ws;
}
#Override public void onMessage(WebSocket socket, String data) {
socket.broadcast(getWebSockets(), data);
}
}
My grizzly-websockets version is 2.3.22. Any suggestion is welcome.
Something like this should work:
public class BroadcastApplication extends WebSocketApplication {
private final Broadcaster broadcaster;
public BroadcastApplication(Broadcaster broadcaster) {
this.broadcaster = broadcaster;
}
#Override
public WebSocket createSocket(ProtocolHandler handler,
HttpRequestPacket requestPacket, WebSocketListener... listeners) {
return new BroadcastWebSocket(broadcaster, handler, requestPacket, listeners);
}
#Override
public void onMessage(WebSocket socket, String data) {
socket.broadcast(getWebSockets(), data);
}
private static class BroadcastWebSocket extends DefaultWebSocket {
public BroadcastWebSocket(Broadcaster broadcaster,
ProtocolHandler protocolHandler,
HttpRequestPacket request,
WebSocketListener... listeners) {
super(protocolHandler, request, listeners);
this.broadcaster = broadcaster;
}
}
}
This is probably obvious, but I am new to this paradigm. I create a Jetty Server and register my websocket class as follows:
Server server = new Server(8080);
WebSocketHandler wsHandler = new WebSocketHandler()
{
#Override
public void configure(WebSocketServletFactory factory)
{
factory.register(MyEchoSocket.class);
}
};
server.setHandler(wsHandler);
The websocket receives messages fine. I would like to also be able to send messages out from the server without having first received a message from the client. How do I access the MyEchoSocket instance that's created when the connection opens? Or, more generally, how do I send messages on the socket outside of the onText method in MyEchoSocket?
Two common techniques, presented here in a super simplified chatroom concept.
Option #1: Have WebSocket report back its state to a central location
#WebSocket
public class ChatSocket {
public Session session;
#OnWebSocketConnect
public void onConnect(Session session) {
this.session = session;
ChatRoom.getInstance().join(this);
}
#OnWebSocketMessage
public void onText(String message) {
ChatRoom.getInstance().writeAllMembers("Hello all");
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
ChatRoom.getInstance().part(this);
}
}
public class ChatRoom {
private static final ChatRoom INSTANCE = new ChatRoom();
public static ChatRoom getInstance()
{
return INSTANCE;
}
private List<ChatSocket> members = new ArrayList<>();
public void join(ChatSocket socket)
{
members.add(socket);
}
public void part(ChatSocket socket)
{
members.remove(socket);
}
public void writeAllMembers(String message)
{
for(ChatSocket member: members)
{
member.session.getRemote().sendStringByFuture(message);
}
}
public void writeSpecificMember(String memberName, String message)
{
ChatSocket member = findMemberByName(memberName);
member.session.getRemote().sendStringByFuture(message);
}
public ChatSocket findMemberByName(String memberName)
{
// left as exercise to reader
}
}
Then simply use the central location to talk to the websockets of your choice.
ChatRoom.getInstance().writeSpecificMember("alex", "Hello");
// or
ChatRoom.getInstance().writeAllMembers("Hello all");
Option #2: Have WebSocket be created manually with WebSocketCreator
#WebSocket
public class ChatSocket {
public ChatRoom chatroom;
public ChatSocket(ChatRoom chatroom)
{
this.chatroom = chatroom;
}
#OnWebSocketConnect
public void onConnect(Session session) {
chatroom.join(this);
}
#OnWebSocketMessage
public void onText(String message) {
chatroom.writeAllMembers(message);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
chatroom.part(this);
}
}
public class ChatCreator implements WebSocketCreator
{
private ChatRoom chatroom;
public ChatCreator(ChatRoom chatroom)
{
this.chatroom = chatroom;
}
public Object createWebSocket(UpgradeRequest request,
UpgradeResponse response)
{
// We want to create the Chat Socket and associate
// it with our chatroom implementation
return new ChatSocket(chatroom);
}
}
public class ChatHandler extends WebSocketHandler
{
private ChatRoom chatroom = new ChatRoom();
#Override
public void configure(WebSocketServletFactory factory)
{
factory.setCreator(new ChatCreator(chatroom));
}
}
At this point you can use the same techniques as above to talk to the websockets of your choice.