[1] reports a bug related to FXMLLoader for FXML controllers being implemented 
in any one of the
javax.script languages: the invoked scripts are not supplied the standardized 
entries
"javax.script.filename" (a string denoting the filename that hosts the script) 
and
"javax.script.argv" (an Object[] of positional arguments in the case of event 
scripts) in their
engine scope Bindings.

The FXML file below demonstrates how scripts can be defined (using some 
hypothetical Java script
language named "rpsl"). In the case of a runtime error (or for debugging 
purposes) the script
engines therefore cannot supply the filename that hosts the script that caused 
a runtime error (or
which gets currently debugged).

I have prepared a fix for [1], but would like to communicate what it does and 
its reasonings first
(making it easy for script programmers to locate erroneous scripts and to fetch 
the event argument
as a script argument in event scripts).

---

To illustrate the problem at hand the file "demo_01.fxml" below has been 
created, which among other
things defines:

  * line # 6: process instruction defines some Java script language named 
"rpsl" to be used for
    executing the scripts of the fxml file
  * line # 11: defines an empty "fx:script" element, denoting in its "source" 
attribute the external
    script file named "demo_01_topscript.rpsl" (note: the Button element with 
the fx:id "idButton"
    is not yet defined at that point in time)
  * line # 15: defines a Button element with the fx:id "idButton"
  * line # 17: defines a script (PCDATA) for the "onMouseClicked" event 
attribute for the Button
    element (fx:id "idButton")
  * line # 18 : defines a script (PCDATA) for the "onButton" event attribute 
for the Button element
    (fx:id "idButton")
  * line # 21: defines an empty "fx:script" element, denoting in its "source" 
attribute the external
    script file named "demo_01_middlescript.rpsl"
  * line # 27: defines an empty "fx:script" element, denoting in its "source" 
attribute the external
    script file named "demo_01_bottomscript.rpsl"
  * line # 29: defines an  "fx:script" element with contained PCDATA script 
code (note: ends in line
    # 32)
  * line # 32: defines an  "fx:script" element with contained CDATA script code

Currently,

  * whatever script gets run (lines # 11, #17, #18, #21, #27, #29, #32), the 
name of the file
    hosting the script is unknown, because of the missing entry 
"javax.script.filename" in the
    engine scope Bindings,

  * the event scripts (lines # 17, #18) cannot fetch the "event" argument as an 
argument, because of
    the missing entry "javax.script.argv"

The proposed fix does the following:

  * scripts stored in external files (lines #11, #21, # 27): the value of the 
"source" attribute
    gets stored with the key "javax.script.filename" in the engine scope 
Bindings, yielding e.g.:

      o line # 11:  ...path-to..."demo_01_topscript.rpsl"
      o line # 21: ...path-to..."demo_01_middlescript.rpsl"
      o line #27: ...path-to..."demo_01_bottomscript.rpsl"

  * scripts contained in "fx:script" elements (lines #29, # 32): the FXML 
location path is used as
    the hosting filename with the string "-script_starting_at_line_#" appended 
and stored with the
    key "javax.script.filename" in the engine scope Bindings, yielding e.g.:

      o line # 29: ...path-to... "demo_01.fxml-script_starting_at_line_29"
      o line # 32: ...path-to... "demo_01.fxml-script_starting_at_line_32"

      o notes:
          + the dash ('-') following the FXML filename is meant to make 
spotting/parsing easier
          + the appended text should be self-describing, allowing the 
programmer to immediately spot
            the position of the script in question


  * event scripts (lines #17, #18): 
      o the single "event" argument is stored in the local scope Bindings, and 
now in addition gets
        supplied as the single argument in the single-element Object array 
stored with
        "javax.script.argv" in the engine scope Bindings

      o the FXML location path is used as the hosting filename with the string
        "-${eventAttributeName}_attribute_in_element_ending_at_line_#" and 
stored with the key
        "javax.script.filename" in the engine scope Bindings, yielding e.g.:

          + line #17: ...path-to... 
"demo_01.fxml-onAction_attribute_in_element_ending_at_line_19"
          + line #19: ...path-to... 
"demo_01.fxml-onMouseClicked_attribute_in_element_ending_at_line_19"

      o notes:
          + the dash ('-') following the FXML filename is meant to make 
spotting/parsing easier
          + the appended text should be self-describing, allowing the 
programmer to closely spot the
            position of the event script in question
          + using a minimal edit approach, it is not possible for the suggested 
fix to fetch the
            starting line (and column) number of the element for which the 
event attributes get
            processed (nor the exact position of the event attributes for that 
matter) in FXMLLoader
            therefore hinting the programmer at 
"_xxx_attribute_in_element_ending_at_line_#". This
            is regarded to be sufficient and will allow the programmer to 
immediately locate the
            position in the FXML file of the script that may have caused a 
runtime exception.


"demo_01.fxml":

        <?xml version="1.0" encoding="UTF-8"?>
       
        <?import javafx.scene.control.Button?>
        <?import javafx.scene.layout.AnchorPane?>
       
        <!-- line #  6 --> <?language rpsl?>
       
        <AnchorPane fx:id="idRoot" prefHeight="240.0" prefWidth="480.0"
                    xmlns:fx="http://javafx.com/fxml/1";>
       
        <!-- line # 11 -->     <fx:script source="demo_01_topscript.rpsl" />
       
                               <children>
       
        <!-- line # 15 -->         <Button fx:id="idButton" text="Press me!"
                                           layoutX="210.0" layoutY="137.0"
                                           onMouseClicked="demo_01.fxml 
embedded event -
MouseClicked - line # 17 (PCDATA)"
                           onAction="demo_01.fxml embedded event - ActionEvent 
- line # 18 - LF
entity (&amp;#10;) forces linebreak in attribute value: &#10;
        (this is on a new line) these characters in attribute values need to be 
escaped: &lt;, &gt;,
&amp;, these if used as delimiters: &quot;, &apos; (PCDATA)" />
       
        <!-- line # 21 -->         <fx:script 
source="demo_01_middlescript.rpsl" />
       
                               </children>
       
        <!-- line # 25 -->     <fx:script>demo_01.fxml embedded script rpsl - 
line # 25</fx:script>
       
        <!-- line # 27 -->     <fx:script source="demo_01_bottomscript.rpsl" />
       
        <!-- line # 29 --> <fx:script>something (line # 29)(PCDATA)
            in   a=&amp;b  (line # 30)
            the  b&gt;1   (line # 31)
            news c&lt;2   (line # 32) </fx:script>   
<fx:script><![CDATA[demo_01.fxml (line # 32):
        CDATA-section ("<![CDATA[") allows any characters including <, > and & 
!! (no need to escape
(line # 33)
        these special characters; it is plain CDATA which does not get 
processed, just passed on    
(line # 34)
        including LF etc.                                                       
                    
(line # 35)
                in   a=&b  (line # 36)
            the  b>1   (line # 37)
            news c<2   (line # 38)
        Watch out that in the code there is no string that exactly matches the 
end tag              
(line # 39)
        for a CDATA-section 
(close-square-bracket+close-square-bracket+greater-character            
(line # 40) ]]></fx:script>
       
        </AnchorPane>


Any comments, questions, suggestions?

---rony

[1] "JDK-8234959 FXMLLoader does not populate ENGINE_SCOPE Bindings with 
FILENAME and ARGV": 
<https://bugs.openjdk.java.net/browse/JI-9062887>


Reply via email to