In our Zone extension, we create a ScheduledFuture thread that executes every second and loops through a collection of a model class with an integer value that we want to keep track of:
RawSchedule.java - we need to keep track of secondsRemaining here
Code: Select all
package com.noobs2d.jumbocinema.youtube;
public class RawSchedule {
private int duration;
private boolean playing;
private int secondsRemaining;
private String watchDate;
private boolean removable;
public RawSchedule(int duration, boolean playing, int secondsRemaining, String watchDate) {
this.duration = duration;
this.playing = playing;
this.secondsRemaining = secondsRemaining;
this.watchDate = watchDate;
}
public void decrementSecondsRemaining() {
secondsRemaining--;
}
public int getDuration() {
return duration;
}
public int getSecondsRemaining() {
return secondsRemaining;
}
public String getWatchDate() {
return watchDate;
}
public boolean isPlaying() {
return playing;
}
public boolean isRemovable() {
return removable;
}
public boolean isSecondsRemainingNegative() {
return secondsRemaining < 0;
}
public void play() {
playing = true;
}
public void setRemovable(boolean removable) {
this.removable = removable;
}
/**
* Makes the secondsRemaining become the duration. This should only be called when the schedule starts playing.
*/
public void switchSecondsRemaining() {
secondsRemaining = duration;
}
}
After updating, we send it back to all users through this line (see ScheduleTimer.java below):
Code: Select all
parentExtension.send(schedules.get(i).getWatchDate(), returnData, parentExtension.getParentZone().getUserManager().getAllUsers());
I've tried tracing the value of that model's instance variable and it updates fine, but once we send it back to all the users in the zone, the updated value of the instance in the thread doesn't get passed.
For example, if the instance of RawSchedule's value of secondsRemaining is 340 and a user logs in, he gets the 340 every second, but it stays like that, while in the server, the trace continues to change (decrement, as planned).
The way we made the extensions is through a single project only; we just change the way which main extension class to use (i.e., we have MainZoneExtension that we use for the zone and Main that we use for the rooms, which is in a single jar file. Since we need to get the instance of the timer through casting getParentExtension() to MainZonExtension to get a reference to our timer thread, we had to share the jar file in __lib__ as instructed here.
The following are classes that is related to this problem.
ScheduleTimer.java
Code: Select all
package com.noobs2d.jumbocinema.youtube;
import java.util.ArrayList;
public class ScheduleTimer {
private class TaskRunner implements Runnable {
@Override
public void run() {
checkRemoveableItems();
sendTime();
}
private void checkRemoveableItems() {
try {
for (int i = 0; i < schedules.size(); i++)
if (schedules.get(i).isRemovable())
schedules.remove(i);
} catch (Exception e) {
parentExtension.trace("Error removing instance from collection: " + e.getMessage());
}
}
}
private SFSExtension parentExtension;
private ArrayList<RawSchedule> schedules;
public ScheduleTimer(SFSExtension parentExtension) {
this.parentExtension = parentExtension;
schedules = new ArrayList<RawSchedule>();
SmartFoxServer smartFoxServer = SmartFoxServer.getInstance();
smartFoxServer.getTaskScheduler().scheduleAtFixedRate(new TaskRunner(), 0, 1, TimeUnit.SECONDS);
}
public void addSchedule(RawSchedule scheduleToAdd) {
try {
boolean notInCollectionYet = true;
for (int i = 0; i < schedules.size(); i++)
if (schedules.get(i).getWatchDate() == scheduleToAdd.getWatchDate()) {
notInCollectionYet = false;
i = schedules.size(); //break this loop
}
parentExtension.trace("Adding " + scheduleToAdd.getWatchDate() + " to the thread...");
if (notInCollectionYet) {
schedules.add(scheduleToAdd);
parentExtension.trace("Added " + scheduleToAdd.getWatchDate() + " to the thread!");
}
} catch (Exception e) {
parentExtension.trace("Adding schedule on timer error: " + e.getMessage());
}
}
private void sendTime() {
try {
for (int i = 0; i < schedules.size(); i++) {
schedules.get(i).decrementSecondsRemaining();
boolean swapScheduleTimers = false;
boolean removeItem = false;
if (schedules.get(i).isSecondsRemainingNegative())
if (schedules.get(i).isPlaying())
removeItem = true;
else {
schedules.get(i).play();
swapScheduleTimers = true;
}
ISFSObject returnData = SFSObject.newInstance();
returnData.putInt("REMAINING", (int) (Math.random() * 10000));
returnData.putBool("PLAYING", schedules.get(i).isPlaying());
parentExtension.send(schedules.get(i).getWatchDate(), returnData, parentExtension.getParentZone().getUserManager().getAllUsers());
if (swapScheduleTimers)
schedules.get(i).switchSecondsRemaining();
schedules.get(i).setRemovable(removeItem);
}
} catch (Exception e) {
parentExtension.trace("Timer thread error: " + e.getMessage());
}
}
}
MainZoneExtension.java
Code: Select all
package com.noobs2d.jumbocinema;
import com.noobs2d.jumbocinema.youtube.ScheduleTimer;
import com.smartfoxserver.openspace.OpenSpaceExtension;
public class MainZoneExtension extends OpenSpaceExtension {
private ScheduleTimer timer;
@Override
public void _init() {
super._init();
trace("ZONE EXTENSION LOADED!");
timer = new ScheduleTimer(this);
}
public ScheduleTimer getTimer() {
return timer;
}
}
Are we doing a bad architecture of the extensions? It seems to me like the instances inside the thread are getting maintained. I even tried returning a random value every thread execution but it's still the same; I get the same value every extension response in the client but the trace in the server side says a different and updated value.
I hope you guys can help us with this. Thanks a lot!