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 }