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