< prev index next >

modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java

Print this page

  46 import java.util.LinkedList;
  47 import java.util.List;
  48 import java.util.Map;
  49 import java.util.ResourceBundle;
  50 import java.util.Set;
  51 import java.util.regex.Pattern;
  52 
  53 import javafx.beans.DefaultProperty;
  54 import javafx.beans.InvalidationListener;
  55 import javafx.beans.property.Property;
  56 import javafx.beans.value.ChangeListener;
  57 import javafx.beans.value.ObservableValue;
  58 import javafx.collections.*;
  59 import javafx.event.Event;
  60 import javafx.event.EventHandler;
  61 import javafx.util.Builder;
  62 import javafx.util.BuilderFactory;
  63 import javafx.util.Callback;
  64 
  65 import javax.script.Bindings;


  66 import javax.script.ScriptContext;
  67 import javax.script.ScriptEngine;
  68 import javax.script.ScriptEngineManager;
  69 import javax.script.ScriptException;
  70 import javax.script.SimpleBindings;
  71 import javax.xml.stream.XMLInputFactory;
  72 import javax.xml.stream.XMLStreamConstants;
  73 import javax.xml.stream.XMLStreamException;
  74 import javax.xml.stream.XMLStreamReader;
  75 import javax.xml.stream.util.StreamReaderDelegate;
  76 
  77 import com.sun.javafx.beans.IDProperty;
  78 import com.sun.javafx.fxml.BeanAdapter;
  79 import com.sun.javafx.fxml.ParseTraceElement;
  80 import com.sun.javafx.fxml.PropertyNotFoundException;
  81 import com.sun.javafx.fxml.expression.Expression;
  82 import com.sun.javafx.fxml.expression.ExpressionValue;
  83 import com.sun.javafx.fxml.expression.KeyPath;
  84 import static com.sun.javafx.FXPermissions.MODIFY_FXML_CLASS_LOADER_PERMISSION;
  85 import com.sun.javafx.fxml.FXMLLoaderHelper;

