Need some PUB/SUB Jedis Help Bukkit - java

I am currently having some trouble with this code:
public class ChatPlugin extends JavaPlugin implements Listener{
private static ChatPlugin instance;
private final static String CHANNEL = "chat";
private JedisPool jedisPool;
private ChatChannel chatChannel;
#Override
public void onEnable()
{
instance = this;
saveDefaultConfig();
this.jedisPool = new JedisPool(new JedisPoolConfig(), getConfig().getString("redis-host"), 6379, 0,getConfig().getString("redis-password"));
this.chatChannel = new ChatChannel();
this.jedisPool.getResource().subscribe(this.chatChannel, new String[]{"chat"});
Bukkit.getPluginManager().registerEvents(this, this);
getCommand("chat").setExecutor(this);
}
#Override
public void onDisable()
{
instance = null;
this.chatChannel.unsubscribe();
this.jedisPool.destroy();
}
#Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (command.getName().equalsIgnoreCase("chat"))
{
getJedis().publish(CHANNEL, args[0]);
sender.sendMessage(ChatColor.GREEN + "Sent!");
}
return true;
}
public Jedis getJedis(){
return jedisPool.getResource();
}
public static ChatPlugin getInstance() {
return instance;
}
public class ChatChannel extends JedisPubSub {
#Override
public void onMessage(String channel, String message) {
new BukkitRunnable(){
#Override
public void run() {
Bukkit.broadcastMessage(message);
}
}.runTask(ChatPlugin.getInstance());
}
}
}
This is my first time working with redis' PUB/SUB feature, and I don't really know what is happening. There are no stacktraces, it's just, when the plugin enables, it freezes. Yes, I know this is because I am doing it on the main thread, but even if I run it async (Which I have) it still does not work.
Hope someone can help!
Thanks

