For this purpose, we need to know:
- the localization: add a grey marker on the map.
- the content of the plugged yoctopuce device: add a green marker on the map (localization prerequisite)
- the content of the database: red marker on the map (the plugged yoctodevice is a prerequisite)
As everything is loaded asynchronously with callbacks, we could do the following:
- get the localization
- In the callback of the location, get the content of the plugged device
- In the callback of the plugged device, get the content of the database
However, that would mean the database access is performed relatively late in the startup sequence and would cause a very slow UI.
The other approach is to load all the elements at the same time, however, depending on the responsiveness of the GPS localization, we may get the result of the yocto device before the localization. As we must know the localization when we get the yoctopuce device, we may end up with complex code that needs to check what has been already found before putting the marker on the map.
In order to simplify the flow, we will use a callback queue that will manage the callbacks priorities. The behavior will be the following:
- When a callback is called
- Check if the callback is the one with highest priority, if it is not, mark the callback as completed and do not call it
- If it is the one with the highest priority: call it
- Check the next callback (in term of priority), if is marked as finished, loop on step 3.
This behavior allows us to have the good reordering of callbacks and make sure that we will have the functions called at the beginning but with the callbacks properly ordered.
SequentialCallback
Here is the class which performs the queuing of callback. The order is specified by the sequence of the createCallback function call. For simplicity's sake, the subclasses of GenericManagedCallback are not provided here.
33 34 public class SequentialCallback { 35 36 private Logger logger = Logger.getLogger(this.getClass().getName()); 37 private List<GenericManagedCallback> callbacks; 38 39 40 public SequentialCallback() { 41 callbacks = new ArrayList<GenericManagedCallback>(); 42 } 43 44 public AsyncCallback createCallback(AsyncCallback entry) { 45 ManagedCallback callback = new ManagedCallback(entry); 46 47 callbacks.add(callback); 48 return callback; 49 } 50 51 public YoctoCallback createCallback(YoctoCallback yoctoCallback) { 52 YoctoManagedCallback callback = new YoctoManagedCallback(yoctoCallback); 53 callbacks.add(callback); 54 return callback; 55 } 56 57 private synchronized void checkTrigger() { 58 GenericManagedCallback last = null; 59 for (GenericManagedCallback callback : callbacks) { 60 if (callback.isFinished()) { 61 callback.trigger(); 62 } else { 63 last = callback; 64 break; 65 } 66 } 67 68 if (last != null) 69 while (!last.equals(callbacks.get(0))) 70 callbacks.remove(0); 71 72 } 73 74 public Runnable createCallback(Runnable runnable) { 75 RunnableCallback callback = new RunnableCallback(runnable); 76 callbacks.add(callback); 77 return callback; 78 } 79 80 81 private abstract class GenericManagedCallback { 82 private Throwable t; 83 private Object o; 84 private boolean throwableCaught; 85 private boolean objectFound; 86 87 public GenericManagedCallback() { 88 throwableCaught = false; 89 objectFound = false; 90 } 91 92 public void trigger() { 93 logger.info("Triggering current callback: " + this); 94 95 if (objectFound) success(o); 96 if (throwableCaught) failure(t); 97 } 98 99 protected abstract void success(Object o); 100 101 protected abstract void failure(Throwable t); 102 103 public boolean isFinished() { 104 return objectFound || throwableCaught; 105 } 106 107 public void onFailure(Throwable caught) { 108 throwableCaught = true; 109 t = caught; 110 checkTrigger(); 111 } 112 113 public void onSuccess(Object result) { 114 objectFound = true; 115 o = result; 116 checkTrigger(); 117 } 118 } 119 ... 205 } 206
Calling the callback
To create the callbacks, it becomes now relatively easy, here is how we get the data in the yoctopuce devices:
117 SequentialCallback callback = new SequentialCallback(); 118 119 ... 135 //noinspection unchecked 136 currentHub.refresh(callback.createCallback(new YoctoCallback<Hub>() { 137 public void onSuccess(Hub hub) { 138 logger.info("Hub with serial number: " + hub.getYocto().getSerialNumber() + " has been found"); 139 if (latLng != null) { 140 141 hub.getDto().setLatitude(latLng.getLatitude()); 142 hub.getDto().setLongitude(latLng.getLongitude()); 143 map.removeOverlay(currentMarker); 144 currentMarker = MarkerFactory.getInstance().getYoctoMarker(map, hub); 145 map.addOverlay(currentMarker); 146 147 148 //Now let's save the hub in DB 149 worldMapService.addHub(hub.getDto(), new AsyncCallback<Void>() { 150 public void onFailure(Throwable caught) { 151 logger.severe("Impossible to save hub: " + caught); 152 } 153 154 public void onSuccess(Void result) { 155 logger.fine("Hub successfully saved"); 156 } 157 }); 158 159 refreshHub(hub); 160 } 161 }
- at line 135: //noinspection unchecked: is an indication for Intellij Idea to avoid complaining about possible class cast exceptions.
- at line 139: we check if the localization has succeeded or not: we know that it has returned but we do not know if it was successful or not.
- at line 145: we add the marker on the map
- at line 149, we update the database
This concludes the introduction of the GWT & yoctopuce introduction. The next post will describe how to use Google App Engine to store the data and how to put the project in production.
Aucun commentaire:
Enregistrer un commentaire