1541                 }
1542 
1543                 if (engine == null) {
1544                     throw constructLoadException("Unable to locate scripting engine for"
1545                         + " extension " + extension + ".");
1546                 }
1547 
1548                 try {
1549                     URL location;
1550                     if (source.charAt(0) == '/') {
1551                         // FIXME: JIGSAW -- use Class.getResourceAsStream if resource is in a module
1552                         location = cl.getResource(source.substring(1));
1553                     } else {
1554                         if (FXMLLoader.this.location == null) {
1555                             throw constructLoadException("Base location is undefined.");
1556                         }
1557 
1558                         location = new URL(FXMLLoader.this.location, source);
1559                     }
1560                     Bindings engineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
1561                     engineBindings.put(engine.FILENAME, location.getPath());

1562 
1563                     InputStreamReader scriptReader = null;

1564                     try {
1565                         scriptReader = new InputStreamReader(location.openStream(), charset);
1566                         engine.eval(scriptReader);
1567                     } catch(ScriptException exception) {
1568                         exception.printStackTrace();










1569                     } finally {
1570                         if (scriptReader != null) {
1571                             scriptReader.close();
1572                         }
1573                     }
1574                 } catch (IOException exception) {
1575                     throw constructLoadException(exception);






















1576                 }
1577             }
1578         }
1579 
1580         @Override
1581         public void processEndElement() throws IOException {
1582             super.processEndElement();
1583 
1584             if (value != null && !staticLoad) {
1585                 // Evaluate the script

1586                 try {
1587                     Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
1588                     engineBindings.put(scriptEngine.FILENAME, location.getPath() + "-script_starting_at_line_"
1589                                        + (getLineNumber() - (int) ((String) value).codePoints().filter(c -> c == '\n').count()));
1590                     scriptEngine.eval((String)value);

















1591                 } catch (ScriptException exception) {
1592                     System.err.println(exception.getMessage());
1593                 }
1594             }
1595         }
1596 
1597         @Override
1598         public void processCharacters() throws LoadException {
1599             if (source != null) {
1600                 throw constructLoadException("Script source already specified.");
1601             }
1602 
1603             if (scriptEngine == null && !staticLoad) {
1604                 throw constructLoadException("Page language not specified.");
1605             }
1606 
1607             updateValue(xmlStreamReader.getText());
1608         }
1609 
1610         @Override
1611         public void processAttribute(String prefix, String localName, String value)
1612             throws IOException {

1664 
1665     // Event handler that delegates to a method defined by the controller object
1666     private static class ControllerMethodEventHandler<T extends Event> implements EventHandler<T> {
1667         private final MethodHandler handler;
1668 
1669         public ControllerMethodEventHandler(MethodHandler handler) {
1670             this.handler = handler;
1671         }
1672 
1673         @Override
1674         public void handle(T event) {
1675             handler.invoke(event);
1676         }
1677     }
1678 
1679     // Event handler implemented in script code
1680     private static class ScriptEventHandler implements EventHandler<Event> {
1681         public final String script;
1682         public final ScriptEngine scriptEngine;
1683         public final String filename;


1684 
1685         public ScriptEventHandler(String script, ScriptEngine scriptEngine, String filename) {
1686             this.script = script;
1687             this.scriptEngine = scriptEngine;
1688             this.filename = filename;











1689         }
1690 
1691         @Override
1692         public void handle(Event event) {
1693             // Don't pollute the page namespace with values defined in the script
1694             Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
1695             Bindings localBindings = scriptEngine.createBindings();
1696             localBindings.putAll(engineBindings);
1697             localBindings.put(EVENT_KEY, event);
1698             localBindings.put(scriptEngine.ARGV, new Object[]{event});
1699             localBindings.put(scriptEngine.FILENAME, filename);
1700             // Execute the script
1701             try {
1702                 scriptEngine.eval(script, localBindings);
1703             } catch (ScriptException exception){
1704                 throw new RuntimeException(exception);




1705             }
1706         }
1707     }
1708 
1709     // Observable list change listener
1710     private static class ObservableListChangeAdapter implements ListChangeListener {
1711         private final MethodHandler handler;
1712 
1713         public ObservableListChangeAdapter(MethodHandler handler) {
1714             this.handler = handler;
1715         }
1716 
1717         @Override
1718         @SuppressWarnings("unchecked")
1719         public void onChanged(Change change) {
1720             if (handler != null) {
1721                 handler.invoke(change);
1722             }
1723         }
1724     }

1802 
1803     private Object root = null;
1804     private Object controller = null;
1805 
1806     private BuilderFactory builderFactory;
1807     private Callback<Class<?>, Object> controllerFactory;
1808     private Charset charset;
1809 
1810     private final LinkedList<FXMLLoader> loaders;
1811 
1812     private ClassLoader classLoader = null;
1813     private boolean staticLoad = false;
1814     private LoadListener loadListener = null;
1815 
1816     private FXMLLoader parentLoader;
1817 
1818     private XMLStreamReader xmlStreamReader = null;
1819     private Element current = null;
1820 
1821     private ScriptEngine scriptEngine = null;

1822 
1823     private List<String> packages = new LinkedList<String>();
1824     private Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
1825 
1826     private ScriptEngineManager scriptEngineManager = null;
1827 
1828     private static ClassLoader defaultClassLoader = null;
1829 
1830     private static final Pattern extraneousWhitespacePattern = Pattern.compile("\\s+");
1831 
1832     private static BuilderFactory DEFAULT_BUILDER_FACTORY = new JavaFXBuilderFactory();
1833 
1834     /**
1835      * The character set used when character set is not explicitly specified.
1836      */
1837     public static final String DEFAULT_CHARSET_NAME = "UTF-8";
1838 
1839     /**
1840      * The tag name of language processing instruction.
1841      */
1842     public static final String LANGUAGE_PROCESSING_INSTRUCTION = "language";
1843     /**
1844      * The tag name of import processing instruction.
1845      */
1846     public static final String IMPORT_PROCESSING_INSTRUCTION = "import";
1847 






1848     /**
1849      * Prefix of 'fx' namespace.
1850      */
1851     public static final String FX_NAMESPACE_PREFIX = "fx";
1852     /**
1853      * The name of fx:controller attribute of a root.
1854      */
1855     public static final String FX_CONTROLLER_ATTRIBUTE = "controller";
1856     /**
1857      * The name of fx:id attribute.
1858      */
1859     public static final String FX_ID_ATTRIBUTE = "id";
1860     /**
1861      * The name of fx:value attribute.
1862      */
1863     public static final String FX_VALUE_ATTRIBUTE = "value";
1864     /**
1865      * The tag name of 'fx:constant'.
1866      * @since JavaFX 2.2
1867      */

2661      */
2662     ParseTraceElement[] getParseTrace() {
2663         ParseTraceElement[] parseTrace = new ParseTraceElement[loaders.size()];
2664 
2665         int i = 0;
2666         for (FXMLLoader loader : loaders) {
2667             parseTrace[i++] = new ParseTraceElement(loader.location, (loader.current != null) ?
2668                 loader.getLineNumber() : -1);
2669         }
2670 
2671         return parseTrace;
2672     }
2673 
2674     private void processProcessingInstruction() throws LoadException {
2675         String piTarget = xmlStreamReader.getPITarget().trim();
2676 
2677         if (piTarget.equals(LANGUAGE_PROCESSING_INSTRUCTION)) {
2678             processLanguage();
2679         } else if (piTarget.equals(IMPORT_PROCESSING_INSTRUCTION)) {
2680             processImport();




2681         }
2682     }
2683 
2684     private void processLanguage() throws LoadException {
2685         if (scriptEngine != null) {
2686             throw constructLoadException("Page language already set.");
2687         }
2688 
2689         String language = xmlStreamReader.getPIData();
2690 
2691         if (loadListener != null) {
2692             loadListener.readLanguageProcessingInstruction(language);
2693         }
2694 
2695         if (!staticLoad) {
2696             ScriptEngineManager scriptEngineManager = getScriptEngineManager();
2697             scriptEngine = scriptEngineManager.getEngineByName(language);
2698         }
2699     }
2700 

  46 import java.util.LinkedList;
  47 import java.util.List;
  48 import java.util.Map;
  49 import java.util.ResourceBundle;
  50 import java.util.Set;
  51 import java.util.regex.Pattern;
  52 
  53 import javafx.beans.DefaultProperty;
  54 import javafx.beans.InvalidationListener;
  55 import javafx.beans.property.Property;
  56 import javafx.beans.value.ChangeListener;
  57 import javafx.beans.value.ObservableValue;
  58 import javafx.collections.*;
  59 import javafx.event.Event;
  60 import javafx.event.EventHandler;
  61 import javafx.util.Builder;
  62 import javafx.util.BuilderFactory;
  63 import javafx.util.Callback;
  64 
  65 import javax.script.Bindings;
  66 import javax.script.Compilable;
  67 import javax.script.CompiledScript;
  68 import javax.script.ScriptContext;
  69 import javax.script.ScriptEngine;
  70 import javax.script.ScriptEngineManager;
  71 import javax.script.ScriptException;
  72 import javax.script.SimpleBindings;
  73 import javax.xml.stream.XMLInputFactory;
  74 import javax.xml.stream.XMLStreamConstants;
  75 import javax.xml.stream.XMLStreamException;
  76 import javax.xml.stream.XMLStreamReader;
  77 import javax.xml.stream.util.StreamReaderDelegate;
  78 
  79 import com.sun.javafx.beans.IDProperty;
  80 import com.sun.javafx.fxml.BeanAdapter;
  81 import com.sun.javafx.fxml.ParseTraceElement;
  82 import com.sun.javafx.fxml.PropertyNotFoundException;
  83 import com.sun.javafx.fxml.expression.Expression;
  84 import com.sun.javafx.fxml.expression.ExpressionValue;
  85 import com.sun.javafx.fxml.expression.KeyPath;
  86 import static com.sun.javafx.FXPermissions.MODIFY_FXML_CLASS_LOADER_PERMISSION;
  87 import com.sun.javafx.fxml.FXMLLoaderHelper;

1543                 }
1544 
1545                 if (engine == null) {
1546                     throw constructLoadException("Unable to locate scripting engine for"
1547                         + " extension " + extension + ".");
1548                 }
1549 
1550                 try {
1551                     URL location;
1552                     if (source.charAt(0) == '/') {
1553                         // FIXME: JIGSAW -- use Class.getResourceAsStream if resource is in a module
1554                         location = cl.getResource(source.substring(1));
1555                     } else {
1556                         if (FXMLLoader.this.location == null) {
1557                             throw constructLoadException("Base location is undefined.");
1558                         }
1559 
1560                         location = new URL(FXMLLoader.this.location, source);
1561                     }
1562                     Bindings engineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
1563                     String filename = location.getPath();
1564                     engineBindings.put(engine.FILENAME, filename);
1565 
1566                     InputStreamReader scriptReader = null;
1567                     String script=null;
1568                     try {
1569                         scriptReader = new InputStreamReader(location.openStream(), charset);
1570                         StringBuilder sb = new StringBuilder();
1571                         final int bufSize = 4096;
1572                         char[] charBuffer = new char[bufSize];
1573                         int n;
1574                         do {
1575                             n = scriptReader.read(charBuffer,0,bufSize);
1576                             if (n > 0) {
1577                                 sb.append(new String(charBuffer,0,n));
1578                           }
1579                         } while (n > -1);
1580                         script = sb.toString();
1581                     } catch (IOException exception) {
1582                         throw constructLoadException(exception);
1583                     } finally {
1584                         if (scriptReader != null) {
1585                             scriptReader.close();
1586                         }
1587                     }
1588                     try {
1589                         if (engine instanceof Compilable && compileScript) {
1590                             CompiledScript compiledScript = null;
1591                             try {
1592                                 compiledScript=((Compilable) engine).compile(script);
1593                             } catch (ScriptException compileExc) {
1594                                 Logging.getJavaFXLogger().warning(filename + ": compiling caused \"" + compileExc +
1595                                     "\", falling back to evaluating script in uncompiled mode");
1596                             }
1597                             if (compiledScript != null) {
1598                                 compiledScript.eval();
1599                             } else { // fallback to uncompiled mode
1600                                 engine.eval(script);
1601                             }
1602                         } else {
1603                             engine.eval(script);
1604                         }
1605                     } catch (ScriptException exception) {
1606                         System.err.println(filename + ": caused ScriptException");
1607                         exception.printStackTrace();
1608                     }
1609                 }
1610                 catch (IOException exception) {
1611                   throw constructLoadException(exception);
1612                 }
1613             }
1614         }
1615 
1616         @Override
1617         public void processEndElement() throws IOException {
1618             super.processEndElement();
1619 
1620             if (value != null && !staticLoad) {
1621                 // Evaluate the script
1622                 String filename = null;
1623                 try {
1624                     Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
1625                     String script = (String) value;
1626                     filename = location.getPath() + "-script_starting_at_line_"
1627                                        + (getLineNumber() - (int) script.codePoints().filter(c -> c == '\n').count());
1628                     engineBindings.put(scriptEngine.FILENAME, filename);
1629                     if (scriptEngine instanceof Compilable && compileScript) {
1630                         CompiledScript compiledScript = null;
1631                         try {
1632                             compiledScript=((Compilable) scriptEngine).compile(script);
1633                         } catch (ScriptException compileExc) {
1634                             Logging.getJavaFXLogger().warning(filename + ": compiling caused \"" + compileExc +
1635                                 "\", falling back to evaluating script in uncompiled mode");
1636                         }
1637                         if (compiledScript != null) {
1638                             compiledScript.eval();
1639                         } else { // fallback to uncompiled mode
1640                             scriptEngine.eval(script);
1641                         }
1642                     } else {
1643                         scriptEngine.eval(script);
1644                     }
1645                 } catch (ScriptException exception) {
1646                     System.err.println(filename + ": caused ScriptException\n" + exception.getMessage());
1647                 }
1648             }
1649         }
1650 
1651         @Override
1652         public void processCharacters() throws LoadException {
1653             if (source != null) {
1654                 throw constructLoadException("Script source already specified.");
1655             }
1656 
1657             if (scriptEngine == null && !staticLoad) {
1658                 throw constructLoadException("Page language not specified.");
1659             }
1660 
1661             updateValue(xmlStreamReader.getText());
1662         }
1663 
1664         @Override
1665         public void processAttribute(String prefix, String localName, String value)
1666             throws IOException {

1718 
1719     // Event handler that delegates to a method defined by the controller object
1720     private static class ControllerMethodEventHandler<T extends Event> implements EventHandler<T> {
1721         private final MethodHandler handler;
1722 
1723         public ControllerMethodEventHandler(MethodHandler handler) {
1724             this.handler = handler;
1725         }
1726 
1727         @Override
1728         public void handle(T event) {
1729             handler.invoke(event);
1730         }
1731     }
1732 
1733     // Event handler implemented in script code
1734     private static class ScriptEventHandler implements EventHandler<Event> {
1735         public final String script;
1736         public final ScriptEngine scriptEngine;
1737         public final String filename;
1738         public CompiledScript compiledScript;
1739         public boolean isCompiled=false;
1740 
1741         public ScriptEventHandler(String script, ScriptEngine scriptEngine, String filename) {
1742             this.script = script;
1743             this.scriptEngine = scriptEngine;
1744             this.filename = filename;
1745             if (scriptEngine instanceof Compilable  && compileScript) {
1746                 try {
1747                     // supply the filename to the scriptEngine engine scope Bindings in case it is needed for compilation
1748                     scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE).put(scriptEngine.FILENAME, filename);
1749                     this.compiledScript = ((Compilable) scriptEngine).compile(script);
1750                     this.isCompiled = true;
1751                 } catch (ScriptException compileExc) {
1752                     Logging.getJavaFXLogger().warning(filename + ": compiling caused \"" + compileExc +
1753                         "\", falling back to evaluating script in uncompiled mode");
1754                 }
1755             }
1756         }
1757 
1758         @Override
1759         public void handle(Event event) {
1760             // Don't pollute the page namespace with values defined in the script
1761             Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
1762             Bindings localBindings = scriptEngine.createBindings();
1763             localBindings.putAll(engineBindings);
1764             localBindings.put(EVENT_KEY, event);
1765             localBindings.put(scriptEngine.ARGV, new Object[]{event});
1766             localBindings.put(scriptEngine.FILENAME, filename);
1767             // Execute the script
1768             try {
1769                 if (isCompiled) {
1770                    compiledScript.eval(localBindings);
1771                 } else {
1772                    scriptEngine.eval(script, localBindings);
1773                 }
1774             } catch (ScriptException exception) {
1775                 throw new RuntimeException(filename + ": caused ScriptException", exception);
1776             }
1777         }
1778     }
1779 
1780     // Observable list change listener
1781     private static class ObservableListChangeAdapter implements ListChangeListener {
1782         private final MethodHandler handler;
1783 
1784         public ObservableListChangeAdapter(MethodHandler handler) {
1785             this.handler = handler;
1786         }
1787 
1788         @Override
1789         @SuppressWarnings("unchecked")
1790         public void onChanged(Change change) {
1791             if (handler != null) {
1792                 handler.invoke(change);
1793             }
1794         }
1795     }