You didn't sent us your saveDefaultConfig method so first of all check out if the plugin config is created correctly. After checking that you don't made any mistakes regarding Bukkit or any logical mistake, try to google for any example or try to find examples on programcreek.com (I've found some for jedis there).
If you still get no clue: try doing what you should have done before you've asked here. Read the wiki of Jedis!
https://github.com/xetorthio/jedis/wiki

Related

JavaFX ObservableList change not updating ListView

So I am creating a UI with JavaFX for a server controller, what it is does not matter, all that is important is that the server.getClients(); returns an ArrayList of IClients.
I wish to display these clients (they are represented by IP but once again, this doesn't seem relevant) in a ListView. However, clients may connect at any given point in time and when this happens, they get added to the server's IClient ArrayList. When this List is updated, I want the ListView to refresh and show the new client. For some reason, I simply cannot get this to work.
I am very new to JavaFX and I think I might be overseeing something.
I'm very sorry if this is a duplicate or obvious, I have searched for a long time over the past couple of days but I might have overlooked a solution.
The following code is the abbreviated version of my FXMLController for the JavaFX application:
/*imports*/
public class FXMLController implements Initializable {//serverUI.FXMLController
#FXML private ListView clientListView;
/*some more (irrelevant) code*/
private IServer server;
/*some more (irrelevant) code*/
private ObservableList<IClient> serverClientsObservableList;
#Override
public void initialize(URL url, ResourceBundle rb) {
System.out.println("initialization...");
/*some more (irrelevant) code*/
//the server was started here
// FXML Controls
initClientListView();
/*some more (irrelevant) code*/
System.out.println("initialized");
}
/*some more (irrelevant) code*/
private void initClientListView() {
System.out.println("clientListView");
serverClientsObservableList = FXCollections.observableList(server.getClients());
serverClientsObservableList.addListener(new ListChangeListener<IClient>() {
#Override
public void onChanged(ListChangeListener.Change<? extends IClient> change) {
System.out.println("list change detected");
//is any of the followin three lines really necessary to update the ListView content?
serverClientsObservableList.setAll(server.getClients());
clientListView.setItems(null);
clientListView.setItems(serverClientsObservableList);
}
});
clientListView.setItems(serverClientsObservableList);
}
/*some more (irrelevant) code*/
}
EDIT:
I don't want to refresh the ListView when something in the IClients changes, nothing changes in them. I want to refresh the ListView when a NEW IClient is ADDED to the server's client list. The ListView should show the NEW IClient
EDIT2:
According to the suggested duplicate I tried the following, however I don't really understand what it's doing and how it works. This did not solve the problem, it gives me an error when I try to create the new Observable[]
Callback<IClient, Observable[]> extractor = new Callback<IClient, Observable[]>() {
#Override
public Observable[] call(IClient c) {
return new Observable[] {c.getNameProperty()};
}
};
ObservableList<IClient> clientOList = FXCollections.observableArrayList(extractor);
Additionally: the code where I add the clients to the server.
Long story short, this is an assignment where we have to user RMI in an inverse way, the server commands the clients. Clients register themselves to the server's list and that's where they're added to the IClient list.
package serviceImplementation;
import commandService.ICommand;
import commandServiceImplementation.CommandResult;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import service.IClient;
import service.IServer;
public class ServerService extends UnicastRemoteObject implements IServer {
private ArrayList<IClient> clients;
public ServerService() throws RemoteException {
clients = new ArrayList<>();
}
#Override
public boolean register(IClient client) throws RemoteException {
if(!clients.contains(client)) {
clients.add(client);
return true;
}
return false;
}
#Override
public boolean unRegister(IClient client) throws RemoteException {
if(clients.contains(client)) {
clients.remove(client);
return true;
}
return false;
}
#Override
public String ping() throws RemoteException {
long arrival = System.currentTimeMillis();
System.out.println("Got pinged at [" + arrival + "]");
return ("server ponged [" + arrival + "]");
}
#Override
public CommandResult sendCommand(ICommand command, IClient targetClient) throws RemoteException {
if(clients.contains(targetClient)) {
return clients.get(clients.indexOf(targetClient)).executeCommand(command);
}
return null;
}
#Override
public ArrayList<IClient> getClients() {
return clients;
}
}
Your observable list is created as a wrapper for the underlying list in the ServerService using FXCollections.observableList(...). The observable list that is returned by this just wraps the underlying list, so it always contains the same elements as the underlying list. However, as noted in the documentation:
mutation operations made directly to the underlying list are not reported to observers of any ObservableList that wraps it.
When clients are registered or unregistered in the server service, you add them to the underlying list. Since the underlying list is not an observable list, no notifications are fired, and so the ListView does not know to refresh itself.
One possible solution may be to use an ObservableList in the ServerService:
public class ServerService extends UnicastRemoteObject implements IServer {
private ObservableList<IClient> clients;
public ServerService() throws RemoteException {
clients = FXCollections.observableArrayList();
}
// ...
#Override
public ObservableList<IClient> getClients() {
return clients;
}
}
and then you do
private void initClientListView() {
clientListView.setItems(server.getClients());
}
Note that this couples your ServerService to the JavaFX API; this is probably not too bad as the JavaFX Collections API does not rely on any UI elements at all.
However, the code above will not work if your clients are registered/unregistered on a background thread (i.e. not on the FX Application Thread), which is almost certainly the case. Because of this, you need to make the following changes to make this work:
#Override
public boolean register(IClient client) throws RemoteException {
FutureTask<Boolean> register = new FutureTask<>(() ->
if(!clients.contains(client)) {
clients.add(client);
return true;
}
return false;
);
Platform.runLater(register);
return register.get();
}
#Override
public boolean unRegister(IClient client) throws RemoteException {
FutureTask<Boolean> unRegister = new FutureTask<>(() ->
if(clients.contains(client)) {
clients.remove(client);
return true;
}
return false;
);
Platform.runLater(unRegister);
return unRegister.get();
}
Now your ServerService has a much stronger dependency on JavaFX, because it assume the FX Application Thread is running. You didn't make any specifications about how this is being used, but there's a good chance you don't want this coupling.
An alternative is to support callbacks in the ServerService. You can represent these pretty simply using a Consumer<IClient>. This looks something like:
public class ServerService extends UnicastRemoteObject implements IServer {
private ArrayList<IClient> clients;
private Consumer<IClient> registerCallback = client -> {} ;
private Consumer<IClient> unregisterCallback = client -> {} ;
public ServerService() throws RemoteException {
clients = new ArrayList<>();
}
public void setRegisterCallback(Consumer<IClient> registerCallback) {
this.registerCallback = registerCallback ;
}
public void setUnregisterCallback(Consumer<IClient> unregisterCallback) {
this.unregisterCallback = unregisterCallback ;
}
#Override
public boolean register(IClient client) throws RemoteException {
if(!clients.contains(client)) {
clients.add(client);
registerCallback.accept(client);
return true;
}
return false;
}
#Override
public boolean unRegister(IClient client) throws RemoteException {
if(clients.contains(client)) {
clients.remove(client);
unregisterCallback.accept(client);
return true;
}
return false;
}
#Override
public String ping() throws RemoteException {
long arrival = System.currentTimeMillis();
System.out.println("Got pinged at [" + arrival + "]");
return ("server ponged [" + arrival + "]");
}
#Override
public CommandResult sendCommand(ICommand command, IClient targetClient) throws RemoteException {
if(clients.contains(targetClient)) {
return clients.get(clients.indexOf(targetClient)).executeCommand(command);
}
return null;
}
#Override
public ArrayList<IClient> getClients() {
return clients;
}
}
and now in your UI code you do
private void initClientListView() {
System.out.println("clientListView");
serverClientsObservableList = FXCollections.observableArrayList(server.getClients());
server.setRegisterCallback(client -> Platform.runLater(() ->
serverClientsObservableList.add(client)));
server.setUnregisterCallback(client -> Platform.runLater(() ->
serverClientsObservableList.remove(client)));
clientListView.setItems(serverClientsObservableList);
}

How do I handle file saves properly in NetBeans platform project (plugin)

I try to create a new language support for NetBeans 7.4 and higher.
When files are being saved locally I need to deploy them to a server. So I need to handle the save event. I did this implementing Savable:
public class VFDataObject extends MultiDataObject implements Savable {
.......
#Override
public void save() throws IOException {
.......
}
}
And it worked perfectly for the Save event. But then I realized I need to extend HtmlDataObject instead of MultiDataObject:
public class VFDataObject extends HtmlDataObject implements Savable {
.......
#Override
public void save() throws IOException {
.......
}
}
And now the save() doesn't get executed. Why? Since HtmlDataObject extends MultiDataObject. What should be done to make that work?
Also is there a way to catch Save All event in NetBeans as well? Do you have any info on if anything changed in 8.0 in this regards?
Thanks a lot.
Have you tried OnSaveTask SPI (https://netbeans.org/bugzilla/show_bug.cgi?id=140719)? The API can be used to perform tasks when files of a given type are saved.
Something like this can be used to listen to all the save events on a given MIME type (in this case "text/x-sieve-java"):
public static class CustomOnSaveTask implements OnSaveTask {
private final Context context;
public CustomOnSaveTask(Context ctx) {
context = ctx;
}
#Override
public void performTask() {
System.out.println(">>> Save performed on " +
NbEditorUtilities.getDataObject(context.getDocument()).toString());
}
#Override
public void runLocked(Runnable r) {
r.run();
}
#Override
public boolean cancel() {
return true;
}
#MimeRegistration(mimeType = "text/x-sieve-java", service = OnSaveTask.Factory.class, position = 1600)
public static class CustomOnSaveTaskFactory implements OnSaveTask.Factory {
#Override
public OnSaveTask createTask(Context cntxt) {
return new CustomOnSaveTask(cntxt);
}
}
}

custom listener is null

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.

How to navigate in a circle

the title might be not very descriptive but i couldn't think of a better one.
The problem is as follows:
I have one screen (ScreenOne) with a link to another screen (ScreenTwo).
On the ScreenTwo is a link back to ScreenOne.
I implemented this via custom RichTextFields and a custom ChangeListener.
Now the problem is that i keep getting a StackOverflowError!
Is there any way to navigate back and forth in that way?
regards matt
public class MyApp extends UiApplication
{
public static void main(String[] args)
{
MyApp theApp = new MyApp();
theApp.enterEventDispatcher();
}
public MyApp()
{
ScreenOne so = ScreenProvider.getInstance().getScreenOne();
so.initialize();
ScreenProvider.getInstance().getScreenTwo().initialize();
pushScreen(so);
}
}
public class ScreenOne extends MainScreen {
MyTextField link;
public ScreenOne() {
link = new MyTextField("FirstScreen");
add(link);
}
public void initialize(){
link.setChangeListener((FieldChangeListener) new MyFieldChangeListener(ScreenProvider.getInstance().getScreenTwo()));
}
}
public class ScreenTwo extends MainScreen {
MyTextField link;
public ScreenTwo() {
link = new MyTextField("SecondScreen");
add(link);
}
public void initialize(){
link.setChangeListener((FieldChangeListener) new MyFieldChangeListener(ScreenProvider.getInstance().getScreenOne()));
}
}
public class MyFieldChangeListener implements FieldChangeListener {
private Screen nextScreen;
public MyFieldChangeListener(Screen nextScreen) {
this.nextScreen = nextScreen;
}
public void fieldChanged(Field field, int context) {
UiApplication.getUiApplication().pushScreen(nextScreen);
}
}
public class MyTextField extends RichTextField {
public MyTextField() {
super();
}
public MyTextField(String text) {
super(text);
}
protected boolean touchEvent(TouchEvent message) {
if (TouchEvent.CLICK == message.getEvent()) {
FieldChangeListener listener = getChangeListener();
if (null != listener)
listener.fieldChanged(this, 1);
}
return super.touchEvent(message);
}
}
public class ScreenProvider {
private static ScreenProvider instance = null;
private ScreenProvider(){}
public static ScreenProvider getInstance() {
if (instance == null) {
instance = new ScreenProvider();
}
return instance;
}
private ScreenOne screenOne = new ScreenOne();
private ScreenTwo screenTwo = new ScreenTwo();
public ScreenOne getScreenOne() {
return screenOne;
}
public ScreenTwo getScreenTwo() {
return screenTwo;
}
}
The constructor of ScreenOne creates a ScreenTwo instance, and the constructor of ScreenTwo creates a ScreenOne instance. You have an infinite loop here.
Regarding revision 5 of this question:
new ScreenProvider() -> new ScreenOne() -> ScreenProvider.getInstance() -> new ScreenProvider() -> ...
still infinite. Again, the problem is that you're trying to setup a cycle via object constructors. You need to create the objects first, then assign the next and previous.
Regarding revision 4 of this question:
getScreenOne() -> new ScreenOne() -> getScreenTwo() -> new ScreenTwo() -> getScreenOne() -> newScreenOne() -> ...
you still have an infinite loop, because the constructors are trying to store an instance of each other. You need to construct the objects first, then add the cyclic references.
In your ScreenProvider you don't need to make screen1/screen2 static -- they're members of the singleton instance.
Outside of that the other problem I see in this current version is that you're going to be pushing a screen onto the stack -- that's already on the stack. Try popping the prior screen first.
That overflow error is likely the result of an infinite loop caused by constantly jumping from ScreenOne and ScreenTwo. Could you describe what you actually would want to accomplish and/or show a snippet of code?

Calling an object from another class (java, javafx)

I'm already working on this for weeks to get it working but without success. I'm using Javafx and java for implementing a small chat programm using the smack API (xmpp). The problem is how to get the received messages from java to javafx. The code below is actualy working when I have variable with a static string like "test message" and calling postMessage in java to send it to javafx. But how do I get another object (MessageListener) from java calling postMessage?
public class Java_callback implements RunnableFuture {
FXListener listener;
public String testmsg;
public Java_callback(FXListener listener) {
this.listener = listener;
}
#Override
public void run() throws Exception {
postMessage(testmsg);
}
public void postMessage(final String msg) {
Entry.deferAction(new Runnable() {
#Override
public void run() {
listener.callback(msg);
}
});
}
}
Here the code for processing the message. This part somehow need to call postMessage from the code above.
public void xmpp_create_chat(String msg) {
ChatManager chatmanager = connection.getChatManager();
Chat newChat = chatmanager.createChat("admin#unfc", new MessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
//msgArray.add( new String("Received message: " + message.getBody()) );
//msg_return = "blabla";
//java_callback.postMessage(msg_return);
//test.postMessage(message.getBody());
//System.out.println("Received message: " + message);
}
});
If you make postMessage() static, as in:
public static void postMessage(final String msg);
... then you can make a static method call to it from processMessage(), as in:
Java_callback.postMessage(msg_return);
UPDATE: Change your initializion of listener as well.
private static FXListener listener;
Hopefully this doesn't break something outside of the provided code :)
The class containing your second function has to have a reference to the first object, so that it can make the call.
What needs here is so basic that it's hard to figure out what an example might be.
something like this for your second class:
class MessageReceiver {
private Java_callback callback;
public void setJava_callback(Java_callback callback) {
this.callback = callback;
}
....
void process_message(...) { // inside your inner class
calllback.postMessage(msg);
}
}
Is the magic recipe that inner classes can refer to fields of their containing class?

Categories

Resources