[MySQL] Receiving Data and return it on a Method (Thread-Save)

Discussion in 'Plugin Development' started by PreFiXAUT, Jan 21, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    PreFiXAUT

    Hey everybody, I have been working with MySQL already, so I dont need help with this. I need help with the Thread-Save returning of Data.

    As far as I know, you should ONLY use MySQL in Async Tasks, so Bukkit wont hang while the Database is responding, and that's fine. But I need to return some Data which I receive from the Database. Since it looks like this right now:
    Code:
    public Data getData() {
      // Connection con is already created and initialized
      Bukkit.getScheduler().scheduleSyncDelayedTask(fooPlugin, new Runnable() {
        public void run() {
          PreparedStatement
          [...]
          // Alright, Data parsed and ready to return...but how?
        }
      }
    }
    it can't return Data from the run() method to the getData() method :/

    Any Ideas? Thanks in advance :)
     
  2. Online

    timtower Administrator Administrator Moderator

    @PreFiXAUT mainplugin.sendData(<whateverdatayouhave>)
    Put that in a list or something, then use a synch task to use it again
     
  3. Offline

    PreFiXAUT

    @timtower (/.-) Well...I think I was kinda overthinking it xD Thanks
     
  4. Offline

    PreFiXAUT

    Ok, not solved tho. Same Problem, but I have already figured out the other possible Solutions (I'm just listing tthem here so no one tells me about these):
    • Don't add it to another Task at all (which would block out Bukkit)
    • Create a custom Interface which is triggered (async) when the Data exists (Like RxJava)
    • Trigger a Bukkit-Event (Synced)
    What else could work? :/
     
  5. Offline

    mythbusterma

    @PreFiXAUT

    Have very lazy data, for example if you want to display information on a scoreboard, have a structure to contain the information you want to store, and then request the data. Have whatever is doing the SQL query update that structure, while there is code that occasionally updates the scoreboard using the structure.

    Alternatively, you can schedule work to be done on the main thread next tick after you get the value.
     
  6. Offline

    Rocoty

    Callbacks, anyone?
     
  7. Offline

    PreFiXAUT

    @mythbusterma 1. Option won't work, because the Method returns the Core-Object in my Plugin. And I don't really wanna redo the Plugin (again) so it works with this. 2. How would that look like? Isn't this simply calling a new sync BukkitTask with 1 Tick delay than, and execute the needed Code in it? If so, it's the same problem as the 1. Option :/

    @Rocoty
     
  8. Offline

    mythbusterma

    @PreFiXAUT

    Option #1 will always work.

    You have a pretty good idea of the second one.

    The quote with Rocoty is pretty much exactly what a callback is.

    The first option:

    In some other, invoking class:

    Code:
    ConcurrentHashMap<UUID, PlayerData> data = new ....;
    SQLConnectionManager manager = new ....;
    
    // a constructor, or onEnable(), to meet your suiting
    public <init> () {
         new BukkitRunnable () {
                @Override
                public void run() {
                     for (Player player: Bukkit.getOnlinePlayers()) {
                        if(data.get(player.getUUID() != null) {
                            // do something with the player's data
                         }
                      }
                }
            }.runTaskTimer(plugin, 10, 10);
            // other stuff
    }
    
    public void addData(UUID uuid, PlayerData data) {
          data.put(uuid, data);
    }
    
    And include this at some point in the class: manager.requestData(UUID, this);

    In a class named SQLConnectionManager (or something of that nature):

    Code:
    public void requestInformation(final UUID uuid, <otherclass> callback) {
          new BukkitRunnable () {
                @Override
                public void run() {
                     /* request data from the server associated with uuid and store it in a PlayerData object data*/
                     PlayerData data  = /*...*/;
                    
                     callback.addData(uuid,data);
                   }
             }.runTaskAsynchronously(plugin, 0);
    }

    The second option:

    In the invoking class:

    manager.requestData(UUID, plugin);


    In some class similar to SQLConnectionManager:

    Code:
    public void requestData(final UUID uuid, final JavaPlugin plugin) {
         new BukkitTask() {
             @Override
             public void run() {
                   /* get the information, declare as final*/
                   new BukkitTask() {
                        @Override
                        public void run() {
                             /* do something with it */
                        }
                    }.runTask(plugin);
              }
        }.runTaskAsynchronously(plugin);
    }
     
  9. Offline

    xTrollxDudex

    My recommendation is using ExecutorServices, or more specifically, the submit(Callable) method.

    PHP:
    ExecutorService executor Executors.newSingleThreadExecutor(new ThreadFactory() {
        
    // Do not prevent shutdown of a plugin
        
    public Thread newThread(Runnable r) {
            
    Thread t = new Thread(r);
            
    t.setDameon(true);
            return 
    t;
        }
    });

    Future<Datafuture executor.submit(new Callable<Data>() {
        public 
    Data call() throws Exception {
            
    // Process
        
    }
    });

    // You can do whatever you want before finding the value of future
    // or you can return immediately
    return future.get();
     
    Last edited by a moderator: Jan 25, 2015
    mazentheamazin likes this.
Thread Status:
Not open for further replies.

Share This Page