1 /* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.oracle.javafx.scenebuilder.kit.fxom; 33 34 import com.oracle.javafx.scenebuilder.kit.util.Deprecation; 35 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName; 36 import com.sun.javafx.fxml.LoadListener; 37 import java.io.ByteArrayInputStream; 38 import java.io.IOException; 39 import java.io.InputStream; 40 import java.nio.charset.Charset; 41 import javafx.fxml.FXMLLoader; 42 43 44 /** 45 * 46 * 47 */ 48 class FXOMLoader implements LoadListener { 49 50 private final FXOMDocument document; 51 private TransientNode currentTransientNode; 52 private GlueCursor glueCursor; 53 54 /* 55 * FXOMLoader 56 */ 57 58 public FXOMLoader(FXOMDocument document) { 59 assert document != null; 60 assert document.getGlue().getRootElement() != null; 61 this.document = document; 62 } 63 64 public void load(String fxmlText) throws java.io.IOException { 65 assert fxmlText != null; 66 67 final ClassLoader classLoader; 68 if (document.getClassLoader() != null) { 69 classLoader = document.getClassLoader(); 70 } else { 71 classLoader = FXMLLoader.getDefaultClassLoader(); 72 } 73 74 FXMLLoader fxmlLoader = new FXMLLoader(); 75 76 fxmlLoader.setLocation(document.getLocation()); 77 fxmlLoader.setResources(new ResourceKeyCollector(document.getResources())); 78 fxmlLoader.setClassLoader(new TransientClassLoader(classLoader)); 79 fxmlLoader.setBuilderFactory(new FXOMBuilderFactory(classLoader)); 80 Deprecation.setStaticLoad(fxmlLoader, true); 81 Deprecation.setLoadListener(fxmlLoader, this); 82 83 final Charset utf8 = Charset.forName("UTF-8"); 84 try (final InputStream is = new ByteArrayInputStream(fxmlText.getBytes(utf8))) { 85 glueCursor = new GlueCursor(document.getGlue()); 86 currentTransientNode = null; 87 assert is.markSupported(); 88 is.reset(); 89 document.setSceneGraphRoot(fxmlLoader.load(is)); 90 // assert document.isConsistent(); // TODO Eric - Returns true on Preview 91 } catch(RuntimeException | IOException x) { 92 throw new IOException(x); 93 } 94 } 95 96 public FXOMDocument getDocument() { 97 return document; 98 } 99 100 101 /* 102 * LoadListener 103 */ 104 105 @Override 106 public void readImportProcessingInstruction(String data) { 107 } 108 109 @Override 110 public void readLanguageProcessingInstruction(String data) { 111 } 112 113 @Override 114 public void readComment(String string) { 115 } 116 117 @Override 118 public void beginInstanceDeclarationElement(Class<?> declaredClass) { 119 assert declaredClass != null; 120 assert glueCursor.getCurrentElement().getTagName().equals(PropertyName.makeClassFullName(declaredClass)) || 121 glueCursor.getCurrentElement().getTagName().equals(declaredClass.getCanonicalName()); 122 123 final TransientObject transientInstance 124 = new TransientObject(currentTransientNode, 125 declaredClass, glueCursor.getCurrentElement()); 126 127 currentTransientNode = transientInstance; 128 glueCursor.moveToNextElement(); 129 } 130 131 @Override 132 public void beginUnknownTypeElement(String unknownClassName) { 133 assert unknownClassName != null; 134 assert glueCursor.getCurrentElement().getTagName().equals(unknownClassName); 135 136 final TransientObject transientInstance 137 = new TransientObject(currentTransientNode, 138 unknownClassName, glueCursor.getCurrentElement()); 139 140 currentTransientNode = transientInstance; 141 glueCursor.moveToNextElement(); 142 } 143 144 @Override 145 public void beginIncludeElement() { 146 assert glueCursor.getCurrentElement().getTagName().equals("fx:include"); 147 148 final TransientIntrinsic transientIntrinsic 149 = new TransientIntrinsic(currentTransientNode, 150 FXOMIntrinsic.Type.FX_INCLUDE, glueCursor.getCurrentElement()); 151 152 currentTransientNode = transientIntrinsic; 153 glueCursor.moveToNextElement(); 154 } 155 156 @Override 157 public void beginReferenceElement() { 158 assert glueCursor.getCurrentElement().getTagName().equals("fx:reference"); 159 160 final TransientIntrinsic transientIntrinsic 161 = new TransientIntrinsic(currentTransientNode, 162 FXOMIntrinsic.Type.FX_REFERENCE, glueCursor.getCurrentElement()); 163 164 currentTransientNode = transientIntrinsic; 165 glueCursor.moveToNextElement(); 166 } 167 168 @Override 169 public void beginCopyElement() { 170 assert glueCursor.getCurrentElement().getTagName().equals("fx:copy"); 171 172 final TransientIntrinsic transientIntrinsic 173 = new TransientIntrinsic(currentTransientNode, 174 FXOMIntrinsic.Type.FX_COPY, glueCursor.getCurrentElement()); 175 176 currentTransientNode = transientIntrinsic; 177 glueCursor.moveToNextElement(); 178 } 179 180 @Override 181 public void beginRootElement() { 182 assert glueCursor.getCurrentElement().getTagName().equals("fx:root"); 183 184 final TransientObject transientInstance 185 = new TransientObject(currentTransientNode, 186 glueCursor.getCurrentElement()); 187 188 currentTransientNode = transientInstance; 189 glueCursor.moveToNextElement(); 190 } 191 192 @Override 193 public void beginPropertyElement(String name, Class<?> staticClass) { 194 assert name != null; 195 196 final TransientProperty transientProperty 197 = new TransientProperty(currentTransientNode, 198 new PropertyName(name, staticClass), 199 glueCursor.getCurrentElement()); 200 201 currentTransientNode = transientProperty; 202 glueCursor.moveToNextElement(); 203 } 204 205 @Override 206 public void beginUnknownStaticPropertyElement(String string) { 207 currentTransientNode = new TransientIgnored(currentTransientNode); 208 glueCursor.moveToNextElement(); 209 } 210 211 @Override 212 public void beginScriptElement() { 213 currentTransientNode = new TransientIgnored(currentTransientNode); 214 glueCursor.moveToNextElement(); 215 } 216 217 @Override 218 public void beginDefineElement() { 219 currentTransientNode = new TransientIgnored(currentTransientNode); 220 glueCursor.moveToNextElement(); 221 } 222 223 @Override 224 public void readInternalAttribute(String attrName, String attrValue) { 225 assert currentTransientNode instanceof TransientObject || 226 currentTransientNode instanceof TransientIntrinsic; 227 228 if (attrName.equals("type")) { 229 assert currentTransientNode instanceof TransientObject; 230 final TransientObject transientObject = (TransientObject) currentTransientNode; 231 transientObject.setFxRootType(attrValue); 232 } 233 } 234 235 @Override 236 public void readPropertyAttribute(String name, Class<?> staticClass, String fxmlValue) { 237 assert currentTransientNode instanceof TransientObject 238 || currentTransientNode instanceof TransientIntrinsic 239 || currentTransientNode instanceof TransientProperty; 240 241 assert name != null; 242 243 final PropertyName pname = new PropertyName(name, staticClass); 244 final FXOMPropertyT fxomProperty = new FXOMPropertyT(document, pname, null, null, fxmlValue); 245 246 if (currentTransientNode instanceof TransientObject) { 247 final TransientObject transientInstance = (TransientObject) currentTransientNode; 248 transientInstance.getProperties().add(fxomProperty); 249 } else if (currentTransientNode instanceof TransientProperty) { 250 final TransientProperty transientProperty = (TransientProperty) currentTransientNode; 251 transientProperty.getCollectedProperties().add(fxomProperty); 252 } else { 253 // TODO(elp): for now, we ignore properties declared in fx:include. 254 // To be implemented later. 255 } 256 } 257 258 @Override 259 public void readUnknownStaticPropertyAttribute(String string, String string1) { 260 // TODO(elp) : implement FXOMLoader.readUnknownStaticPropertyAttribute. 261 } 262 263 @Override 264 public void readEventHandlerAttribute(String name, String hashStatement) { 265 // Same as readPropertyAttribute() 266 readPropertyAttribute(name, null, hashStatement); 267 } 268 269 @Override 270 public void endElement(Object sceneGraphObject) { 271 272 currentTransientNode.setSceneGraphObject(sceneGraphObject); 273 274 if (currentTransientNode instanceof TransientObject) { 275 final TransientObject currentInstance = (TransientObject) currentTransientNode; 276 final FXOMObject currentFxomObject = currentInstance.makeFxomObject(document); 277 final TransientNode currentParent = currentInstance.getParentNode(); 278 if (currentParent instanceof TransientProperty) { 279 final TransientProperty parentProperty = (TransientProperty) currentParent; 280 parentProperty.getValues().add(currentFxomObject); 281 } else if (currentParent instanceof TransientObject) { 282 final TransientObject parentInstance = (TransientObject) currentParent; 283 parentInstance.getCollectedItems().add(currentFxomObject); 284 } else if (currentParent instanceof TransientIgnored) { 285 // currentObject is an object inside an fx:define section 286 // Nothing to do for now 287 } else { 288 assert currentParent == null; 289 document.updateRoots(currentFxomObject, currentFxomObject.getSceneGraphObject()); 290 } 291 292 } else if (currentTransientNode instanceof TransientIntrinsic) { 293 final TransientIntrinsic currentIntrinsic = (TransientIntrinsic) currentTransientNode; 294 final FXOMIntrinsic currentFxomIntrinsic = currentIntrinsic.makeFxomIntrinsic(document); 295 final TransientNode currentParent = currentIntrinsic.getParentNode(); 296 297 if (currentParent instanceof TransientProperty) { 298 final TransientProperty parentProperty = (TransientProperty) currentParent; 299 parentProperty.getValues().add(currentFxomIntrinsic); 300 } else if (currentParent instanceof TransientObject) { 301 final TransientObject parentInstance = (TransientObject) currentParent; 302 parentInstance.getCollectedItems().add(currentFxomIntrinsic); 303 } else if (currentParent instanceof TransientIgnored) { 304 // currentObject is an object inside an fx:define section 305 // Nothing to do for now 306 } else { 307 assert currentParent == null; 308 document.updateRoots(currentFxomIntrinsic, currentFxomIntrinsic.getSceneGraphObject()); 309 } 310 } else if (currentTransientNode instanceof TransientProperty) { 311 final TransientProperty currentProperty = (TransientProperty) currentTransientNode; 312 final TransientNode currentParent = currentProperty.getParentNode(); 313 final FXOMProperty currentFxomProperty = currentProperty.makeFxomProperty(document); 314 assert currentParent instanceof TransientObject; 315 final TransientObject parentObject = (TransientObject) currentParent; 316 parentObject.getProperties().add(currentFxomProperty); 317 // We ignore sceneGraphObject 318 } else { 319 assert currentTransientNode instanceof TransientIgnored; 320 // Nothing to do in this case 321 } 322 323 currentTransientNode = currentTransientNode.getParentNode(); 324 } 325 }