1873 
1874     private Object root = null;
1875     private Object controller = null;
1876 
1877     private BuilderFactory builderFactory;
1878     private Callback<Class<?>, Object> controllerFactory;
1879     private Charset charset;
1880 
1881     private final LinkedList<FXMLLoader> loaders;
1882 
1883     private ClassLoader classLoader = null;
1884     private boolean staticLoad = false;
1885     private LoadListener loadListener = null;
1886 
1887     private FXMLLoader parentLoader;
1888 
1889     private XMLStreamReader xmlStreamReader = null;
1890     private Element current = null;
1891 
1892     private ScriptEngine scriptEngine = null;
1893     private static boolean compileScript = true;
1894 
1895     private List<String> packages = new LinkedList<String>();
1896     private Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
1897 
1898     private ScriptEngineManager scriptEngineManager = null;
1899 
1900     private static ClassLoader defaultClassLoader = null;
1901 
1902     private static final Pattern extraneousWhitespacePattern = Pattern.compile("\\s+");
1903 
1904     private static BuilderFactory DEFAULT_BUILDER_FACTORY = new JavaFXBuilderFactory();
1905 
1906     /**
1907      * The character set used when character set is not explicitly specified.
1908      */
1909     public static final String DEFAULT_CHARSET_NAME = "UTF-8";
1910 
1911     /**
1912      * The tag name of language processing instruction.
1913      */
1914     public static final String LANGUAGE_PROCESSING_INSTRUCTION = "language";
1915     /**
1916      * The tag name of import processing instruction.
1917      */
1918     public static final String IMPORT_PROCESSING_INSTRUCTION = "import";
1919 
1920     /**
1921      * The tag name of the compile processing instruction.
1922      * @since 15
1923      */
1924     public static final String COMPILE_PROCESSING_INSTRUCTION = "compile";
1925 
1926     /**
1927      * Prefix of 'fx' namespace.
1928      */
1929     public static final String FX_NAMESPACE_PREFIX = "fx";
1930     /**
1931      * The name of fx:controller attribute of a root.
1932      */
1933     public static final String FX_CONTROLLER_ATTRIBUTE = "controller";
1934     /**
1935      * The name of fx:id attribute.
1936      */
1937     public static final String FX_ID_ATTRIBUTE = "id";
1938     /**
1939      * The name of fx:value attribute.
1940      */
1941     public static final String FX_VALUE_ATTRIBUTE = "value";
1942     /**
1943      * The tag name of 'fx:constant'.
1944      * @since JavaFX 2.2
1945      */

