PageRenderTime 88ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/deploy/javafx-deploy/src/js/dtjava.js

https://bitbucket.org/rbair/rbair-controls-8
JavaScript | 3253 lines | 1769 code | 274 blank | 1210 comment | 643 complexity | 5d0eb5a76df3f29273b747499bd53337 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
  3. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  4. */
  5. /**
  6. The Java Deployment Toolkit is utility to deploy Java content in
  7. the browser as applets or applications using right version of Java.
  8. If needed it can initiate upgrade of user's system to install required
  9. components of Java platform.
  10. <p>
  11. Note that some of Deployment Toolkit methods may not be fully operational if
  12. used before web page body is loaded (because DT native plugins could not be instantiated).
  13. If you intend to use it before web page DOM tree is ready then dtjava.js
  14. need to be loaded inside the body element of the page and before use of other DT APIs.
  15. @module java/deployment_toolkit
  16. */
  17. var dtjava = function() {
  18. function notNull(o) {
  19. return (o != undefined && o != null);
  20. }
  21. function isDef(fn) {
  22. return (fn != null && typeof fn != "undefined");
  23. }
  24. //return true if any of patterns from query list is found in the given string
  25. function containsAny(lst, str) {
  26. for (var q = 0; q < lst.length; q++) {
  27. if (str.indexOf(lst[q]) != -1) {
  28. return true;
  29. }
  30. }
  31. return false;
  32. }
  33. /* Location of static web content - images, javascript files. */
  34. var jscodebase = (function () {
  35. // <script> elements are added to the DOM and run synchronously,
  36. // the currently running script will also be the last element in the array
  37. var scripts = document.getElementsByTagName("script");
  38. var src = scripts[scripts.length - 1].getAttribute("src");
  39. return src.substring(0, src.lastIndexOf('/') + 1);
  40. })();
  41. //set to true to disable FX auto install (before release)
  42. var noFXAutoInstall = false;
  43. // JRE version we start to have JRE and FX true co-bundle
  44. var minJRECobundleVersion = "1.7.0_06";
  45. //aliases
  46. var d = document;
  47. var w = window;
  48. var cbDone = false; //done with onload callbacks
  49. var domCb = []; //list of callbacks
  50. var ua = null;
  51. //add function to be called on DOM ready event
  52. function addOnDomReady(fn) {
  53. if (cbDone) {
  54. fn();
  55. } else {
  56. domCb[domCb.length] = fn;
  57. }
  58. }
  59. //invoke pending onload callbacks
  60. function invokeCallbacks() {
  61. if (!cbDone) {
  62. //swfoject.js tests whether DOM is actually ready first
  63. // in order to not fire too early. Use same heuristic
  64. try {
  65. var t = d.getElementsByTagName("body")[0].appendChild(
  66. d.createElement("div"));
  67. t.parentNode.removeChild(t);
  68. } catch (e) {
  69. return;
  70. }
  71. cbDone = true;
  72. for (var i = 0; i < domCb.length; i++) {
  73. domCb[i]();
  74. }
  75. }
  76. }
  77. //cross browser onload support.
  78. //Derived from swfobject.js
  79. function addOnload(fn) {
  80. if (isDef(w.addEventListener)) {
  81. w.addEventListener("load", fn, false);
  82. } else if (isDef(d.addEventListener)) {
  83. d.addEventListener("load", fn, false);
  84. } else if (isDef(w.attachEvent)) {
  85. w.attachEvent("onload", fn);
  86. //TODO: swfobject also keeps references to the listeners to detach them on onload
  87. // to avoid memory leaks ...
  88. } else if (typeof w.onload == "function") {
  89. var fnOld = w.onload;
  90. w.onload = function() {
  91. fnOld();
  92. fn();
  93. };
  94. } else {
  95. w.onload = fn;
  96. }
  97. }
  98. function detectEnv() {
  99. var dom = isDef(d.getElementById) && isDef(d.getElementsByTagName) && isDef(d.createElement);
  100. var u = navigator.userAgent.toLowerCase(),
  101. p = navigator.platform.toLowerCase();
  102. //NB: may need to be refined as some user agent may contain strings related to other browsers
  103. // (e.g. Chrome has both Safari and mozilla, Safari also has mozilla
  104. var windows = p ? /win/.test(p) : /win/.test(u),
  105. mac = p ? /mac/.test(p) : /mac/.test(u),
  106. linux = p ? /linux/.test(p) : /linux/.test(u),
  107. chrome = /chrome/.test(u),
  108. // get webkit version or false if not webkit
  109. webkit = !chrome && /webkit/.test(u) ?
  110. parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false,
  111. opera = /opera/.test(u),
  112. cputype = null,
  113. osVersion = null;
  114. var ie = false;
  115. try {
  116. //Used to be using trick from
  117. // http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
  118. //ie = !+"\v1",
  119. //but it does not work with IE9 in standards mode
  120. //Reverting to alternative - use execScript
  121. ie = isDef(window.execScript);
  122. } catch (ee) {
  123. //if javafx app is in the iframe and content of main window is coming from other domain
  124. // then some browsers may restrict access to outer window properties,
  125. // e.g. FF can throw exception for top.execScript (see RT-17885)
  126. //We could revert to more naive test, e.g. test user agent for "MSIE " string
  127. // but so far IE does not seem to throw exception => if we get here it is not IE anyways
  128. ie = false;
  129. }
  130. //we are not required to detect everything and can leave values null as
  131. // long as we later treat them accordingly.
  132. //We use "cputype" to detect if given hardware is supported,
  133. // e.g. we do not support PPC or iPhone/iPad despite they are running Mac OS
  134. //We use "osVersion" to detect if Java/JavaFX can be installed on this OS
  135. // e.g. Oracle Java for Mac requires 10.7.3
  136. if (mac) {
  137. if ((p && /intel/.test(p)) || /intel/.test(u)) {
  138. cputype = "intel";
  139. }
  140. //looking for things like 10_7, 10_6_8, 10.4, 11_2_2 in the user agent
  141. var t = u.match(/(1[0-9_\.]+)[^0-9_\.]/);
  142. //normalize to "." separators
  143. osVersion = notNull(t) ? t[0].replace(/_/g, ".") : null;
  144. }
  145. // Check mime types. Works with netscape family browsers and checks latest installed plugin only
  146. var mm = navigator.mimeTypes;
  147. var jre = null;
  148. var deploy = null;
  149. var fx = null;
  150. //Cache configuration from plugin mimetypes
  151. //It is only available for NPAPI browsers
  152. for (var t = 0; t < mm.length; t++) {
  153. // The jpi-version is the JRE version.
  154. var m = navigator.mimeTypes[t].type;
  155. if (m.indexOf("application/x-java-applet;jpi-version") != -1 && m.indexOf('=') != -1) {
  156. jre = m.substring(m.indexOf('=') + 1);
  157. }
  158. //Supported for 7u6 or later
  159. if (m.indexOf("application/x-java-applet;deploy") != -1 && m.indexOf('=') != -1) {
  160. deploy = m.substring(m.indexOf('=') + 1);
  161. }
  162. //javafx version for cobundled javafx (7u6+)
  163. if (m.indexOf("application/x-java-applet;javafx") != -1 && m.indexOf('=') != -1) {
  164. fx = m.substring(m.indexOf('=') + 1);
  165. }
  166. }
  167. return {haveDom:dom, wk:webkit, ie:ie, win:windows,
  168. linux:linux, mac:mac, op: opera, chrome:chrome,
  169. jre:jre, deploy:deploy, fx:fx,
  170. cputype: cputype, osVersion: osVersion};
  171. }
  172. //partially derived from swfobject.js
  173. var initDone = false;
  174. function init() {
  175. if (initDone) return;
  176. ua = detectEnv();
  177. if (!ua.haveDom) {
  178. return;
  179. }
  180. //NB: dtjava.js can be added dynamically and init() can be called after
  181. // document onload event is fired
  182. if (( isDef(d.readyState) && d.readyState == "complete") ||
  183. (!isDef(d.readyState) &&
  184. (d.getElementsByTagName("body")[0] || d.body))) {
  185. invokeCallbacks();
  186. }
  187. if (!cbDone) {
  188. if (isDef(d.addEventListener)) {
  189. d.addEventListener("DOMContentLoaded",
  190. invokeCallbacks, false);
  191. }
  192. if (ua.ie && ua.win) {
  193. d.attachEvent("onreadystatechange", function() {
  194. if (d.readyState == "complete") {
  195. d.detachEvent("onreadystatechange", arguments.callee);
  196. invokeCallbacks();
  197. }
  198. });
  199. if (w == top) { // if not inside an iframe
  200. (function() {
  201. if (cbDone) {
  202. return;
  203. }
  204. //AI: what for??
  205. try {
  206. d.documentElement.doScroll("left");
  207. } catch(e) {
  208. setTimeout(arguments.callee, 0);
  209. return;
  210. }
  211. invokeCallbacks();
  212. })();
  213. }
  214. }
  215. if (ua.wk) {
  216. (function() {
  217. if (cbDone) {
  218. return;
  219. }
  220. if (!/loaded|complete/.test(d.readyState)) {
  221. setTimeout(arguments.callee, 0);
  222. return;
  223. }
  224. invokeCallbacks();
  225. })();
  226. }
  227. addOnload(invokeCallbacks);
  228. }
  229. //only try to install native plugin if we do not have DTLite
  230. //Practically this means we are running NPAPI browser on Windows
  231. //(Chrome or FF) and recent JRE (7u4+?)
  232. if (!haveDTLite()) {
  233. installNativePlugin();
  234. }
  235. }
  236. /**
  237. This class provides details on why current platform does not meet
  238. application platform requirements. Note that severe problems are
  239. reported immediately and therefore full check may be not performed and
  240. some (unrelated to fatal problem)
  241. methods may provide false positive answers.
  242. <p>
  243. If multiple components do not match then worst status is reported.
  244. Application need to repeat checks on each individual component
  245. if it want to find out all details.
  246. @class PlatformMismatchEvent
  247. @for dtjava
  248. */
  249. function PlatformMismatchEvent(a) {
  250. //expect to get all parameters needed
  251. for (var p in a) {
  252. this[p] = a[p];
  253. }
  254. /**
  255. * @method toString
  256. * @return {string}
  257. * Returns string replesentation of event. Useful for debugging.
  258. */
  259. this.toString = function() {
  260. return "MISMATCH [os=" + this.os + ", browser=" + this.browser
  261. + ", jre=" + this.jre + ", fx=" + this.fx
  262. + ", relaunch=" + this.relaunch + ", platform="
  263. + this.platform + "]";
  264. };
  265. /**
  266. @method isUnsupportedPlatform
  267. @return {boolean}
  268. Returns true if this platform (OS/hardware) is not supported in a way
  269. to satisfy all platfrom requirements.
  270. (E.g. page is viewed on iPhone or JavaFX 2.0 application on Solaris.)
  271. <p>
  272. Note that this does not include browser match data.
  273. If platform is unsupported then application can not be
  274. launched and user need to use another platform to view it.
  275. */
  276. this.isUnsupportedPlatform = function() {
  277. return this.os;
  278. };
  279. /**
  280. @method isUnsupportedBrowser
  281. @return {boolean}
  282. Returns true if error is because current browser is not supported.
  283. <p>
  284. If true is returned and isRelaunchNeeded() returns true too then
  285. there are known supported browsers browsers for this platform.
  286. (but they are not necessary installed on end user system)
  287. */
  288. this.isUnsupportedBrowser = function() {
  289. return this.browser;
  290. };
  291. /**
  292. @method jreStatus
  293. @return {string}
  294. Returns "ok" if error was not due to missing JRE.
  295. Otherwise return error code characterizing the problem:
  296. <ul>
  297. <li> none - no JRE were detected on the system
  298. <li> old - some version of JRE was detected but it does not match platform requirements
  299. <li> oldplugin - matching JRE found but it is configured to use deprecated Java plugin that
  300. does not support Java applets
  301. <ul>
  302. <p>
  303. canAutoInstall() and isRelaunchNeeded() can be used to
  304. get more details on how seamless user' install experience will be.
  305. */
  306. this.jreStatus = function() {
  307. return this.jre;
  308. };
  309. /**
  310. * @method jreInstallerURL
  311. * @param {string} locale (optional) Locale to be used for installation web page
  312. * @return {string}
  313. *
  314. * Return URL of page to visit to install required version of Java.
  315. * If matching java runtime is already installed or not officially supported
  316. * then return value is null.
  317. */
  318. this.jreInstallerURL = function(locale) {
  319. if (this.os && (this.jre == "old" || this.jre == "none")) {
  320. return getJreUrl(locale);
  321. }
  322. return null;
  323. };
  324. /**
  325. @method javafxStatus
  326. @return {string}
  327. Returns "ok" if error was not due to missing JavaFX.
  328. Otherwise return error code characterizing the problem:
  329. <ul>
  330. <li> none - no JavaFX runtime is detected on the system
  331. <li> old - some version of JavaFX runtime iss detected but it does not match platform requirements
  332. <li> disabled - matching JavaFX is detected but it is disabled
  333. <li> unsupported - JavaFX is not supported on this platform
  334. <ul>
  335. <p>
  336. canAutoInstall() and isRelaunchNeeded() can be used to
  337. get more details on how seamless user' install experience will be.
  338. */
  339. this.javafxStatus = function() {
  340. return this.fx;
  341. };
  342. /**
  343. * @method javafxInstallerURL
  344. * @param {string} locale (optional) Locale to be used for installation web page
  345. * @return {string}
  346. *
  347. * Return URL of page to visit to install required version of JavaFX.
  348. * If matching JavaFX runtime is already installed or not officially supported
  349. * then return value is null.
  350. */
  351. this.javafxInstallerURL = function(locale) {
  352. if (!this.os && (this.fx == "old" || this.fx == "none")) {
  353. return getFxUrl(locale);
  354. }
  355. return null;
  356. };
  357. /**
  358. @method canAutoInstall
  359. @return {boolean}
  360. Returns true if installation of missing components can be
  361. triggered automatically. In particular, ture is returned
  362. if there are no missing components too.
  363. <p>
  364. If any of missing components need to be installed manually
  365. (i.e. click through additional web pages) then false is returned.
  366. */
  367. this.canAutoInstall = function() {
  368. return isAutoInstallEnabled(this.platform, this.jre, this.fx);
  369. };
  370. /**
  371. @method isRelaunchNeeded
  372. @return {boolean}
  373. Returns true if browser relaunch is needed before application can be loaded.
  374. This often is true in conjuction with need to perform installation.
  375. <p>
  376. Other typical case - use of unsupported browser when
  377. it is known that there are supported browser for this pltaform.
  378. Then both isUnsupportedBrowser() and isRelaunchNeeded() return true.
  379. */
  380. this.isRelaunchNeeded = function() {
  381. return this.relaunch;
  382. };
  383. }
  384. //returns version of instaled JavaFX runtime matching requested version
  385. //or null otherwise
  386. function getInstalledFXVersion(requestedVersion) {
  387. //NPAPI browser and JRE with cobundle
  388. if (ua.fx != null && versionCheckFX(requestedVersion, ua.fx)) {
  389. return ua.fx;
  390. }
  391. //try to use DT
  392. var p = getPlugin();
  393. if (notNull(p)) {
  394. try {
  395. return p.getInstalledFXVersion(requestedVersion);
  396. } catch(e) {}
  397. }
  398. return null;
  399. }
  400. //concatenate list with space as separator
  401. function listToString(lst) {
  402. if (lst != null) {
  403. return lst.join(" ");
  404. } else {
  405. return null;
  406. }
  407. }
  408. function addArgToList(lst, arg) {
  409. if (notNull(lst)) {
  410. lst.push(arg);
  411. return lst;
  412. } else {
  413. var res = [arg];
  414. return res;
  415. }
  416. }
  417. function doLaunch(ld, platform, cb) {
  418. var app = normalizeApp(ld, true);
  419. //required argument is missing
  420. if (!(notNull(app) && notNull(app.url))) {
  421. throw "Required attribute missing! (application url need to be specified)";
  422. }
  423. //if we got array we need to copy over!
  424. platform = new dtjava.Platform(platform);
  425. //normalize handlers
  426. cb = new dtjava.Callbacks(cb);
  427. var launchFunc = function() {
  428. //prepare jvm arguments
  429. var jvmArgs = notNull(platform.jvmargs) ? platform.jvmargs : null;
  430. if (notNull(platform.javafx)) {
  431. //if FX is needed we know it is available or
  432. // we will not get here
  433. var v = getInstalledFXVersion(platform.javafx);
  434. //add hint that we need FX toolkit to avoid relaunch
  435. // if JNLP is not embedded
  436. jvmArgs = addArgToList(jvmArgs, " -Djnlp.fx=" + v);
  437. //for swing applications embedding FX we do not want this property as it will
  438. // trigger FX toolkit and lead to app failure!
  439. //But for JavaFX application it saves us relaunch as otherwise we wil launch with AWT toolkit ...
  440. if (!notNull(ld.toolkit) || ld.toolkit == "fx") {
  441. jvmArgs = addArgToList(jvmArgs, " -Djnlp.tk=jfx");
  442. }
  443. }
  444. //if we on 7u6+ we can use DTLite plugin in the NPAPI browsers
  445. //Caveat: as of 7u6 it does not work with Chrome on Linux because Chrome expects
  446. // DTLite plugin to implement xembed (or claim to support xembed)
  447. if (haveDTLite() && !(ua.linux && ua.chrome)) {
  448. if (doLaunchUsingDTLite(app, jvmArgs, cb)) {
  449. return;
  450. }
  451. }
  452. //Did not launch yet? Try DT plugin (7u2+)
  453. var p = getPlugin();
  454. if (notNull(p)) {
  455. try {
  456. try {
  457. //check if new DT APIs are available
  458. if (versionCheck("10.6+", ua.deploy)) {
  459. // obj.launchApp({"url" : "http://somewhere/my.jnlp",
  460. // "jnlp_content" : "... BASE 64 ...",
  461. // "vmargs" : [ "-ea -Djnlp.foo=bar"
  462. // "appargs" : [ "first arg, second arg" ]
  463. // "params" : {"p1" : "aaa", "p2" : "bbb"}});
  464. var callArgs = {"url":app.url};
  465. if (notNull(jvmArgs)) {
  466. callArgs["vmargs"] = jvmArgs;
  467. }
  468. //Only use HTML parameters, they are supposed to overwrite values in the JNLP
  469. //In the future we want to pass arguments too but this needs also be exposed for
  470. // embedded deployment
  471. if (notNull(app.params)) {
  472. //copy over and ensure all values are strings
  473. // (native code will ignore them otherwise)
  474. var ptmp = {};
  475. for (var k in app.params) {
  476. ptmp[k] = String(app.params[k]);
  477. }
  478. callArgs["params"] = ptmp;
  479. }
  480. if (notNull(app.jnlp_content)) {
  481. callArgs["jnlp_content"] = app.jnlp_content;
  482. }
  483. var err = p.launchApp(callArgs);
  484. if (err == 0) { //0 - error
  485. if (isDef(cb.onRuntimeError)) {
  486. cb.onRuntimeError(app.id);
  487. }
  488. }
  489. } else { //revert to old DT APIs
  490. //older DT APIs expects vmargs as a single string
  491. if (!p.launchApp(app.url, app.jnlp_content, listToString(jvmArgs))) {
  492. if (isDef(cb.onRuntimeError)) {
  493. cb.onRuntimeError(app.id);
  494. }
  495. }
  496. }
  497. return;
  498. } catch (ee) { //temp support for older build of DT
  499. if (!p.launchApp(app.url, app.jnlp_content)) {
  500. if (isDef(cb.onRuntimeError)) {
  501. cb.onRuntimeError(app.id);
  502. }
  503. }
  504. return;
  505. }
  506. } catch (e) {
  507. //old DT
  508. }
  509. } //old Java (pre DTLite)? not Windows? or old DT
  510. //use old way to launch it using java plugin
  511. var o = getWebstartObject(app.url);
  512. if (notNull(d.body)) {
  513. d.body.appendChild(o);
  514. } else {
  515. //should never happen
  516. d.write(o.innerHTML);
  517. }
  518. }
  519. var r = doValidateRelaxed(platform);
  520. //can not launch, try to fix
  521. if (r != null) {
  522. resolveAndLaunch(app, platform, r, cb, launchFunc);
  523. } else {
  524. launchFunc();
  525. }
  526. }
  527. //process unhandled platform error - convert to code and call callback
  528. function reportPlatformError(app, r, cb) {
  529. if (isDef(cb.onDeployError)) {
  530. cb.onDeployError(app, r);
  531. }
  532. }
  533. function isDTInitialized(p) {
  534. //if plugin is blocked then p.version will be undefined
  535. return p != null && isDef(p.version);
  536. }
  537. //Wait until DT plugin is initialized and then run the code
  538. //Currently we only use it for embeded apps and Chrome on Windows
  539. function runUsingDT(label, f) {
  540. // Possible situations:
  541. // a) plugin is live and we can simply run code
  542. // - just run the code
  543. // b) plugin is in the DOM tree but it is not initialized yet (e.g. Chrome blocking)
  544. // and there is live timer (pendingCount > 0)
  545. // - there could be another request. We will APPEND to it
  546. // (this is different from dtlite as in this case we can not have multiple clicks)
  547. // - renew timer life counter (do not want new timer)
  548. // c) plugin is in the DOM tree and it is not fully initialized yet but timer is stopped
  549. // - overwrite old request
  550. // - restart timer
  551. //
  552. // Problem we are solving:
  553. // when plugin is ready to serve request? How do we schedule call to happen when plugin is initialized?
  554. // Caveat:
  555. // Chrome can popup dialog asking user to grant permissions to load the plugin.
  556. // There is no API to detect dialog is shown and when user grants or declines permissions
  557. //
  558. // Note:
  559. // If we set property on plugin object before it is unblocked then they seem to be lost
  560. // and are not propagated to the final object once it is instantiated.
  561. //
  562. // Workaround we use:
  563. // Once plugin is added we will be checking if it is initialized and once we detect it we will execute code.
  564. // We will stop checking after some time.
  565. var p = getPlugin();
  566. if (p == null) {
  567. return; //NO DT
  568. }
  569. if (isDTInitialized(p)) {
  570. f(p);
  571. } else {
  572. // see if we need new timer
  573. var waitAndUse = null;
  574. if (!isDef(dtjava.dtPendingCnt) || dtjava.dtPendingCnt == 0) {
  575. waitAndUse = function () {
  576. if (isDTInitialized(p)) {
  577. if (notNull(dtjava.dtPending)) {
  578. for (var i in dtjava.dtPending) {
  579. dtjava.dtPending[i]();
  580. }
  581. }
  582. return;
  583. }
  584. if (dtjava.dtPendingCnt > 0) {
  585. dtjava.dtPendingCnt--;
  586. setTimeout(waitAndUse, 500);
  587. }
  588. }
  589. }
  590. //add new task in queue
  591. if (!notNull(dtjava.dtPending) || dtjava.dtPendingCnt == 0) {
  592. dtjava.dtPending = {};
  593. }
  594. dtjava.dtPending[label] = f; //use map to ensure repitative actions are not queued (e.g. multiple click to launch webstart)
  595. //reset the timer counter
  596. dtjava.dtPendingCnt = 1000; //timer is gone after 500s
  597. //start timer if needed
  598. if (waitAndUse != null) waitAndUse();
  599. }
  600. }
  601. //returns same mismatch event if not resolved, null if resolved
  602. function resolveAndLaunch(app, platform, v, cb, launchFunction) {
  603. var p = getPlugin();
  604. //Special case: Chrome/Windows
  605. // (Note: IE may also block activeX control but then it will block attempts to use it too)
  606. if (ua.chrome && ua.win && p != null && !isDTInitialized(p)) {
  607. //this likely means DT plugin is blocked by Chrome
  608. //tell user to grant permissions and retry
  609. var actionLabel;
  610. if (notNull(app.placeholder)) {
  611. var onClickFunc = function() {w.open("http://www.java.com/en/download/faq/chrome.xml"); return false;};
  612. var msg1 = "Please give Java permission to run on this browser web page.";
  613. var msg2 = "Click for more information.";
  614. var altText = "";
  615. doShowMessageInTheArea(app, msg1, msg2, altText, "javafx-chrome.png", onClickFunc);
  616. actionLabel = app.id + "-embed";
  617. } else {
  618. v.jre = "blocked";
  619. reportPlatformError(app, v, cb);
  620. actionLabel = "launch"; //we only queue ONE webstart launch.
  621. //Do not want to try to queue different apps - bad UE
  622. // (once user enable multiple things can spawn)
  623. //Note: what if multiple webstart apps are set to launch on page load (suer do not need to click)?
  624. // Guess do not worry for now
  625. //Note: app.id may be null in case of webstart app.
  626. }
  627. //now we need to start waiter. Once DT is initialized we can proceeed
  628. var retryFunc = function() {
  629. var vnew = doValidateRelaxed(platform);
  630. if (vnew == null) { //no problems with env
  631. launchFunction();
  632. } else {
  633. resolveAndLaunch(app, platform, vnew, cb, launchFunction);
  634. }
  635. };
  636. runUsingDT(actionLabel, retryFunc);
  637. return;
  638. }
  639. if (!v.isUnsupportedPlatform() && !v.isUnsupportedBrowser()) { //otherwise fatal, at least until restart of browser
  640. if (isMissingComponent(v) && isDef(cb.onInstallNeeded)) {
  641. var resolveFunc= function() {
  642. //once install is over we need to revalidate
  643. var vnew = doValidateRelaxed(platform);
  644. if (vnew == null) { //if no problems found - can launch
  645. launchFunction();
  646. } else { //TODO: what happens if we installed everything but relaunch is needed??
  647. //We can not get here if component install was not offered for any or missing componens
  648. //(if auto install was possible, see doInstall() implementation)
  649. //Hence, it is safe to assume we failed to meet requirements
  650. reportPlatformError(app, vnew, cb);
  651. //TODO: may be should call itself again but
  652. // then it easy can become infinite loop
  653. //e.g. user installs but we fail to detect it because DT
  654. // is not FX aware and retry, etc.
  655. //TODO: think it through
  656. }
  657. };
  658. cb.onInstallNeeded(app, platform, cb,
  659. v.canAutoInstall(), v.isRelaunchNeeded(), resolveFunc);
  660. return;
  661. }
  662. }
  663. reportPlatformError(app, v, cb);
  664. }
  665. function haveDTLite() {
  666. if (ua.deploy != null) {
  667. return versionCheck("10.6+", ua.deploy);
  668. }
  669. return false;
  670. }
  671. function isDTLiteInitialized(p) {
  672. //if plugin is blocked then p.version will be undefined
  673. return p != null && isDef(p.version);
  674. }
  675. function getDTLitePlugin() {
  676. return document.getElementById("dtlite");
  677. }
  678. function doInjectDTLite() {
  679. //do not want more than one plugin
  680. if (getDTLitePlugin() != null) return;
  681. var p = document.createElement('embed');
  682. p.width = '10px';
  683. p.height = '10px';
  684. p.id = "dtlite";
  685. p.type = "application/x-java-applet"; //means we get latest
  686. var div = document.createElement("div");
  687. div.style.position = "relative";
  688. div.style.left = "-10000px";
  689. div.appendChild(p);
  690. var e = document.getElementsByTagName("body");
  691. e[0].appendChild(div);
  692. }
  693. function runUsingDTLite(f) {
  694. // Possible situations:
  695. // a) first request, plugin is not in the DOM tree yet
  696. // - add plugin
  697. // - setup wait mechanism and run f() once plugin is ready
  698. // b) plugin is live and we can simply run code
  699. // - just run the code
  700. // c) plugin is in the DOM tree but it is not initialized yet (e.g. Chrome blocking)
  701. // and there is live timer (pendingCount > 0)
  702. // - there could be another request. We will override it (e.g. user clicked multiple times)
  703. // - renew timer life counter (do not want new timer)
  704. // d) plugin is in the DOM tree and it is not fully initialized yet but timer is stopped
  705. // - overwrite old request
  706. // - restart timer
  707. //
  708. // Problem:
  709. // when plugin is ready to serve request? How do we schedule call to happen when plugin is initialized?
  710. // Caveat:
  711. // Chrome can popup dialog asking user to grant permissions to load the plugin.
  712. // There is no API to detect dialog is shown and when user grants or declines permissions
  713. //
  714. // Note:
  715. // If we set property on plugin object before it is unblocked then they seem to be lost
  716. // and are not propagated to the final object once it is instantiated.
  717. //
  718. // Workaround we use:
  719. // Once plugin is added we will be checking if it is initialized and once we detect it we will execute code.
  720. // We will stop checking after some time.
  721. var p = getDTLitePlugin();
  722. if (p == null) {
  723. doInjectDTLite();
  724. p = getDTLitePlugin();
  725. }
  726. if (isDTLiteInitialized(p)) {
  727. f(p);
  728. } else {
  729. // see if we need new timer
  730. var waitAndUse = null;
  731. if (!isDef(dtjava.dtlitePendingCnt) || dtjava.dtlitePendingCnt == 0) {
  732. waitAndUse = function () {
  733. if (isDef(p.version)) {
  734. if (dtjava.pendingLaunch != null) {
  735. dtjava.pendingLaunch(p);
  736. }
  737. dtjava.pendingLaunch = null;
  738. return;
  739. }
  740. if (dtjava.dtlitePendingCnt > 0) {
  741. dtjava.dtlitePendingCnt--;
  742. setTimeout(waitAndUse, 500);
  743. }
  744. }
  745. }
  746. //add new task in queue
  747. dtjava.pendingLaunch = f;
  748. //reset the timer counter
  749. dtjava.dtlitePendingCnt = 1000; //timer is gone after 500s
  750. //start timer if needed
  751. if (waitAndUse != null) {
  752. waitAndUse();
  753. }
  754. }
  755. }
  756. function doLaunchUsingDTLite(app, jvmargs, cb) {
  757. var launchIt = function() {
  758. var pp = getDTLitePlugin();
  759. if (pp == null) {
  760. //should not be possible as we guard before enter this function
  761. if (isDef(cb.onRuntimeError)) {
  762. cb.onRuntimeError(app.id);
  763. }
  764. }
  765. //DTLite only support new invocation API
  766. // obj.launchApp({"url" : "http://somewhere/my.jnlp",
  767. // "jnlp_content" : "... BASE 64 ...",
  768. // "vmargs" : [ "-ea -Djnlp.foo=bar"
  769. // "appargs" : [ "first arg, second arg" ]
  770. // "params" : {"p1" : "aaa", "p2" : "bbb"}});
  771. var callArgs = {"url" : app.url};
  772. if (notNull(jvmargs)) {
  773. callArgs["vmargs"] = jvmargs;
  774. }
  775. //Only use HTML parameters, they are supposed to overwrite values in the JNLP
  776. //In the future we want to pass arguments too but this needs also be exposed for
  777. // embedded deployment
  778. if (notNull(app.params)) {
  779. //copy over and ensure all values are stings
  780. // (native code will ignore them otherwise)
  781. var ptmp = {};
  782. for (var k in app.params) {
  783. ptmp[k] = String(app.params[k]);
  784. }
  785. callArgs["params"] = ptmp;
  786. }
  787. if (notNull(app.jnlp_content)) {
  788. callArgs["jnlp_content"] = app.jnlp_content;
  789. }
  790. var err = pp.launchApp(callArgs);
  791. if (err == 0) { //0 - error
  792. if (isDef(cb.onRuntimeError)) {
  793. cb.onRuntimeError(app.id);
  794. }
  795. }
  796. };
  797. if (versionCheck("10.4+", ua.deploy)) { //only for NPAPI browsers
  798. runUsingDTLite(launchIt);
  799. return true;
  800. }
  801. return false;
  802. }
  803. function getWebstartObject(jnlp) {
  804. var wo = null;
  805. if (ua.ie) { //TODO: attempt to use object in FF 3.6 lead to hang. Revert to embed for now
  806. //TODO: Should Chrome use object?
  807. //object tag itself
  808. wo = d.createElement('object');
  809. wo.width = '1px'; //zero size reports invalid argument in IE!
  810. wo.height = '1px'; //TODO: make it less distruptive to page layout? hide div?
  811. var p = d.createElement('param');
  812. p.name = 'launchjnlp';
  813. p.value = jnlp;
  814. wo.appendChild(p);
  815. p = d.createElement('param');
  816. p.name = 'docbase';
  817. p.value = notNull(d.documentURI) ? d.documentURI : d.URL;
  818. wo.appendChild(p);
  819. if (!ua.ie) {
  820. //NB:do not need to use exact version in mime type as generic should be mapped to latest?
  821. wo.type = "application/x-java-applet;version=1.7";
  822. } else {
  823. wo.classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
  824. }
  825. } else { //TODO: else part should go away once we figure out what is going on with FF
  826. wo = d.createElement('embed');
  827. wo.width = '0px';
  828. wo.height = '0px';
  829. //NB: dot notation did not work for custom attributes??? revert to setAttribute
  830. wo.setAttribute('launchjnlp', jnlp);
  831. wo.setAttribute('docbase', (notNull(d.documentURI) ? d.documentURI : d.URL));
  832. //NB:do not need to use exact version in mime type as generic should be mapped to latest?
  833. wo.type = "application/x-java-applet;version=1.7";
  834. }
  835. var div = d.createElement("div");
  836. div.style.position = "relative";
  837. div.style.left = "-10000px";
  838. div.appendChild(wo);
  839. return div;
  840. }
  841. //this is similar to version check rules except for
  842. // JavaFX we treat version slightly differently.
  843. //For Javafx version really is FAMILY.UPDATE_VERSION
  844. // where FAMILY is everything before first dot
  845. // E.g.
  846. // 2.0.1 => family 2, update 0.1
  847. // 2.0 => family 2. update 0.0
  848. //
  849. // JavaFX version requirements are always treated as "not earlier than this update".
  850. // I.e. we expect
  851. // 2.2.0 to match 2.2*, 2.2+, 2.1+, 2.1*, 2.0 and 1+
  852. // but not match 2.2.1+, 2.2.1*, 2.3*, 2.3+ or 1*
  853. function versionCheckFX(query, version) {
  854. if (query == null || query.length == 0) {
  855. return true;
  856. }
  857. var endChar = query.charAt(query.length - 1);
  858. var familyOnly = (endChar == '*');
  859. if (!familyOnly) {
  860. if (endChar == '+') {
  861. return versionCheck(query, version);
  862. } else { //must be fixed version, e.g. 2.0
  863. return versionCheck(query + '+', version);
  864. }
  865. } else {
  866. return (versionCheck(query.charAt(0)+".*", version) && //required family (version belongs to family 2)
  867. versionCheck(query.substring(0, query.length - 1)+"+", version)); //global lookup (version >= 2.1.1), replace * with +
  868. }
  869. }
  870. //Convert version string into 4 element array with version components
  871. //If input string has fewer components then pad with zeros from the right
  872. //If input string ends with suffix like '+' or '*' then it is stripped
  873. //
  874. //Examples:
  875. // 10.1.2.3 => {10, 1, 2, 3}
  876. // 10.1 => {10, 1, 0, 0}
  877. // 10.1+ => {10, 1, 0, 0}
  878. function convertVersionToArray(versionString) {
  879. if (versionString != null) {
  880. var c = versionString.charAt(versionString.length - 1);
  881. //if it is not digit we want to strip last char
  882. if (c <= '0' || c >= '9') {
  883. versionString = versionString.substring(0, versionString.length - 1);
  884. }
  885. }
  886. //corner case inputs
  887. if (versionString == null || versionString.length == 0) {
  888. return [0, 0, 0, 0];
  889. }
  890. var arr = versionString.split(".");
  891. while (arr.length < 4) {
  892. arr.push(0);
  893. }
  894. return arr;
  895. }
  896. //checks where given version string matches query
  897. //
  898. //NB: assume format is correct. Can add format check later if needed
  899. function versionCheck(query, version) {
  900. if (query == null || query.length == 0) return true;
  901. var c = query.charAt(query.length - 1);
  902. //if it is not explicit pattern but does not have update version then need to append *
  903. if (c != '+' && c != '*' && (query.indexOf('_') != -1 && c != '_')) {
  904. query = query + "*";
  905. c = '*';
  906. }
  907. query = query.substring(0, query.length - 1);
  908. //if query ends with ".", "_" then we want to strip it to allow match of "1.6.*" to shorter form such as "1.6"
  909. //TODO: add support for match of "1.7.0*" to "1.7"?
  910. if (query.length > 0) {
  911. var z = query.charAt(query.length - 1);
  912. if (z == '.' || z == '_') {
  913. query = query.substring(0, query.length - 1);
  914. }
  915. }
  916. if (c == '*') {
  917. //it is match if version starts from it
  918. return (version.indexOf(query) == 0);
  919. } else if (c == '+') {
  920. //lexicographical comparison is not good here as we may have case like
  921. // query="10.6*" and version="10.10.2"
  922. //Approach:
  923. // split into tokens and compare each of tokens numerically
  924. //Keep comparing until tokens are the same or we reached end.
  925. //If tokens differ then we have a match if query is smaller and
  926. // non-match if it is greater
  927. var qArr = convertVersionToArray(query);
  928. var vArr = convertVersionToArray(version);
  929. //qArr and vArr are expected to be arrays of same length
  930. for (var idx=0; idx < qArr.length; idx++) {
  931. if (qArr[idx] < vArr[idx]) {
  932. //query is smaller
  933. return true;
  934. } else if (qArr[idx] < vArr[idx]) {
  935. //query is larger => fail
  936. return false;
  937. }
  938. }
  939. //query is equal to version => it is ok
  940. return true;
  941. }
  942. return false;
  943. }
  944. //as JavaFX comes with own plugin binaries then check based on mime types, etc.
  945. // may be false positive as it only checks for plugin version, not real JRE
  946. //Here we check that DT plugin is aware of JRE installations
  947. //Note that:
  948. // - if DT is not available we will return false but we only do this i
  949. // ready to launch => DT must be found
  950. // - we do not want to check in jreCheck() as we want to avoid loading
  951. // DT plugin if we can (as old DT may make it not possible to autostart)
  952. function doublecheckJrePresence() {
  953. if (!haveDTLite()) { //basically IE on windows or Old JRE on windows
  954. var p = getPlugin();
  955. if (p != null) {
  956. return true;
  957. //WORKAROUND: bug in native DT!!! TODO: What version? bypass for it only
  958. //return (p.jvms.getLength() > 0);
  959. }
  960. return false;
  961. }
  962. //if we are not using native DT plugin (i.e. using DTLite) then no way we can do sanity check
  963. // => assume first check is accurate
  964. return true;
  965. }
  966. function jreCheck(jre) {
  967. // Check if latest JRE is exposed in mimetype and if it is good enough (only for NPAPI browsers)
  968. if (ua.jre != null) {
  969. if (versionCheck(jre, ua.jre)) {
  970. return "ok";
  971. }
  972. //Note: if we have JRE but it is not match that means we may need an upgrade message
  973. // but we still could be able to get more accurate answer with native DT plugin
  974. }
  975. //try to use DT plugin
  976. var p = getPlugin();
  977. if (p != null) {
  978. var VMs = p.jvms;
  979. for (var i = 0; VMs != null && i < VMs.getLength(); i++) {
  980. if (versionCheck(jre, VMs.get(i).version)) {
  981. if (!ua.ie && notNull(navigator.mimeTypes)) {
  982. //if mime types are available but plugin is not there =>
  983. // it is disabled
  984. if (!notNull(navigator.mimeTypes["application/x-java-applet"])) {
  985. return "disabled";
  986. }
  987. }
  988. return "ok";
  989. }
  990. }
  991. //do not need to try other ways if used DT
  992. return "none";
  993. }
  994. //No full DT => On Windows we can not launch FX anyways
  995. // but may have old JRE
  996. //And we might be able to launch on Mac/Linux
  997. //This is only IE on Windows. This gives no update version. only e.g. 1.6.0
  998. //and also cause java plugin to be loaded => browser will need to be restarted
  999. //if new JRE is installed.
  1000. //However, if we got here than DT is not available and autoinstall is not possible
  1001. if (ua.ie) {
  1002. var lst = ["1.8.0", "1.7.0", "1.6.0", "1.5.0"];
  1003. for (var v = 0; v < lst.length; v++) {
  1004. if (versionCheck(jre, lst[v])) {
  1005. try {
  1006. //TODO: FIXME: This does not seem to work in my testing in IE7?
  1007. var axo = new ActiveXObject("JavaWebStart.isInstalled." + lst[v] + ".0");
  1008. // This is not hit if the above throws an exception.
  1009. return "ok";
  1010. } catch (ignored) {
  1011. }
  1012. }
  1013. }
  1014. }
  1015. return "none";
  1016. }
  1017. function checkJRESupport() {
  1018. //Negative test. New platforms will not be rejected
  1019. var osProblem = ['iPhone', 'iPod'];
  1020. var os = containsAny(osProblem, navigator.userAgent);
  1021. //Do not support Chrome/Mac as Chrome is 32 bit only
  1022. var browser = (ua.mac && ua.chrome && ua.cputype == "intel");
  1023. //autoinstall possible if native plugin is detected or OS is fine
  1024. auto = os || (getPlugin() != null);
  1025. //false is no problem found
  1026. return {os: os, browser: browser, auto: auto};
  1027. }
  1028. //it is not clear if we can work in IE6
  1029. // but it is hard to test and JRE7 does not even support it
  1030. // mark as unsupported for now
  1031. function isUnsupportedVersionOfIE() {
  1032. if (ua.ie) {
  1033. try {
  1034. //these functions are defined in IE only
  1035. var v = 10*ScriptEngineMajorVersion() + ScriptEngineMinorVersion();
  1036. if (v < 57) return true; //IE7 will have 57
  1037. } catch (err) {
  1038. //really old IE?
  1039. return true;
  1040. }
  1041. }
  1042. return false;
  1043. }
  1044. function checkFXSupport() {
  1045. var browser;
  1046. if (ua.win) {
  1047. //do not support Opera and Safari
  1048. // (not really tested, may be it works but known to have problems with DT detection)
  1049. browser = ua.op || ua.wk || isUnsupportedVersionOfIE();
  1050. //false is no problem found
  1051. return {os: false, browser: browser};
  1052. } else if (ua.mac && ua.cputype == "intel") { //do not support PPC/iphone/ipad ...
  1053. var os = !versionCheck("10.7.3+", ua.osVersion); //10.7.3 or later!
  1054. browser = ua.op ||
  1055. (ua.mac && ua.chrome); //Opera is not supported
  1056. //Chrome on Mac is 32 bit => plugin only work in 64 bit ...
  1057. //TODO: How do we detect FF running in 32 bit mode?
  1058. //false is no problem found
  1059. return {os: os, browser: browser};
  1060. } else if (ua.linux) {
  1061. browser = ua.op; //Opera unsupported
  1062. //false is no problem found
  1063. return {os: false, browser: browser};
  1064. } else {
  1065. //unknown unsupported OS
  1066. return {os: true, browser: false};
  1067. }
  1068. }
  1069. function relaxVersion(v) {
  1070. if (notNull(v) && v.length > 0) {
  1071. var c = v.charAt(v.length - 1);
  1072. if (c == '*') {
  1073. v = v.substring(0, v.length - 1)+"+";
  1074. } else if (c != '+') { //exact version (e.g. 1.6)
  1075. v = v + "+";
  1076. }
  1077. }
  1078. return v;
  1079. }
  1080. //we relax validation rules where we try to embed or launch app
  1081. // in order to deal with requests for OLDER jres at the java level
  1082. //Basically we convert request for version in JRE family to request for any future JRE
  1083. //We do NOT do same for JavaFX right now. There is no real need before 3.0 and it is not clear if it is good thing
  1084. //
  1085. //Note we keep validation strict for install and validate-only scenarios.
  1086. // This allows to query accurate details from javascript
  1087. function doValidateRelaxed(platform) {
  1088. var p = new dtjava.Platform(platform);
  1089. p.jvm = relaxVersion(p.jvm);
  1090. //p.javafx = relaxVersion(p.javafx);
  1091. return doValidate(p);
  1092. }
  1093. function doValidate(platform) {
  1094. //ensure some platform is set (we could get array too!)
  1095. platform = new dtjava.Platform(platform);
  1096. //problem markers
  1097. var fx = "ok", jre = "ok", restart = false, os = false, browser = false,
  1098. p, details;
  1099. //check JRE
  1100. if (notNull(platform.jvm) && jreCheck(platform.jvm) != "ok") { //matching JRE not found
  1101. var res = jreCheck("*");
  1102. if (res == "ok") {
  1103. jre = "old";
  1104. } else {
  1105. jre = res; //"none" or "disabled"
  1106. }
  1107. details = checkJRESupport();
  1108. if (details.os) {
  1109. jre = "unsupported";
  1110. os = true;
  1111. }
  1112. browser = details.browser;
  1113. }
  1114. /* if (notNull(platform.plugin) && jre == "ok") {
  1115. try {
  1116. p = getPlugin();
  1117. //TEMPORARY DISABLE because isPlugin2() is broken in 1.7.0
  1118. // it is not fixed in 7-client but if FX is enabled then
  1119. // it must be new plugin anyways
  1120. //=> keep this disabled for now until we find use case
  1121. if (false && (p == null || !p.isPlugin2())) {
  1122. //TODO: FIXME: seem to get here always because isPlugin2() returns 0?
  1123. jre = "oldplugin";
  1124. relaunch = true;

Large files files are truncated, but you can click here to view the full file