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 57KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674
  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.HashMap;
  18. import java.util.Map;
  19. import java.util.logging.Logger;
  20. import com.google.gwt.aria.client.LiveValue;
  21. import com.google.gwt.aria.client.RelevantValue;
  22. import com.google.gwt.aria.client.Roles;
  23. import com.google.gwt.core.client.Duration;
  24. import com.google.gwt.core.client.GWT;
  25. import com.google.gwt.core.client.JavaScriptObject;
  26. import com.google.gwt.core.client.JsArrayString;
  27. import com.google.gwt.core.client.Scheduler;
  28. import com.google.gwt.dom.client.Element;
  29. import com.google.gwt.event.shared.EventBus;
  30. import com.google.gwt.event.shared.EventHandler;
  31. import com.google.gwt.event.shared.GwtEvent;
  32. import com.google.gwt.event.shared.HandlerRegistration;
  33. import com.google.gwt.event.shared.HasHandlers;
  34. import com.google.gwt.event.shared.SimpleEventBus;
  35. import com.google.gwt.http.client.URL;
  36. import com.google.gwt.user.client.Command;
  37. import com.google.gwt.user.client.DOM;
  38. import com.google.gwt.user.client.Timer;
  39. import com.google.gwt.user.client.ui.HasWidgets;
  40. import com.google.gwt.user.client.ui.Widget;
  41. import com.vaadin.client.ApplicationConfiguration.ErrorMessage;
  42. import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent;
  43. import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
  44. import com.vaadin.client.ResourceLoader.ResourceLoadListener;
  45. import com.vaadin.client.communication.CommunicationProblemHandler;
  46. import com.vaadin.client.communication.Heartbeat;
  47. import com.vaadin.client.communication.ReconnectingCommunicationProblemHandler;
  48. import com.vaadin.client.communication.RpcManager;
  49. import com.vaadin.client.communication.ServerCommunicationHandler;
  50. import com.vaadin.client.communication.ServerMessageHandler;
  51. import com.vaadin.client.communication.ServerRpcQueue;
  52. import com.vaadin.client.componentlocator.ComponentLocator;
  53. import com.vaadin.client.metadata.ConnectorBundleLoader;
  54. import com.vaadin.client.ui.AbstractComponentConnector;
  55. import com.vaadin.client.ui.FontIcon;
  56. import com.vaadin.client.ui.Icon;
  57. import com.vaadin.client.ui.ImageIcon;
  58. import com.vaadin.client.ui.VContextMenu;
  59. import com.vaadin.client.ui.VNotification;
  60. import com.vaadin.client.ui.VOverlay;
  61. import com.vaadin.client.ui.ui.UIConnector;
  62. import com.vaadin.shared.AbstractComponentState;
  63. import com.vaadin.shared.VaadinUriResolver;
  64. import com.vaadin.shared.Version;
  65. import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
  66. import com.vaadin.shared.util.SharedUtil;
  67. /**
  68. * This is the client side communication "engine", managing client-server
  69. * communication with its server side counterpart
  70. * com.vaadin.server.VaadinService.
  71. *
  72. * Client-side connectors receive updates from the corresponding server-side
  73. * connector (typically component) as state updates or RPC calls. The connector
  74. * has the possibility to communicate back with its server side counter part
  75. * through RPC calls.
  76. *
  77. * TODO document better
  78. *
  79. * Entry point classes (widgetsets) define <code>onModuleLoad()</code>.
  80. */
  81. public class ApplicationConnection implements HasHandlers {
  82. @Deprecated
  83. public static final String MODIFIED_CLASSNAME = StyleConstants.MODIFIED;
  84. @Deprecated
  85. public static final String DISABLED_CLASSNAME = StyleConstants.DISABLED;
  86. @Deprecated
  87. public static final String REQUIRED_CLASSNAME = StyleConstants.REQUIRED;
  88. @Deprecated
  89. public static final String REQUIRED_CLASSNAME_EXT = StyleConstants.REQUIRED_EXT;
  90. @Deprecated
  91. public static final String ERROR_CLASSNAME_EXT = StyleConstants.ERROR_EXT;
  92. /**
  93. * A string that, if found in a non-JSON response to a UIDL request, will
  94. * cause the browser to refresh the page. If followed by a colon, optional
  95. * whitespace, and a URI, causes the browser to synchronously load the URI.
  96. *
  97. * <p>
  98. * This allows, for instance, a servlet filter to redirect the application
  99. * to a custom login page when the session expires. For example:
  100. * </p>
  101. *
  102. * <pre>
  103. * if (sessionExpired) {
  104. * response.setHeader(&quot;Content-Type&quot;, &quot;text/html&quot;);
  105. * response.getWriter().write(
  106. * myLoginPageHtml + &quot;&lt;!-- Vaadin-Refresh: &quot;
  107. * + request.getContextPath() + &quot; --&gt;&quot;);
  108. * }
  109. * </pre>
  110. */
  111. public static final String UIDL_REFRESH_TOKEN = "Vaadin-Refresh";
  112. private final HashMap<String, String> resourcesMap = new HashMap<String, String>();
  113. private WidgetSet widgetSet;
  114. private VContextMenu contextMenu = null;
  115. private final UIConnector uIConnector;
  116. protected boolean cssLoaded = false;
  117. /** Parameters for this application connection loaded from the web-page */
  118. private ApplicationConfiguration configuration;
  119. private final LayoutManager layoutManager;
  120. private final RpcManager rpcManager;
  121. /** Event bus for communication events */
  122. private EventBus eventBus = GWT.create(SimpleEventBus.class);
  123. public enum State {
  124. INITIALIZING, RUNNING, TERMINATED;
  125. }
  126. private State state = State.INITIALIZING;
  127. /**
  128. * The communication handler methods are called at certain points during
  129. * communication with the server. This allows for making add-ons that keep
  130. * track of different aspects of the communication.
  131. */
  132. public interface CommunicationHandler extends EventHandler {
  133. void onRequestStarting(RequestStartingEvent e);
  134. void onResponseHandlingStarted(ResponseHandlingStartedEvent e);
  135. void onResponseHandlingEnded(ResponseHandlingEndedEvent e);
  136. }
  137. public static class RequestStartingEvent extends ApplicationConnectionEvent {
  138. public static Type<CommunicationHandler> TYPE = new Type<CommunicationHandler>();
  139. public RequestStartingEvent(ApplicationConnection connection) {
  140. super(connection);
  141. }
  142. @Override
  143. public Type<CommunicationHandler> getAssociatedType() {
  144. return TYPE;
  145. }
  146. @Override
  147. protected void dispatch(CommunicationHandler handler) {
  148. handler.onRequestStarting(this);
  149. }
  150. }
  151. public static class ResponseHandlingEndedEvent extends
  152. ApplicationConnectionEvent {
  153. public static Type<CommunicationHandler> TYPE = new Type<CommunicationHandler>();
  154. public ResponseHandlingEndedEvent(ApplicationConnection connection) {
  155. super(connection);
  156. }
  157. @Override
  158. public Type<CommunicationHandler> getAssociatedType() {
  159. return TYPE;
  160. }
  161. @Override
  162. protected void dispatch(CommunicationHandler handler) {
  163. handler.onResponseHandlingEnded(this);
  164. }
  165. }
  166. public static abstract class ApplicationConnectionEvent extends
  167. GwtEvent<CommunicationHandler> {
  168. private ApplicationConnection connection;
  169. protected ApplicationConnectionEvent(ApplicationConnection connection) {
  170. this.connection = connection;
  171. }
  172. public ApplicationConnection getConnection() {
  173. return connection;
  174. }
  175. }
  176. public static class ResponseHandlingStartedEvent extends
  177. ApplicationConnectionEvent {
  178. public ResponseHandlingStartedEvent(ApplicationConnection connection) {
  179. super(connection);
  180. }
  181. public static Type<CommunicationHandler> TYPE = new Type<CommunicationHandler>();
  182. @Override
  183. public Type<CommunicationHandler> getAssociatedType() {
  184. return TYPE;
  185. }
  186. @Override
  187. protected void dispatch(CommunicationHandler handler) {
  188. handler.onResponseHandlingStarted(this);
  189. }
  190. }
  191. /**
  192. * Event triggered when a application is stopped by calling
  193. * {@link ApplicationConnection#setApplicationRunning(false)}.
  194. *
  195. * To listen for the event add a {@link ApplicationStoppedHandler} by
  196. * invoking
  197. * {@link ApplicationConnection#addHandler(ApplicationConnection.ApplicationStoppedEvent.Type, ApplicationStoppedHandler)}
  198. * to the {@link ApplicationConnection}
  199. *
  200. * @since 7.1.8
  201. * @author Vaadin Ltd
  202. */
  203. public static class ApplicationStoppedEvent extends
  204. GwtEvent<ApplicationStoppedHandler> {
  205. public static Type<ApplicationStoppedHandler> TYPE = new Type<ApplicationStoppedHandler>();
  206. @Override
  207. public Type<ApplicationStoppedHandler> getAssociatedType() {
  208. return TYPE;
  209. }
  210. @Override
  211. protected void dispatch(ApplicationStoppedHandler listener) {
  212. listener.onApplicationStopped(this);
  213. }
  214. }
  215. /**
  216. * Allows custom handling of communication errors.
  217. */
  218. public interface CommunicationErrorHandler {
  219. /**
  220. * Called when a communication error has occurred. Returning
  221. * <code>true</code> from this method suppresses error handling.
  222. *
  223. * @param details
  224. * A string describing the error.
  225. * @param statusCode
  226. * The HTTP status code (e.g. 404, etc).
  227. * @return true if the error reporting should be suppressed, false to
  228. * perform normal error reporting.
  229. */
  230. public boolean onError(String details, int statusCode);
  231. }
  232. /**
  233. * A listener for listening to application stopped events. The listener can
  234. * be added to a {@link ApplicationConnection} by invoking
  235. * {@link ApplicationConnection#addHandler(ApplicationStoppedEvent.Type, ApplicationStoppedHandler)}
  236. *
  237. * @since 7.1.8
  238. * @author Vaadin Ltd
  239. */
  240. public interface ApplicationStoppedHandler extends EventHandler {
  241. /**
  242. * Triggered when the {@link ApplicationConnection} marks a previously
  243. * running application as stopped by invoking
  244. * {@link ApplicationConnection#setApplicationRunning(false)}
  245. *
  246. * @param event
  247. * the event triggered by the {@link ApplicationConnection}
  248. */
  249. void onApplicationStopped(ApplicationStoppedEvent event);
  250. }
  251. private CommunicationErrorHandler communicationErrorDelegate = null;
  252. private VLoadingIndicator loadingIndicator;
  253. private Heartbeat heartbeat = GWT.create(Heartbeat.class);
  254. private boolean tooltipInitialized = false;
  255. private final VaadinUriResolver uriResolver = new VaadinUriResolver() {
  256. @Override
  257. protected String getVaadinDirUrl() {
  258. return getConfiguration().getVaadinDirUrl();
  259. }
  260. @Override
  261. protected String getServiceUrlParameterName() {
  262. return getConfiguration().getServiceUrlParameterName();
  263. }
  264. @Override
  265. protected String getServiceUrl() {
  266. return getConfiguration().getServiceUrl();
  267. }
  268. @Override
  269. protected String getThemeUri() {
  270. return ApplicationConnection.this.getThemeUri();
  271. }
  272. @Override
  273. protected String encodeQueryStringParameterValue(String queryString) {
  274. return URL.encodeQueryString(queryString);
  275. }
  276. };
  277. public static class MultiStepDuration extends Duration {
  278. private int previousStep = elapsedMillis();
  279. public void logDuration(String message) {
  280. logDuration(message, 0);
  281. }
  282. public void logDuration(String message, int minDuration) {
  283. int currentTime = elapsedMillis();
  284. int stepDuration = currentTime - previousStep;
  285. if (stepDuration >= minDuration) {
  286. getLogger().info(message + ": " + stepDuration + " ms");
  287. }
  288. previousStep = currentTime;
  289. }
  290. }
  291. public ApplicationConnection() {
  292. // Assuming UI data is eagerly loaded
  293. ConnectorBundleLoader.get().loadBundle(
  294. ConnectorBundleLoader.EAGER_BUNDLE_NAME, null);
  295. uIConnector = GWT.create(UIConnector.class);
  296. rpcManager = GWT.create(RpcManager.class);
  297. layoutManager = GWT.create(LayoutManager.class);
  298. layoutManager.setConnection(this);
  299. tooltip = GWT.create(VTooltip.class);
  300. loadingIndicator = GWT.create(VLoadingIndicator.class);
  301. loadingIndicator.setConnection(this);
  302. serverRpcQueue = GWT.create(ServerRpcQueue.class);
  303. serverRpcQueue.setConnection(this);
  304. communicationProblemHandler = GWT
  305. .create(ReconnectingCommunicationProblemHandler.class);
  306. communicationProblemHandler.setConnection(this);
  307. serverMessageHandler = GWT.create(ServerMessageHandler.class);
  308. serverMessageHandler.setConnection(this);
  309. serverCommunicationHandler = GWT
  310. .create(ServerCommunicationHandler.class);
  311. serverCommunicationHandler.setConnection(this);
  312. }
  313. public void init(WidgetSet widgetSet, ApplicationConfiguration cnf) {
  314. getLogger().info("Starting application " + cnf.getRootPanelId());
  315. getLogger().info("Using theme: " + cnf.getThemeName());
  316. getLogger().info(
  317. "Vaadin application servlet version: "
  318. + cnf.getServletVersion());
  319. if (!cnf.getServletVersion().equals(Version.getFullVersion())) {
  320. getLogger()
  321. .severe("Warning: your widget set seems to be built with a different "
  322. + "version than the one used on server. Unexpected "
  323. + "behavior may occur.");
  324. }
  325. this.widgetSet = widgetSet;
  326. configuration = cnf;
  327. ComponentLocator componentLocator = new ComponentLocator(this);
  328. String appRootPanelName = cnf.getRootPanelId();
  329. // remove the end (window name) of autogenerated rootpanel id
  330. appRootPanelName = appRootPanelName.replaceFirst("-\\d+$", "");
  331. initializeTestbenchHooks(componentLocator, appRootPanelName);
  332. initializeClientHooks();
  333. uIConnector.init(cnf.getRootPanelId(), this);
  334. tooltip.setOwner(uIConnector.getWidget());
  335. getLoadingIndicator().show();
  336. heartbeat.init(this);
  337. // Ensure the overlay container is added to the dom and set as a live
  338. // area for assistive devices
  339. Element overlayContainer = VOverlay.getOverlayContainer(this);
  340. Roles.getAlertRole().setAriaLiveProperty(overlayContainer,
  341. LiveValue.ASSERTIVE);
  342. VOverlay.setOverlayContainerLabel(this,
  343. getUIConnector().getState().overlayContainerLabel);
  344. Roles.getAlertRole().setAriaRelevantProperty(overlayContainer,
  345. RelevantValue.ADDITIONS);
  346. }
  347. /**
  348. * Starts this application. Don't call this method directly - it's called by
  349. * {@link ApplicationConfiguration#startNextApplication()}, which should be
  350. * called once this application has started (first response received) or
  351. * failed to start. This ensures that the applications are started in order,
  352. * to avoid session-id problems.
  353. *
  354. */
  355. public void start() {
  356. String jsonText = configuration.getUIDL();
  357. if (jsonText == null) {
  358. // initial UIDL not in DOM, request from server
  359. getServerCommunicationHandler().resynchronize();
  360. } else {
  361. // initial UIDL provided in DOM, continue as if returned by request
  362. // Hack to avoid logging an error in endRequest()
  363. getServerCommunicationHandler().startRequest();
  364. getServerMessageHandler().handleMessage(
  365. ServerMessageHandler.parseJson(jsonText));
  366. }
  367. // Tooltip can't be created earlier because the
  368. // necessary fields are not setup to add it in the
  369. // correct place in the DOM
  370. if (!tooltipInitialized) {
  371. tooltipInitialized = true;
  372. ApplicationConfiguration.runWhenDependenciesLoaded(new Command() {
  373. @Override
  374. public void execute() {
  375. getVTooltip().initializeAssistiveTooltips();
  376. }
  377. });
  378. }
  379. }
  380. /**
  381. * Checks if there is some work to be done on the client side
  382. *
  383. * @return true if the client has some work to be done, false otherwise
  384. */
  385. private boolean isActive() {
  386. return !getServerMessageHandler().isInitialUidlHandled()
  387. || isWorkPending()
  388. || getServerCommunicationHandler().hasActiveRequest()
  389. || isExecutingDeferredCommands();
  390. }
  391. private native void initializeTestbenchHooks(
  392. ComponentLocator componentLocator, String TTAppId)
  393. /*-{
  394. var ap = this;
  395. var client = {};
  396. client.isActive = $entry(function() {
  397. return ap.@com.vaadin.client.ApplicationConnection::isActive()();
  398. });
  399. var vi = ap.@com.vaadin.client.ApplicationConnection::getVersionInfo()();
  400. if (vi) {
  401. client.getVersionInfo = function() {
  402. return vi;
  403. }
  404. }
  405. client.getProfilingData = $entry(function() {
  406. var smh = ap.@com.vaadin.client.ApplicationConnection::getServerMessageHandler();
  407. var pd = [
  408. smh.@com.vaadin.client.communication.ServerMessageHandler::lastProcessingTime,
  409. smh.@com.vaadin.client.communication.ServerMessageHandler::totalProcessingTime
  410. ];
  411. pd = pd.concat(smh.@com.vaadin.client.communication.ServerMessageHandler::serverTimingInfo);
  412. pd[pd.length] = smh.@com.vaadin.client.communication.ServerMessageHandler::bootstrapTime;
  413. return pd;
  414. });
  415. client.getElementByPath = $entry(function(id) {
  416. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getElementByPath(Ljava/lang/String;)(id);
  417. });
  418. client.getElementByPathStartingAt = $entry(function(id, element) {
  419. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getElementByPathStartingAt(Ljava/lang/String;Lcom/google/gwt/dom/client/Element;)(id, element);
  420. });
  421. client.getElementsByPath = $entry(function(id) {
  422. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getElementsByPath(Ljava/lang/String;)(id);
  423. });
  424. client.getElementsByPathStartingAt = $entry(function(id, element) {
  425. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getElementsByPathStartingAt(Ljava/lang/String;Lcom/google/gwt/dom/client/Element;)(id, element);
  426. });
  427. client.getPathForElement = $entry(function(element) {
  428. return componentLocator.@com.vaadin.client.componentlocator.ComponentLocator::getPathForElement(Lcom/google/gwt/dom/client/Element;)(element);
  429. });
  430. client.initializing = false;
  431. $wnd.vaadin.clients[TTAppId] = client;
  432. }-*/;
  433. /**
  434. * Helper for tt initialization
  435. */
  436. private JavaScriptObject getVersionInfo() {
  437. return configuration.getVersionInfoJSObject();
  438. }
  439. /**
  440. * Publishes a JavaScript API for mash-up applications.
  441. * <ul>
  442. * <li><code>vaadin.forceSync()</code> sends pending variable changes, in
  443. * effect synchronizing the server and client state. This is done for all
  444. * applications on host page.</li>
  445. * <li><code>vaadin.postRequestHooks</code> is a map of functions which gets
  446. * called after each XHR made by vaadin application. Note, that it is
  447. * attaching js functions responsibility to create the variable like this:
  448. *
  449. * <code><pre>
  450. * if(!vaadin.postRequestHooks) {vaadin.postRequestHooks = new Object();}
  451. * postRequestHooks.myHook = function(appId) {
  452. * if(appId == "MyAppOfInterest") {
  453. * // do the staff you need on xhr activity
  454. * }
  455. * }
  456. * </pre></code> First parameter passed to these functions is the identifier
  457. * of Vaadin application that made the request.
  458. * </ul>
  459. *
  460. * TODO make this multi-app aware
  461. */
  462. private native void initializeClientHooks()
  463. /*-{
  464. var app = this;
  465. var oldSync;
  466. if ($wnd.vaadin.forceSync) {
  467. oldSync = $wnd.vaadin.forceSync;
  468. }
  469. $wnd.vaadin.forceSync = $entry(function() {
  470. if (oldSync) {
  471. oldSync();
  472. }
  473. app.@com.vaadin.client.ApplicationConnection::sendPendingVariableChanges()();
  474. });
  475. var oldForceLayout;
  476. if ($wnd.vaadin.forceLayout) {
  477. oldForceLayout = $wnd.vaadin.forceLayout;
  478. }
  479. $wnd.vaadin.forceLayout = $entry(function() {
  480. if (oldForceLayout) {
  481. oldForceLayout();
  482. }
  483. app.@com.vaadin.client.ApplicationConnection::forceLayout()();
  484. });
  485. }-*/;
  486. /**
  487. * Runs possibly registered client side post request hooks. This is expected
  488. * to be run after each uidl request made by Vaadin application.
  489. *
  490. * @param appId
  491. */
  492. public static native void runPostRequestHooks(String appId)
  493. /*-{
  494. if ($wnd.vaadin.postRequestHooks) {
  495. for ( var hook in $wnd.vaadin.postRequestHooks) {
  496. if (typeof ($wnd.vaadin.postRequestHooks[hook]) == "function") {
  497. try {
  498. $wnd.vaadin.postRequestHooks[hook](appId);
  499. } catch (e) {
  500. }
  501. }
  502. }
  503. }
  504. }-*/;
  505. /**
  506. * If on Liferay and logged in, ask the client side session management
  507. * JavaScript to extend the session duration.
  508. *
  509. * Otherwise, Liferay client side JavaScript will explicitly expire the
  510. * session even though the server side considers the session to be active.
  511. * See ticket #8305 for more information.
  512. */
  513. public static native void extendLiferaySession()
  514. /*-{
  515. if ($wnd.Liferay && $wnd.Liferay.Session) {
  516. $wnd.Liferay.Session.extend();
  517. // if the extend banner is visible, hide it
  518. if ($wnd.Liferay.Session.banner) {
  519. $wnd.Liferay.Session.banner.remove();
  520. }
  521. }
  522. }-*/;
  523. /**
  524. * Requests an analyze of layouts, to find inconsistencies. Exclusively used
  525. * for debugging during development.
  526. *
  527. * @deprecated as of 7.1. Replaced by {@link UIConnector#analyzeLayouts()}
  528. */
  529. @Deprecated
  530. public void analyzeLayouts() {
  531. getUIConnector().analyzeLayouts();
  532. }
  533. /**
  534. * Sends a request to the server to print details to console that will help
  535. * the developer to locate the corresponding server-side connector in the
  536. * source code.
  537. *
  538. * @param serverConnector
  539. * @deprecated as of 7.1. Replaced by
  540. * {@link UIConnector#showServerDebugInfo(ServerConnector)}
  541. */
  542. @Deprecated
  543. void highlightConnector(ServerConnector serverConnector) {
  544. getUIConnector().showServerDebugInfo(serverConnector);
  545. }
  546. int cssWaits = 0;
  547. protected ServerRpcQueue serverRpcQueue;
  548. protected CommunicationProblemHandler communicationProblemHandler;
  549. protected ServerMessageHandler serverMessageHandler;
  550. protected ServerCommunicationHandler serverCommunicationHandler;
  551. static final int MAX_CSS_WAITS = 100;
  552. public void executeWhenCSSLoaded(final Command c) {
  553. if (!isCSSLoaded() && cssWaits < MAX_CSS_WAITS) {
  554. (new Timer() {
  555. @Override
  556. public void run() {
  557. executeWhenCSSLoaded(c);
  558. }
  559. }).schedule(50);
  560. // Show this message just once
  561. if (cssWaits++ == 0) {
  562. getLogger().warning(
  563. "Assuming CSS loading is not complete, "
  564. + "postponing render phase. "
  565. + "(.v-loading-indicator height == 0)");
  566. }
  567. } else {
  568. cssLoaded = true;
  569. if (cssWaits >= MAX_CSS_WAITS) {
  570. getLogger().severe("CSS files may have not loaded properly.");
  571. }
  572. c.execute();
  573. }
  574. }
  575. /**
  576. * Checks whether or not the CSS is loaded. By default checks the size of
  577. * the loading indicator element.
  578. *
  579. * @return
  580. */
  581. protected boolean isCSSLoaded() {
  582. return cssLoaded
  583. || getLoadingIndicator().getElement().getOffsetHeight() != 0;
  584. }
  585. /**
  586. * Shows the communication error notification.
  587. *
  588. * @param details
  589. * Optional details.
  590. * @param statusCode
  591. * The status code returned for the request
  592. *
  593. */
  594. public void showCommunicationError(String details, int statusCode) {
  595. getLogger().severe("Communication error: " + details);
  596. showError(details, configuration.getCommunicationError());
  597. }
  598. /**
  599. * Shows the authentication error notification.
  600. *
  601. * @param details
  602. * Optional details.
  603. */
  604. public void showAuthenticationError(String details) {
  605. getLogger().severe("Authentication error: " + details);
  606. showError(details, configuration.getAuthorizationError());
  607. }
  608. /**
  609. * Shows the session expiration notification.
  610. *
  611. * @param details
  612. * Optional details.
  613. */
  614. public void showSessionExpiredError(String details) {
  615. getLogger().severe("Session expired: " + details);
  616. showError(details, configuration.getSessionExpiredError());
  617. }
  618. /**
  619. * Shows an error notification.
  620. *
  621. * @param details
  622. * Optional details.
  623. * @param message
  624. * An ErrorMessage describing the error.
  625. */
  626. protected void showError(String details, ErrorMessage message) {
  627. VNotification.showError(this, message.getCaption(),
  628. message.getMessage(), details, message.getUrl());
  629. }
  630. /**
  631. * Checks if the client has running or scheduled commands
  632. */
  633. private boolean isWorkPending() {
  634. ConnectorMap connectorMap = getConnectorMap();
  635. JsArrayObject<ServerConnector> connectors = connectorMap
  636. .getConnectorsAsJsArray();
  637. int size = connectors.size();
  638. for (int i = 0; i < size; i++) {
  639. ServerConnector conn = connectors.get(i);
  640. if (isWorkPending(conn)) {
  641. return true;
  642. }
  643. if (conn instanceof ComponentConnector) {
  644. ComponentConnector compConn = (ComponentConnector) conn;
  645. if (isWorkPending(compConn.getWidget())) {
  646. return true;
  647. }
  648. }
  649. }
  650. return false;
  651. }
  652. private static boolean isWorkPending(Object object) {
  653. return object instanceof DeferredWorker
  654. && ((DeferredWorker) object).isWorkPending();
  655. }
  656. /**
  657. * Checks if deferred commands are (potentially) still being executed as a
  658. * result of an update from the server. Returns true if a deferred command
  659. * might still be executing, false otherwise. This will not work correctly
  660. * if a deferred command is added in another deferred command.
  661. * <p>
  662. * Used by the native "client.isActive" function.
  663. * </p>
  664. *
  665. * @return true if deferred commands are (potentially) being executed, false
  666. * otherwise
  667. */
  668. private boolean isExecutingDeferredCommands() {
  669. Scheduler s = Scheduler.get();
  670. if (s instanceof VSchedulerImpl) {
  671. return ((VSchedulerImpl) s).hasWorkQueued();
  672. } else {
  673. return false;
  674. }
  675. }
  676. /**
  677. * Returns the loading indicator used by this ApplicationConnection
  678. *
  679. * @return The loading indicator for this ApplicationConnection
  680. */
  681. public VLoadingIndicator getLoadingIndicator() {
  682. return loadingIndicator;
  683. }
  684. /**
  685. * Determines whether or not the loading indicator is showing.
  686. *
  687. * @return true if the loading indicator is visible
  688. * @deprecated As of 7.1. Use {@link #getLoadingIndicator()} and
  689. * {@link VLoadingIndicator#isVisible()}.isVisible() instead.
  690. */
  691. @Deprecated
  692. public boolean isLoadingIndicatorVisible() {
  693. return getLoadingIndicator().isVisible();
  694. }
  695. public void loadStyleDependencies(JsArrayString dependencies) {
  696. // Assuming no reason to interpret in a defined order
  697. ResourceLoadListener resourceLoadListener = new ResourceLoadListener() {
  698. @Override
  699. public void onLoad(ResourceLoadEvent event) {
  700. ApplicationConfiguration.endDependencyLoading();
  701. }
  702. @Override
  703. public void onError(ResourceLoadEvent event) {
  704. getLogger()
  705. .severe(event.getResourceUrl()
  706. + " could not be loaded, or the load detection failed because the stylesheet is empty.");
  707. // The show must go on
  708. onLoad(event);
  709. }
  710. };
  711. ResourceLoader loader = ResourceLoader.get();
  712. for (int i = 0; i < dependencies.length(); i++) {
  713. String url = translateVaadinUri(dependencies.get(i));
  714. ApplicationConfiguration.startDependencyLoading();
  715. loader.loadStylesheet(url, resourceLoadListener);
  716. }
  717. }
  718. public void loadScriptDependencies(final JsArrayString dependencies) {
  719. if (dependencies.length() == 0) {
  720. return;
  721. }
  722. // Listener that loads the next when one is completed
  723. ResourceLoadListener resourceLoadListener = new ResourceLoadListener() {
  724. @Override
  725. public void onLoad(ResourceLoadEvent event) {
  726. if (dependencies.length() != 0) {
  727. String url = translateVaadinUri(dependencies.shift());
  728. ApplicationConfiguration.startDependencyLoading();
  729. // Load next in chain (hopefully already preloaded)
  730. event.getResourceLoader().loadScript(url, this);
  731. }
  732. // Call start for next before calling end for current
  733. ApplicationConfiguration.endDependencyLoading();
  734. }
  735. @Override
  736. public void onError(ResourceLoadEvent event) {
  737. getLogger().severe(
  738. event.getResourceUrl() + " could not be loaded.");
  739. // The show must go on
  740. onLoad(event);
  741. }
  742. };
  743. ResourceLoader loader = ResourceLoader.get();
  744. // Start chain by loading first
  745. String url = translateVaadinUri(dependencies.shift());
  746. ApplicationConfiguration.startDependencyLoading();
  747. loader.loadScript(url, resourceLoadListener);
  748. if (ResourceLoader.supportsInOrderScriptExecution()) {
  749. for (int i = 0; i < dependencies.length(); i++) {
  750. String preloadUrl = translateVaadinUri(dependencies.get(i));
  751. loader.loadScript(preloadUrl, null);
  752. }
  753. } else {
  754. // Preload all remaining
  755. for (int i = 0; i < dependencies.length(); i++) {
  756. String preloadUrl = translateVaadinUri(dependencies.get(i));
  757. loader.preloadResource(preloadUrl, null);
  758. }
  759. }
  760. }
  761. private void addVariableToQueue(String connectorId, String variableName,
  762. Object value, boolean immediate) {
  763. boolean lastOnly = !immediate;
  764. // note that type is now deduced from value
  765. serverRpcQueue.add(new LegacyChangeVariablesInvocation(connectorId,
  766. variableName, value), lastOnly);
  767. if (immediate) {
  768. serverRpcQueue.flush();
  769. }
  770. }
  771. /**
  772. * @deprecated as of 7.6, use {@link ServerRpcQueue#flush()}
  773. */
  774. @Deprecated
  775. public void sendPendingVariableChanges() {
  776. serverRpcQueue.flush();
  777. }
  778. /**
  779. * Sends a new value for the given paintables given variable to the server.
  780. * <p>
  781. * The update is actually queued to be sent at a suitable time. If immediate
  782. * is true, the update is sent as soon as possible. If immediate is false,
  783. * the update will be sent along with the next immediate update.
  784. * </p>
  785. *
  786. * @param paintableId
  787. * the id of the paintable that owns the variable
  788. * @param variableName
  789. * the name of the variable
  790. * @param newValue
  791. * the new value to be sent
  792. * @param immediate
  793. * true if the update is to be sent as soon as possible
  794. */
  795. public void updateVariable(String paintableId, String variableName,
  796. ServerConnector newValue, boolean immediate) {
  797. addVariableToQueue(paintableId, variableName, newValue, immediate);
  798. }
  799. /**
  800. * Sends a new value for the given paintables given variable to the server.
  801. * <p>
  802. * The update is actually queued to be sent at a suitable time. If immediate
  803. * is true, the update is sent as soon as possible. If immediate is false,
  804. * the update will be sent along with the next immediate update.
  805. * </p>
  806. *
  807. * @param paintableId
  808. * the id of the paintable that owns the variable
  809. * @param variableName
  810. * the name of the variable
  811. * @param newValue
  812. * the new value to be sent
  813. * @param immediate
  814. * true if the update is to be sent as soon as possible
  815. */
  816. public void updateVariable(String paintableId, String variableName,
  817. String newValue, boolean immediate) {
  818. addVariableToQueue(paintableId, variableName, newValue, immediate);
  819. }
  820. /**
  821. * Sends a new value for the given paintables given variable to the server.
  822. * <p>
  823. * The update is actually queued to be sent at a suitable time. If immediate
  824. * is true, the update is sent as soon as possible. If immediate is false,
  825. * the update will be sent along with the next immediate update.
  826. * </p>
  827. *
  828. * @param paintableId
  829. * the id of the paintable that owns the variable
  830. * @param variableName
  831. * the name of the variable
  832. * @param newValue
  833. * the new value to be sent
  834. * @param immediate
  835. * true if the update is to be sent as soon as possible
  836. */
  837. public void updateVariable(String paintableId, String variableName,
  838. int newValue, boolean immediate) {
  839. addVariableToQueue(paintableId, variableName, newValue, immediate);
  840. }
  841. /**
  842. * Sends a new value for the given paintables given variable to the server.
  843. * <p>
  844. * The update is actually queued to be sent at a suitable time. If immediate
  845. * is true, the update is sent as soon as possible. If immediate is false,
  846. * the update will be sent along with the next immediate update.
  847. * </p>
  848. *
  849. * @param paintableId
  850. * the id of the paintable that owns the variable
  851. * @param variableName
  852. * the name of the variable
  853. * @param newValue
  854. * the new value to be sent
  855. * @param immediate
  856. * true if the update is to be sent as soon as possible
  857. */
  858. public void updateVariable(String paintableId, String variableName,
  859. long newValue, boolean immediate) {
  860. addVariableToQueue(paintableId, variableName, newValue, immediate);
  861. }
  862. /**
  863. * Sends a new value for the given paintables given variable to the server.
  864. * <p>
  865. * The update is actually queued to be sent at a suitable time. If immediate
  866. * is true, the update is sent as soon as possible. If immediate is false,
  867. * the update will be sent along with the next immediate update.
  868. * </p>
  869. *
  870. * @param paintableId
  871. * the id of the paintable that owns the variable
  872. * @param variableName
  873. * the name of the variable
  874. * @param newValue
  875. * the new value to be sent
  876. * @param immediate
  877. * true if the update is to be sent as soon as possible
  878. */
  879. public void updateVariable(String paintableId, String variableName,
  880. float newValue, boolean immediate) {
  881. addVariableToQueue(paintableId, variableName, newValue, immediate);
  882. }
  883. /**
  884. * Sends a new value for the given paintables given variable to the server.
  885. * <p>
  886. * The update is actually queued to be sent at a suitable time. If immediate
  887. * is true, the update is sent as soon as possible. If immediate is false,
  888. * the update will be sent along with the next immediate update.
  889. * </p>
  890. *
  891. * @param paintableId
  892. * the id of the paintable that owns the variable
  893. * @param variableName
  894. * the name of the variable
  895. * @param newValue
  896. * the new value to be sent
  897. * @param immediate
  898. * true if the update is to be sent as soon as possible
  899. */
  900. public void updateVariable(String paintableId, String variableName,
  901. double newValue, boolean immediate) {
  902. addVariableToQueue(paintableId, variableName, newValue, immediate);
  903. }
  904. /**
  905. * Sends a new value for the given paintables given variable to the server.
  906. * <p>
  907. * The update is actually queued to be sent at a suitable time. If immediate
  908. * is true, the update is sent as soon as possible. If immediate is false,
  909. * the update will be sent along with the next immediate update.
  910. * </p>
  911. *
  912. * @param paintableId
  913. * the id of the paintable that owns the variable
  914. * @param variableName
  915. * the name of the variable
  916. * @param newValue
  917. * the new value to be sent
  918. * @param immediate
  919. * true if the update is to be sent as soon as possible
  920. */
  921. public void updateVariable(String paintableId, String variableName,
  922. boolean newValue, boolean immediate) {
  923. addVariableToQueue(paintableId, variableName, newValue, immediate);
  924. }
  925. /**
  926. * Sends a new value for the given paintables given variable to the server.
  927. * <p>
  928. * The update is actually queued to be sent at a suitable time. If immediate
  929. * is true, the update is sent as soon as possible. If immediate is false,
  930. * the update will be sent along with the next immediate update.
  931. * </p>
  932. *
  933. * @param paintableId
  934. * the id of the paintable that owns the variable
  935. * @param variableName
  936. * the name of the variable
  937. * @param map
  938. * the new values to be sent
  939. * @param immediate
  940. * true if the update is to be sent as soon as possible
  941. */
  942. public void updateVariable(String paintableId, String variableName,
  943. Map<String, Object> map, boolean immediate) {
  944. addVariableToQueue(paintableId, variableName, map, immediate);
  945. }
  946. /**
  947. * Sends a new value for the given paintables given variable to the server.
  948. * <p>
  949. * The update is actually queued to be sent at a suitable time. If immediate
  950. * is true, the update is sent as soon as possible. If immediate is false,
  951. * the update will be sent along with the next immediate update.
  952. * <p>
  953. * A null array is sent as an empty array.
  954. *
  955. * @param paintableId
  956. * the id of the paintable that owns the variable
  957. * @param variableName
  958. * the name of the variable
  959. * @param values
  960. * the new value to be sent
  961. * @param immediate
  962. * true if the update is to be sent as soon as possible
  963. */
  964. public void updateVariable(String paintableId, String variableName,
  965. String[] values, boolean immediate) {
  966. addVariableToQueue(paintableId, variableName, values, immediate);
  967. }
  968. /**
  969. * Sends a new value for the given paintables given variable to the server.
  970. * <p>
  971. * The update is actually queued to be sent at a suitable time. If immediate
  972. * is true, the update is sent as soon as possible. If immediate is false,
  973. * the update will be sent along with the next immediate update.
  974. * <p>
  975. * A null array is sent as an empty array.
  976. *
  977. * @param paintableId
  978. * the id of the paintable that owns the variable
  979. * @param variableName
  980. * the name of the variable
  981. * @param values
  982. * the new value to be sent
  983. * @param immediate
  984. * true if the update is to be sent as soon as possible
  985. */
  986. public void updateVariable(String paintableId, String variableName,
  987. Object[] values, boolean immediate) {
  988. addVariableToQueue(paintableId, variableName, values, immediate);
  989. }
  990. /**
  991. * Does absolutely nothing. Replaced by {@link LayoutManager}.
  992. *
  993. * @param container
  994. * @deprecated As of 7.0, serves no purpose
  995. */
  996. @Deprecated
  997. public void runDescendentsLayout(HasWidgets container) {
  998. }
  999. /**
  1000. * This will cause re-layouting of all components. Mainly used for
  1001. * development. Published to JavaScript.
  1002. */
  1003. public void forceLayout() {
  1004. Duration duration = new Duration();
  1005. layoutManager.forceLayout();
  1006. getLogger().info("forceLayout in " + duration.elapsedMillis() + " ms");
  1007. }
  1008. /**
  1009. * Returns false
  1010. *
  1011. * @param paintable
  1012. * @return false, always
  1013. * @deprecated As of 7.0, serves no purpose
  1014. */
  1015. @Deprecated
  1016. private boolean handleComponentRelativeSize(ComponentConnector paintable) {
  1017. return false;
  1018. }
  1019. /**
  1020. * Returns false
  1021. *
  1022. * @param paintable
  1023. * @return false, always
  1024. * @deprecated As of 7.0, serves no purpose
  1025. */
  1026. @Deprecated
  1027. public boolean handleComponentRelativeSize(Widget widget) {
  1028. return handleComponentRelativeSize(connectorMap.getConnector(widget));
  1029. }
  1030. @Deprecated
  1031. public ComponentConnector getPaintable(UIDL uidl) {
  1032. // Non-component connectors shouldn't be painted from legacy connectors
  1033. return (ComponentConnector) getConnector(uidl.getId(),
  1034. Integer.parseInt(uidl.getTag()));
  1035. }
  1036. /**
  1037. * Get either an existing ComponentConnector or create a new
  1038. * ComponentConnector with the given type and id.
  1039. *
  1040. * If a ComponentConnector with the given id already exists, returns it.
  1041. * Otherwise creates and registers a new ComponentConnector of the given
  1042. * type.
  1043. *
  1044. * @param connectorId
  1045. * Id of the paintable
  1046. * @param connectorType
  1047. * Type of the connector, as passed from the server side
  1048. *
  1049. * @return Either an existing ComponentConnector or a new ComponentConnector
  1050. * of the given type
  1051. */
  1052. public ServerConnector getConnector(String connectorId, int connectorType) {
  1053. if (!connectorMap.hasConnector(connectorId)) {
  1054. return createAndRegisterConnector(connectorId, connectorType);
  1055. }
  1056. return connectorMap.getConnector(connectorId);
  1057. }
  1058. /**
  1059. * Creates a new ServerConnector with the given type and id.
  1060. *
  1061. * Creates and registers a new ServerConnector of the given type. Should
  1062. * never be called with the connector id of an existing connector.
  1063. *
  1064. * @param connectorId
  1065. * Id of the new connector
  1066. * @param connectorType
  1067. * Type of the connector, as passed from the server side
  1068. *
  1069. * @return A new ServerConnector of the given type
  1070. */
  1071. private ServerConnector createAndRegisterConnector(String connectorId,
  1072. int connectorType) {
  1073. Profiler.enter("ApplicationConnection.createAndRegisterConnector");
  1074. // Create and register a new connector with the given type
  1075. ServerConnector p = widgetSet.createConnector(connectorType,
  1076. configuration);
  1077. connectorMap.registerConnector(connectorId, p);
  1078. p.doInit(connectorId, this);
  1079. Profiler.leave("ApplicationConnection.createAndRegisterConnector");
  1080. return p;
  1081. }
  1082. /**
  1083. * Gets a resource that has been pre-loaded via UIDL, such as custom
  1084. * layouts.
  1085. *
  1086. * @param name
  1087. * identifier of the resource to get
  1088. * @return the resource
  1089. */
  1090. public String getResource(String name) {
  1091. return resourcesMap.get(name);
  1092. }
  1093. /**
  1094. * Sets a resource that has been pre-loaded via UIDL, such as custom
  1095. * layouts.
  1096. *
  1097. * @param name
  1098. * identifier of the resource to Set
  1099. * @param resource
  1100. * the resource
  1101. */
  1102. public void setResource(String name, String resource) {
  1103. resourcesMap.put(name, resource);
  1104. }
  1105. /**
  1106. * Singleton method to get instance of app's context menu.
  1107. *
  1108. * @return VContextMenu object
  1109. */
  1110. public VContextMenu getContextMenu() {
  1111. if (contextMenu == null) {
  1112. contextMenu = new VContextMenu();
  1113. contextMenu.setOwner(uIConnector.getWidget());
  1114. DOM.setElementProperty(contextMenu.getElement(), "id",
  1115. "PID_VAADIN_CM");
  1116. }
  1117. return contextMenu;
  1118. }
  1119. /**
  1120. * Gets an {@link Icon} instance corresponding to a URI.
  1121. *
  1122. * @since 7.2
  1123. * @param uri
  1124. * @return Icon object
  1125. */
  1126. public Icon getIcon(String uri) {
  1127. Icon icon;
  1128. if (uri == null) {
  1129. return null;
  1130. } else if (FontIcon.isFontIconUri(uri)) {
  1131. icon = GWT.create(FontIcon.class);
  1132. } else {
  1133. icon = GWT.create(ImageIcon.class);
  1134. }
  1135. icon.setUri(translateVaadinUri(uri));
  1136. return icon;
  1137. }
  1138. /**
  1139. * Translates custom protocols in UIDL URI's to be recognizable by browser.
  1140. * All uri's from UIDL should be routed via this method before giving them
  1141. * to browser due URI's in UIDL may contain custom protocols like theme://.
  1142. *
  1143. * @param uidlUri
  1144. * Vaadin URI from uidl
  1145. * @return translated URI ready for browser
  1146. */
  1147. public String translateVaadinUri(String uidlUri) {
  1148. return uriResolver.resolveVaadinUri(uidlUri);
  1149. }
  1150. /**
  1151. * Gets the URI for the current theme. Can be used to reference theme
  1152. * resources.
  1153. *
  1154. * @return URI to the current theme
  1155. */
  1156. public String getThemeUri() {
  1157. return configuration.getVaadinDirUrl() + "themes/"
  1158. + getUIConnector().getActiveTheme();
  1159. }
  1160. /* Extended title handling */
  1161. private final VTooltip tooltip;
  1162. private ConnectorMap connectorMap = GWT.create(ConnectorMap.class);
  1163. /**
  1164. * Use to notify that the given component's caption has changed; layouts may
  1165. * have to be recalculated.
  1166. *
  1167. * @param component
  1168. * the Paintable whose caption has changed
  1169. * @deprecated As of 7.0.2, has not had any effect for a long time
  1170. */
  1171. @Deprecated
  1172. public void captionSizeUpdated(Widget widget) {
  1173. // This doesn't do anything, it's just kept here for compatibility
  1174. }
  1175. /**
  1176. * Gets the main view
  1177. *
  1178. * @return the main view
  1179. */
  1180. public UIConnector getUIConnector() {
  1181. return uIConnector;
  1182. }
  1183. /**
  1184. * Gets the {@link ApplicationConfiguration} for the current application.
  1185. *
  1186. * @see ApplicationConfiguration
  1187. * @return the configuration for this application
  1188. */
  1189. public ApplicationConfiguration getConfiguration() {
  1190. return configuration;
  1191. }
  1192. /**
  1193. * Checks if there is a registered server side listener for the event. The
  1194. * list of events which has server side listeners is updated automatically
  1195. * before the component is updated so the value is correct if called from
  1196. * updatedFromUIDL.
  1197. *
  1198. * @param paintable
  1199. * The connector to register event listeners for
  1200. * @param eventIdentifier
  1201. * The identifier for the event
  1202. * @return true if at least one listener has been registered on server side
  1203. * for the event identified by eventIdentifier.
  1204. * @deprecated As of 7.0. Use
  1205. * {@link AbstractComponentState#hasEventListener(String)}
  1206. * instead
  1207. */
  1208. @Deprecated
  1209. public boolean hasEventListeners(ComponentConnector paintable,
  1210. String eventIdentifier) {
  1211. return paintable.hasEventListener(eventIdentifier);
  1212. }
  1213. /**
  1214. * Adds the get parameters to the uri and returns the new uri that contains
  1215. * the parameters.
  1216. *
  1217. * @param uri
  1218. * The uri to which the parameters should be added.
  1219. * @param extraParams
  1220. * One or more parameters in the format "a=b" or "c=d&e=f". An
  1221. * empty string is allowed but will not modify the url.
  1222. * @return The modified URI with the get parameters in extraParams added.
  1223. * @deprecated Use {@link SharedUtil#addGetParameters(String,String)}
  1224. * instead
  1225. */
  1226. @Deprecated
  1227. public static String addGetParameters(String uri, String extraParams) {
  1228. return SharedUtil.addGetParameters(uri, extraParams);
  1229. }
  1230. ConnectorMap getConnectorMap() {
  1231. return connectorMap;
  1232. }
  1233. /**
  1234. * @deprecated As of 7.0. No longer serves any purpose.
  1235. */
  1236. @Deprecated
  1237. public void unregisterPaintable(ServerConnector p) {
  1238. getLogger().info(
  1239. "unregisterPaintable (unnecessarily) called for "
  1240. + Util.getConnectorString(p));
  1241. }
  1242. /**
  1243. * Get VTooltip instance related to application connection
  1244. *
  1245. * @return VTooltip instance
  1246. */
  1247. public VTooltip getVTooltip() {
  1248. return tooltip;
  1249. }
  1250. /**
  1251. * Method provided for backwards compatibility. Duties previously done by
  1252. * this method is now handled by the state change event handler in
  1253. * AbstractComponentConnector. The only function this method has is to
  1254. * return true if the UIDL is a "cached" update.
  1255. *
  1256. * @param component
  1257. * @param uidl
  1258. * @param manageCaption
  1259. * @deprecated As of 7.0, no longer serves any purpose
  1260. * @return
  1261. */
  1262. @Deprecated
  1263. public boolean updateComponent(Widget component, UIDL uidl,
  1264. boolean manageCaption) {
  1265. ComponentConnector connector = getConnectorMap()
  1266. .getConnector(component);
  1267. if (!AbstractComponentConnector.isRealUpdate(uidl)) {
  1268. return true;
  1269. }
  1270. if (!manageCaption) {
  1271. getLogger()
  1272. .warning(
  1273. Util.getConnectorString(connector)
  1274. + " 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.");
  1275. }
  1276. return false;
  1277. }
  1278. /**
  1279. * @deprecated As of 7.0. Use
  1280. * {@link AbstractComponentConnector#hasEventListener(String)}
  1281. * instead
  1282. */
  1283. @Deprecated
  1284. public boolean hasEventListeners(Widget widget, String eventIdentifier) {
  1285. ComponentConnector connector = getConnectorMap().getConnector(widget);
  1286. if (connector == null) {
  1287. /*
  1288. * No connector will exist in cases where Vaadin widgets have been
  1289. * re-used without implementing server<->client communication.
  1290. */
  1291. return false;
  1292. }
  1293. return hasEventListeners(getConnectorMap().getConnector(widget),
  1294. eventIdentifier);
  1295. }
  1296. LayoutManager getLayoutManager() {
  1297. return layoutManager;
  1298. }
  1299. /**
  1300. * Schedules a heartbeat request to occur after the configured heartbeat
  1301. * interval elapses if the interval is a positive number. Otherwise, does
  1302. * nothing.
  1303. *
  1304. * @deprecated as of 7.2, use {@link Heartbeat#schedule()} instead
  1305. */
  1306. @Deprecated
  1307. protected void scheduleHeartbeat() {
  1308. heartbeat.schedule();
  1309. }
  1310. /**
  1311. * Sends a heartbeat request to the server.
  1312. * <p>
  1313. * Heartbeat requests are used to inform the server that the client-side is
  1314. * still alive. If the client page is closed or the connection lost, the
  1315. * server will eventually close the inactive UI.
  1316. *
  1317. * @deprecated as of 7.2, use {@link Heartbeat#send()} instead
  1318. */
  1319. @Deprecated
  1320. protected void sendHeartbeat() {
  1321. heartbeat.send();
  1322. }
  1323. public void handleCommunicationError(String details, int statusCode) {
  1324. boolean handled = false;
  1325. if (communicationErrorDelegate != null) {
  1326. handled = communicationErrorDelegate.onError(details, statusCode);
  1327. }
  1328. if (!handled) {
  1329. showCommunicationError(details, statusCode);
  1330. }
  1331. }
  1332. /**
  1333. * Sets the delegate that is called whenever a communication error occurrs.
  1334. *
  1335. * @param delegate
  1336. * the delegate.
  1337. */
  1338. public void setCommunicationErrorDelegate(CommunicationErrorHandler delegate) {
  1339. communicationErrorDelegate = delegate;
  1340. }
  1341. public void setApplicationRunning(boolean applicationRunning) {
  1342. if (getState() == State.TERMINATED) {
  1343. if (applicationRunning) {
  1344. getLogger()
  1345. .severe("Tried to restart a terminated application. This is not supported");
  1346. } else {
  1347. getLogger()
  1348. .warning(
  1349. "Tried to stop a terminated application. This should not be done");
  1350. }
  1351. return;
  1352. } else if (getState() == State.INITIALIZING) {
  1353. if (applicationRunning) {
  1354. state = State.RUNNING;
  1355. } else {
  1356. getLogger()
  1357. .warning(
  1358. "Tried to stop the application before it has started. This should not be done");
  1359. }
  1360. } else if (getState() == State.RUNNING) {
  1361. if (!applicationRunning) {
  1362. state = State.TERMINATED;
  1363. eventBus.fireEvent(new ApplicationStoppedEvent());
  1364. } else {
  1365. getLogger()
  1366. .warning(
  1367. "Tried to start an already running application. This should not be done");
  1368. }
  1369. }
  1370. }
  1371. /**
  1372. * Checks if the application is in the {@link State#RUNNING} state.
  1373. *
  1374. * @since
  1375. * @return true if the application is in the running state, false otherwise
  1376. */
  1377. public boolean isApplicationRunning() {
  1378. return state == State.RUNNING;
  1379. }
  1380. public <H extends EventHandler> HandlerRegistration addHandler(
  1381. GwtEvent.Type<H> type, H handler) {
  1382. return eventBus.addHandler(type, handler);
  1383. }
  1384. @Override
  1385. public void fireEvent(GwtEvent<?> event) {
  1386. eventBus.fireEvent(event);
  1387. }
  1388. /**
  1389. * Calls {@link ComponentConnector#flush()} on the active connector. Does
  1390. * nothing if there is no active (focused) connector.
  1391. */
  1392. public void flushActiveConnector() {
  1393. ComponentConnector activeConnector = getActiveConnector();
  1394. if (activeConnector == null) {
  1395. return;
  1396. }
  1397. activeConnector.flush();
  1398. }
  1399. /**
  1400. * Gets the active connector for focused element in browser.
  1401. *
  1402. * @return Connector for focused element or null.
  1403. */
  1404. private ComponentConnector getActiveConnector() {
  1405. Element focusedElement = WidgetUtil.getFocusedElement();
  1406. if (focusedElement == null) {
  1407. return null;
  1408. }
  1409. return Util.getConnectorForElement(this, getUIConnector().getWidget(),
  1410. focusedElement);
  1411. }
  1412. private static Logger getLogger() {
  1413. return Logger.getLogger(ApplicationConnection.class.getName());
  1414. }
  1415. /**
  1416. * Returns the hearbeat instance.
  1417. */
  1418. public Heartbeat getHeartbeat() {
  1419. return heartbeat;
  1420. }
  1421. /**
  1422. * Returns the state of this application. An application state goes from
  1423. * "initializing" to "running" to "stopped". There is no way for an
  1424. * application to go back to a previous state, i.e. a stopped application
  1425. * can never be re-started
  1426. *
  1427. * @since
  1428. * @return the current state of this application
  1429. */
  1430. public State getState() {
  1431. return state;
  1432. }
  1433. /**
  1434. * Gets the server RPC queue for this application
  1435. *
  1436. * @return the server RPC queue
  1437. */
  1438. public ServerRpcQueue getServerRpcQueue() {
  1439. return serverRpcQueue;
  1440. }
  1441. /**
  1442. * Gets the communication error handler for this application
  1443. *
  1444. * @return the server RPC queue
  1445. */
  1446. public CommunicationProblemHandler getCommunicationProblemHandler() {
  1447. return communicationProblemHandler;
  1448. }
  1449. /**
  1450. * Gets the server message handler for this application
  1451. *
  1452. * @return the server message handler
  1453. */
  1454. public ServerMessageHandler getServerMessageHandler() {
  1455. return serverMessageHandler;
  1456. }
  1457. /**
  1458. * Gets the server rpc manager for this application
  1459. *
  1460. * @return the server rpc manager
  1461. */
  1462. public RpcManager getRpcManager() {
  1463. return rpcManager;
  1464. }
  1465. /**
  1466. * Gets the server communication handler for this application
  1467. *
  1468. * @return the server communication handler
  1469. */
  1470. public ServerCommunicationHandler getServerCommunicationHandler() {
  1471. return serverCommunicationHandler;
  1472. }
  1473. /**
  1474. * @return the widget set
  1475. */
  1476. public WidgetSet getWidgetSet() {
  1477. return widgetSet;
  1478. }
  1479. public int getLastSeenServerSyncId() {
  1480. return getServerMessageHandler().getLastSeenServerSyncId();
  1481. }
  1482. }