2739      */
2740     ParseTraceElement[] getParseTrace() {
2741         ParseTraceElement[] parseTrace = new ParseTraceElement[loaders.size()];
2742 
2743         int i = 0;
2744         for (FXMLLoader loader : loaders) {
2745             parseTrace[i++] = new ParseTraceElement(loader.location, (loader.current != null) ?
2746                 loader.getLineNumber() : -1);
2747         }
2748 
2749         return parseTrace;
2750     }
2751 
2752     private void processProcessingInstruction() throws LoadException {
2753         String piTarget = xmlStreamReader.getPITarget().trim();
2754 
2755         if (piTarget.equals(LANGUAGE_PROCESSING_INSTRUCTION)) {
2756             processLanguage();
2757         } else if (piTarget.equals(IMPORT_PROCESSING_INSTRUCTION)) {
2758             processImport();
2759         } else if (piTarget.equals(COMPILE_PROCESSING_INSTRUCTION)) {
2760             String strCompile=xmlStreamReader.getPIData().trim();
2761             // if PIData() is empty string then default to true, otherwise use Boolean.parseBoolean(string) to determine the boolean value
2762             compileScript = (strCompile.length()==0 ? true : Boolean.parseBoolean(strCompile));
2763         }
2764     }
2765 
2766     private void processLanguage() throws LoadException {
2767         if (scriptEngine != null) {
2768             throw constructLoadException("Page language already set.");
2769         }
2770 
2771         String language = xmlStreamReader.getPIData();
2772 
2773         if (loadListener != null) {
2774             loadListener.readLanguageProcessingInstruction(language);
2775         }
2776 
2777         if (!staticLoad) {
2778             ScriptEngineManager scriptEngineManager = getScriptEngineManager();
2779             scriptEngine = scriptEngineManager.getEngineByName(language);
2780         }
2781     }
2782 
< prev index next >