You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ApplicationConnection.java 73KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123
  1. /*
  2. * Copyright 2000-2014 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client;
  17. import java.util.Date;
  18. import java.util.HashMap;
  19. import java.util.Map;
  20. import java.util.logging.Logger;
  21. import com.google.gwt.aria.client.LiveValue;
  22. import com.google.gwt.aria.client.RelevantValue;
  23. import com.google.gwt.aria.client.Roles;
  24. import com.google.gwt.core.client.Duration;
  25. import com.google.gwt.core.client.GWT;
  26. import com.google.gwt.core.client.JavaScriptObject;
  27. import com.google.gwt.core.client.JsArrayString;
  28. import com.google.gwt.core.client.Scheduler;
  29. import com.google.gwt.dom.client.Element;
  30. import com.google.gwt.event.shared.EventBus;
  31. import com.google.gwt.event.shared.EventHandler;
  32. import com.google.gwt.event.shared.GwtEvent;
  33. import com.google.gwt.event.shared.HandlerRegistration;
  34. import com.google.gwt.event.shared.HasHandlers;
  35. import com.google.gwt.event.shared.SimpleEventBus;
  36. import com.google.gwt.http.client.Request;
  37. import com.google.gwt.http.client.RequestBuilder;
  38. import com.google.gwt.http.client.RequestCallback;
  39. import com.google.gwt.http.client.RequestException;
  40. import com.google.gwt.http.client.Response;
  41. import com.google.gwt.http.client.URL;
  42. import com.google.gwt.user.client.Command;
  43. import com.google.gwt.user.client.DOM;
  44. import com.google.gwt.user.client.Timer;
  45. import com.google.gwt.user.client.Window;
  46. import com.google.gwt.user.client.Window.ClosingEvent;
  47. import com.google.gwt.user.client.Window.ClosingHandler;
  48. import com.google.gwt.user.client.ui.HasWidgets;
  49. import com.google.gwt.user.client.ui.Widget;
  50. import com.vaadin.client.ApplicationConfiguration.ErrorMessage;
  51. import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent;
  52. import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
  53. import com.vaadin.client.ResourceLoader.ResourceLoadListener;
  54. import com.vaadin.client.communication.CommunicationProblemEvent;
  55. import com.vaadin.client.communication.CommunicationProblemHandler;
  56. import com.vaadin.client.communication.Heartbeat;
  57. import com.vaadin.client.communication.PushConnection;
  58. import com.vaadin.client.communication.RpcManager;
  59. import com.vaadin.client.communication.ServerMessageHandler;
  60. import com.vaadin.client.communication.ServerRpcQueue;
  61. import com.vaadin.client.componentlocator.ComponentLocator;
  62. import com.vaadin.client.metadata.ConnectorBundleLoader;
  63. import com.vaadin.client.ui.AbstractComponentConnector;
  64. import com.vaadin.client.ui.FontIcon;
  65. import com.vaadin.client.ui.Icon;
  66. import com.vaadin.client.ui.ImageIcon;
  67. import com.vaadin.client.ui.VContextMenu;
  68. import com.vaadin.client.ui.VNotification;
  69. import com.vaadin.client.ui.VOverlay;
  70. import com.vaadin.client.ui.ui.UIConnector;
  71. import com.vaadin.shared.AbstractComponentState;
  72. import com.vaadin.shared.ApplicationConstants;
  73. import com.vaadin.shared.JsonConstants;
  74. import com.vaadin.shared.VaadinUriResolver;
  75. import com.vaadin.shared.Version;
  76. import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
  77. import com.vaadin.shared.ui.ui.UIConstants;
  78. import com.vaadin.shared.ui.ui.UIState.PushConfigurationState;
  79. import com.vaadin.shared.util.SharedUtil;
  80. import elemental.json.Json;
  81. import elemental.json.JsonArray;
  82. import elemental.json.JsonObject;
  83. /**
  84. * This is the client side communication "engine", managing client-server
  85. * communication with its server side counterpart
  86. * com.vaadin.server.VaadinService.
  87. *
  88. * Client-side connectors receive updates from the corresponding server-side
  89. * connector (typically component) as state updates or RPC calls. The connector
  90. * has the possibility to communicate back with its server side counter part
  91. * through RPC calls.
  92. *
  93. * TODO document better
  94. *
  95. * Entry point classes (widgetsets) define <code>onModuleLoad()</code>.
  96. */
  97. public class ApplicationConnection implements HasHandlers {
  98. @Deprecated
  99. public static final String MODIFIED_CLASSNAME = StyleConstants.MODIFIED;
  100. @Deprecated
  101. public static final String DISABLED_CLASSNAME = StyleConstants.DISABLED;
  102. @Deprecated
  103. public static final String REQUIRED_CLASSNAME = StyleConstants.REQUIRED;
  104. @Deprecated
  105. public static final String REQUIRED_CLASSNAME_EXT = StyleConstants.REQUIRED_EXT;
  106. @Deprecated
  107. public static final String ERROR_CLASSNAME_EXT = StyleConstants.ERROR_EXT;
  108. /**
  109. * A string that, if found in a non-JSON response to a UIDL request, will
  110. * cause the browser to refresh the page. If followed by a colon, optional
  111. * whitespace, and a URI, causes the browser to synchronously load the URI.
  112. *
  113. * <p>
  114. * This allows, for instance, a servlet filter to redirect the application
  115. * to a custom login page when the session expires. For example:
  116. * </p>
  117. *
  118. * <pre>
  119. * if (sessionExpired) {
  120. * response.setHeader(&quot;Content-Type&quot;, &quot;text/html&quot;);
  121. * response.getWriter().write(
  122. * myLoginPageHtml + &quot;&lt;!-- Vaadin-Refresh: &quot;
  123. * + request.getContextPath() + &quot; --&gt;&quot;);
  124. * }
  125. * </pre>
  126. */
  127. public static final String UIDL_REFRESH_TOKEN = "Vaadin-Refresh";
  128. private final String JSON_COMMUNICATION_PREFIX = "for(;;);[";
  129. private final String JSON_COMMUNICATION_SUFFIX = "]";
  130. private final HashMap<String, String> resourcesMap = new HashMap<String, String>();
  131. private WidgetSet widgetSet;
  132. private VContextMenu contextMenu = null;
  133. private final UIConnector uIConnector;
  134. private boolean hasActiveRequest = false;
  135. /**
  136. * Webkit will ignore outgoing requests while waiting for a response to a
  137. * navigation event (indicated by a beforeunload event). When this happens,
  138. * we should keep trying to send the request every now and then until there
  139. * is a response or until it throws an exception saying that it is already
  140. * being sent.
  141. */
  142. private boolean webkitMaybeIgnoringRequests = false;
  143. protected boolean cssLoaded = false;
  144. /** Parameters for this application connection loaded from the web-page */
  145. private ApplicationConfiguration configuration;
  146. private Date requestStartTime;
  147. private final LayoutManager layoutManager;
  148. private final RpcManager rpcManager;
  149. private PushConnection push;
  150. /** Event bus for communication events */
  151. private EventBus eventBus = GWT.create(SimpleEventBus.class);
  152. public enum State {
  153. INITIALIZING, RUNNING, TERMINATED;
  154. }
  155. private State state = State.INITIALIZING;
  156. /**
  157. * The communication handler methods are called at certain points during
  158. * communication with the server. This allows for making add-ons that keep
  159. * track of different aspects of the communication.
  160. */
  161. public interface CommunicationHandler extends EventHandler {
  162. void onRequestStarting(RequestStartingEvent e);
  163. void onResponseHandlingStarted(ResponseHandlingStartedEvent e);
  164. void onResponseHandlingEnded(ResponseHandlingEndedEvent e);
  165. }
  166. public static class RequestStartingEvent extends ApplicationConnectionEvent {
  167. public static Type<CommunicationHandler> TYPE = new Type<CommunicationHandler>();
  168. public RequestStartingEvent(ApplicationConnection connection) {
  169. super(connection);
  170. }
  171. @Override
  172. public Type<CommunicationHandler> getAssociatedType() {
  173. return TYPE;
  174. }
  175. @Override
  176. protected void dispatch(CommunicationHandler handler) {
  177. handler.onRequestStarting(this);
  178. }
  179. }
  180. public static class ResponseHandlingEndedEvent extends
  181. ApplicationConnectionEvent {
  182. public static Type<CommunicationHandler> TYPE = new Type<CommunicationHandler>();
  183. public ResponseHandlingEndedEvent(ApplicationConnection connection) {
  184. super(connection);
  185. }
  186. @Override
  187. public Type<CommunicationHandler> getAssociatedType() {
  188. return TYPE;
  189. }
  190. @Override
  191. protected void dispatch(CommunicationHandler handler) {
  192. handler.onResponseHandlingEnded(this);
  193. }
  194. }
  195. public static abstract class ApplicationConnectionEvent extends
  196. GwtEvent<CommunicationHandler> {
  197. private ApplicationConnection connection;
  198. protected ApplicationConnectionEvent(ApplicationConnection connection) {
  199. this.connection = connection;
  200. }
  201. public ApplicationConnection getConnection() {
  202. return connection;
  203. }
  204. }
  205. public static class ResponseHandlingStartedEvent extends
  206. ApplicationConnectionEvent {
  207. public ResponseHandlingStartedEvent(ApplicationConnection connection) {
  208. super(connection);
  209. }
  210. public static Type<CommunicationHandler> TYPE = new Type<CommunicationHandler>();
  211. @Override
  212. public Type<CommunicationHandler> getAssociatedType() {
  213. return TYPE;
  214. }
  215. @Override
  216. protected void dispatch(CommunicationHandler handler) {
  217. handler.onResponseHandlingStarted(this);
  218. }
  219. }
  220. /**
  221. * Event triggered when a application is stopped by calling
  222. * {@link ApplicationConnection#setApplicationRunning(false)}.
  223. *
  224. * To listen for the event add a {@link ApplicationStoppedHandler} by
  225. * invoking
  226. * {@link ApplicationConnection#addHandler(ApplicationConnection.ApplicationStoppedEvent.Type, ApplicationStoppedHandler)}
  227. * to the {@link ApplicationConnection}
  228. *
  229. * @since 7.1.8
  230. * @author Vaadin Ltd
  231. */
  232. public static class ApplicationStoppedEvent extends
  233. GwtEvent<ApplicationStoppedHandler> {
  234. public static Type<ApplicationStoppedHandler> TYPE = new Type<ApplicationStoppedHandler>();
  235. @Override
  236. public Type<ApplicationStoppedHandler> getAssociatedType() {
  237. return TYPE;
  238. }
  239. @Override
  240. protected void dispatch(ApplicationStoppedHandler listener) {
  241. listener.onApplicationStopped(this);
  242. }
  243. }
  244. /**
  245. * Allows custom handling of communication errors.
  246. */
  247. public interface CommunicationErrorHandler {
  248. /**
  249. * Called when a communication error has occurred. Returning
  250. * <code>true</code> from this method suppresses error handling.
  251. *
  252. * @param details
  253. * A string describing the error.
  254. * @param statusCode
  255. * The HTTP status code (e.g. 404, etc).
  256. * @return true if the error reporting should be suppressed, false to
  257. * perform normal error reporting.
  258. */
  259. public boolean onError(String details, int statusCode);
  260. }
  261. /**
  262. * A listener for listening to application stopped events. The listener can
  263. * be added to a {@link ApplicationConnection} by invoking
  264. * {@link ApplicationConnection#addHandler(ApplicationStoppedEvent.Type, ApplicationStoppedHandler)}
  265. *
  266. * @since 7.1.8
  267. * @author Vaadin Ltd
  268. */
  269. public interface ApplicationStoppedHandler extends EventHandler {
  270. /**
  271. * Triggered when the {@link ApplicationConnection} marks a previously
  272. * running application as stopped by invoking
  273. * {@link ApplicationConnection#setApplicationRunning(false)}
  274. *
  275. * @param event
  276. * the event triggered by the {@link ApplicationConnection}
  277. */
  278. void onApplicationStopped(ApplicationStoppedEvent event);
  279. }
  280. private CommunicationErrorHandler communicationErrorDelegate = null;
  281. private VLoadingIndicator loadingIndicator;
  282. private Heartbeat heartbeat = GWT.create(Heartbeat.class);
  283. private boolean tooltipInitialized = false;
  284. private final VaadinUriResolver uriResolver = new VaadinUriResolver() {
  285. @Override
  286. protected String getVaadinDirUrl() {
  287. return getConfiguration().getVaadinDirUrl();
  288. }
  289. @Override
  290. protected String getServiceUrlParameterName() {
  291. return getConfiguration().getServiceUrlParameterName();
  292. }
  293. @Override
  294. protected String getServiceUrl() {
  295. return getConfiguration().getServiceUrl();
  296. }
  297. @Override
  298. protected String getThemeUri() {
  299. return ApplicationConnection.this.getThemeUri();
  300. }
  301. @Override
  302. protected String encodeQueryStringParameterValue(String queryString) {
  303. return URL.encodeQueryString(queryString);
  304. }
  305. };
  306. public static class MultiStepDuration extends Duration {
  307. private int previousStep = elapsedMillis();
  308. public void logDuration(String message) {
  309. logDuration(message, 0);
  310. }
  311. public void logDuration(String message, int minDuration) {
  312. int currentTime = elapsedMillis();
  313. int stepDuration = currentTime - previousStep;
  314. if (stepDuration >= minDuration) {
  315. getLogger().info(message + ": " + stepDuration + " ms");
  316. }
  317. previousStep = currentTime;
  318. }
  319. }
  320. public ApplicationConnection() {
  321. // Assuming UI data is eagerly loaded
  322. ConnectorBundleLoader.get().loadBundle(
  323. ConnectorBundleLoader.EAGER_BUNDLE_NAME, null);
  324. uIConnector = GWT.create(UIConnector.class);
  325. rpcManager = GWT.create(RpcManager.class);
  326. layoutManager = GWT.create(LayoutManager.class);
  327. layoutManager.setConnection(this);
  328. tooltip = GWT.create(VTooltip.class);
  329. loadingIndicator = GWT.create(VLoadingIndicator.class);
  330. loadingIndicator.setConnection(this);
  331. serverRpcQueue = GWT.create(ServerRpcQueue.class);
  332. serverRpcQueue.setConnection(this);
  333. communicationProblemHandler = GWT
  334. .create(CommunicationProblemHandler.class);
  335. communicationProblemHandler.setConnection(this);
  336. serverMessageHandler = GWT.create(ServerMessageHandler.class);
  337. serverMessageHandler.setConnection(this);
  338. }
  339. public void init(WidgetSet widgetSet, ApplicationConfiguration cnf) {
  340. getLogger().info("Starting application " + cnf.getRootPanelId());
  341. getLogger().info("Using theme: " + cnf.getThemeName());
  342. getLogger().info(
  343. "Vaadin application servlet version: "
  344. + cnf.getServletVersion());
  345. if (!cnf.getServletVersion().equals(Version.getFullVersion())) {
  346. getLogger()
  347. .severe("Warning: your widget set seems to be built with a different "
  348. + "version than the one used on server. Unexpected "
  349. + "behavior may occur.");
  350. }
  351. this.widgetSet = widgetSet;
  352. configuration = cnf;
  353. ComponentLocator componentLocator = new ComponentLocator(this);
  354. String appRootPanelName = cnf.getRootPanelId();
  355. // remove the end (window name) of autogenerated rootpanel id
  356. appRootPanelName = appRootPanelName.replaceFirst("-\\d+$", "");
  357. initializeTestbenchHooks(componentLocator, appRootPanelName);
  358. initializeClientHooks();
  359. uIConnector.init(cnf.getRootPanelId(), this);
  360. tooltip.setOwner(uIConnector.getWidget());
  361. getLoadingIndicator().show();
  362. heartbeat.init(this);
  363. Window.addWindowClosingHandler(new ClosingHandler() {
  364. @Override
  365. public void onWindowClosing(ClosingEvent event) {
  366. webkitMaybeIgnoringRequests = true;
  367. }
  368. });
  369. // Ensure the overlay container is added to the dom and set as a live
  370. // area for assistive devices
  371. Element overlayContainer = VOverlay.getOverlayContainer(this);
  372. Roles.getAlertRole().setAriaLiveProperty(overlayContainer,
  373. LiveValue.ASSERTIVE);
  374. VOverlay.setOverlayContainerLabel(this,
  375. getUIConnector().getState().overlayContainerLabel);
  376. Roles.getAlertRole().setAriaRelevantProperty(overlayContainer,
  377. RelevantValue.ADDITIONS);
  378. }
  379. /**
  380. * Starts this application. Don't call this method directly - it's called by
  381. * {@link ApplicationConfiguration#startNextApplication()}, which should be
  382. * called once this application has started (first response received) or
  383. * failed to start. This ensures that the applications are started in order,
  384. * to avoid session-id problems.
  385. *
  386. */
  387. public void start() {
  388. String jsonText = configuration.getUIDL();
  389. if (jsonText == null) {
  390. // inital UIDL not in DOM, request later
  391. repaintAll();
  392. } else {
  393. // initial UIDL provided in DOM, continue as if returned by request
  394. // Hack to avoid logging an error in endRequest()
  395. startRequest();
  396. handleJSONText(jsonText, -1);
  397. }
  398. // Tooltip can't be created earlier because the
  399. // necessary fields are not setup to add it in the
  400. // correct place in the DOM
  401. if (!tooltipInitialized) {
  402. tooltipInitialized = true;
  403. ApplicationConfiguration.runWhenDependenciesLoaded(new Command() {
  404. @Override
  405. public void execute() {
  406. getVTooltip().initializeAssistiveTooltips();
  407. }
  408. });
  409. }
  410. }
  411. /**
  412. * Checks if there is some work to be done on the client side
  413. *
  414. * @return true if the client has some work to be done, false otherwise
  415. */
  416. private boolean isActive() {
  417. return !getServerMessageHandler().isInitialUidlHandled()
  418. || isWorkPending() || hasActiveRequest()
  419. || isExecutingDeferredCommands();
  420. }
  421. private native void initializeTestbenchHooks(
  422. ComponentLocator componentLocator, String TTAppId)
  423. /*-{
  424. var ap = this;
  425. var client = {};
  426. client.isActive = $entry(function() {
  427. return ap.@com.vaadin.client.ApplicationConnection::isActive()();
  428. });
  429. var vi = ap.@com.vaadin.client.ApplicationConnection::getVersionInfo()();
  430. if (vi) {
  431. client.getVersionInfo = function() {
  432. return vi;
  433. }
  434. }
  435. client.getProfilingData = $entry(function() {
  436. var smh = ap.@com.vaadin.client.ApplicationConnection::getServerMessageHandler();
  437. var pd = [
  438. smh.@com.vaadin.client.communication.ServerMessageHandler::lastProcessingTime,
  439. smh.@com.vaadin.client.communication.ServerMessageHandler::totalProcessingTime
  440. ];
  441. pd = pd.concat(smh.@com.vaadin.client.communication.ServerMessageHandler::serverTimingInfo);
  442. pd[pd.length] = smh.@com.vaadin.client.communication.ServerMessageHandler::bootstrapTime;
  443. return pd;
  444. });
  445. client.getElementByPath = $entry(function(id) {
  446. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getElementByPath(Ljava/lang/String;)(id);
  447. });
  448. client.getElementByPathStartingAt = $entry(function(id, element) {
  449. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getElementByPathStartingAt(Ljava/lang/String;Lcom/google/gwt/dom/client/Element;)(id, element);
  450. });
  451. client.getElementsByPath = $entry(function(id) {
  452. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getElementsByPath(Ljava/lang/String;)(id);
  453. });
  454. client.getElementsByPathStartingAt = $entry(function(id, element) {
  455. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getElementsByPathStartingAt(Ljava/lang/String;Lcom/google/gwt/dom/client/Element;)(id, element);
  456. });
  457. client.getPathForElement = $entry(function(element) {
  458. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getPathForElement(Lcom/google/gwt/dom/client/Element;)(element);
  459. });
  460. client.initializing = false;
  461. $wnd.vaadin.clients[TTAppId] = client;
  462. }-*/;
  463. /**
  464. * Helper for tt initialization
  465. */
  466. private JavaScriptObject getVersionInfo() {
  467. return configuration.getVersionInfoJSObject();
  468. }
  469. /**
  470. * Publishes a JavaScript API for mash-up applications.
  471. * <ul>
  472. * <li><code>vaadin.forceSync()</code> sends pending variable changes, in
  473. * effect synchronizing the server and client state. This is done for all
  474. * applications on host page.</li>
  475. * <li><code>vaadin.postRequestHooks</code> is a map of functions which gets
  476. * called after each XHR made by vaadin application. Note, that it is
  477. * attaching js functions responsibility to create the variable like this:
  478. *
  479. * <code><pre>
  480. * if(!vaadin.postRequestHooks) {vaadin.postRequestHooks = new Object();}
  481. * postRequestHooks.myHook = function(appId) {
  482. * if(appId == "MyAppOfInterest") {
  483. * // do the staff you need on xhr activity
  484. * }
  485. * }
  486. * </pre></code> First parameter passed to these functions is the identifier
  487. * of Vaadin application that made the request.
  488. * </ul>
  489. *
  490. * TODO make this multi-app aware
  491. */
  492. private native void initializeClientHooks()
  493. /*-{
  494. var app = this;
  495. var oldSync;
  496. if ($wnd.vaadin.forceSync) {
  497. oldSync = $wnd.vaadin.forceSync;
  498. }
  499. $wnd.vaadin.forceSync = $entry(function() {
  500. if (oldSync) {
  501. oldSync();
  502. }
  503. app.@com.vaadin.client.ApplicationConnection::sendPendingVariableChanges()();
  504. });
  505. var oldForceLayout;
  506. if ($wnd.vaadin.forceLayout) {
  507. oldForceLayout = $wnd.vaadin.forceLayout;
  508. }
  509. $wnd.vaadin.forceLayout = $entry(function() {
  510. if (oldForceLayout) {
  511. oldForceLayout();
  512. }
  513. app.@com.vaadin.client.ApplicationConnection::forceLayout()();
  514. });
  515. }-*/;
  516. /**
  517. * Runs possibly registered client side post request hooks. This is expected
  518. * to be run after each uidl request made by Vaadin application.
  519. *
  520. * @param appId
  521. */
  522. private static native void runPostRequestHooks(String appId)
  523. /*-{
  524. if ($wnd.vaadin.postRequestHooks) {
  525. for ( var hook in $wnd.vaadin.postRequestHooks) {
  526. if (typeof ($wnd.vaadin.postRequestHooks[hook]) == "function") {
  527. try {
  528. $wnd.vaadin.postRequestHooks[hook](appId);
  529. } catch (e) {
  530. }
  531. }
  532. }
  533. }
  534. }-*/;
  535. /**
  536. * If on Liferay and logged in, ask the client side session management
  537. * JavaScript to extend the session duration.
  538. *
  539. * Otherwise, Liferay client side JavaScript will explicitly expire the
  540. * session even though the server side considers the session to be active.
  541. * See ticket #8305 for more information.
  542. */
  543. protected native void extendLiferaySession()
  544. /*-{
  545. if ($wnd.Liferay && $wnd.Liferay.Session) {
  546. $wnd.Liferay.Session.extend();
  547. // if the extend banner is visible, hide it
  548. if ($wnd.Liferay.Session.banner) {
  549. $wnd.Liferay.Session.banner.remove();
  550. }
  551. }
  552. }-*/;
  553. /**
  554. * Indicates whether or not there are currently active UIDL requests. Used
  555. * internally to sequence requests properly, seldom needed in Widgets.
  556. *
  557. * @return true if there are active requests
  558. */
  559. public boolean hasActiveRequest() {
  560. return hasActiveRequest;
  561. }
  562. private String getRepaintAllParameters() {
  563. String parameters = ApplicationConstants.URL_PARAMETER_REPAINT_ALL
  564. + "=1";
  565. return parameters;
  566. }
  567. public void repaintAll() {
  568. makeUidlRequest(Json.createArray(), getRepaintAllParameters());
  569. }
  570. /**
  571. * Requests an analyze of layouts, to find inconsistencies. Exclusively used
  572. * for debugging during development.
  573. *
  574. * @deprecated as of 7.1. Replaced by {@link UIConnector#analyzeLayouts()}
  575. */
  576. @Deprecated
  577. public void analyzeLayouts() {
  578. getUIConnector().analyzeLayouts();
  579. }
  580. /**
  581. * Sends a request to the server to print details to console that will help
  582. * the developer to locate the corresponding server-side connector in the
  583. * source code.
  584. *
  585. * @param serverConnector
  586. * @deprecated as of 7.1. Replaced by
  587. * {@link UIConnector#showServerDebugInfo(ServerConnector)}
  588. */
  589. @Deprecated
  590. void highlightConnector(ServerConnector serverConnector) {
  591. getUIConnector().showServerDebugInfo(serverConnector);
  592. }
  593. /**
  594. * Makes an UIDL request to the server.
  595. *
  596. * @param reqInvocations
  597. * Data containing RPC invocations and all related information.
  598. * @param extraParams
  599. * Parameters that are added as GET parameters to the url.
  600. * Contains key=value pairs joined by & characters or is empty if
  601. * no parameters should be added. Should not start with any
  602. * special character.
  603. */
  604. protected void makeUidlRequest(final JsonArray reqInvocations,
  605. final String extraParams) {
  606. startRequest();
  607. JsonObject payload = Json.createObject();
  608. String csrfToken = getServerMessageHandler().getCsrfToken();
  609. if (!csrfToken.equals(ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE)) {
  610. payload.put(ApplicationConstants.CSRF_TOKEN, csrfToken);
  611. }
  612. payload.put(ApplicationConstants.RPC_INVOCATIONS, reqInvocations);
  613. payload.put(ApplicationConstants.SERVER_SYNC_ID,
  614. getServerMessageHandler().getLastSeenServerSyncId());
  615. getLogger()
  616. .info("Making UIDL Request with params: " + payload.toJson());
  617. String uri = translateVaadinUri(ApplicationConstants.APP_PROTOCOL_PREFIX
  618. + ApplicationConstants.UIDL_PATH + '/');
  619. if (extraParams != null && extraParams.length() > 0) {
  620. if (extraParams.equals(getRepaintAllParameters())) {
  621. payload.put(ApplicationConstants.RESYNCHRONIZE_ID, true);
  622. } else {
  623. uri = SharedUtil.addGetParameters(uri, extraParams);
  624. }
  625. }
  626. uri = SharedUtil.addGetParameters(uri, UIConstants.UI_ID_PARAMETER
  627. + "=" + configuration.getUIId());
  628. doUidlRequest(uri, payload, true);
  629. }
  630. /**
  631. * Sends an asynchronous or synchronous UIDL request to the server using the
  632. * given URI.
  633. *
  634. * @param uri
  635. * The URI to use for the request. May includes GET parameters
  636. * @param payload
  637. * The contents of the request to send
  638. * @param retry
  639. * true when a status code 0 should be retried
  640. * @since 7.3.7
  641. */
  642. public void doUidlRequest(final String uri, final JsonObject payload,
  643. final boolean retry) {
  644. RequestCallback requestCallback = new RequestCallback() {
  645. @Override
  646. public void onError(Request request, Throwable exception) {
  647. getCommunicationProblemHandler().xhrException(
  648. payload,
  649. new CommunicationProblemEvent(request, uri, payload,
  650. exception));
  651. }
  652. @Override
  653. public void onResponseReceived(Request request, Response response) {
  654. getLogger().info(
  655. "Server visit took "
  656. + String.valueOf((new Date()).getTime()
  657. - requestStartTime.getTime()) + "ms");
  658. int statusCode = response.getStatusCode();
  659. if (statusCode != 200) {
  660. // There was a problem
  661. CommunicationProblemEvent problemEvent = new CommunicationProblemEvent(
  662. request, uri, payload, response);
  663. getCommunicationProblemHandler().xhrInvalidStatusCode(
  664. problemEvent, retry);
  665. return;
  666. }
  667. String contentType = response.getHeader("Content-Type");
  668. if (contentType == null
  669. || !contentType.startsWith("application/json")) {
  670. getCommunicationProblemHandler().xhrInvalidContent(
  671. new CommunicationProblemEvent(request, uri,
  672. payload, response));
  673. return;
  674. }
  675. // for(;;);["+ realJson +"]"
  676. String responseText = response.getText();
  677. if (!responseText.startsWith(JSON_COMMUNICATION_PREFIX)) {
  678. getCommunicationProblemHandler().xhrInvalidContent(
  679. new CommunicationProblemEvent(request, uri,
  680. payload, response));
  681. return;
  682. }
  683. final String jsonText = responseText.substring(
  684. JSON_COMMUNICATION_PREFIX.length(),
  685. responseText.length()
  686. - JSON_COMMUNICATION_SUFFIX.length());
  687. handleJSONText(jsonText, statusCode);
  688. }
  689. };
  690. if (push != null) {
  691. push.push(payload);
  692. } else {
  693. try {
  694. doAjaxRequest(uri, payload, requestCallback);
  695. } catch (RequestException e) {
  696. getCommunicationProblemHandler().xhrException(payload,
  697. new CommunicationProblemEvent(null, uri, payload, e));
  698. }
  699. }
  700. }
  701. /**
  702. * Handles received UIDL JSON text, parsing it, and passing it on to the
  703. * appropriate handlers, while logging timing information.
  704. *
  705. * @param jsonText
  706. * @param statusCode
  707. */
  708. private void handleJSONText(String jsonText, int statusCode) {
  709. final Date start = new Date();
  710. final ValueMap json;
  711. try {
  712. json = parseJSONResponse(jsonText);
  713. } catch (final Exception e) {
  714. endRequest();
  715. showCommunicationError(e.getMessage() + " - Original JSON-text:"
  716. + jsonText, statusCode);
  717. return;
  718. }
  719. getLogger().info(
  720. "JSON parsing took " + (new Date().getTime() - start.getTime())
  721. + "ms");
  722. if (getState() == State.RUNNING) {
  723. getServerMessageHandler().handleUIDLMessage(start, jsonText, json);
  724. } else if (getState() == State.INITIALIZING) {
  725. // Application is starting up for the first time
  726. setApplicationRunning(true);
  727. handleWhenCSSLoaded(jsonText, json);
  728. } else {
  729. getLogger()
  730. .warning(
  731. "Ignored received message because application has already been stopped");
  732. return;
  733. }
  734. }
  735. /**
  736. * Sends an asynchronous UIDL request to the server using the given URI.
  737. *
  738. * @param uri
  739. * The URI to use for the request. May includes GET parameters
  740. * @param payload
  741. * The contents of the request to send
  742. * @param requestCallback
  743. * The handler for the response
  744. * @throws RequestException
  745. * if the request could not be sent
  746. */
  747. protected void doAjaxRequest(String uri, JsonObject payload,
  748. RequestCallback requestCallback) throws RequestException {
  749. RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, uri);
  750. // TODO enable timeout
  751. // rb.setTimeoutMillis(timeoutMillis);
  752. // TODO this should be configurable
  753. rb.setHeader("Content-Type", JsonConstants.JSON_CONTENT_TYPE);
  754. rb.setRequestData(payload.toJson());
  755. rb.setCallback(requestCallback);
  756. final Request request = rb.send();
  757. if (webkitMaybeIgnoringRequests && BrowserInfo.get().isWebkit()) {
  758. final int retryTimeout = 250;
  759. new Timer() {
  760. @Override
  761. public void run() {
  762. // Use native js to access private field in Request
  763. if (resendRequest(request) && webkitMaybeIgnoringRequests) {
  764. // Schedule retry if still needed
  765. schedule(retryTimeout);
  766. }
  767. }
  768. }.schedule(retryTimeout);
  769. }
  770. }
  771. private static native boolean resendRequest(Request request)
  772. /*-{
  773. var xhr = request.@com.google.gwt.http.client.Request::xmlHttpRequest
  774. if (xhr.readyState != 1) {
  775. // Progressed to some other readyState -> no longer blocked
  776. return false;
  777. }
  778. try {
  779. xhr.send();
  780. return true;
  781. } catch (e) {
  782. // send throws exception if it is running for real
  783. return false;
  784. }
  785. }-*/;
  786. int cssWaits = 0;
  787. protected ServerRpcQueue serverRpcQueue;
  788. protected CommunicationProblemHandler communicationProblemHandler;
  789. protected ServerMessageHandler serverMessageHandler;
  790. static final int MAX_CSS_WAITS = 100;
  791. protected void handleWhenCSSLoaded(final String jsonText,
  792. final ValueMap json) {
  793. if (!isCSSLoaded() && cssWaits < MAX_CSS_WAITS) {
  794. (new Timer() {
  795. @Override
  796. public void run() {
  797. handleWhenCSSLoaded(jsonText, json);
  798. }
  799. }).schedule(50);
  800. // Show this message just once
  801. if (cssWaits++ == 0) {
  802. getLogger().warning(
  803. "Assuming CSS loading is not complete, "
  804. + "postponing render phase. "
  805. + "(.v-loading-indicator height == 0)");
  806. }
  807. } else {
  808. cssLoaded = true;
  809. if (cssWaits >= MAX_CSS_WAITS) {
  810. getLogger().severe("CSS files may have not loaded properly.");
  811. }
  812. getServerMessageHandler().handleUIDLMessage(new Date(), jsonText,
  813. json);
  814. }
  815. }
  816. /**
  817. * Checks whether or not the CSS is loaded. By default checks the size of
  818. * the loading indicator element.
  819. *
  820. * @return
  821. */
  822. protected boolean isCSSLoaded() {
  823. return cssLoaded
  824. || getLoadingIndicator().getElement().getOffsetHeight() != 0;
  825. }
  826. /**
  827. * Shows the communication error notification.
  828. *
  829. * @param details
  830. * Optional details.
  831. * @param statusCode
  832. * The status code returned for the request
  833. *
  834. */
  835. protected void showCommunicationError(String details, int statusCode) {
  836. getLogger().severe("Communication error: " + details);
  837. showError(details, configuration.getCommunicationError());
  838. }
  839. /**
  840. * Shows the authentication error notification.
  841. *
  842. * @param details
  843. * Optional details.
  844. */
  845. public void showAuthenticationError(String details) {
  846. getLogger().severe("Authentication error: " + details);
  847. showError(details, configuration.getAuthorizationError());
  848. }
  849. /**
  850. * Shows the session expiration notification.
  851. *
  852. * @param details
  853. * Optional details.
  854. */
  855. public void showSessionExpiredError(String details) {
  856. getLogger().severe("Session expired: " + details);
  857. showError(details, configuration.getSessionExpiredError());
  858. }
  859. /**
  860. * Shows an error notification.
  861. *
  862. * @param details
  863. * Optional details.
  864. * @param message
  865. * An ErrorMessage describing the error.
  866. */
  867. protected void showError(String details, ErrorMessage message) {
  868. VNotification.showError(this, message.getCaption(),
  869. message.getMessage(), details, message.getUrl());
  870. }
  871. protected void startRequest() {
  872. if (hasActiveRequest) {
  873. getLogger().severe(
  874. "Trying to start a new request while another is active");
  875. }
  876. hasActiveRequest = true;
  877. requestStartTime = new Date();
  878. eventBus.fireEvent(new RequestStartingEvent(this));
  879. }
  880. public void endRequest() {
  881. if (!hasActiveRequest) {
  882. getLogger().severe("No active request");
  883. }
  884. // After sendInvocationsToServer() there may be a new active
  885. // request, so we must set hasActiveRequest to false before, not after,
  886. // the call. Active requests used to be tracked with an integer counter,
  887. // so setting it after used to work but not with the #8505 changes.
  888. hasActiveRequest = false;
  889. webkitMaybeIgnoringRequests = false;
  890. if (isApplicationRunning()) {
  891. if (serverRpcQueue.isFlushPending()) {
  892. sendInvocationsToServer();
  893. }
  894. runPostRequestHooks(configuration.getRootPanelId());
  895. }
  896. // deferring to avoid flickering
  897. Scheduler.get().scheduleDeferred(new Command() {
  898. @Override
  899. public void execute() {
  900. if (!isApplicationRunning()
  901. || !(hasActiveRequest() || serverRpcQueue
  902. .isFlushPending())) {
  903. getLoadingIndicator().hide();
  904. // If on Liferay and session expiration management is in
  905. // use, extend session duration on each request.
  906. // Doing it here rather than before the request to improve
  907. // responsiveness.
  908. // Postponed until the end of the next request if other
  909. // requests still pending.
  910. extendLiferaySession();
  911. }
  912. }
  913. });
  914. eventBus.fireEvent(new ResponseHandlingEndedEvent(this));
  915. }
  916. /**
  917. * Checks if the client has running or scheduled commands
  918. */
  919. private boolean isWorkPending() {
  920. ConnectorMap connectorMap = getConnectorMap();
  921. JsArrayObject<ServerConnector> connectors = connectorMap
  922. .getConnectorsAsJsArray();
  923. int size = connectors.size();
  924. for (int i = 0; i < size; i++) {
  925. ServerConnector conn = connectors.get(i);
  926. if (isWorkPending(conn)) {
  927. return true;
  928. }
  929. if (conn instanceof ComponentConnector) {
  930. ComponentConnector compConn = (ComponentConnector) conn;
  931. if (isWorkPending(compConn.getWidget())) {
  932. return true;
  933. }
  934. }
  935. }
  936. return false;
  937. }
  938. private static boolean isWorkPending(Object object) {
  939. return object instanceof DeferredWorker
  940. && ((DeferredWorker) object).isWorkPending();
  941. }
  942. /**
  943. * Checks if deferred commands are (potentially) still being executed as a
  944. * result of an update from the server. Returns true if a deferred command
  945. * might still be executing, false otherwise. This will not work correctly
  946. * if a deferred command is added in another deferred command.
  947. * <p>
  948. * Used by the native "client.isActive" function.
  949. * </p>
  950. *
  951. * @return true if deferred commands are (potentially) being executed, false
  952. * otherwise
  953. */
  954. private boolean isExecutingDeferredCommands() {
  955. Scheduler s = Scheduler.get();
  956. if (s instanceof VSchedulerImpl) {
  957. return ((VSchedulerImpl) s).hasWorkQueued();
  958. } else {
  959. return false;
  960. }
  961. }
  962. /**
  963. * Returns the loading indicator used by this ApplicationConnection
  964. *
  965. * @return The loading indicator for this ApplicationConnection
  966. */
  967. public VLoadingIndicator getLoadingIndicator() {
  968. return loadingIndicator;
  969. }
  970. /**
  971. * Determines whether or not the loading indicator is showing.
  972. *
  973. * @return true if the loading indicator is visible
  974. * @deprecated As of 7.1. Use {@link #getLoadingIndicator()} and
  975. * {@link VLoadingIndicator#isVisible()}.isVisible() instead.
  976. */
  977. @Deprecated
  978. public boolean isLoadingIndicatorVisible() {
  979. return getLoadingIndicator().isVisible();
  980. }
  981. private static native ValueMap parseJSONResponse(String jsonText)
  982. /*-{
  983. try {
  984. return JSON.parse(jsonText);
  985. } catch (ignored) {
  986. return eval('(' + jsonText + ')');
  987. }
  988. }-*/;
  989. public void loadStyleDependencies(JsArrayString dependencies) {
  990. // Assuming no reason to interpret in a defined order
  991. ResourceLoadListener resourceLoadListener = new ResourceLoadListener() {
  992. @Override
  993. public void onLoad(ResourceLoadEvent event) {
  994. ApplicationConfiguration.endDependencyLoading();
  995. }
  996. @Override
  997. public void onError(ResourceLoadEvent event) {
  998. getLogger()
  999. .severe(event.getResourceUrl()
  1000. + " could not be loaded, or the load detection failed because the stylesheet is empty.");
  1001. // The show must go on
  1002. onLoad(event);
  1003. }
  1004. };
  1005. ResourceLoader loader = ResourceLoader.get();
  1006. for (int i = 0; i < dependencies.length(); i++) {
  1007. String url = translateVaadinUri(dependencies.get(i));
  1008. ApplicationConfiguration.startDependencyLoading();
  1009. loader.loadStylesheet(url, resourceLoadListener);
  1010. }
  1011. }
  1012. public void loadScriptDependencies(final JsArrayString dependencies) {
  1013. if (dependencies.length() == 0) {
  1014. return;
  1015. }
  1016. // Listener that loads the next when one is completed
  1017. ResourceLoadListener resourceLoadListener = new ResourceLoadListener() {
  1018. @Override
  1019. public void onLoad(ResourceLoadEvent event) {
  1020. if (dependencies.length() != 0) {
  1021. String url = translateVaadinUri(dependencies.shift());
  1022. ApplicationConfiguration.startDependencyLoading();
  1023. // Load next in chain (hopefully already preloaded)
  1024. event.getResourceLoader().loadScript(url, this);
  1025. }
  1026. // Call start for next before calling end for current
  1027. ApplicationConfiguration.endDependencyLoading();
  1028. }
  1029. @Override
  1030. public void onError(ResourceLoadEvent event) {
  1031. getLogger().severe(
  1032. event.getResourceUrl() + " could not be loaded.");
  1033. // The show must go on
  1034. onLoad(event);
  1035. }
  1036. };
  1037. ResourceLoader loader = ResourceLoader.get();
  1038. // Start chain by loading first
  1039. String url = translateVaadinUri(dependencies.shift());
  1040. ApplicationConfiguration.startDependencyLoading();
  1041. loader.loadScript(url, resourceLoadListener);
  1042. if (ResourceLoader.supportsInOrderScriptExecution()) {
  1043. for (int i = 0; i < dependencies.length(); i++) {
  1044. String preloadUrl = translateVaadinUri(dependencies.get(i));
  1045. loader.loadScript(preloadUrl, null);
  1046. }
  1047. } else {
  1048. // Preload all remaining
  1049. for (int i = 0; i < dependencies.length(); i++) {
  1050. String preloadUrl = translateVaadinUri(dependencies.get(i));
  1051. loader.preloadResource(preloadUrl, null);
  1052. }
  1053. }
  1054. }
  1055. private void addVariableToQueue(String connectorId, String variableName,
  1056. Object value, boolean immediate) {
  1057. boolean lastOnly = !immediate;
  1058. // note that type is now deduced from value
  1059. serverRpcQueue.add(new LegacyChangeVariablesInvocation(connectorId,
  1060. variableName, value), lastOnly);
  1061. if (immediate) {
  1062. serverRpcQueue.flush();
  1063. }
  1064. }
  1065. /**
  1066. * @deprecated as of 7.6, use {@link ServerRpcQueue#flush()}
  1067. */
  1068. @Deprecated
  1069. public void sendPendingVariableChanges() {
  1070. serverRpcQueue.flush();
  1071. }
  1072. public void doSendPendingVariableChanges() {
  1073. if (!isApplicationRunning()) {
  1074. getLogger()
  1075. .warning(
  1076. "Trying to send RPC from not yet started or stopped application");
  1077. return;
  1078. }
  1079. if (hasActiveRequest() || (push != null && !push.isActive())) {
  1080. // There is an active request or push is enabled but not active
  1081. // -> send when current request completes or push becomes active
  1082. } else {
  1083. sendInvocationsToServer();
  1084. }
  1085. }
  1086. /**
  1087. * Sends all pending method invocations (server RPC and legacy variable
  1088. * changes) to the server.
  1089. *
  1090. */
  1091. private void sendInvocationsToServer() {
  1092. if (serverRpcQueue.isEmpty()) {
  1093. return;
  1094. }
  1095. if (ApplicationConfiguration.isDebugMode()) {
  1096. Util.logMethodInvocations(this, serverRpcQueue.getAll());
  1097. }
  1098. boolean showLoadingIndicator = serverRpcQueue.showLoadingIndicator();
  1099. JsonArray reqJson = serverRpcQueue.toJson();
  1100. serverRpcQueue.clear();
  1101. if (reqJson.length() == 0) {
  1102. // Nothing to send, all invocations were filtered out (for
  1103. // non-existing connectors)
  1104. getLogger()
  1105. .warning(
  1106. "All RPCs filtered out, not sending anything to the server");
  1107. return;
  1108. }
  1109. String extraParams = "";
  1110. if (!getConfiguration().isWidgetsetVersionSent()) {
  1111. if (!extraParams.isEmpty()) {
  1112. extraParams += "&";
  1113. }
  1114. String widgetsetVersion = Version.getFullVersion();
  1115. extraParams += "v-wsver=" + widgetsetVersion;
  1116. getConfiguration().setWidgetsetVersionSent();
  1117. }
  1118. if (showLoadingIndicator) {
  1119. getLoadingIndicator().trigger();
  1120. }
  1121. makeUidlRequest(reqJson, extraParams);
  1122. }
  1123. /**
  1124. * Sends a new value for the given paintables given variable to the server.
  1125. * <p>
  1126. * The update is actually queued to be sent at a suitable time. If immediate
  1127. * is true, the update is sent as soon as possible. If immediate is false,
  1128. * the update will be sent along with the next immediate update.
  1129. * </p>
  1130. *
  1131. * @param paintableId
  1132. * the id of the paintable that owns the variable
  1133. * @param variableName
  1134. * the name of the variable
  1135. * @param newValue
  1136. * the new value to be sent
  1137. * @param immediate
  1138. * true if the update is to be sent as soon as possible
  1139. */
  1140. public void updateVariable(String paintableId, String variableName,
  1141. ServerConnector newValue, boolean immediate) {
  1142. addVariableToQueue(paintableId, variableName, newValue, immediate);
  1143. }
  1144. /**
  1145. * Sends a new value for the given paintables given variable to the server.
  1146. * <p>
  1147. * The update is actually queued to be sent at a suitable time. If immediate
  1148. * is true, the update is sent as soon as possible. If immediate is false,
  1149. * the update will be sent along with the next immediate update.
  1150. * </p>
  1151. *
  1152. * @param paintableId
  1153. * the id of the paintable that owns the variable
  1154. * @param variableName
  1155. * the name of the variable
  1156. * @param newValue
  1157. * the new value to be sent
  1158. * @param immediate
  1159. * true if the update is to be sent as soon as possible
  1160. */
  1161. public void updateVariable(String paintableId, String variableName,
  1162. String newValue, boolean immediate) {
  1163. addVariableToQueue(paintableId, variableName, newValue, immediate);
  1164. }
  1165. /**
  1166. * Sends a new value for the given paintables given variable to the server.
  1167. * <p>
  1168. * The update is actually queued to be sent at a suitable time. If immediate
  1169. * is true, the update is sent as soon as possible. If immediate is false,
  1170. * the update will be sent along with the next immediate update.
  1171. * </p>
  1172. *
  1173. * @param paintableId
  1174. * the id of the paintable that owns the variable
  1175. * @param variableName
  1176. * the name of the variable
  1177. * @param newValue
  1178. * the new value to be sent
  1179. * @param immediate
  1180. * true if the update is to be sent as soon as possible
  1181. */
  1182. public void updateVariable(String paintableId, String variableName,
  1183. int newValue, boolean immediate) {
  1184. addVariableToQueue(paintableId, variableName, newValue, immediate);
  1185. }
  1186. /**
  1187. * Sends a new value for the given paintables given variable to the server.
  1188. * <p>
  1189. * The update is actually queued to be sent at a suitable time. If immediate
  1190. * is true, the update is sent as soon as possible. If immediate is false,
  1191. * the update will be sent along with the next immediate update.
  1192. * </p>
  1193. *
  1194. * @param paintableId
  1195. * the id of the paintable that owns the variable
  1196. * @param variableName
  1197. * the name of the variable
  1198. * @param newValue
  1199. * the new value to be sent
  1200. * @param immediate
  1201. * true if the update is to be sent as soon as possible
  1202. */
  1203. public void updateVariable(String paintableId, String variableName,
  1204. long newValue, boolean immediate) {
  1205. addVariableToQueue(paintableId, variableName, newValue, immediate);
  1206. }
  1207. /**
  1208. * Sends a new value for the given paintables given variable to the server.
  1209. * <p>
  1210. * The update is actually queued to be sent at a suitable time. If immediate
  1211. * is true, the update is sent as soon as possible. If immediate is false,
  1212. * the update will be sent along with the next immediate update.
  1213. * </p>
  1214. *
  1215. * @param paintableId
  1216. * the id of the paintable that owns the variable
  1217. * @param variableName
  1218. * the name of the variable
  1219. * @param newValue
  1220. * the new value to be sent
  1221. * @param immediate
  1222. * true if the update is to be sent as soon as possible
  1223. */
  1224. public void updateVariable(String paintableId, String variableName,
  1225. float newValue, boolean immediate) {
  1226. addVariableToQueue(paintableId, variableName, newValue, immediate);
  1227. }
  1228. /**
  1229. * Sends a new value for the given paintables given variable to the server.
  1230. * <p>
  1231. * The update is actually queued to be sent at a suitable time. If immediate
  1232. * is true, the update is sent as soon as possible. If immediate is false,
  1233. * the update will be sent along with the next immediate update.
  1234. * </p>
  1235. *
  1236. * @param paintableId
  1237. * the id of the paintable that owns the variable
  1238. * @param variableName
  1239. * the name of the variable
  1240. * @param newValue
  1241. * the new value to be sent
  1242. * @param immediate
  1243. * true if the update is to be sent as soon as possible
  1244. */
  1245. public void updateVariable(String paintableId, String variableName,
  1246. double newValue, boolean immediate) {
  1247. addVariableToQueue(paintableId, variableName, newValue, immediate);
  1248. }
  1249. /**
  1250. * Sends a new value for the given paintables given variable to the server.
  1251. * <p>
  1252. * The update is actually queued to be sent at a suitable time. If immediate
  1253. * is true, the update is sent as soon as possible. If immediate is false,
  1254. * the update will be sent along with the next immediate update.
  1255. * </p>
  1256. *
  1257. * @param paintableId
  1258. * the id of the paintable that owns the variable
  1259. * @param variableName
  1260. * the name of the variable
  1261. * @param newValue
  1262. * the new value to be sent
  1263. * @param immediate
  1264. * true if the update is to be sent as soon as possible
  1265. */
  1266. public void updateVariable(String paintableId, String variableName,
  1267. boolean newValue, boolean immediate) {
  1268. addVariableToQueue(paintableId, variableName, newValue, immediate);
  1269. }
  1270. /**
  1271. * Sends a new value for the given paintables given variable to the server.
  1272. * <p>
  1273. * The update is actually queued to be sent at a suitable time. If immediate
  1274. * is true, the update is sent as soon as possible. If immediate is false,
  1275. * the update will be sent along with the next immediate update.
  1276. * </p>
  1277. *
  1278. * @param paintableId
  1279. * the id of the paintable that owns the variable
  1280. * @param variableName
  1281. * the name of the variable
  1282. * @param map
  1283. * the new values to be sent
  1284. * @param immediate
  1285. * true if the update is to be sent as soon as possible
  1286. */
  1287. public void updateVariable(String paintableId, String variableName,
  1288. Map<String, Object> map, boolean immediate) {
  1289. addVariableToQueue(paintableId, variableName, map, immediate);
  1290. }
  1291. /**
  1292. * Sends a new value for the given paintables given variable to the server.
  1293. * <p>
  1294. * The update is actually queued to be sent at a suitable time. If immediate
  1295. * is true, the update is sent as soon as possible. If immediate is false,
  1296. * the update will be sent along with the next immediate update.
  1297. * <p>
  1298. * A null array is sent as an empty array.
  1299. *
  1300. * @param paintableId
  1301. * the id of the paintable that owns the variable
  1302. * @param variableName
  1303. * the name of the variable
  1304. * @param values
  1305. * the new value to be sent
  1306. * @param immediate
  1307. * true if the update is to be sent as soon as possible
  1308. */
  1309. public void updateVariable(String paintableId, String variableName,
  1310. String[] values, boolean immediate) {
  1311. addVariableToQueue(paintableId, variableName, values, immediate);
  1312. }
  1313. /**
  1314. * Sends a new value for the given paintables given variable to the server.
  1315. * <p>
  1316. * The update is actually queued to be sent at a suitable time. If immediate
  1317. * is true, the update is sent as soon as possible. If immediate is false,
  1318. * the update will be sent along with the next immediate update.
  1319. * <p>
  1320. * A null array is sent as an empty array.
  1321. *
  1322. * @param paintableId
  1323. * the id of the paintable that owns the variable
  1324. * @param variableName
  1325. * the name of the variable
  1326. * @param values
  1327. * the new value to be sent
  1328. * @param immediate
  1329. * true if the update is to be sent as soon as possible
  1330. */
  1331. public void updateVariable(String paintableId, String variableName,
  1332. Object[] values, boolean immediate) {
  1333. addVariableToQueue(paintableId, variableName, values, immediate);
  1334. }
  1335. /**
  1336. * Does absolutely nothing. Replaced by {@link LayoutManager}.
  1337. *
  1338. * @param container
  1339. * @deprecated As of 7.0, serves no purpose
  1340. */
  1341. @Deprecated
  1342. public void runDescendentsLayout(HasWidgets container) {
  1343. }
  1344. /**
  1345. * This will cause re-layouting of all components. Mainly used for
  1346. * development. Published to JavaScript.
  1347. */
  1348. public void forceLayout() {
  1349. Duration duration = new Duration();
  1350. layoutManager.forceLayout();
  1351. getLogger().info("forceLayout in " + duration.elapsedMillis() + " ms");
  1352. }
  1353. /**
  1354. * Returns false
  1355. *
  1356. * @param paintable
  1357. * @return false, always
  1358. * @deprecated As of 7.0, serves no purpose
  1359. */
  1360. @Deprecated
  1361. private boolean handleComponentRelativeSize(ComponentConnector paintable) {
  1362. return false;
  1363. }
  1364. /**
  1365. * Returns false
  1366. *
  1367. * @param paintable
  1368. * @return false, always
  1369. * @deprecated As of 7.0, serves no purpose
  1370. */
  1371. @Deprecated
  1372. public boolean handleComponentRelativeSize(Widget widget) {
  1373. return handleComponentRelativeSize(connectorMap.getConnector(widget));
  1374. }
  1375. @Deprecated
  1376. public ComponentConnector getPaintable(UIDL uidl) {
  1377. // Non-component connectors shouldn't be painted from legacy connectors
  1378. return (ComponentConnector) getConnector(uidl.getId(),
  1379. Integer.parseInt(uidl.getTag()));
  1380. }
  1381. /**
  1382. * Get either an existing ComponentConnector or create a new
  1383. * ComponentConnector with the given type and id.
  1384. *
  1385. * If a ComponentConnector with the given id already exists, returns it.
  1386. * Otherwise creates and registers a new ComponentConnector of the given
  1387. * type.
  1388. *
  1389. * @param connectorId
  1390. * Id of the paintable
  1391. * @param connectorType
  1392. * Type of the connector, as passed from the server side
  1393. *
  1394. * @return Either an existing ComponentConnector or a new ComponentConnector
  1395. * of the given type
  1396. */
  1397. public ServerConnector getConnector(String connectorId, int connectorType) {
  1398. if (!connectorMap.hasConnector(connectorId)) {
  1399. return createAndRegisterConnector(connectorId, connectorType);
  1400. }
  1401. return connectorMap.getConnector(connectorId);
  1402. }
  1403. /**
  1404. * Creates a new ServerConnector with the given type and id.
  1405. *
  1406. * Creates and registers a new ServerConnector of the given type. Should
  1407. * never be called with the connector id of an existing connector.
  1408. *
  1409. * @param connectorId
  1410. * Id of the new connector
  1411. * @param connectorType
  1412. * Type of the connector, as passed from the server side
  1413. *
  1414. * @return A new ServerConnector of the given type
  1415. */
  1416. private ServerConnector createAndRegisterConnector(String connectorId,
  1417. int connectorType) {
  1418. Profiler.enter("ApplicationConnection.createAndRegisterConnector");
  1419. // Create and register a new connector with the given type
  1420. ServerConnector p = widgetSet.createConnector(connectorType,
  1421. configuration);
  1422. connectorMap.registerConnector(connectorId, p);
  1423. p.doInit(connectorId, this);
  1424. Profiler.leave("ApplicationConnection.createAndRegisterConnector");
  1425. return p;
  1426. }
  1427. /**
  1428. * Gets a resource that has been pre-loaded via UIDL, such as custom
  1429. * layouts.
  1430. *
  1431. * @param name
  1432. * identifier of the resource to get
  1433. * @return the resource
  1434. */
  1435. public String getResource(String name) {
  1436. return resourcesMap.get(name);
  1437. }
  1438. /**
  1439. * Sets a resource that has been pre-loaded via UIDL, such as custom
  1440. * layouts.
  1441. *
  1442. * @param name
  1443. * identifier of the resource to Set
  1444. * @param resource
  1445. * the resource
  1446. */
  1447. public void setResource(String name, String resource) {
  1448. resourcesMap.put(name, resource);
  1449. }
  1450. /**
  1451. * Singleton method to get instance of app's context menu.
  1452. *
  1453. * @return VContextMenu object
  1454. */
  1455. public VContextMenu getContextMenu() {
  1456. if (contextMenu == null) {
  1457. contextMenu = new VContextMenu();
  1458. contextMenu.setOwner(uIConnector.getWidget());
  1459. DOM.setElementProperty(contextMenu.getElement(), "id",
  1460. "PID_VAADIN_CM");
  1461. }
  1462. return contextMenu;
  1463. }
  1464. /**
  1465. * Gets an {@link Icon} instance corresponding to a URI.
  1466. *
  1467. * @since 7.2
  1468. * @param uri
  1469. * @return Icon object
  1470. */
  1471. public Icon getIcon(String uri) {
  1472. Icon icon;
  1473. if (uri == null) {
  1474. return null;
  1475. } else if (FontIcon.isFontIconUri(uri)) {
  1476. icon = GWT.create(FontIcon.class);
  1477. } else {
  1478. icon = GWT.create(ImageIcon.class);
  1479. }
  1480. icon.setUri(translateVaadinUri(uri));
  1481. return icon;
  1482. }
  1483. /**
  1484. * Translates custom protocols in UIDL URI's to be recognizable by browser.
  1485. * All uri's from UIDL should be routed via this method before giving them
  1486. * to browser due URI's in UIDL may contain custom protocols like theme://.
  1487. *
  1488. * @param uidlUri
  1489. * Vaadin URI from uidl
  1490. * @return translated URI ready for browser
  1491. */
  1492. public String translateVaadinUri(String uidlUri) {
  1493. return uriResolver.resolveVaadinUri(uidlUri);
  1494. }
  1495. /**
  1496. * Gets the URI for the current theme. Can be used to reference theme
  1497. * resources.
  1498. *
  1499. * @return URI to the current theme
  1500. */
  1501. public String getThemeUri() {
  1502. return configuration.getVaadinDirUrl() + "themes/"
  1503. + getUIConnector().getActiveTheme();
  1504. }
  1505. /* Extended title handling */
  1506. private final VTooltip tooltip;
  1507. private ConnectorMap connectorMap = GWT.create(ConnectorMap.class);
  1508. /**
  1509. * Use to notify that the given component's caption has changed; layouts may
  1510. * have to be recalculated.
  1511. *
  1512. * @param component
  1513. * the Paintable whose caption has changed
  1514. * @deprecated As of 7.0.2, has not had any effect for a long time
  1515. */
  1516. @Deprecated
  1517. public void captionSizeUpdated(Widget widget) {
  1518. // This doesn't do anything, it's just kept here for compatibility
  1519. }
  1520. /**
  1521. * Gets the main view
  1522. *
  1523. * @return the main view
  1524. */
  1525. public UIConnector getUIConnector() {
  1526. return uIConnector;
  1527. }
  1528. /**
  1529. * Gets the {@link ApplicationConfiguration} for the current application.
  1530. *
  1531. * @see ApplicationConfiguration
  1532. * @return the configuration for this application
  1533. */
  1534. public ApplicationConfiguration getConfiguration() {
  1535. return configuration;
  1536. }
  1537. /**
  1538. * Checks if there is a registered server side listener for the event. The
  1539. * list of events which has server side listeners is updated automatically
  1540. * before the component is updated so the value is correct if called from
  1541. * updatedFromUIDL.
  1542. *
  1543. * @param paintable
  1544. * The connector to register event listeners for
  1545. * @param eventIdentifier
  1546. * The identifier for the event
  1547. * @return true if at least one listener has been registered on server side
  1548. * for the event identified by eventIdentifier.
  1549. * @deprecated As of 7.0. Use
  1550. * {@link AbstractComponentState#hasEventListener(String)}
  1551. * instead
  1552. */
  1553. @Deprecated
  1554. public boolean hasEventListeners(ComponentConnector paintable,
  1555. String eventIdentifier) {
  1556. return paintable.hasEventListener(eventIdentifier);
  1557. }
  1558. /**
  1559. * Adds the get parameters to the uri and returns the new uri that contains
  1560. * the parameters.
  1561. *
  1562. * @param uri
  1563. * The uri to which the parameters should be added.
  1564. * @param extraParams
  1565. * One or more parameters in the format "a=b" or "c=d&e=f". An
  1566. * empty string is allowed but will not modify the url.
  1567. * @return The modified URI with the get parameters in extraParams added.
  1568. * @deprecated Use {@link SharedUtil#addGetParameters(String,String)}
  1569. * instead
  1570. */
  1571. @Deprecated
  1572. public static String addGetParameters(String uri, String extraParams) {
  1573. return SharedUtil.addGetParameters(uri, extraParams);
  1574. }
  1575. ConnectorMap getConnectorMap() {
  1576. return connectorMap;
  1577. }
  1578. /**
  1579. * @deprecated As of 7.0. No longer serves any purpose.
  1580. */
  1581. @Deprecated
  1582. public void unregisterPaintable(ServerConnector p) {
  1583. getLogger().info(
  1584. "unregisterPaintable (unnecessarily) called for "
  1585. + Util.getConnectorString(p));
  1586. }
  1587. /**
  1588. * Get VTooltip instance related to application connection
  1589. *
  1590. * @return VTooltip instance
  1591. */
  1592. public VTooltip getVTooltip() {
  1593. return tooltip;
  1594. }
  1595. /**
  1596. * Method provided for backwards compatibility. Duties previously done by
  1597. * this method is now handled by the state change event handler in
  1598. * AbstractComponentConnector. The only function this method has is to
  1599. * return true if the UIDL is a "cached" update.
  1600. *
  1601. * @param component
  1602. * @param uidl
  1603. * @param manageCaption
  1604. * @deprecated As of 7.0, no longer serves any purpose
  1605. * @return
  1606. */
  1607. @Deprecated
  1608. public boolean updateComponent(Widget component, UIDL uidl,
  1609. boolean manageCaption) {
  1610. ComponentConnector connector = getConnectorMap()
  1611. .getConnector(component);
  1612. if (!AbstractComponentConnector.isRealUpdate(uidl)) {
  1613. return true;
  1614. }
  1615. if (!manageCaption) {
  1616. getLogger()
  1617. .warning(
  1618. Util.getConnectorString(connector)
  1619. + " called updateComponent with manageCaption=false. The parameter was ignored - override delegateCaption() to return false instead. It is however not recommended to use caption this way at all.");
  1620. }
  1621. return false;
  1622. }
  1623. /**
  1624. * @deprecated As of 7.0. Use
  1625. * {@link AbstractComponentConnector#hasEventListener(String)}
  1626. * instead
  1627. */
  1628. @Deprecated
  1629. public boolean hasEventListeners(Widget widget, String eventIdentifier) {
  1630. ComponentConnector connector = getConnectorMap().getConnector(widget);
  1631. if (connector == null) {
  1632. /*
  1633. * No connector will exist in cases where Vaadin widgets have been
  1634. * re-used without implementing server<->client communication.
  1635. */
  1636. return false;
  1637. }
  1638. return hasEventListeners(getConnectorMap().getConnector(widget),
  1639. eventIdentifier);
  1640. }
  1641. LayoutManager getLayoutManager() {
  1642. return layoutManager;
  1643. }
  1644. /**
  1645. * Schedules a heartbeat request to occur after the configured heartbeat
  1646. * interval elapses if the interval is a positive number. Otherwise, does
  1647. * nothing.
  1648. *
  1649. * @deprecated as of 7.2, use {@link Heartbeat#schedule()} instead
  1650. */
  1651. @Deprecated
  1652. protected void scheduleHeartbeat() {
  1653. heartbeat.schedule();
  1654. }
  1655. /**
  1656. * Sends a heartbeat request to the server.
  1657. * <p>
  1658. * Heartbeat requests are used to inform the server that the client-side is
  1659. * still alive. If the client page is closed or the connection lost, the
  1660. * server will eventually close the inactive UI.
  1661. *
  1662. * @deprecated as of 7.2, use {@link Heartbeat#send()} instead
  1663. */
  1664. @Deprecated
  1665. protected void sendHeartbeat() {
  1666. heartbeat.send();
  1667. }
  1668. public void handleCommunicationError(String details, int statusCode) {
  1669. boolean handled = false;
  1670. if (communicationErrorDelegate != null) {
  1671. handled = communicationErrorDelegate.onError(details, statusCode);
  1672. }
  1673. if (!handled) {
  1674. showCommunicationError(details, statusCode);
  1675. }
  1676. }
  1677. /**
  1678. * Sets the delegate that is called whenever a communication error occurrs.
  1679. *
  1680. * @param delegate
  1681. * the delegate.
  1682. */
  1683. public void setCommunicationErrorDelegate(CommunicationErrorHandler delegate) {
  1684. communicationErrorDelegate = delegate;
  1685. }
  1686. public void setApplicationRunning(boolean applicationRunning) {
  1687. if (getState() == State.TERMINATED) {
  1688. if (applicationRunning) {
  1689. getLogger()
  1690. .severe("Tried to restart a terminated application. This is not supported");
  1691. } else {
  1692. getLogger()
  1693. .warning(
  1694. "Tried to stop a terminated application. This should not be done");
  1695. }
  1696. return;
  1697. } else if (getState() == State.INITIALIZING) {
  1698. if (applicationRunning) {
  1699. state = State.RUNNING;
  1700. } else {
  1701. getLogger()
  1702. .warning(
  1703. "Tried to stop the application before it has started. This should not be done");
  1704. }
  1705. } else if (getState() == State.RUNNING) {
  1706. if (!applicationRunning) {
  1707. state = State.TERMINATED;
  1708. eventBus.fireEvent(new ApplicationStoppedEvent());
  1709. } else {
  1710. getLogger()
  1711. .warning(
  1712. "Tried to start an already running application. This should not be done");
  1713. }
  1714. }
  1715. }
  1716. /**
  1717. * Checks if the application is in the {@link State#RUNNING} state.
  1718. *
  1719. * @since
  1720. * @return true if the application is in the running state, false otherwise
  1721. */
  1722. public boolean isApplicationRunning() {
  1723. return state == State.RUNNING;
  1724. }
  1725. public <H extends EventHandler> HandlerRegistration addHandler(
  1726. GwtEvent.Type<H> type, H handler) {
  1727. return eventBus.addHandler(type, handler);
  1728. }
  1729. @Override
  1730. public void fireEvent(GwtEvent<?> event) {
  1731. eventBus.fireEvent(event);
  1732. }
  1733. /**
  1734. * Calls {@link ComponentConnector#flush()} on the active connector. Does
  1735. * nothing if there is no active (focused) connector.
  1736. */
  1737. public void flushActiveConnector() {
  1738. ComponentConnector activeConnector = getActiveConnector();
  1739. if (activeConnector == null) {
  1740. return;
  1741. }
  1742. activeConnector.flush();
  1743. }
  1744. /**
  1745. * Gets the active connector for focused element in browser.
  1746. *
  1747. * @return Connector for focused element or null.
  1748. */
  1749. private ComponentConnector getActiveConnector() {
  1750. Element focusedElement = WidgetUtil.getFocusedElement();
  1751. if (focusedElement == null) {
  1752. return null;
  1753. }
  1754. return Util.getConnectorForElement(this, getUIConnector().getWidget(),
  1755. focusedElement);
  1756. }
  1757. /**
  1758. * Sets the status for the push connection.
  1759. *
  1760. * @param enabled
  1761. * <code>true</code> to enable the push connection;
  1762. * <code>false</code> to disable the push connection.
  1763. */
  1764. public void setPushEnabled(boolean enabled) {
  1765. final PushConfigurationState pushState = uIConnector.getState().pushConfiguration;
  1766. if (enabled && push == null) {
  1767. push = GWT.create(PushConnection.class);
  1768. push.init(this, pushState, new CommunicationErrorHandler() {
  1769. @Override
  1770. public boolean onError(String details, int statusCode) {
  1771. handleCommunicationError(details, statusCode);
  1772. return true;
  1773. }
  1774. });
  1775. } else if (!enabled && push != null && push.isActive()) {
  1776. push.disconnect(new Command() {
  1777. @Override
  1778. public void execute() {
  1779. push = null;
  1780. /*
  1781. * If push has been enabled again while we were waiting for
  1782. * the old connection to disconnect, now is the right time
  1783. * to open a new connection
  1784. */
  1785. if (pushState.mode.isEnabled()) {
  1786. setPushEnabled(true);
  1787. }
  1788. /*
  1789. * Send anything that was enqueued while we waited for the
  1790. * connection to close
  1791. */
  1792. if (serverRpcQueue.isFlushPending()) {
  1793. sendPendingVariableChanges();
  1794. }
  1795. }
  1796. });
  1797. }
  1798. }
  1799. public void handlePushMessage(String message) {
  1800. handleJSONText(message, 200);
  1801. }
  1802. /**
  1803. * Returns a human readable string representation of the method used to
  1804. * communicate with the server.
  1805. *
  1806. * @since 7.1
  1807. * @return A string representation of the current transport type
  1808. */
  1809. public String getCommunicationMethodName() {
  1810. if (push != null) {
  1811. return "Push (" + push.getTransportType() + ")";
  1812. } else {
  1813. return "XHR";
  1814. }
  1815. }
  1816. private static Logger getLogger() {
  1817. return Logger.getLogger(ApplicationConnection.class.getName());
  1818. }
  1819. /**
  1820. * Returns the hearbeat instance.
  1821. */
  1822. public Heartbeat getHeartbeat() {
  1823. return heartbeat;
  1824. }
  1825. /**
  1826. * Returns the state of this application. An application state goes from
  1827. * "initializing" to "running" to "stopped". There is no way for an
  1828. * application to go back to a previous state, i.e. a stopped application
  1829. * can never be re-started
  1830. *
  1831. * @since
  1832. * @return the current state of this application
  1833. */
  1834. public State getState() {
  1835. return state;
  1836. }
  1837. /**
  1838. * Gets the server RPC queue for this application
  1839. *
  1840. * @return the server RPC queue
  1841. */
  1842. public ServerRpcQueue getServerRpcQueue() {
  1843. return serverRpcQueue;
  1844. }
  1845. /**
  1846. * Gets the communication error handler for this application
  1847. *
  1848. * @return the server RPC queue
  1849. */
  1850. public CommunicationProblemHandler getCommunicationProblemHandler() {
  1851. return communicationProblemHandler;
  1852. }
  1853. /**
  1854. * Gets the server message handler for this application
  1855. *
  1856. * @return the server message handler
  1857. */
  1858. public ServerMessageHandler getServerMessageHandler() {
  1859. return serverMessageHandler;
  1860. }
  1861. /**
  1862. * Gets the server rpc manager for this application
  1863. *
  1864. * @return the server rpc manager
  1865. */
  1866. public RpcManager getRpcManager() {
  1867. return rpcManager;
  1868. }
  1869. /**
  1870. * @return the widget set
  1871. */
  1872. public WidgetSet getWidgetSet() {
  1873. return widgetSet;
  1874. }
  1875. /**
  1876. * @since
  1877. * @return
  1878. */
  1879. public int getLastSeenServerSyncId() {
  1880. return getServerMessageHandler().getLastSeenServerSyncId();
  1881. }
  1882. }