Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8234959

FXMLLoader does not populate ENGINE_SCOPE Bindings with FILENAME and ARGV

XMLWordPrintable

    • x86
    • linux

      ADDITIONAL SYSTEM INFORMATION :
      Tested on 64-Bit-Ubuntu Linux, OpenJDK 11.0.5
      Tested on Windows-7-64-Bit, Oracle Java 8

      A DESCRIPTION OF THE PROBLEM :
      Testcase that demonstrates that FXMLLoader does not set [1]
      ScriptEngine.FILENAME and [2] ScriptEngine.ARGV entries in
      ScriptContext.ENGINE_SCOPE Bindings.

      To run the test case:

      - unzip testcaseFXMLLoaderScriptEngines.zip,

      - change into "testcaseFXMLLoaderScriptEngines" subdirectory,

      - run the testcase by issuing the following command:

        - Unix:

              java -cp .:RgfPseudoScriptEngine.jar FXMLLoaderTestCase4ScriptEngineScope

        - Windows:

              java -cp .;RgfPseudoScriptEngine.jar FXMLLoaderTestCase4ScriptEngineScope

      FXMLLoaderTestCase4ScriptEngineScope loads "demo_01.fxml" which is a controller
      that uses the pseudo script language rgf.scriptEngine.RgfPseudoScriptEngine,
      which logs the eval() invocations with the script code and the Bindings of the
      ScriptContext.

      Comparing "demo_01.fxml" and the output of the above test case demonstrates that
      FXMLLoader does not popuplate the [3] ENGINE_SCOPE Bindings with the filename of
      the script that gets evaluated, nor does add the ARGV entry to the ENGINE_SCOPE
      Bindings in the case of events (just an entry named "event").

      In case of errors (during development or deployment) it is not possible
      therefore to point to the file (external file or the fxml-file defining
      explicitly script code) in which a runtime error has occurred.

      In the case of an event callback, if ARGV was defined the script code could
      directly fetch and interact with the supplied event object argument. In the
      case that a script engine does not automatically make Bindings entry available
      as implicit variables (e.g. for scoping reasons) it becomes cumbersome or even
      impossible in some script engine implementations (if they do not provide access
      to the Bindings) to get at the event argument of the callback invocation.

      The JSR-223 specifications lists all the (reserved) ScriptEngine constants that
      are meant to be used as reserved keys for the ENGINE_SCOPE Bindings, whenever
      appropriate cf. [0] p. l50 ff. (A ScriptEngine is supposed to populate and
      maintain the ENGINE_SCOPE Bindings hence the definition of these constants with
      the class.)

      Running the above program on Windows yields the output captured and supplied in
      [4].

      The supplied patch [5] changes FXMLLoader.java such,

      - that the ScriptEngine.FILENAME entry is always set in the ENGINE_SCOPE
        Bindings. In the case that the scripts are hosted in a fxml-file that file
        path will be used together with an appended string that hints at the location
        in the fxml file from where the script has been taken for evaluation. In the
        case of event handling scripts that appended string hints at the location in
        the fxml-file where the event attribute with the script code got used.

      - and that the ScriptEngine.ARGV entry is always set in the ENGINE_SCOPE
        Bindings for event callbacks using the 'event' object as the single argument.

      Applying the patch and running the above program on Linux yields the output
      captured and supplied in [6].

      ---

      The jar-file [7] needs merely to be put on the CLASSPATH (or MODULE_PATH as a
      proper module-info.class is included, the module name is "rgf.scriptEngine") to
      make the pseudo scripting language available and to run the supplied testcase.
      The RgfPseudoScriptEngine (script engine name and extension is "rpsl")
      implementation should also make it possible to create test units for asserting
      that Java script hosts are populating the ScriptContext Bindings according to
      specifications.

      All Java classes come with their source code (the script engine service file and
      module-info.{java|class} are contained in the jar file).

      Having signed the OCA you may use all of the supplied code freely.

      If there is anything you need or that I could provide, please let me know.

      ---rony

      [0] JSR-223 specification at <https://jcp.org/en/jsr/detail?id=223&gt;, download
          <https://jcp.org/aboutJava/communityprocess/pfd/jsr223/index.html&gt;:
          "java_scripting-1_0-fr-spec.pdf"

      [1] <https://docs.oracle.com/en/java/javase/11/docs/api/java.scripting/javax/script/ScriptEngine.html#FILENAME>

      [2] <https://docs.oracle.com/en/java/javase/11/docs/api/java.scripting/javax/script/ScriptEngine.html#ARGV>

      [3] <https://docs.oracle.com/en/java/javase/11/docs/api/java.scripting/javax/script/ScriptContext.html#ENGINE_SCOPE>

      [4] Output of running the testcase on Windows (Java 8): "info/Demo_output_without_fix.txt"

      [5] FXMLLoader patch: "info/diff_add_FILENAME_ARGV_to_FXMLLoader_preferable_20191121.txt"

      [6] Output of running the testcase after patching FXMLLoader with [5] on Linux (OpenJDK 11.0.5):
          "info/Demo_output_with_fix_and_linenumbers.txt"

      [7] Pseudo script engine implementation to be put on the CLASSPATH or MODULE_PATH (module
          name "rgf.scriptEngine"): <RgfPseudoScriptEngine.jar>

      [8] FXML test case:

          - FXMLLoaderTestCase4ScriptEngineScope.{java|class}
            ... loads "demo_01.rxml" and dumps the engine and global Bindings

          - demo_01.fxml
          ... FXML file using scripts in the pseudo script language [7] as controller,
              either as external or embedded scripts, including scripts for event
              handling Action and MouseClicked events

          - demo_01_bottomscript.rpsl ... serving as external script file

          - demo_01_middlescript.rpsl ... serving as external script file

          - demo_01_topscript.rpsl ... serving as external script file


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the test case program "FXMLLoaderTestCase4ScriptEngineScope.java" which is an FXML application using an artificial script engine ("RgfPseudoScriptEngine.java", "RgfPseudoScriptEngineFactory.java") that is used as the controller language for "demo_01.fxml". "RgfPseudoScriptEngine.java" logs all eval() invocations together with the submitted script code and the ScriptContext Bindings for ENGINE_SCOPE and GLOBAL_SCOPE.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -

      Listing eval() invocation information (evalDataList):

      ScriptEngine: [rgf.scriptEngine.RgfPseudoScriptEngine@51521cc1]

      eval() invocation # 1:

      script: [demo_01_topscript.rpsl file - pseudo script in external file, starts with the filename

      ]

      Bindings for scope # 100 (ENGINE_SCOPE):

      Bindings for scope # 200 (GLOBAL_SCOPE):

      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]

      [location]: [file:demo_01.fxml]

      [resources]: [null]



      eval() invocation # 2:

      script: [demo_01_middlescript.rpsl file - pseudo script in external file, starts with the filename

      ]

      Bindings for scope # 100 (ENGINE_SCOPE):

      Bindings for scope # 200 (GLOBAL_SCOPE):

      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']

      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]

      [location]: [file:demo_01.fxml]

      [resources]: [null]



      eval() invocation # 3:

      script: [demo_01.fxml embedded script rpsl - line # 25]

      Bindings for scope # 100 (ENGINE_SCOPE):

      Bindings for scope # 200 (GLOBAL_SCOPE):

      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']

      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]

      [location]: [file:demo_01.fxml]

      [resources]: [null]



      eval() invocation # 4:

      script: [demo_01_bottomscript.rpsl file - pseudo script in external file, starts with the filename

      ]

      Bindings for scope # 100 (ENGINE_SCOPE):

      Bindings for scope # 200 (GLOBAL_SCOPE):

      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']

      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]

      [location]: [file:demo_01.fxml]

      [resources]: [null]



      eval() invocation # 5:

      script: [something (line # 29)
      in (line # 30)
      the (line # 31)
      news (line # 32) ]

      Bindings for scope # 100 (ENGINE_SCOPE):

      Bindings for scope # 200 (GLOBAL_SCOPE):

      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']

      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]

      [location]: [file:demo_01.fxml]

      [resources]: [null]



      eval() invocation # 6:

      script: [demo_01.fxml (line # 32):
      CDATA-section ("<![CDATA[") allows any characters including <, > and & !! (no need to escape
      these special characters; it is plain CDATA which does not get processed, just passed on
      including LF etc.
      Watch out that in the code there is no string that exactly matches the end tag
      for a CDATA-section (close-square-bracket+close-square-bracket+greater-character ]

      Bindings for scope # 100 (ENGINE_SCOPE):

      Bindings for scope # 200 (GLOBAL_SCOPE):

      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']

      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]

      [location]: [file:demo_01.fxml]

      [resources]: [null]



      eval() invocation # 7:

      script: [demo_01.fxml embedded event - ActionEvent - line # 18 - LF entity (&#10;) forces linebreak in attribute value:
       (this is on a new line) these characters in attribute values need to be escaped: <, >, &, these if used as delimiters: ", ']

      Bindings for scope # 100 (ENGINE_SCOPE):

      [event]: [javafx.event.ActionEvent[source=Button[id=idButton, styleClass=button]'Press me!']]

      Bindings for scope # 200 (GLOBAL_SCOPE):

      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']

      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]

      [location]: [file:demo_01.fxml]

      [resources]: [null]



      eval() invocation # 8:

      script: [demo_01.fxml embedded event - ActionEvent - line # 18 - LF entity (&#10;) forces linebreak in attribute value:
       (this is on a new line) these characters in attribute values need to be escaped: <, >, &, these if used as delimiters: ", ']

      Bindings for scope # 100 (ENGINE_SCOPE):

      [event]: [javafx.event.ActionEvent[source=Button[id=idButton, styleClass=button]'Press me!']]

      Bindings for scope # 200 (GLOBAL_SCOPE):

      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']

      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]

      [location]: [file:demo_01.fxml]

      [resources]: [null]



      eval() invocation # 9:

      script: [demo_01.fxml embedded event - MouseClicked - line # 17]

      Bindings for scope # 100 (ENGINE_SCOPE):

      [event]: [MouseEvent [source = Button[id=idButton, styleClass=button]'Press me!', target = Button[id=idButton, styleClass=button]'Press me!', eventType = MOUSE_CLICKED, consumed = false, x = -210.0, y = -137.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = null, point = Point3D [x = 0.0, y = 0.0, z = 0.0], distance = 1.0]]

      Bindings for scope # 200 (GLOBAL_SCOPE):

      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']

      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]

      [location]: [file:demo_01.fxml]

      [resources]: [null]




      ACTUAL -
      Gtk-Message: 13:11:24.484: Failed to load module "topmenu-gtk-module"

      Listing eval() invocation information (evalDataList):
      ScriptEngine: [rgf.scriptEngine.RgfPseudoScriptEngine@4fb64261]
      eval() invocation # 1:
      script: [demo_01_topscript.rpsl file - pseudo script in external file, starts with the filename

      ]
      Bindings for scope # 100 (ENGINE_SCOPE):
      [javax.script.filename]: [demo_01_topscript.rpsl]
      Bindings for scope # 200 (GLOBAL_SCOPE):
      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]
      [location]: [file:demo_01.fxml]
      [resources]: [null]

      eval() invocation # 2:
      script: [demo_01_middlescript.rpsl file - pseudo script in external file, starts with the filename

      ]
      Bindings for scope # 100 (ENGINE_SCOPE):
      [javax.script.filename]: [demo_01_middlescript.rpsl]
      Bindings for scope # 200 (GLOBAL_SCOPE):
      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']
      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]
      [location]: [file:demo_01.fxml]
      [resources]: [null]

      eval() invocation # 3:
      script: [demo_01.fxml embedded script rpsl - line # 25]
      Bindings for scope # 100 (ENGINE_SCOPE):
      [javax.script.filename]: [demo_01.fxml_at_line_25]
      Bindings for scope # 200 (GLOBAL_SCOPE):
      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']
      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]
      [location]: [file:demo_01.fxml]
      [resources]: [null]

      eval() invocation # 4:
      script: [demo_01_bottomscript.rpsl file - pseudo script in external file, starts with the filename

      ]
      Bindings for scope # 100 (ENGINE_SCOPE):
      [javax.script.filename]: [demo_01_bottomscript.rpsl]
      Bindings for scope # 200 (GLOBAL_SCOPE):
      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']
      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]
      [location]: [file:demo_01.fxml]
      [resources]: [null]

      eval() invocation # 5:
      script: [something (line # 29)
      in (line # 30)
      the (line # 31)
      news (line # 32) ]
      Bindings for scope # 100 (ENGINE_SCOPE):
      [javax.script.filename]: [demo_01.fxml_at_line_29]
      Bindings for scope # 200 (GLOBAL_SCOPE):
      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']
      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]
      [location]: [file:demo_01.fxml]
      [resources]: [null]

      eval() invocation # 6:
      script: [demo_01.fxml (line # 32):
      CDATA-section ("<![CDATA[") allows any characters including <, > and & !! (no need to escape
      these special characters; it is plain CDATA which does not get processed, just passed on
      including LF etc.
      Watch out that in the code there is no string that exactly matches the end tag
      for a CDATA-section (close-square-bracket+close-square-bracket+greater-character ]
      Bindings for scope # 100 (ENGINE_SCOPE):
      [javax.script.filename]: [demo_01.fxml_at_line_32]
      Bindings for scope # 200 (GLOBAL_SCOPE):
      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']
      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]
      [location]: [file:demo_01.fxml]
      [resources]: [null]

      eval() invocation # 7:
      script: [demo_01.fxml embedded event - ActionEvent - line # 18 - LF entity (&#10;) forces linebreak in attribute value:
       (this is on a new line) these characters in attribute values need to be escaped: <, >, &, these if used as delimiters: ", ']
      Bindings for scope # 100 (ENGINE_SCOPE):
      [event]: [javafx.event.ActionEvent[source=Button[id=idButton, styleClass=button]'Press me!']]
      [javax.script.argv]: [[Ljava.lang.Object;@42607a4f]
      [javax.script.filename]: [demo_01.fxml_defined_by_control_before_line_19]
      Bindings for scope # 200 (GLOBAL_SCOPE):
      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']
      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]
      [location]: [file:demo_01.fxml]
      [resources]: [null]

      eval() invocation # 8:
      script: [demo_01.fxml embedded event - ActionEvent - line # 18 - LF entity (&#10;) forces linebreak in attribute value:
       (this is on a new line) these characters in attribute values need to be escaped: <, >, &, these if used as delimiters: ", ']
      Bindings for scope # 100 (ENGINE_SCOPE):
      [event]: [javafx.event.ActionEvent[source=Button[id=idButton, styleClass=button]'Press me!']]
      [javax.script.argv]: [[Ljava.lang.Object;@782663d3]
      [javax.script.filename]: [demo_01.fxml_defined_by_control_before_line_19]
      Bindings for scope # 200 (GLOBAL_SCOPE):
      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']
      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]
      [location]: [file:demo_01.fxml]
      [resources]: [null]

      eval() invocation # 9:
      script: [demo_01.fxml embedded event - MouseClicked - line # 17]
      Bindings for scope # 100 (ENGINE_SCOPE):
      [event]: [MouseEvent [source = Button[id=idButton, styleClass=button]'Press me!', target = Button[id=idButton, styleClass=button]'Press me!', eventType = MOUSE_CLICKED, consumed = false, x = -210.0, y = -137.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = null, point = Point3D [x = 0.0, y = 0.0, z = 0.0], distance = 1.0]]
      [javax.script.argv]: [[Ljava.lang.Object;@31f924f5]
      [javax.script.filename]: [demo_01.fxml_defined_by_control_before_line_19]
      Bindings for scope # 200 (GLOBAL_SCOPE):
      [idButton]: [Button[id=idButton, styleClass=button]'Press me!']
      [idRoot]: [AnchorPane[id=idRoot, styleClass=root]]
      [location]: [file:demo_01.fxml]
      [resources]: [null]



      ---------- BEGIN SOURCE ----------
      test case consists of multiple files, such that a single source code file does not yield the above output.

      Packed up the source code and compiled version in a zip-archive with readme.txt for easier testing and analyzes. Please advise how to submit.
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      There is no workaround possible, unfortunately.

      FREQUENCY : always


            aghaisas Ajit Ghaisas
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: