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.

SuperDevMode.java 9.5KB

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
11 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * Copyright 2000-2018 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.logging.Logger;
  18. import com.google.gwt.core.client.GWT;
  19. import com.google.gwt.core.client.JavaScriptObject;
  20. import com.google.gwt.http.client.UrlBuilder;
  21. import com.google.gwt.jsonp.client.JsonpRequestBuilder;
  22. import com.google.gwt.storage.client.Storage;
  23. import com.google.gwt.user.client.Window.Location;
  24. import com.google.gwt.user.client.rpc.AsyncCallback;
  25. import com.vaadin.client.ui.VNotification;
  26. /**
  27. * Class that enables SuperDevMode using a ?superdevmode parameter in the url.
  28. *
  29. * @author Vaadin Ltd
  30. * @since 7.0
  31. *
  32. */
  33. public class SuperDevMode {
  34. private static final int COMPILE_TIMEOUT_IN_SECONDS = 60;
  35. protected static final String SKIP_RECOMPILE = "VaadinSuperDevMode_skip_recompile";
  36. public static class RecompileResult extends JavaScriptObject {
  37. protected RecompileResult() {
  38. }
  39. public final native boolean ok()
  40. /*-{
  41. return this.status == "ok";
  42. }-*/;
  43. }
  44. private static void recompileWidgetsetAndStartInDevMode(
  45. final String serverUrl) {
  46. getLogger().info("Recompiling widgetset using<br/>" + serverUrl
  47. + "<br/>and then reloading in super dev mode");
  48. VNotification n = new VNotification();
  49. n.show("<b>Recompiling widgetset, please wait</b>",
  50. VNotification.CENTERED, VNotification.STYLE_SYSTEM);
  51. JsonpRequestBuilder b = new JsonpRequestBuilder();
  52. b.setCallbackParam("_callback");
  53. b.setTimeout(COMPILE_TIMEOUT_IN_SECONDS * 1000);
  54. b.requestObject(
  55. serverUrl + "recompile/" + GWT.getModuleName() + "?"
  56. + getRecompileParameters(GWT.getModuleName()),
  57. new AsyncCallback<RecompileResult>() {
  58. @Override
  59. public void onSuccess(RecompileResult result) {
  60. getLogger().fine("JSONP compile call successful");
  61. if (!result.ok()) {
  62. getLogger().fine("* result: " + result);
  63. failed();
  64. return;
  65. }
  66. setSession(getSuperDevModeHookKey(),
  67. getSuperDevWidgetSetUrl(GWT.getModuleName(),
  68. serverUrl));
  69. setSession(SKIP_RECOMPILE, "1");
  70. getLogger().fine("* result: OK. Reloading");
  71. Location.reload();
  72. }
  73. @Override
  74. public void onFailure(Throwable caught) {
  75. getLogger().severe("JSONP compile call failed");
  76. // Don't log exception as they are shown as
  77. // notifications
  78. getLogger().severe(caught.getClass().getSimpleName()
  79. + ": " + caught.getMessage());
  80. failed();
  81. }
  82. private void failed() {
  83. VNotification n = new VNotification();
  84. n.addEventListener(
  85. event -> recompileWidgetsetAndStartInDevMode(
  86. serverUrl));
  87. n.show("Recompilation failed.<br/>"
  88. + "Make sure CodeServer is running, "
  89. + "check its output and click to retry",
  90. VNotification.CENTERED,
  91. VNotification.STYLE_SYSTEM);
  92. }
  93. });
  94. }
  95. protected static String getSuperDevWidgetSetUrl(String widgetsetName,
  96. String serverUrl) {
  97. return serverUrl + GWT.getModuleName() + "/" + GWT.getModuleName()
  98. + ".nocache.js";
  99. }
  100. private static native String getRecompileParameters(String moduleName)
  101. /*-{
  102. var prop_map = $wnd.__gwt_activeModules[moduleName].bindings();
  103. // convert map to URL parameter string
  104. var props = [];
  105. for (var key in prop_map) {
  106. props.push(encodeURIComponent(key) + '=' + encodeURIComponent(prop_map[key]))
  107. }
  108. return props.join('&') + '&';
  109. }-*/;
  110. private static void setSession(String key, String value) {
  111. Storage.getSessionStorageIfSupported().setItem(key, value);
  112. }
  113. private static String getSession(String key) {
  114. return Storage.getSessionStorageIfSupported().getItem(key);
  115. }
  116. private static void removeSession(String key) {
  117. Storage.getSessionStorageIfSupported().removeItem(key);
  118. }
  119. protected static void disableDevModeAndReload() {
  120. removeSession(getSuperDevModeHookKey());
  121. redirect(false);
  122. }
  123. protected static void redirect(boolean devModeOn) {
  124. UrlBuilder createUrlBuilder = Location.createUrlBuilder();
  125. if (!devModeOn) {
  126. createUrlBuilder.removeParameter("superdevmode");
  127. } else {
  128. createUrlBuilder.setParameter("superdevmode", "");
  129. }
  130. Location.assign(createUrlBuilder.buildString());
  131. }
  132. private static String getSuperDevModeHookKey() {
  133. String widgetsetName = GWT.getModuleName();
  134. final String superDevModeKey = "__gwtDevModeHook:" + widgetsetName;
  135. return superDevModeKey;
  136. }
  137. private static boolean hasSession(String key) {
  138. return getSession(key) != null;
  139. }
  140. /**
  141. * The URL of the code server. The default URL (http://localhost:9876/) will
  142. * be used if this is empty or null.
  143. *
  144. * @param serverUrl
  145. * The url of the code server or null to use the default
  146. * @return true if recompile started, false if we are running in
  147. * SuperDevMode
  148. */
  149. protected static boolean recompileIfNeeded(String serverUrl) {
  150. if (serverUrl == null || serverUrl.isEmpty()) {
  151. serverUrl = "http://localhost:9876/";
  152. } else {
  153. if (serverUrl.contains(":")) {
  154. serverUrl = "http://" + serverUrl + "/";
  155. } else {
  156. serverUrl = "http://" + serverUrl + ":9876/";
  157. }
  158. }
  159. if (hasSession(SKIP_RECOMPILE)) {
  160. getLogger().info("Running in SuperDevMode");
  161. // When we get here, we are running in super dev mode
  162. // Remove the flag so next reload will recompile
  163. removeSession(SKIP_RECOMPILE);
  164. // Remove the gwt flag so we will not end up in dev mode if we
  165. // remove the url parameter manually
  166. removeSession(getSuperDevModeHookKey());
  167. return false;
  168. }
  169. recompileWidgetsetAndStartInDevMode(serverUrl);
  170. return true;
  171. }
  172. protected static boolean isSuperDevModeEnabledInModule() {
  173. String moduleName = GWT.getModuleName();
  174. return isSuperDevModeEnabledInModule(moduleName);
  175. }
  176. protected static native boolean isSuperDevModeEnabledInModule(
  177. String moduleName)
  178. /*-{
  179. if (!$wnd.__gwt_activeModules)
  180. return false;
  181. var mod = $wnd.__gwt_activeModules[moduleName];
  182. if (!mod)
  183. return false;
  184. if (mod.superdevmode) {
  185. // Running in super dev mode already, it is supported
  186. return true;
  187. }
  188. return !!mod.canRedirect;
  189. }-*/;
  190. /**
  191. * Enables SuperDevMode if the url contains the "superdevmode" parameter.
  192. * <p>
  193. * The caller should not continue initialization of the application if this
  194. * method returns true. The application will be restarted once compilation
  195. * is done and then this method will return false.
  196. * </p>
  197. *
  198. * @return true if a recompile operation has started and the page will be
  199. * reloaded once it is done, false if no recompilation will be done.
  200. */
  201. public static boolean enableBasedOnParameter() {
  202. String superDevModeParameter = Location.getParameter("superdevmode");
  203. if (superDevModeParameter != null) {
  204. // Need to check the recompile flag also because if we are running
  205. // in super dev mode, as a result of the recompile, the enabled
  206. // check will fail...
  207. if (!isSuperDevModeEnabledInModule()) {
  208. showError(
  209. "SuperDevMode is disabled for this module/widgetset.<br/>"
  210. + "Ensure that your module definition (.gwt.xml) does not contain <br/>"
  211. + "&lt;set-configuration-property name=&quot;devModeRedirectEnabled&quot; value=&quot;false&quot; /&gt;<br/>");
  212. return false;
  213. }
  214. return SuperDevMode.recompileIfNeeded(superDevModeParameter);
  215. }
  216. return false;
  217. }
  218. private static void showError(String message) {
  219. VNotification n = new VNotification();
  220. n.show(message, VNotification.CENTERED_TOP, VNotification.STYLE_SYSTEM);
  221. }
  222. private static Logger getLogger() {
  223. return Logger.getLogger(SuperDevMode.class.getName());
  224. }
  225. }