package votorola.s.gwt.stage.talk; // Copyright 2012, Christian Weilbach. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. import votorola.a.web.gwt.App; import votorola.g.hold.Hold; import votorola.g.hold.Spool; import votorola.g.hold.Spool1; import votorola.g.web.gwt.GWTX; import votorola.g.web.gwt.event.Change; import votorola.g.web.gwt.event.ChangeHandler; import votorola.g.web.gwt.event.PropertyChange; import votorola.g.web.gwt.event.PropertyChangeHandler; import votorola.s.gwt.stage.Stage; import votorola.s.gwt.stage.StageV; import votorola.s.gwt.stage.TheatreInitializer0; import votorola.s.gwt.stage.Track; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; import com.google.gwt.event.shared.GwtEvent; import com.google.gwt.event.shared.HasHandlers; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Widget; import com.google.web.bindery.event.shared.HandlerRegistration; /** * A track model for showing recent communications. * * @see TalkTrackV */ public final class TalkTrack implements HasHandlers, Hold, Track { private final Spool spool = new Spool1(); private JsArray msgs; /** * Get the current array of messages. Used by the view * after it is notified via a {@linkplain Change} event. * * @return messages */ public JsArray messages() { return msgs; } private final Loader loader = new Loader(); private final Kicker kicker = new Kicker(); /** * Constructs a TalkTrack. Call {@linkplain #release release}() when done * with it. */ public TalkTrack() { Stage.i().addInitializer(new TheatreInitializer0() // auto-removed { @Override public void initFromComplete(final Stage s, final boolean rPending) { init(s); } @Override public void initToComplete(final Stage s, final boolean rPending) { init(s); } }); } private void init(Stage s) { loader.load(); } private TalkTrackV talkTrackV; // final after newView /** * Create a new view for the stage. This constructs a */ @Override public Widget newView(final StageV stageV) { assert talkTrackV == null; talkTrackV = new TalkTrackV(this, stageV); spool.add(new Hold() { final HandlerRegistration hR = GWTX.i().bus() .addHandlerToSource(Change.TYPE, /* source */ talkTrackV, viewHandler); public void release() { hR.removeHandler(); } }); spool.add(new Hold() { final HandlerRegistration hR = GWTX .i() .bus() .addHandlerToSource(PropertyChange.TYPE, Stage.i(), stageHandler); @Override public void release() { hR.removeHandler(); } }); return talkTrackV; } public void fireEvent(final GwtEvent e) { assert e instanceof Change; GWTX.i().bus().fireEventFromSource(e, TalkTrack.this); } private final PropertyChangeHandler stageHandler = new PropertyChangeHandler() { @Override public void onPropertyChange(PropertyChange e) { if (e.propertyName().equals("pollName") || e.propertyName().equals("actorName")) { loader.load(); } } }; /** * Triggered after view is loaded and initializes the view with a first * fetched. */ private final ChangeHandler viewHandler = new ChangeHandler() { @Override public void onChange(Change e) { kicker.kick(); } }; /** * Querying the database for messages for a pollname filtered by timeframe * and user. Prefix 'h' hardcoded atm. */ private final class Loader implements AsyncCallback { // callback parameter added automatically by JsonpRequestBuilder private final String REQUEST_URL = App.getServletContextLocation() + "/wap?wCall=hHarvest"; public void load() { if (spool.isUnwinding()) return; // though probably impossible, as ticker would be // cancelled final StringBuilder ub = new StringBuilder(); ub.append(REQUEST_URL); if (Stage.i().getPollName() != null) { ub.append("&hPoll=").append(Stage.i().getPollName()); } final String actor = Stage.i().getActorName(); if (actor != null) { ub.append("&hUsers=").append(Stage.i().getActorName()); final String defaultActor = Stage.i().getDefaultActorName(); if(defaultActor != null && !defaultActor.equals(actor)) { ub.append(",").append(defaultActor); } } App.i().jsonpWAP().requestObject(ub.toString(), Loader.this); } @Override public void onFailure(Throwable caught) { Stage.i() .addWarning( "Could not fetch messages: " + caught.getLocalizedMessage()); } @Override public void onSuccess(JavaScriptObject result) { if (spool.isUnwinding()) return; msgs = stripPrefix(result); fireEvent(new Change()); } private final native JsArray stripPrefix( JavaScriptObject prefixJs) /*-{ return prefixJs["h"]; }-*/; } /** * Querying the database for messages for a pollname filtered by timeframe * and user. Prefix 'h' hardcoded atm. */ private final class Kicker implements AsyncCallback { // callback parameter added automatically by JsonpRequestBuilder private final String REQUEST_URL = App.getServletContextLocation() + "/wap?wCall=kKick"; public void kick() { if (spool.isUnwinding()) return; // though probably impossible, as ticker would be // cancelled if (Stage.i().getPollName() == null || Stage.i().getActorName() == null) { return; } final StringBuilder ub = new StringBuilder(); ub.append(REQUEST_URL); ub.append("&kPoll=").append(Stage.i().getPollName()); ub.append("&kUser=").append(Stage.i().getActorName()); App.i().jsonpWAP().requestObject(ub.toString(), Kicker.this); } @Override public void onFailure(Throwable caught) { Stage.i() .addWarning( "Could not kick the harvesters: " + caught.getLocalizedMessage()); } @Override public void onSuccess(JavaScriptObject result) { if (spool.isUnwinding()) return; if (stripPrefix(result)._getBoolean("triggered")) { new Timer() { @Override public void run() { loader.load(); } }.schedule(10 * 1000); } else { // update the view immediately, data has not changed // so UpdateButton will be properly updated. fireEvent(new Change()); } } private final native JsArray stripPrefix( JavaScriptObject prefixJs) /*-{ return prefixJs["k"]; }-*/; } @Override public void release() { spool.unwind(); } }