1 /*
   2  * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.javafx.tools.ant;
  27 
  28 import java.io.File;
  29 import java.util.ArrayList;
  30 import java.util.LinkedList;
  31 import java.util.List;
  32 import java.util.Map;
  33 import java.util.stream.Collectors;
  34 
  35 import com.oracle.tools.packager.StandardBundlerParam;
  36 import com.sun.javafx.tools.ant.Platform.Jvmarg;
  37 import com.sun.javafx.tools.ant.Platform.Property;
  38 import com.sun.javafx.tools.packager.DeployParams;
  39 import com.oracle.tools.packager.Log;
  40 import com.sun.javafx.tools.packager.PackagerException;
  41 import com.sun.javafx.tools.packager.PackagerLib;
  42 import com.sun.javafx.tools.packager.bundlers.Bundler;
  43 import com.sun.javafx.tools.packager.bundlers.Bundler.Bundle;
  44 import com.sun.javafx.tools.packager.bundlers.Bundler.BundleType;
  45 import java.util.ResourceBundle;
  46 import org.apache.tools.ant.BuildException;
  47 import org.apache.tools.ant.DynamicAttribute;
  48 import org.apache.tools.ant.Task;
  49 import org.apache.tools.ant.types.DataType;
  50 
  51 /**
  52  * Generates package for Web deployment and redistribution of application.
  53  * Package includes of set of jar files, JNLP file and HTML file.
  54  *
  55  * Minimal example:
  56  * <pre>
  57  *   &lt;fx:deploy width="600" height="400"
  58  *                 outdir="web-dist" outfile="Fish"&gt;
  59  *       &lt;info title="Sample application"/&gt;
  60  *       &lt;fx:application refid="myapp"/&gt;
  61  *       &lt;fx:resources refid="myresources"/&gt;
  62  *   &lt;/fx:deploy&gt;
  63  * </pre>
  64  * Above example will generate HTML/JNLP files into the web-dist directory
  65  * and use "Fish" as prefix for generated files. Details about application and
  66  * its resources are defined elsewhere in the application and resource elements.
  67  * <p>
  68  * Minimal complete example:
  69  * <pre>
  70  *   &lt;fx:deploy width="600" height="400"
  71  *                 outdir="web-dist" outfile="Fish"&gt;
  72  *       &lt;info title="Sample application"/&gt;
  73  *       &lt;fx:application name="SampleApp"
  74  *              mainClass="testapp.MainApp"
  75  *              preloaderClass="testpreloader.Preloader"/&gt;
  76  *       &lt;fx:resources&gt;
  77  *              &lt;fx:fileset requiredFor="preloader" dir="dist"&gt;
  78  *                &lt;include name="preloader.jar"/&gt;
  79  *             &lt;/fx:fileset&gt;
  80  *              &lt;fx:fileset dir="dist"&gt;
  81  *                &lt;include name="helloworld.jar"/&gt;
  82  *             &lt;/fx:fileset&gt;
  83  *       &lt;/fx:resources&gt;
  84  *   &lt;/fx:deploy&gt;
  85  * </pre>
  86  * Same as above but here application and resource details are defined in place.
  87  * Note that using references helps with reducing code duplication as fx:jar need
  88  * to be used for double clickable jars.
  89  *
  90  * @ant.task name="deploy" category="javafx"
  91  */
  92 public class DeployFXTask extends Task implements DynamicAttribute {
  93 
  94     private static final ResourceBundle I18N =
  95             ResourceBundle.getBundle(DeployFXTask.class.getName());
  96 
  97     private String width = null;
  98     private String height = null;
  99     private String embeddedWidth = null;
 100     private String embeddedHeight = null;
 101     private String outfile = null;
 102     private String outdir = null;
 103     private boolean embedJNLP;
 104     private boolean isExtension = false;
 105     private Boolean signBundle;
 106 
 107     //Before FCS default is to include DT files with app
 108     // to ensure tests are using latest and compatible.
 109     //After FCS default is to use shared copy.
 110     private boolean includeDT = false;
 111 
 112     private String updateMode="background";
 113     private Info appInfo = null;
 114     private Application app = null;
 115     private Resources resources = null;
 116     private Preferences prefs = null;
 117     private String codebase = null;
 118 
 119     //container to embed application into
 120     //could be either string id or js code. If it is string id then it needs to
 121     //be escaped
 122     private String placeholder;
 123 
 124     private PackagerLib packager;
 125     private DeployParams deployParams;
 126 
 127     private Callbacks callbacks;
 128 
 129     boolean offlineAllowed = true;
 130 
 131     //default native bundle settings
 132     // use NONE to avoid large disk space and build time overhead
 133     BundleType nativeBundles = BundleType.NONE;
 134     String bundleFormat = null;
 135     boolean versionCheck = true;
 136 
 137     private boolean verbose = false;
 138     public void setVerbose(boolean v) {
 139         verbose = v;
 140     }
 141 
 142     public void setCodebase(String str) {
 143         codebase = str;
 144     }
 145 
 146     public DeployFXTask() {
 147         packager = new PackagerLib();
 148         deployParams = new DeployParams();
 149     }
 150 
 151     @Override
 152     public void execute() {
 153         boolean isModular = (app.getModule() != null) && !app.getModule().isEmpty();
 154         deployParams.setOutfile(outfile);
 155         deployParams.setOutdir(new File(outdir));
 156 
 157         if (versionCheck) {
 158             if (!com.sun.javafx.tools.ant.VersionCheck.isSameVersion()) {
 159                 throw new BuildException(I18N.getString("message.java.version.mismatch"));
 160             }
 161         }
 162 
 163         if (!isModular &&
 164             (nativeBundles == BundleType.JNLP ||
 165              nativeBundles == BundleType.ALL ||
 166              nativeBundles == BundleType.NONE)) {
 167             deployParams.setOfflineAllowed(offlineAllowed);
 168             deployParams.setVerbose(verbose);
 169             deployParams.setCodebase(codebase);
 170             deployParams.setSignBundle(signBundle);
 171 
 172             if (app.getModule() == null) {
 173                 deployParams.setApplicationClass(app.get().mainClass);
 174             }
 175 
 176             if (width != null) {
 177                 deployParams.setWidth(Integer.valueOf(width));
 178             }
 179 
 180             if (height != null) {
 181                 deployParams.setHeight(Integer.valueOf(height));
 182             }
 183 
 184             if (embeddedWidth != null && embeddedHeight != null) {
 185                 deployParams.setEmbeddedDimensions(embeddedWidth, embeddedHeight);
 186             }
 187 
 188             deployParams.setEmbedJNLP(embedJNLP);
 189             if (perms != null) {
 190                deployParams.setAllPermissions(perms.getElevated());
 191             }
 192 
 193             deployParams.setUpdateMode(updateMode);
 194             deployParams.setExtension(isExtension);
 195             deployParams.setIncludeDT(includeDT);
 196 
 197             if (callbacks != null) {
 198                 for (Callback cb: callbacks.callbacks) {
 199                     deployParams.addCallback(cb.getName(), cb.getCmd());
 200                 }
 201             }
 202 
 203             setPlatform();
 204             setPreferences();
 205 
 206             for (Template t: templateList) {
 207                 deployParams.addTemplate(t.infile, t.outfile);
 208             }
 209         }
 210 
 211         if (isModular &&
 212             (nativeBundles == BundleType.NATIVE ||
 213              nativeBundles == BundleType.IMAGE ||
 214              nativeBundles == BundleType.INSTALLER ||
 215              nativeBundles == BundleType.ALL)) {
 216             if (app != null) {
 217                 if (app.getModule() == null) {
 218                     deployParams.setApplicationClass(app.get().mainClass);
 219                 }
 220                 else {
 221                     int index = app.getModule().indexOf("/");
 222 
 223                     if (index > 0) {
 224                         deployParams.setModule(app.getModule());
 225                     }
 226                     else {
 227                         deployParams.setModule(app.getModule() + "/" + app.get().mainClass);
 228                     }
 229                 }
 230 
 231                 deployParams.setPreloader(app.get().preloaderClass);
 232                 deployParams.setAppId(app.get().id);
 233                 deployParams.setAppName(app.get().name);
 234                 deployParams.setParams(app.get().parameters);
 235                 deployParams.setArguments(app.get().getArguments());
 236                 deployParams.setHtmlParams(app.get().htmlParameters);
 237                 deployParams.setFallback(app.get().fallbackApp);
 238                 deployParams.setSwingAppWithEmbeddedJavaFX(app.get().embeddedIntoSwing);
 239                 deployParams.setVersion(app.get().version);
 240                 deployParams.setId(app.get().id);
 241                 deployParams.setServiceHint(app.get().daemon);
 242 
 243                 setRuntime();






















 244             }
 245 
 246             if (appInfo != null) {
 247                 deployParams.setTitle(appInfo.title);
 248                 deployParams.setVendor(appInfo.vendor);
 249                 deployParams.setDescription(appInfo.appDescription);
 250                 deployParams.setCategory(appInfo.category);
 251                 deployParams.setLicenseType(appInfo.licenseType);
 252                 deployParams.setCopyright(appInfo.copyright);
 253                 deployParams.setEmail(appInfo.email);
 254 
 255                 for (Info.Icon i: appInfo.icons) {
 256                     if (i instanceof Info.Splash) {
 257                        deployParams.addIcon(i.href, i.kind, i.width, i.height, i.depth,
 258                             ((Info.Splash) i).mode);
 259                     } else {
 260                        deployParams.addIcon(i.href, i.kind, i.width, i.height, i.depth,
 261                             DeployParams.RunMode.WEBSTART);
 262                     }
 263                 }
 264 
 265                 deployParams.addBundleArgument(StandardBundlerParam.FILE_ASSOCIATIONS.getID(),
 266                         appInfo.fileAssociations.stream()
 267                             .map(FileAssociation::createLauncherMap)
 268                             .collect(Collectors.toList()));
 269             }
 270 
 271             setPlatform();
 272             setPreferences();
 273         }
 274 
 275         if (!isModular &&
 276             (nativeBundles == BundleType.NATIVE ||
 277              nativeBundles == BundleType.IMAGE ||
 278              nativeBundles == BundleType.INSTALLER ||
 279              nativeBundles == BundleType.ALL)) {
 280             if (app != null) {
 281                 deployParams.setApplicationClass(app.get().mainClass);
 282                 deployParams.setPreloader(app.get().preloaderClass);
 283                 deployParams.setAppId(app.get().id);
 284                 deployParams.setAppName(app.get().name);
 285                 deployParams.setParams(app.get().parameters);
 286                 deployParams.setArguments(app.get().getArguments());
 287                 deployParams.setHtmlParams(app.get().htmlParameters);
 288                 deployParams.setFallback(app.get().fallbackApp);
 289                 deployParams.setSwingAppWithEmbeddedJavaFX(app.get().embeddedIntoSwing);
 290                 deployParams.setVersion(app.get().version);
 291                 deployParams.setId(app.get().id);
 292                 deployParams.setServiceHint(app.get().daemon);
 293 
 294                 setRuntime();
 295             }
 296 
 297             if (appInfo != null) {
 298                 deployParams.setTitle(appInfo.title);
 299                 deployParams.setVendor(appInfo.vendor);
 300                 deployParams.setDescription(appInfo.appDescription);
 301                 deployParams.setCategory(appInfo.category);
 302                 deployParams.setLicenseType(appInfo.licenseType);
 303                 deployParams.setCopyright(appInfo.copyright);
 304                 deployParams.setEmail(appInfo.email);
 305 
 306                 for (Info.Icon i: appInfo.icons) {
 307                     if (i instanceof Info.Splash) {
 308                        deployParams.addIcon(i.href, i.kind, i.width, i.height, i.depth,
 309                             ((Info.Splash) i).mode);
 310                     } else {
 311                        deployParams.addIcon(i.href, i.kind, i.width, i.height, i.depth,
 312                             DeployParams.RunMode.WEBSTART);
 313                     }
 314                 }
 315 
 316                 deployParams.addBundleArgument(StandardBundlerParam.FILE_ASSOCIATIONS.getID(),
 317                         appInfo.fileAssociations.stream()
 318                             .map(FileAssociation::createLauncherMap)
 319                             .collect(Collectors.toList()));
 320             }
 321 
 322             setPlatform();
 323             setPreferences();
 324         }
 325 
 326         for (BundleArgument ba : bundleArgumentList) {
 327             deployParams.addBundleArgument(ba.arg, ba.value);
 328         }
 329 
 330         deployParams.setPlaceholder(placeholder);
 331 
 332         if (resources != null) {
 333             for (FileSet fs: resources.getResources()) {
 334                 Utils.addResources(deployParams, fs);
 335             }
 336         }
 337 
 338         List<Map<String, ? super Object>> launchersAsMap = new ArrayList<>();
 339         for (SecondaryLauncher sl : secondaryLaunchers) {
 340             launchersAsMap.add(sl.createLauncherMap());
 341         }
 342 
 343         deployParams.addBundleArgument(
 344                 StandardBundlerParam.SECONDARY_LAUNCHERS.getID(),
 345                 launchersAsMap);
 346 
 347         deployParams.setBundleType(nativeBundles);
 348         deployParams.setTargetFormat(bundleFormat);
 349 
 350         Log.setLogger(new AntLog(this.getProject()));
 351 
 352         try {
 353             packager.generateDeploymentPackages(deployParams);
 354         } catch (PackagerException pe) {
 355             if (pe.getCause() != null) {
 356                throw new BuildException(pe.getCause().getMessage(), pe.getCause());
 357             } else {
 358                 throw new BuildException(pe.getMessage(), pe);
 359             }
 360         } catch (Exception e) {
 361             throw new BuildException(e.getMessage(), e);
 362         } finally {
 363             Log.setLogger(null);
 364         }
 365     }
 366 
 367     private void setRuntime() {
 368         if (runtime != null) {
 369             for (String s : runtime.getAddModules()) {
 370                 deployParams.addAddModule(s);
 371             }
 372 
 373             for (String s : runtime.getLimitModules()) {
 374                 deployParams.addLimitModule(s);
 375             }
 376 
 377             deployParams.setModulePath(runtime.getModulePath());
 378 
 379             Boolean stripNativeCommands = runtime.getStripNativeCommands();
 380 
 381             if (stripNativeCommands != null) {
 382                 deployParams.setStripNativeCommands(stripNativeCommands);
 383             }
 384 
 385             Boolean detectModules = runtime.getDetectModules();
 386 
 387             if (detectModules != null) {
 388                 deployParams.setDetectModules(detectModules);
 389             }
 390         }
 391     }
 392 
 393     /**
 394      * Set to true if we are generating an 'extension' JNLP.
 395      *
 396      * @ant.not-required Default is false.
 397      */
 398     public void setExtension(boolean v) {
 399         isExtension = v;
 400     }
 401 
 402     public void setNativeBundles(String v) {
 403         Bundle bundle = Bundler.stringToBundle(v);
 404         this.nativeBundles = bundle.type;
 405         this.bundleFormat = bundle.format;
 406     }
 407 
 408     public void setVersionCheck(String value) {
 409         this.versionCheck = Boolean.valueOf(value);
 410     }
 411 
 412     /**
 413      * Indicates the preferences for when checks for application updates
 414      * are performed. Supported modes are always, timeout and background.
 415      *
 416      * @ant.not-required Default is background.
 417      */
 418     public void setUpdateMode(String v) {
 419         String l = v.toLowerCase();
 420         if ("eager".equals(l)) {
 421             //workaround for doc bug in 2.0
 422             l="always";
 423         }
 424         if (!"always".equals(l) && !"background".equals(l)
 425                 && !"timeout".equals(l)) {
 426             throw new BuildException("Unknown update mode: ["+l+"]." +
 427                     "Supported modes are: 'always', 'timeout' and 'background'");
 428         }
 429         updateMode = l;
 430     }
 431 
 432     /**
 433      * Indicates if the application can be launched offline.
 434      *
 435      * If application is already downloaded and update mode is eager then
 436      * the check will timeout after a few seconds, in which case the cached
 437      * application will be launched instead.
 438      *
 439      * Given a reasonably fast server connection,
 440      * the latest version of the application will usually be run,
 441      * but it is not guaranteed. The application, however, can be run offline.
 442      *
 443      * @ant.not-required Default is true.
 444      */
 445     public void setOfflineAllowed(boolean v) {
 446         offlineAllowed = v;
 447     }
 448 
 449     /**
 450      * Application width for embedding application into Web page
 451      *
 452      * @ant.optional
 453      */
 454     public void setEmbeddedWidth(String w) {
 455         embeddedWidth = w;
 456     }
 457 
 458     /**
 459      * Application width. Used for webstart and embedded applications
 460      * unless emdeddedWidth is specified
 461      *
 462      * @ant.required
 463      */
 464     public void setWidth(String v) {
 465         width = v;
 466     }
 467 
 468     /**
 469      * Application width for embedding application into Web page
 470      *
 471      * @ant.optional
 472      */
 473     public void setEmbeddedHeight(String w) {
 474         embeddedHeight = w;
 475     }
 476 
 477     /**
 478      * Application height. Used for webstart and embedded applications
 479      * unless emdeddedHeight is specified
 480      *
 481      * @ant.required
 482      */
 483     public void setHeight(String v) {
 484         height = v;
 485     }
 486 
 487     /**
 488      * Enable embedding JNLP descriptor into Web page.
 489      * Reduces number of network connections to be made on startup and
 490      * help to improve startup time.
 491      *
 492      * @ant.not-required Default is false.
 493      */
 494     public void setEmbedJNLP(boolean v) {
 495         embedJNLP = v;
 496     }
 497 
 498     /**
 499      * Directory where application package will be saved.
 500      *
 501      * @ant.required
 502      */
 503     public void setOutdir(String v) {
 504         outdir = v;
 505     }
 506 
 507     /**
 508      * Prefix to be used for new generated files.
 509      *
 510      * @ant.required
 511      */
 512     public void setOutfile(String v) {
 513         outfile = v;
 514     }
 515 
 516     /**
 517      * If true then web deployment is done using javascript files
 518      * on java.com. Otherwise copy of javascript file is included into
 519      * application package.
 520      *
 521      * @ant.not-required Before FCS default is false. For FCS default is true.
 522      */
 523     public void setIncludeDT(Boolean v) {
 524         includeDT = v;
 525     }
 526 
 527     /**
 528      * Placeholder in the web page where application will be embedded.
 529      * This is expected to be Javascript DOM object.
 530      *
 531      * @ant.required Either reference or id of placeholder is required.
 532      */
 533     public void setPlaceholderRef(String p) {
 534         this.placeholder = p;
 535     }
 536 
 537     /**
 538      * Id of the placeholder in the web page where application will be embedded.
 539      * Javascript's document.getElementById() is expected to be able to resolve it.
 540      *
 541      * @ant.required Either reference or id of placeholder is required.
 542      */
 543     public void setPlaceholderId(String id) {
 544         //raw id of the placeholder, need to escape it
 545         this.placeholder = "'"+id+"'";
 546     }
 547 
 548     public void setSignBundle(boolean signBundle) {
 549         this.signBundle = signBundle;
 550     }
 551 
 552     public Info createInfo() {
 553         appInfo = new Info();
 554         return appInfo;
 555     }
 556 
 557     public Application createApplication() {
 558         app = new Application();
 559         return app;
 560     }
 561 
 562     public Preferences createPreferences() {
 563         prefs = new Preferences();
 564         return prefs;
 565     }
 566 
 567     public Callbacks createCallbacks() {
 568         if (callbacks != null) {
 569             throw new BuildException("Only one callbacks element is supported.");
 570         }
 571         callbacks = new Callbacks();
 572         return callbacks;
 573     }
 574 
 575     public Resources createResources() {
 576         if (resources != null) {
 577             throw new BuildException("Only one resources element is supported.");
 578         }
 579         resources = new Resources();
 580         return resources;
 581     }
 582 
 583     List<Template> templateList = new LinkedList<>();
 584 
 585     public Template createTemplate() {
 586         Template t = new Template();
 587         templateList.add(t);
 588         return t;
 589     }
 590 
 591     Platform platform;
 592 
 593     public Platform createPlatform() {
 594         platform = new Platform();
 595         return platform;
 596     }
 597 
 598     private Permissions perms = null;
 599 
 600     public Permissions createPermissions() {
 601         perms = new Permissions();
 602         return perms;
 603     }
 604 
 605     List<BundleArgument> bundleArgumentList = new LinkedList<>();
 606 
 607     public BundleArgument createBundleArgument() {
 608         BundleArgument ba = new BundleArgument();
 609         bundleArgumentList.add(ba);
 610         return ba;
 611     }
 612 
 613     private List<SecondaryLauncher> secondaryLaunchers = new ArrayList<>();
 614 
 615     public SecondaryLauncher createSecondaryLauncher() {
 616         SecondaryLauncher sl = new SecondaryLauncher();
 617         secondaryLaunchers.add(sl);
 618         return sl;
 619     }
 620 
 621     private Runtime runtime = null;
 622 
 623     public Runtime createRuntime() {
 624         runtime = new Runtime();
 625         return runtime;
 626     }
 627 
 628     @Override
 629     public void setDynamicAttribute(String name, String value) throws BuildException {
 630         //Use qName and value - can't really validate anything until we know which bundlers we have, so this has
 631         //to done (way) downstream
 632         bundleArgumentList.add(new BundleArgument(name, value));
 633     }
 634 
 635     private void setPlatform() {
 636         if (platform != null) {
 637             Platform pl = platform.get();
 638             if (pl.j2se != null) {
 639                 deployParams.setJRE(pl.j2se);
 640             }
 641             if (pl.javafx != null) {
 642                 deployParams.setJavafx(pl.javafx);
 643             }
 644 
 645             //only pass it further if it was explicitly set
 646             // as we do not want to override default
 647             if (pl.javaRoot != null) {
 648                 if (Platform.USE_SYSTEM_JRE.equals(pl.javaRoot)) {
 649                     deployParams.setJavaRuntimeSource(null);
 650                 } else {
 651                     deployParams.setJavaRuntimeSource(new File(pl.javaRoot));
 652                 }
 653             }
 654 
 655             for (Property p: pl.properties) {
 656                 deployParams.addJvmProperty(p.name, p.value);
 657             }
 658             for (Jvmarg a: pl.jvmargs) {
 659                 deployParams.addJvmArg(a.value);
 660             }
 661             for (Property a: pl.jvmUserArgs) {
 662                 deployParams.addJvmUserArg(a.name, a.value);
 663             }
 664         }
 665     }
 666 
 667     private void setPreferences() {
 668         if (prefs != null) {
 669             deployParams.setNeedShortcut(prefs.getShortcut());
 670             deployParams.setNeedInstall(prefs.getInstall());
 671             deployParams.setNeedMenu(prefs.getMenu());
 672             deployParams.setSystemWide(prefs.getSystemInstall());
 673             deployParams.setInstalldirChooser(prefs.getInstalldirChooser());
 674         }
 675     }
 676 
 677     /**
 678      * Template to preprocess.
 679      * <p>
 680      * Template is the HTML file containing markers to be replaced with
 681      * javascript or HTML snippets needed to deploy JavaFX application on the
 682      * Web page. This allows to deploy application into "real" Web pages
 683      * and simplify development process if application is tightly
 684      * integrated with the page (e.g. uses javascript to communicate to it).
 685      * <p>
 686      * Marker has the form of #XXX# or #XXX(id)#. Where id is identifier
 687      * of an application and XXX is one of following:
 688      * <ul>
 689      *   <li>DT.SCRIPT.URL - location of dtjava.js
 690      *   <li>DT.SCRIPT.CODE - script element to include dtjava.js
 691      *   <li>DT.EMBED.CODE.DYNAMIC - code to embed application into given placeholder
 692      *         It is expected it will be wrapped into function()
 693      *   <li>DT.EMBED.CODE.ONLOAD - all code needed to embed application into Web page
 694      *               using onload hook (except inclusion of dtjava.js)
 695      *   <li>DT.LAUNCH.CODE - code need to launch application.
 696      *          Expected to be wrappend into function().
 697      * </ul>
 698      *
 699      * Page with multiple different applications can be processed multiple times
 700      * - one per application. To avoid confusion markers need to use
 701      * application ids  (alphanumeric string no spaces).
 702      * <p>
 703      * If input and output files are the same then template is processed in place.
 704      * <p>
 705      * Example:
 706      * <pre>
 707      *     &lt;template file="App_template.html" tofile="App.html"/&gt;
 708      * </pre>
 709      *
 710      * @ant.type name="Template" category="javafx"
 711      */
 712     public static class Template extends DataType {
 713         File infile = null;
 714         File outfile = null;
 715 
 716         /**
 717          * Input file.
 718          *
 719          * @ant.required
 720          */
 721         public void setFile(File f) {
 722             infile = f;
 723         }
 724 
 725         /**
 726          * Output file (after preprocessing).
 727          *
 728          * @ant.not-required Default is the same as input file.
 729          */
 730         public void setTofile(File f) {
 731             outfile = f;
 732         }
 733     }
 734 
 735     /**
 736      * An argument to be passed off to the bundlers.
 737      *
 738      * Each bundler uses a set of arguments that may be shared across
 739      * the different bundlers or it may be specific to each bundler.
 740      *
 741      * Some bundlers declare argument types that are not known to the JDK
 742      * and may be specific to the particular bundler (such as Mac App Store
 743      * categories).  These arguments allow you to set and adjust these a
 744      * rguments.
 745      *
 746      * @ant.type name="BundleArgument" category="javafx"
 747      */
 748     public static class BundleArgument extends DataType {
 749         String arg = null;
 750         String value = null;
 751 
 752         BundleArgument() {
 753 
 754         }
 755 
 756         BundleArgument(String arg, String value) {
 757             this.arg = arg;
 758             this.value = value;
 759         }
 760 
 761         /**
 762          * Name of the bundle argument.
 763          *
 764          * @ant.required
 765          */
 766         public void setArg(String arg) {
 767             this.arg = arg;
 768         }
 769 
 770         /**
 771          * Value for the bundle argument.
 772          *
 773          * @ant.not-required Default is a literal null
 774          */
 775         public void setValue(String value) {
 776             this.value = value;
 777         }
 778     }
 779 }
--- EOF ---