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.

AbstractJavaScriptExtension.java 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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.server;
  17. import com.vaadin.shared.JavaScriptExtensionState;
  18. import com.vaadin.shared.communication.ServerRpc;
  19. import com.vaadin.ui.JavaScriptFunction;
  20. import elemental.json.Json;
  21. import elemental.json.JsonValue;
  22. /**
  23. * Base class for Extensions with all client-side logic implemented using
  24. * JavaScript.
  25. * <p>
  26. * When a new JavaScript extension is initialized in the browser, the framework
  27. * will look for a globally defined JavaScript function that will initialize the
  28. * extension. The name of the initialization function is formed by replacing .
  29. * with _ in the name of the server-side class. If no such function is defined,
  30. * each super class is used in turn until a match is found. The framework will
  31. * thus first attempt with <code>com_example_MyExtension</code> for the
  32. * server-side
  33. * <code>com.example.MyExtension extends AbstractJavaScriptExtension</code>
  34. * class. If MyExtension instead extends <code>com.example.SuperExtension</code>
  35. * , then <code>com_example_SuperExtension</code> will also be attempted if
  36. * <code>com_example_MyExtension</code> has not been defined.
  37. * <p>
  38. *
  39. * The initialization function will be called with <code>this</code> pointing to
  40. * a connector wrapper object providing integration to Vaadin. Please note that
  41. * in JavaScript, <code>this</code> is not necessarily defined inside callback
  42. * functions and it might therefore be necessary to assign the reference to a
  43. * separate variable, e.g. <code>var self = this;</code>. The following
  44. * functions are provided by the connector wrapper object:
  45. * <ul>
  46. * <li><code>getConnectorId()</code> - returns a string with the id of the
  47. * connector.</li>
  48. * <li><code>getParentId([connectorId])</code> - returns a string with the id of
  49. * the connector's parent. If <code>connectorId</code> is provided, the id of
  50. * the parent of the corresponding connector with the passed id is returned
  51. * instead.</li>
  52. * <li><code>getElement([connectorId])</code> - returns the DOM Element that is
  53. * the root of a connector's widget. <code>null</code> is returned if the
  54. * connector can not be found or if the connector doesn't have a widget. If
  55. * <code>connectorId</code> is not provided, the connector id of the current
  56. * connector will be used.</li>
  57. * <li><code>getState()</code> - returns an object corresponding to the shared
  58. * state defined on the server. The scheme for conversion between Java and
  59. * JavaScript types is described bellow.</li>
  60. * <li><code>registerRpc([name, ] rpcObject)</code> - registers the
  61. * <code>rpcObject</code> as a RPC handler. <code>rpcObject</code> should be an
  62. * object with field containing functions for all eligible RPC functions. If
  63. * <code>name</code> is provided, the RPC handler will only used for RPC calls
  64. * for the RPC interface with the same fully qualified Java name. If no
  65. * <code>name</code> is provided, the RPC handler will be used for all incoming
  66. * RPC invocations where the RPC method name is defined as a function field in
  67. * the handler. The scheme for conversion between Java types in the RPC
  68. * interface definition and the JavaScript values passed as arguments to the
  69. * handler functions is described bellow.</li>
  70. * <li><code>getRpcProxy([name])</code> - returns an RPC proxy object. If
  71. * <code>name</code> is provided, the proxy object will contain functions for
  72. * all methods in the RPC interface with the same fully qualified name, provided
  73. * a RPC handler has been registered by the server-side code. If no
  74. * <code>name</code> is provided, the returned RPC proxy object will contain
  75. * functions for all methods in all RPC interfaces registered for the connector
  76. * on the server. If the same method name is present in multiple registered RPC
  77. * interfaces, the corresponding function in the RPC proxy object will throw an
  78. * exception when called. The scheme for conversion between Java types in the
  79. * RPC interface and the JavaScript values that should be passed to the
  80. * functions is described bellow.</li>
  81. * <li><code>translateVaadinUri(uri)</code> - Translates a Vaadin URI to a URL
  82. * that can be used in the browser. This is just way of accessing
  83. * {@link com.vaadin.client.ApplicationConnection#translateVaadinUri(String)}</li>
  84. * </ul>
  85. * The connector wrapper also supports these special functions:
  86. * <ul>
  87. * <li><code>onStateChange</code> - If the JavaScript code assigns a function to
  88. * the field, that function is called whenever the contents of the shared state
  89. * is changed.</li>
  90. * <li>Any field name corresponding to a call to
  91. * {@link #addFunction(String, JavaScriptFunction)} on the server will
  92. * automatically be present as a function that triggers the registered function
  93. * on the server.</li>
  94. * <li>Any field name referred to using {@link #callFunction(String, Object...)}
  95. * on the server will be called if a function has been assigned to the field.</li>
  96. * </ul>
  97. * <p>
  98. *
  99. * Values in the Shared State and in RPC calls are converted between Java and
  100. * JavaScript using the following conventions:
  101. * <ul>
  102. * <li>Primitive Java numbers (byte, char, int, long, float, double) and their
  103. * boxed types (Byte, Character, Integer, Long, Float, Double) are represented
  104. * by JavaScript numbers.</li>
  105. * <li>The primitive Java boolean and the boxed Boolean are represented by
  106. * JavaScript booleans.</li>
  107. * <li>Java Strings are represented by JavaScript strings.</li>
  108. * <li>Java Dates are represented by JavaScript numbers containing the timestamp
  109. * </li>
  110. * <li>List, Set and all arrays in Java are represented by JavaScript arrays.</li>
  111. * <li>Map&lt;String, ?&gt; in Java is represented by JavaScript object with
  112. * fields corresponding to the map keys.</li>
  113. * <li>Any other Java Map is represented by a JavaScript array containing two
  114. * arrays, the first contains the keys and the second contains the values in the
  115. * same order.</li>
  116. * <li>A Java Bean is represented by a JavaScript object with fields
  117. * corresponding to the bean's properties.</li>
  118. * <li>A Java Connector is represented by a JavaScript string containing the
  119. * connector's id.</li>
  120. * <li>A pluggable serialization mechanism is provided for types not described
  121. * here. Please refer to the documentation for specific types for serialization
  122. * information.</li>
  123. * </ul>
  124. *
  125. * @author Vaadin Ltd
  126. * @since 7.0.0
  127. */
  128. public abstract class AbstractJavaScriptExtension extends AbstractExtension {
  129. private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper(
  130. this);
  131. /**
  132. * Creates a new JavasScript extension instance without extending any
  133. * connector.
  134. */
  135. public AbstractJavaScriptExtension() {
  136. // Empty default constructor
  137. }
  138. /**
  139. * Creates a new JavaScript extension extending the provided connector.
  140. *
  141. * @since 7.4
  142. *
  143. * @param target
  144. * the connector to extend
  145. */
  146. public AbstractJavaScriptExtension(AbstractClientConnector target) {
  147. this();
  148. extend(target);
  149. }
  150. @Override
  151. protected <T extends ServerRpc> void registerRpc(T implementation,
  152. Class<T> rpcInterfaceType) {
  153. super.registerRpc(implementation, rpcInterfaceType);
  154. callbackHelper.registerRpc(rpcInterfaceType);
  155. }
  156. /**
  157. * Register a {@link JavaScriptFunction} that can be called from the
  158. * JavaScript using the provided name. A JavaScript function with the
  159. * provided name will be added to the connector wrapper object (initially
  160. * available as <code>this</code>). Calling that JavaScript function will
  161. * cause the call method in the registered {@link JavaScriptFunction} to be
  162. * invoked with the same arguments.
  163. *
  164. * @param functionName
  165. * the name that should be used for client-side callback
  166. * @param function
  167. * the {@link JavaScriptFunction} object that will be invoked
  168. * when the JavaScript function is called
  169. */
  170. protected void addFunction(String functionName, JavaScriptFunction function) {
  171. callbackHelper.registerCallback(functionName, function);
  172. }
  173. /**
  174. * Invoke a named function that the connector JavaScript has added to the
  175. * JavaScript connector wrapper object. The arguments can be any boxed
  176. * primitive type, String, {@link JsonValue} or arrays of any other
  177. * supported type. Complex types (e.g. List, Set, Map, Connector or any
  178. * JavaBean type) must be explicitly serialized to a {@link JsonValue}
  179. * before sending. This can be done either with
  180. * {@link JsonCodec#encode(Object, JsonValue, java.lang.reflect.Type, com.vaadin.ui.ConnectorTracker)}
  181. * or using the factory methods in {@link Json}.
  182. *
  183. * @param name
  184. * the name of the function
  185. * @param arguments
  186. * function arguments
  187. */
  188. protected void callFunction(String name, Object... arguments) {
  189. callbackHelper.invokeCallback(name, arguments);
  190. }
  191. @Override
  192. protected JavaScriptExtensionState getState() {
  193. return (JavaScriptExtensionState) super.getState();
  194. }
  195. }