1 /*
   2  * Copyright (c) 2011, 2015, 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 com.sun.javafx.tools.packager.CreateJarParams;
  29 import com.sun.javafx.tools.packager.PackagerLib;
  30 import java.io.File;
  31 import java.util.Enumeration;
  32 import java.util.HashMap;
  33 import java.util.LinkedList;
  34 import java.util.List;
  35 import java.util.Map;
  36 import org.apache.tools.ant.BuildException;
  37 import org.apache.tools.ant.Task;
  38 import org.apache.tools.ant.taskdefs.Manifest;
  39 import org.apache.tools.ant.types.FileSet;
  40 
  41 /**
  42  * Package javafx application into jar file. The set of files to be included is
  43  * defined by one or more nested fileset. Task also accepts jar Manifest to embed it into
  44  * result jar file.
  45  * <p>
  46  * In addition to just creating jar archive it also:
  47  * <ul>
  48  *   <li> embeds of JavaFX launcher (for double clickable jars)
  49  *   <li> embeds of fallback AWT applet (to be used if JavaFX is not available)
  50  *   <li> ensures jar manifests do not have "bad" entries (such as Class-Path)
  51  * </ul>
  52  *
  53  * @ant.task name="jar" category="javafx"
  54  */
  55 public class FXJar extends Task {
  56     private String destFile = null;
  57     private String codebase = null;
  58     private Application app = null;
  59     private Platform platform = null;
  60     private Resources resources = null;
  61     private List<FileSet> filesets = new LinkedList<FileSet>();
  62     private Manifest manifest = null;
  63 
  64     private PackagerLib packager;
  65     private CreateJarParams createJarParams;
  66 
  67     private boolean css2bin = false;
  68 
  69     private boolean verbose = false;
  70     public void setVerbose(boolean v) {
  71         verbose = v;
  72     }
  73 
  74     public Application createApplication() {
  75         app = new Application();
  76         return app;
  77     }
  78 
  79     public Platform createPlatform() {
  80         platform = new Platform();
  81         return platform;
  82     }
  83 
  84     private Permissions perms = null;
  85 
  86     public Permissions createPermissions() {
  87         perms = new Permissions();
  88         return perms;
  89     }
  90 
  91     public Resources createResources() {
  92         resources = new Resources();
  93         return resources;
  94     }
  95 
  96     /**
  97      * Location of output file.
  98      *
  99      * @ant.required
 100      */
 101     public void setDestfile(String v) {
 102         destFile = v;
 103     }
 104 
 105     /*
 106      * If specified, then packager adds the "Codebase" attribute to the manifest file
 107      *
 108      * @ant.not-required Default is null.
 109      */
 110     public void setCodebase(String v) {
 111         codebase = v;
 112     }
 113 
 114     /**
 115      * Enable converting CSS files to binary format for faster parsing at
 116      * runtime.
 117      *
 118      * @ant.not-required Default is false.
 119      */
 120     public void setCss2Bin(boolean v) {
 121         css2bin = v;
 122     }
 123 
 124     public FXJar() {
 125         packager = new PackagerLib();
 126         createJarParams = new CreateJarParams();
 127     }
 128 
 129 
 130     @Override
 131     public void execute() {
 132         checkAttributesAndElements();
 133 
 134         createJarParams.setCss2bin(css2bin);
 135 
 136         if (app != null) {
 137            createJarParams.setApplicationClass(app.get().mainClass);
 138            createJarParams.setPreloader(app.get().preloaderClass);
 139            createJarParams.setFallback(app.get().fallbackApp);
 140            createJarParams.setParams(app.get().parameters);
 141            createJarParams.setArguments(app.get().getArguments());
 142         }
 143 
 144         if (perms != null) {
 145             createJarParams.setAllPermissions(perms.getElevated());
 146         }
 147 
 148         if (codebase != null) {
 149             createJarParams.setCodebase(codebase);
 150         }
 151 
 152         if (platform != null) {
 153            createJarParams.setFxVersion(platform.get().javafx);
 154         }
 155 
 156         if (resources != null) {
 157             createJarParams.setClasspath(resources.exportAsClassPath());
 158         }
 159 
 160         final File f = new File(destFile);
 161         createJarParams.setOutdir(f.isAbsolute()
 162                                       ? null
 163                                       : getProject().getBaseDir());
 164         createJarParams.setOutfile(destFile);
 165 
 166         if (manifest != null) {
 167             createJarParams.setManifestAttrs(getAttrSet(manifest));
 168         }
 169 
 170         for (FileSet fileset: filesets) {
 171            Utils.addResources(createJarParams, fileset);
 172         }
 173 
 174         try {
 175             packager.packageAsJar(createJarParams);
 176         } catch (Exception e) {
 177             throw new BuildException(e.getMessage(), e);
 178         }
 179     }
 180 
 181     public Manifest createManifest() {
 182         manifest = new Manifest();
 183         return manifest;
 184     }
 185 
 186     public FileSet createFileSet() {
 187         FileSet fileset = new FileSet();
 188         fileset.setProject(getProject());
 189         filesets.add(fileset);
 190         return fileset;
 191     }
 192 
 193     private void checkAttributesAndElements() {
 194         if (destFile == null) {
 195             throw new BuildException("You must specify the destfile file to create.");
 196         }
 197 
 198         File f = new File(destFile);
 199         if (!f.isAbsolute()) {
 200             f = new File(getProject().getBaseDir(), destFile);
 201         }
 202         if (f.exists() && !f.isFile()) {
 203             throw new BuildException(destFile + " is not a file.");
 204         }
 205 
 206         if (f.exists() && !f.canWrite()) {
 207             throw new BuildException(destFile + " is read-only.");
 208         }
 209 
 210         if (filesets.isEmpty()) {
 211             throw new BuildException("You must specify at least one fileset to be packed.");
 212         }
 213 
 214         boolean haveNonEmpty = false;
 215         for (FileSet fileset: filesets) {
 216             if (fileset.size() != 0) {
 217                 haveNonEmpty = true;
 218                 break;
 219             }
 220         }
 221 
 222         if (!haveNonEmpty) {
 223             throw new BuildException("All filesets are empty.");
 224         }
 225 
 226         if (app != null) {
 227             app.selfcheck();
 228         }
 229     }
 230 
 231     private static Map<String, String> getAttrSet(Manifest manifest) {
 232         Map<String, String> result = new HashMap<String, String>();
 233 
 234         Manifest.Section mainSection = manifest.getMainSection();
 235         for (Enumeration e = mainSection.getAttributeKeys(); e.hasMoreElements();) {
 236             String attrKey = (String) e.nextElement();
 237             Manifest.Attribute attr = mainSection.getAttribute(attrKey);
 238             result.put(attr.getName(), attr.getValue());
 239         }
 240         return result;
 241     }
 242 }