/deploy/javafx-deploy/src/js/dtjava.js
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
- /*
- * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- /**
- The Java Deployment Toolkit is utility to deploy Java content in
- the browser as applets or applications using right version of Java.
- If needed it can initiate upgrade of user's system to install required
- components of Java platform.
- <p>
- Note that some of Deployment Toolkit methods may not be fully operational if
- used before web page body is loaded (because DT native plugins could not be instantiated).
- If you intend to use it before web page DOM tree is ready then dtjava.js
- need to be loaded inside the body element of the page and before use of other DT APIs.
- @module java/deployment_toolkit
- */
- var dtjava = function() {
- function notNull(o) {
- return (o != undefined && o != null);
- }
- function isDef(fn) {
- return (fn != null && typeof fn != "undefined");
- }
- //return true if any of patterns from query list is found in the given string
- function containsAny(lst, str) {
- for (var q = 0; q < lst.length; q++) {
- if (str.indexOf(lst[q]) != -1) {
- return true;
- }
- }
- return false;
- }
- /* Location of static web content - images, javascript files. */
- var jscodebase = (function () {
- // <script> elements are added to the DOM and run synchronously,
- // the currently running script will also be the last element in the array
- var scripts = document.getElementsByTagName("script");
- var src = scripts[scripts.length - 1].getAttribute("src");
- return src.substring(0, src.lastIndexOf('/') + 1);
- })();
- //set to true to disable FX auto install (before release)
- var noFXAutoInstall = false;
-
- // JRE version we start to have JRE and FX true co-bundle
- var minJRECobundleVersion = "1.7.0_06";
- //aliases
- var d = document;
- var w = window;
- var cbDone = false; //done with onload callbacks
- var domCb = []; //list of callbacks
- var ua = null;
- //add function to be called on DOM ready event
- function addOnDomReady(fn) {
- if (cbDone) {
- fn();
- } else {
- domCb[domCb.length] = fn;
- }
- }
- //invoke pending onload callbacks
- function invokeCallbacks() {
- if (!cbDone) {
- //swfoject.js tests whether DOM is actually ready first
- // in order to not fire too early. Use same heuristic
- try {
- var t = d.getElementsByTagName("body")[0].appendChild(
- d.createElement("div"));
- t.parentNode.removeChild(t);
- } catch (e) {
- return;
- }
- cbDone = true;
- for (var i = 0; i < domCb.length; i++) {
- domCb[i]();
- }
- }
- }
- //cross browser onload support.
- //Derived from swfobject.js
- function addOnload(fn) {
- if (isDef(w.addEventListener)) {
- w.addEventListener("load", fn, false);
- } else if (isDef(d.addEventListener)) {
- d.addEventListener("load", fn, false);
- } else if (isDef(w.attachEvent)) {
- w.attachEvent("onload", fn);
- //TODO: swfobject also keeps references to the listeners to detach them on onload
- // to avoid memory leaks ...
- } else if (typeof w.onload == "function") {
- var fnOld = w.onload;
- w.onload = function() {
- fnOld();
- fn();
- };
- } else {
- w.onload = fn;
- }
- }
- function detectEnv() {
- var dom = isDef(d.getElementById) && isDef(d.getElementsByTagName) && isDef(d.createElement);
- var u = navigator.userAgent.toLowerCase(),
- p = navigator.platform.toLowerCase();
- //NB: may need to be refined as some user agent may contain strings related to other browsers
- // (e.g. Chrome has both Safari and mozilla, Safari also has mozilla
- var windows = p ? /win/.test(p) : /win/.test(u),
- mac = p ? /mac/.test(p) : /mac/.test(u),
- linux = p ? /linux/.test(p) : /linux/.test(u),
- chrome = /chrome/.test(u),
- // get webkit version or false if not webkit
- webkit = !chrome && /webkit/.test(u) ?
- parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false,
- opera = /opera/.test(u),
- cputype = null,
- osVersion = null;
- var ie = false;
- try {
- //Used to be using trick from
- // http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
- //ie = !+"\v1",
- //but it does not work with IE9 in standards mode
- //Reverting to alternative - use execScript
- ie = isDef(window.execScript);
- } catch (ee) {
- //if javafx app is in the iframe and content of main window is coming from other domain
- // then some browsers may restrict access to outer window properties,
- // e.g. FF can throw exception for top.execScript (see RT-17885)
- //We could revert to more naive test, e.g. test user agent for "MSIE " string
- // but so far IE does not seem to throw exception => if we get here it is not IE anyways
- ie = false;
- }
- //we are not required to detect everything and can leave values null as
- // long as we later treat them accordingly.
- //We use "cputype" to detect if given hardware is supported,
- // e.g. we do not support PPC or iPhone/iPad despite they are running Mac OS
- //We use "osVersion" to detect if Java/JavaFX can be installed on this OS
- // e.g. Oracle Java for Mac requires 10.7.3
- if (mac) {
- if ((p && /intel/.test(p)) || /intel/.test(u)) {
- cputype = "intel";
- }
- //looking for things like 10_7, 10_6_8, 10.4, 11_2_2 in the user agent
- var t = u.match(/(1[0-9_\.]+)[^0-9_\.]/);
- //normalize to "." separators
- osVersion = notNull(t) ? t[0].replace(/_/g, ".") : null;
- }
- // Check mime types. Works with netscape family browsers and checks latest installed plugin only
- var mm = navigator.mimeTypes;
- var jre = null;
- var deploy = null;
- var fx = null;
- //Cache configuration from plugin mimetypes
- //It is only available for NPAPI browsers
- for (var t = 0; t < mm.length; t++) {
- // The jpi-version is the JRE version.
- var m = navigator.mimeTypes[t].type;
- if (m.indexOf("application/x-java-applet;jpi-version") != -1 && m.indexOf('=') != -1) {
- jre = m.substring(m.indexOf('=') + 1);
- }
- //Supported for 7u6 or later
- if (m.indexOf("application/x-java-applet;deploy") != -1 && m.indexOf('=') != -1) {
- deploy = m.substring(m.indexOf('=') + 1);
- }
- //javafx version for cobundled javafx (7u6+)
- if (m.indexOf("application/x-java-applet;javafx") != -1 && m.indexOf('=') != -1) {
- fx = m.substring(m.indexOf('=') + 1);
- }
- }
- return {haveDom:dom, wk:webkit, ie:ie, win:windows,
- linux:linux, mac:mac, op: opera, chrome:chrome,
- jre:jre, deploy:deploy, fx:fx,
- cputype: cputype, osVersion: osVersion};
- }
- //partially derived from swfobject.js
- var initDone = false;
- function init() {
- if (initDone) return;
- ua = detectEnv();
- if (!ua.haveDom) {
- return;
- }
- //NB: dtjava.js can be added dynamically and init() can be called after
- // document onload event is fired
- if (( isDef(d.readyState) && d.readyState == "complete") ||
- (!isDef(d.readyState) &&
- (d.getElementsByTagName("body")[0] || d.body))) {
- invokeCallbacks();
- }
- if (!cbDone) {
- if (isDef(d.addEventListener)) {
- d.addEventListener("DOMContentLoaded",
- invokeCallbacks, false);
- }
- if (ua.ie && ua.win) {
- d.attachEvent("onreadystatechange", function() {
- if (d.readyState == "complete") {
- d.detachEvent("onreadystatechange", arguments.callee);
- invokeCallbacks();
- }
- });
- if (w == top) { // if not inside an iframe
- (function() {
- if (cbDone) {
- return;
- }
- //AI: what for??
- try {
- d.documentElement.doScroll("left");
- } catch(e) {
- setTimeout(arguments.callee, 0);
- return;
- }
- invokeCallbacks();
- })();
- }
- }
- if (ua.wk) {
- (function() {
- if (cbDone) {
- return;
- }
- if (!/loaded|complete/.test(d.readyState)) {
- setTimeout(arguments.callee, 0);
- return;
- }
- invokeCallbacks();
- })();
- }
- addOnload(invokeCallbacks);
- }
- //only try to install native plugin if we do not have DTLite
- //Practically this means we are running NPAPI browser on Windows
- //(Chrome or FF) and recent JRE (7u4+?)
- if (!haveDTLite()) {
- installNativePlugin();
- }
- }
- /**
- This class provides details on why current platform does not meet
- application platform requirements. Note that severe problems are
- reported immediately and therefore full check may be not performed and
- some (unrelated to fatal problem)
- methods may provide false positive answers.
- <p>
- If multiple components do not match then worst status is reported.
- Application need to repeat checks on each individual component
- if it want to find out all details.
- @class PlatformMismatchEvent
- @for dtjava
- */
- function PlatformMismatchEvent(a) {
- //expect to get all parameters needed
- for (var p in a) {
- this[p] = a[p];
- }
- /**
- * @method toString
- * @return {string}
- * Returns string replesentation of event. Useful for debugging.
- */
- this.toString = function() {
- return "MISMATCH [os=" + this.os + ", browser=" + this.browser
- + ", jre=" + this.jre + ", fx=" + this.fx
- + ", relaunch=" + this.relaunch + ", platform="
- + this.platform + "]";
- };
- /**
- @method isUnsupportedPlatform
- @return {boolean}
- Returns true if this platform (OS/hardware) is not supported in a way
- to satisfy all platfrom requirements.
- (E.g. page is viewed on iPhone or JavaFX 2.0 application on Solaris.)
- <p>
- Note that this does not include browser match data.
- If platform is unsupported then application can not be
- launched and user need to use another platform to view it.
- */
- this.isUnsupportedPlatform = function() {
- return this.os;
- };
- /**
- @method isUnsupportedBrowser
- @return {boolean}
- Returns true if error is because current browser is not supported.
- <p>
- If true is returned and isRelaunchNeeded() returns true too then
- there are known supported browsers browsers for this platform.
- (but they are not necessary installed on end user system)
- */
- this.isUnsupportedBrowser = function() {
- return this.browser;
- };
- /**
- @method jreStatus
- @return {string}
- Returns "ok" if error was not due to missing JRE.
- Otherwise return error code characterizing the problem:
- <ul>
- <li> none - no JRE were detected on the system
- <li> old - some version of JRE was detected but it does not match platform requirements
- <li> oldplugin - matching JRE found but it is configured to use deprecated Java plugin that
- does not support Java applets
- <ul>
- <p>
- canAutoInstall() and isRelaunchNeeded() can be used to
- get more details on how seamless user' install experience will be.
- */
- this.jreStatus = function() {
- return this.jre;
- };
- /**
- * @method jreInstallerURL
- * @param {string} locale (optional) Locale to be used for installation web page
- * @return {string}
- *
- * Return URL of page to visit to install required version of Java.
- * If matching java runtime is already installed or not officially supported
- * then return value is null.
- */
- this.jreInstallerURL = function(locale) {
- if (this.os && (this.jre == "old" || this.jre == "none")) {
- return getJreUrl(locale);
- }
- return null;
- };
- /**
- @method javafxStatus
- @return {string}
- Returns "ok" if error was not due to missing JavaFX.
- Otherwise return error code characterizing the problem:
- <ul>
- <li> none - no JavaFX runtime is detected on the system
- <li> old - some version of JavaFX runtime iss detected but it does not match platform requirements
- <li> disabled - matching JavaFX is detected but it is disabled
- <li> unsupported - JavaFX is not supported on this platform
- <ul>
- <p>
- canAutoInstall() and isRelaunchNeeded() can be used to
- get more details on how seamless user' install experience will be.
- */
- this.javafxStatus = function() {
- return this.fx;
- };
- /**
- * @method javafxInstallerURL
- * @param {string} locale (optional) Locale to be used for installation web page
- * @return {string}
- *
- * Return URL of page to visit to install required version of JavaFX.
- * If matching JavaFX runtime is already installed or not officially supported
- * then return value is null.
- */
- this.javafxInstallerURL = function(locale) {
- if (!this.os && (this.fx == "old" || this.fx == "none")) {
- return getFxUrl(locale);
- }
- return null;
- };
- /**
- @method canAutoInstall
- @return {boolean}
- Returns true if installation of missing components can be
- triggered automatically. In particular, ture is returned
- if there are no missing components too.
- <p>
- If any of missing components need to be installed manually
- (i.e. click through additional web pages) then false is returned.
- */
- this.canAutoInstall = function() {
- return isAutoInstallEnabled(this.platform, this.jre, this.fx);
- };
- /**
- @method isRelaunchNeeded
- @return {boolean}
- Returns true if browser relaunch is needed before application can be loaded.
- This often is true in conjuction with need to perform installation.
- <p>
- Other typical case - use of unsupported browser when
- it is known that there are supported browser for this pltaform.
- Then both isUnsupportedBrowser() and isRelaunchNeeded() return true.
- */
- this.isRelaunchNeeded = function() {
- return this.relaunch;
- };
- }
- //returns version of instaled JavaFX runtime matching requested version
- //or null otherwise
- function getInstalledFXVersion(requestedVersion) {
- //NPAPI browser and JRE with cobundle
- if (ua.fx != null && versionCheckFX(requestedVersion, ua.fx)) {
- return ua.fx;
- }
- //try to use DT
- var p = getPlugin();
- if (notNull(p)) {
- try {
- return p.getInstalledFXVersion(requestedVersion);
- } catch(e) {}
- }
- return null;
- }
- //concatenate list with space as separator
- function listToString(lst) {
- if (lst != null) {
- return lst.join(" ");
- } else {
- return null;
- }
- }
- function addArgToList(lst, arg) {
- if (notNull(lst)) {
- lst.push(arg);
- return lst;
- } else {
- var res = [arg];
- return res;
- }
- }
- function doLaunch(ld, platform, cb) {
- var app = normalizeApp(ld, true);
- //required argument is missing
- if (!(notNull(app) && notNull(app.url))) {
- throw "Required attribute missing! (application url need to be specified)";
- }
- //if we got array we need to copy over!
- platform = new dtjava.Platform(platform);
- //normalize handlers
- cb = new dtjava.Callbacks(cb);
- var launchFunc = function() {
- //prepare jvm arguments
- var jvmArgs = notNull(platform.jvmargs) ? platform.jvmargs : null;
- if (notNull(platform.javafx)) {
- //if FX is needed we know it is available or
- // we will not get here
- var v = getInstalledFXVersion(platform.javafx);
- //add hint that we need FX toolkit to avoid relaunch
- // if JNLP is not embedded
- jvmArgs = addArgToList(jvmArgs, " -Djnlp.fx=" + v);
- //for swing applications embedding FX we do not want this property as it will
- // trigger FX toolkit and lead to app failure!
- //But for JavaFX application it saves us relaunch as otherwise we wil launch with AWT toolkit ...
- if (!notNull(ld.toolkit) || ld.toolkit == "fx") {
- jvmArgs = addArgToList(jvmArgs, " -Djnlp.tk=jfx");
- }
- }
- //if we on 7u6+ we can use DTLite plugin in the NPAPI browsers
- //Caveat: as of 7u6 it does not work with Chrome on Linux because Chrome expects
- // DTLite plugin to implement xembed (or claim to support xembed)
- if (haveDTLite() && !(ua.linux && ua.chrome)) {
- if (doLaunchUsingDTLite(app, jvmArgs, cb)) {
- return;
- }
- }
- //Did not launch yet? Try DT plugin (7u2+)
- var p = getPlugin();
- if (notNull(p)) {
- try {
- try {
- //check if new DT APIs are available
- if (versionCheck("10.6+", ua.deploy)) {
- // obj.launchApp({"url" : "http://somewhere/my.jnlp",
- // "jnlp_content" : "... BASE 64 ...",
- // "vmargs" : [ "-ea -Djnlp.foo=bar"
- // "appargs" : [ "first arg, second arg" ]
- // "params" : {"p1" : "aaa", "p2" : "bbb"}});
- var callArgs = {"url":app.url};
- if (notNull(jvmArgs)) {
- callArgs["vmargs"] = jvmArgs;
- }
- //Only use HTML parameters, they are supposed to overwrite values in the JNLP
- //In the future we want to pass arguments too but this needs also be exposed for
- // embedded deployment
- if (notNull(app.params)) {
- //copy over and ensure all values are strings
- // (native code will ignore them otherwise)
- var ptmp = {};
- for (var k in app.params) {
- ptmp[k] = String(app.params[k]);
- }
- callArgs["params"] = ptmp;
- }
- if (notNull(app.jnlp_content)) {
- callArgs["jnlp_content"] = app.jnlp_content;
- }
- var err = p.launchApp(callArgs);
- if (err == 0) { //0 - error
- if (isDef(cb.onRuntimeError)) {
- cb.onRuntimeError(app.id);
- }
- }
- } else { //revert to old DT APIs
- //older DT APIs expects vmargs as a single string
- if (!p.launchApp(app.url, app.jnlp_content, listToString(jvmArgs))) {
- if (isDef(cb.onRuntimeError)) {
- cb.onRuntimeError(app.id);
- }
- }
- }
- return;
- } catch (ee) { //temp support for older build of DT
- if (!p.launchApp(app.url, app.jnlp_content)) {
- if (isDef(cb.onRuntimeError)) {
- cb.onRuntimeError(app.id);
- }
- }
- return;
- }
- } catch (e) {
- //old DT
- }
- } //old Java (pre DTLite)? not Windows? or old DT
- //use old way to launch it using java plugin
- var o = getWebstartObject(app.url);
- if (notNull(d.body)) {
- d.body.appendChild(o);
- } else {
- //should never happen
- d.write(o.innerHTML);
- }
- }
- var r = doValidateRelaxed(platform);
- //can not launch, try to fix
- if (r != null) {
- resolveAndLaunch(app, platform, r, cb, launchFunc);
- } else {
- launchFunc();
- }
- }
- //process unhandled platform error - convert to code and call callback
- function reportPlatformError(app, r, cb) {
- if (isDef(cb.onDeployError)) {
- cb.onDeployError(app, r);
- }
- }
- function isDTInitialized(p) {
- //if plugin is blocked then p.version will be undefined
- return p != null && isDef(p.version);
- }
- //Wait until DT plugin is initialized and then run the code
- //Currently we only use it for embeded apps and Chrome on Windows
- function runUsingDT(label, f) {
- // Possible situations:
- // a) plugin is live and we can simply run code
- // - just run the code
- // b) plugin is in the DOM tree but it is not initialized yet (e.g. Chrome blocking)
- // and there is live timer (pendingCount > 0)
- // - there could be another request. We will APPEND to it
- // (this is different from dtlite as in this case we can not have multiple clicks)
- // - renew timer life counter (do not want new timer)
- // c) plugin is in the DOM tree and it is not fully initialized yet but timer is stopped
- // - overwrite old request
- // - restart timer
- //
- // Problem we are solving:
- // when plugin is ready to serve request? How do we schedule call to happen when plugin is initialized?
- // Caveat:
- // Chrome can popup dialog asking user to grant permissions to load the plugin.
- // There is no API to detect dialog is shown and when user grants or declines permissions
- //
- // Note:
- // If we set property on plugin object before it is unblocked then they seem to be lost
- // and are not propagated to the final object once it is instantiated.
- //
- // Workaround we use:
- // Once plugin is added we will be checking if it is initialized and once we detect it we will execute code.
- // We will stop checking after some time.
- var p = getPlugin();
- if (p == null) {
- return; //NO DT
- }
- if (isDTInitialized(p)) {
- f(p);
- } else {
- // see if we need new timer
- var waitAndUse = null;
- if (!isDef(dtjava.dtPendingCnt) || dtjava.dtPendingCnt == 0) {
- waitAndUse = function () {
- if (isDTInitialized(p)) {
- if (notNull(dtjava.dtPending)) {
- for (var i in dtjava.dtPending) {
- dtjava.dtPending[i]();
- }
- }
- return;
- }
- if (dtjava.dtPendingCnt > 0) {
- dtjava.dtPendingCnt--;
- setTimeout(waitAndUse, 500);
- }
- }
- }
- //add new task in queue
- if (!notNull(dtjava.dtPending) || dtjava.dtPendingCnt == 0) {
- dtjava.dtPending = {};
- }
- dtjava.dtPending[label] = f; //use map to ensure repitative actions are not queued (e.g. multiple click to launch webstart)
- //reset the timer counter
- dtjava.dtPendingCnt = 1000; //timer is gone after 500s
- //start timer if needed
- if (waitAndUse != null) waitAndUse();
- }
- }
- //returns same mismatch event if not resolved, null if resolved
- function resolveAndLaunch(app, platform, v, cb, launchFunction) {
- var p = getPlugin();
- //Special case: Chrome/Windows
- // (Note: IE may also block activeX control but then it will block attempts to use it too)
- if (ua.chrome && ua.win && p != null && !isDTInitialized(p)) {
- //this likely means DT plugin is blocked by Chrome
- //tell user to grant permissions and retry
- var actionLabel;
- if (notNull(app.placeholder)) {
- var onClickFunc = function() {w.open("http://www.java.com/en/download/faq/chrome.xml"); return false;};
- var msg1 = "Please give Java permission to run on this browser web page.";
- var msg2 = "Click for more information.";
- var altText = "";
- doShowMessageInTheArea(app, msg1, msg2, altText, "javafx-chrome.png", onClickFunc);
- actionLabel = app.id + "-embed";
- } else {
- v.jre = "blocked";
- reportPlatformError(app, v, cb);
- actionLabel = "launch"; //we only queue ONE webstart launch.
- //Do not want to try to queue different apps - bad UE
- // (once user enable multiple things can spawn)
- //Note: what if multiple webstart apps are set to launch on page load (suer do not need to click)?
- // Guess do not worry for now
- //Note: app.id may be null in case of webstart app.
- }
- //now we need to start waiter. Once DT is initialized we can proceeed
- var retryFunc = function() {
- var vnew = doValidateRelaxed(platform);
- if (vnew == null) { //no problems with env
- launchFunction();
- } else {
- resolveAndLaunch(app, platform, vnew, cb, launchFunction);
- }
- };
- runUsingDT(actionLabel, retryFunc);
- return;
- }
- if (!v.isUnsupportedPlatform() && !v.isUnsupportedBrowser()) { //otherwise fatal, at least until restart of browser
- if (isMissingComponent(v) && isDef(cb.onInstallNeeded)) {
- var resolveFunc= function() {
- //once install is over we need to revalidate
- var vnew = doValidateRelaxed(platform);
- if (vnew == null) { //if no problems found - can launch
- launchFunction();
- } else { //TODO: what happens if we installed everything but relaunch is needed??
- //We can not get here if component install was not offered for any or missing componens
- //(if auto install was possible, see doInstall() implementation)
- //Hence, it is safe to assume we failed to meet requirements
- reportPlatformError(app, vnew, cb);
- //TODO: may be should call itself again but
- // then it easy can become infinite loop
- //e.g. user installs but we fail to detect it because DT
- // is not FX aware and retry, etc.
- //TODO: think it through
- }
- };
- cb.onInstallNeeded(app, platform, cb,
- v.canAutoInstall(), v.isRelaunchNeeded(), resolveFunc);
- return;
- }
- }
- reportPlatformError(app, v, cb);
- }
- function haveDTLite() {
- if (ua.deploy != null) {
- return versionCheck("10.6+", ua.deploy);
- }
- return false;
- }
- function isDTLiteInitialized(p) {
- //if plugin is blocked then p.version will be undefined
- return p != null && isDef(p.version);
- }
- function getDTLitePlugin() {
- return document.getElementById("dtlite");
- }
- function doInjectDTLite() {
- //do not want more than one plugin
- if (getDTLitePlugin() != null) return;
- var p = document.createElement('embed');
- p.width = '10px';
- p.height = '10px';
- p.id = "dtlite";
- p.type = "application/x-java-applet"; //means we get latest
- var div = document.createElement("div");
- div.style.position = "relative";
- div.style.left = "-10000px";
- div.appendChild(p);
- var e = document.getElementsByTagName("body");
- e[0].appendChild(div);
- }
- function runUsingDTLite(f) {
- // Possible situations:
- // a) first request, plugin is not in the DOM tree yet
- // - add plugin
- // - setup wait mechanism and run f() once plugin is ready
- // b) plugin is live and we can simply run code
- // - just run the code
- // c) plugin is in the DOM tree but it is not initialized yet (e.g. Chrome blocking)
- // and there is live timer (pendingCount > 0)
- // - there could be another request. We will override it (e.g. user clicked multiple times)
- // - renew timer life counter (do not want new timer)
- // d) plugin is in the DOM tree and it is not fully initialized yet but timer is stopped
- // - overwrite old request
- // - restart timer
- //
- // Problem:
- // when plugin is ready to serve request? How do we schedule call to happen when plugin is initialized?
- // Caveat:
- // Chrome can popup dialog asking user to grant permissions to load the plugin.
- // There is no API to detect dialog is shown and when user grants or declines permissions
- //
- // Note:
- // If we set property on plugin object before it is unblocked then they seem to be lost
- // and are not propagated to the final object once it is instantiated.
- //
- // Workaround we use:
- // Once plugin is added we will be checking if it is initialized and once we detect it we will execute code.
- // We will stop checking after some time.
- var p = getDTLitePlugin();
- if (p == null) {
- doInjectDTLite();
- p = getDTLitePlugin();
- }
- if (isDTLiteInitialized(p)) {
- f(p);
- } else {
- // see if we need new timer
- var waitAndUse = null;
- if (!isDef(dtjava.dtlitePendingCnt) || dtjava.dtlitePendingCnt == 0) {
- waitAndUse = function () {
- if (isDef(p.version)) {
- if (dtjava.pendingLaunch != null) {
- dtjava.pendingLaunch(p);
- }
- dtjava.pendingLaunch = null;
- return;
- }
- if (dtjava.dtlitePendingCnt > 0) {
- dtjava.dtlitePendingCnt--;
- setTimeout(waitAndUse, 500);
- }
- }
- }
- //add new task in queue
- dtjava.pendingLaunch = f;
- //reset the timer counter
- dtjava.dtlitePendingCnt = 1000; //timer is gone after 500s
- //start timer if needed
- if (waitAndUse != null) {
- waitAndUse();
- }
- }
- }
- function doLaunchUsingDTLite(app, jvmargs, cb) {
- var launchIt = function() {
- var pp = getDTLitePlugin();
- if (pp == null) {
- //should not be possible as we guard before enter this function
- if (isDef(cb.onRuntimeError)) {
- cb.onRuntimeError(app.id);
- }
- }
-
- //DTLite only support new invocation API
- // obj.launchApp({"url" : "http://somewhere/my.jnlp",
- // "jnlp_content" : "... BASE 64 ...",
- // "vmargs" : [ "-ea -Djnlp.foo=bar"
- // "appargs" : [ "first arg, second arg" ]
- // "params" : {"p1" : "aaa", "p2" : "bbb"}});
- var callArgs = {"url" : app.url};
- if (notNull(jvmargs)) {
- callArgs["vmargs"] = jvmargs;
- }
- //Only use HTML parameters, they are supposed to overwrite values in the JNLP
- //In the future we want to pass arguments too but this needs also be exposed for
- // embedded deployment
- if (notNull(app.params)) {
- //copy over and ensure all values are stings
- // (native code will ignore them otherwise)
- var ptmp = {};
- for (var k in app.params) {
- ptmp[k] = String(app.params[k]);
- }
- callArgs["params"] = ptmp;
- }
- if (notNull(app.jnlp_content)) {
- callArgs["jnlp_content"] = app.jnlp_content;
- }
- var err = pp.launchApp(callArgs);
- if (err == 0) { //0 - error
- if (isDef(cb.onRuntimeError)) {
- cb.onRuntimeError(app.id);
- }
- }
- };
-
- if (versionCheck("10.4+", ua.deploy)) { //only for NPAPI browsers
- runUsingDTLite(launchIt);
- return true;
- }
- return false;
- }
-
- function getWebstartObject(jnlp) {
- var wo = null;
- if (ua.ie) { //TODO: attempt to use object in FF 3.6 lead to hang. Revert to embed for now
- //TODO: Should Chrome use object?
- //object tag itself
- wo = d.createElement('object');
- wo.width = '1px'; //zero size reports invalid argument in IE!
- wo.height = '1px'; //TODO: make it less distruptive to page layout? hide div?
- var p = d.createElement('param');
- p.name = 'launchjnlp';
- p.value = jnlp;
- wo.appendChild(p);
- p = d.createElement('param');
- p.name = 'docbase';
- p.value = notNull(d.documentURI) ? d.documentURI : d.URL;
- wo.appendChild(p);
- if (!ua.ie) {
- //NB:do not need to use exact version in mime type as generic should be mapped to latest?
- wo.type = "application/x-java-applet;version=1.7";
- } else {
- wo.classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
- }
- } else { //TODO: else part should go away once we figure out what is going on with FF
- wo = d.createElement('embed');
- wo.width = '0px';
- wo.height = '0px';
- //NB: dot notation did not work for custom attributes??? revert to setAttribute
- wo.setAttribute('launchjnlp', jnlp);
- wo.setAttribute('docbase', (notNull(d.documentURI) ? d.documentURI : d.URL));
- //NB:do not need to use exact version in mime type as generic should be mapped to latest?
- wo.type = "application/x-java-applet;version=1.7";
- }
- var div = d.createElement("div");
- div.style.position = "relative";
- div.style.left = "-10000px";
- div.appendChild(wo);
- return div;
- }
- //this is similar to version check rules except for
- // JavaFX we treat version slightly differently.
- //For Javafx version really is FAMILY.UPDATE_VERSION
- // where FAMILY is everything before first dot
- // E.g.
- // 2.0.1 => family 2, update 0.1
- // 2.0 => family 2. update 0.0
- //
- // JavaFX version requirements are always treated as "not earlier than this update".
- // I.e. we expect
- // 2.2.0 to match 2.2*, 2.2+, 2.1+, 2.1*, 2.0 and 1+
- // but not match 2.2.1+, 2.2.1*, 2.3*, 2.3+ or 1*
- function versionCheckFX(query, version) {
- if (query == null || query.length == 0) {
- return true;
- }
- var endChar = query.charAt(query.length - 1);
- var familyOnly = (endChar == '*');
- if (!familyOnly) {
- if (endChar == '+') {
- return versionCheck(query, version);
- } else { //must be fixed version, e.g. 2.0
- return versionCheck(query + '+', version);
- }
- } else {
- return (versionCheck(query.charAt(0)+".*", version) && //required family (version belongs to family 2)
- versionCheck(query.substring(0, query.length - 1)+"+", version)); //global lookup (version >= 2.1.1), replace * with +
- }
- }
- //Convert version string into 4 element array with version components
- //If input string has fewer components then pad with zeros from the right
- //If input string ends with suffix like '+' or '*' then it is stripped
- //
- //Examples:
- // 10.1.2.3 => {10, 1, 2, 3}
- // 10.1 => {10, 1, 0, 0}
- // 10.1+ => {10, 1, 0, 0}
- function convertVersionToArray(versionString) {
- if (versionString != null) {
- var c = versionString.charAt(versionString.length - 1);
- //if it is not digit we want to strip last char
- if (c <= '0' || c >= '9') {
- versionString = versionString.substring(0, versionString.length - 1);
- }
- }
- //corner case inputs
- if (versionString == null || versionString.length == 0) {
- return [0, 0, 0, 0];
- }
- var arr = versionString.split(".");
- while (arr.length < 4) {
- arr.push(0);
- }
- return arr;
- }
- //checks where given version string matches query
- //
- //NB: assume format is correct. Can add format check later if needed
- function versionCheck(query, version) {
- if (query == null || query.length == 0) return true;
- var c = query.charAt(query.length - 1);
- //if it is not explicit pattern but does not have update version then need to append *
- if (c != '+' && c != '*' && (query.indexOf('_') != -1 && c != '_')) {
- query = query + "*";
- c = '*';
- }
- query = query.substring(0, query.length - 1);
- //if query ends with ".", "_" then we want to strip it to allow match of "1.6.*" to shorter form such as "1.6"
- //TODO: add support for match of "1.7.0*" to "1.7"?
- if (query.length > 0) {
- var z = query.charAt(query.length - 1);
- if (z == '.' || z == '_') {
- query = query.substring(0, query.length - 1);
- }
- }
- if (c == '*') {
- //it is match if version starts from it
- return (version.indexOf(query) == 0);
- } else if (c == '+') {
- //lexicographical comparison is not good here as we may have case like
- // query="10.6*" and version="10.10.2"
- //Approach:
- // split into tokens and compare each of tokens numerically
- //Keep comparing until tokens are the same or we reached end.
- //If tokens differ then we have a match if query is smaller and
- // non-match if it is greater
- var qArr = convertVersionToArray(query);
- var vArr = convertVersionToArray(version);
- //qArr and vArr are expected to be arrays of same length
- for (var idx=0; idx < qArr.length; idx++) {
- if (qArr[idx] < vArr[idx]) {
- //query is smaller
- return true;
- } else if (qArr[idx] < vArr[idx]) {
- //query is larger => fail
- return false;
- }
- }
- //query is equal to version => it is ok
- return true;
- }
- return false;
- }
- //as JavaFX comes with own plugin binaries then check based on mime types, etc.
- // may be false positive as it only checks for plugin version, not real JRE
- //Here we check that DT plugin is aware of JRE installations
- //Note that:
- // - if DT is not available we will return false but we only do this i
- // ready to launch => DT must be found
- // - we do not want to check in jreCheck() as we want to avoid loading
- // DT plugin if we can (as old DT may make it not possible to autostart)
- function doublecheckJrePresence() {
- if (!haveDTLite()) { //basically IE on windows or Old JRE on windows
- var p = getPlugin();
- if (p != null) {
- return true;
- //WORKAROUND: bug in native DT!!! TODO: What version? bypass for it only
- //return (p.jvms.getLength() > 0);
- }
- return false;
- }
- //if we are not using native DT plugin (i.e. using DTLite) then no way we can do sanity check
- // => assume first check is accurate
- return true;
- }
- function jreCheck(jre) {
- // Check if latest JRE is exposed in mimetype and if it is good enough (only for NPAPI browsers)
- if (ua.jre != null) {
- if (versionCheck(jre, ua.jre)) {
- return "ok";
- }
- //Note: if we have JRE but it is not match that means we may need an upgrade message
- // but we still could be able to get more accurate answer with native DT plugin
- }
- //try to use DT plugin
- var p = getPlugin();
- if (p != null) {
- var VMs = p.jvms;
- for (var i = 0; VMs != null && i < VMs.getLength(); i++) {
- if (versionCheck(jre, VMs.get(i).version)) {
- if (!ua.ie && notNull(navigator.mimeTypes)) {
- //if mime types are available but plugin is not there =>
- // it is disabled
- if (!notNull(navigator.mimeTypes["application/x-java-applet"])) {
- return "disabled";
- }
- }
- return "ok";
- }
- }
- //do not need to try other ways if used DT
- return "none";
- }
- //No full DT => On Windows we can not launch FX anyways
- // but may have old JRE
- //And we might be able to launch on Mac/Linux
- //This is only IE on Windows. This gives no update version. only e.g. 1.6.0
- //and also cause java plugin to be loaded => browser will need to be restarted
- //if new JRE is installed.
- //However, if we got here than DT is not available and autoinstall is not possible
- if (ua.ie) {
- var lst = ["1.8.0", "1.7.0", "1.6.0", "1.5.0"];
- for (var v = 0; v < lst.length; v++) {
- if (versionCheck(jre, lst[v])) {
- try {
- //TODO: FIXME: This does not seem to work in my testing in IE7?
- var axo = new ActiveXObject("JavaWebStart.isInstalled." + lst[v] + ".0");
- // This is not hit if the above throws an exception.
- return "ok";
- } catch (ignored) {
- }
- }
- }
- }
- return "none";
- }
- function checkJRESupport() {
- //Negative test. New platforms will not be rejected
- var osProblem = ['iPhone', 'iPod'];
- var os = containsAny(osProblem, navigator.userAgent);
- //Do not support Chrome/Mac as Chrome is 32 bit only
- var browser = (ua.mac && ua.chrome && ua.cputype == "intel");
- //autoinstall possible if native plugin is detected or OS is fine
- auto = os || (getPlugin() != null);
- //false is no problem found
- return {os: os, browser: browser, auto: auto};
- }
- //it is not clear if we can work in IE6
- // but it is hard to test and JRE7 does not even support it
- // mark as unsupported for now
- function isUnsupportedVersionOfIE() {
- if (ua.ie) {
- try {
- //these functions are defined in IE only
- var v = 10*ScriptEngineMajorVersion() + ScriptEngineMinorVersion();
- if (v < 57) return true; //IE7 will have 57
- } catch (err) {
- //really old IE?
- return true;
- }
- }
- return false;
- }
- function checkFXSupport() {
- var browser;
- if (ua.win) {
- //do not support Opera and Safari
- // (not really tested, may be it works but known to have problems with DT detection)
- browser = ua.op || ua.wk || isUnsupportedVersionOfIE();
- //false is no problem found
- return {os: false, browser: browser};
- } else if (ua.mac && ua.cputype == "intel") { //do not support PPC/iphone/ipad ...
- var os = !versionCheck("10.7.3+", ua.osVersion); //10.7.3 or later!
- browser = ua.op ||
- (ua.mac && ua.chrome); //Opera is not supported
- //Chrome on Mac is 32 bit => plugin only work in 64 bit ...
- //TODO: How do we detect FF running in 32 bit mode?
- //false is no problem found
- return {os: os, browser: browser};
- } else if (ua.linux) {
- browser = ua.op; //Opera unsupported
- //false is no problem found
- return {os: false, browser: browser};
- } else {
- //unknown unsupported OS
- return {os: true, browser: false};
- }
- }
- function relaxVersion(v) {
- if (notNull(v) && v.length > 0) {
- var c = v.charAt(v.length - 1);
- if (c == '*') {
- v = v.substring(0, v.length - 1)+"+";
- } else if (c != '+') { //exact version (e.g. 1.6)
- v = v + "+";
- }
- }
- return v;
- }
- //we relax validation rules where we try to embed or launch app
- // in order to deal with requests for OLDER jres at the java level
- //Basically we convert request for version in JRE family to request for any future JRE
- //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
- //
- //Note we keep validation strict for install and validate-only scenarios.
- // This allows to query accurate details from javascript
- function doValidateRelaxed(platform) {
- var p = new dtjava.Platform(platform);
- p.jvm = relaxVersion(p.jvm);
- //p.javafx = relaxVersion(p.javafx);
- return doValidate(p);
- }
- function doValidate(platform) {
- //ensure some platform is set (we could get array too!)
- platform = new dtjava.Platform(platform);
- //problem markers
- var fx = "ok", jre = "ok", restart = false, os = false, browser = false,
- p, details;
- //check JRE
- if (notNull(platform.jvm) && jreCheck(platform.jvm) != "ok") { //matching JRE not found
- var res = jreCheck("*");
- if (res == "ok") {
- jre = "old";
- } else {
- jre = res; //"none" or "disabled"
- }
- details = checkJRESupport();
- if (details.os) {
- jre = "unsupported";
- os = true;
- }
- browser = details.browser;
- }
- /* if (notNull(platform.plugin) && jre == "ok") {
- try {
- p = getPlugin();
- //TEMPORARY DISABLE because isPlugin2() is broken in 1.7.0
- // it is not fixed in 7-client but if FX is enabled then
- // it must be new plugin anyways
- //=> keep this disabled for now until we find use case
- if (false && (p == null || !p.isPlugin2())) {
- //TODO: FIXME: seem to get here always because isPlugin2() returns 0?
- jre = "oldplugin";
- relaunch = true;
- …
Large files files are truncated, but you can click here to view the full file