4
* Created on April 17, 2007, 12:27 PM
7
package org.netbeans.modules.javawebstart.signtask;
10
import java.io.IOException;
11
import java.io.PrintWriter;
13
import java.util.ArrayList;
14
import java.util.Enumeration;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.Iterator;
18
import java.util.LinkedList;
19
import java.util.List;
21
import java.util.Map.Entry;
24
import java.util.zip.ZipEntry;
25
import java.util.zip.ZipFile;
27
import org.apache.tools.ant.BuildException;
28
import org.apache.tools.ant.DirectoryScanner;
29
import org.apache.tools.ant.Project;
30
import org.apache.tools.ant.Task;
31
import org.apache.tools.ant.taskdefs.SignJar;
32
import org.apache.tools.ant.types.FileSet;
38
public class SignJarsTask extends Task {
40
private static final String SIG_START = "META-INF/";
41
private static final String SIG_END = ".SF";
43
private int compIndex = 1;
45
private String keystore;
46
public void setKeystore(String s) {
50
private String storepass;
51
public void setStorepass(String s) {
55
private String keypass;
56
public void setKeypass(String s) {
61
public void setAlias(String s) {
66
public void setMainjar(File f) {
71
public void setDestdir(File f) {
75
private String codebase;
76
public void setCodebase(String s) {
80
private String compProp;
81
public void setComponentsprop(String s) {
85
private String signedJarsProp;
86
public void setSignedjarsprop(String s) {
90
private List<FileSet> filesets = new LinkedList<FileSet>();
91
public void addFileset(FileSet fs) {
95
public void execute() throws BuildException {
97
Map<Set<String>,List<File>> signersMap = new HashMap(); // Set<signerName> -> List<jarPath>
98
List<File> files2sign = new ArrayList<File>();
99
List<File> alreadySigned = new ArrayList<File>();
101
Iterator it = filesets.iterator();
102
while (it.hasNext()) {
103
FileSet fs = (FileSet) it.next();
104
File dir = fs.getDir(getProject());
108
log("Processing FileSet: " + fs, Project.MSG_VERBOSE);
109
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
110
File basedir = ds.getBasedir();
111
String[] files = ds.getIncludedFiles();
112
for (String f : files) {
114
File fl = new File(basedir, f);
115
Set<String> sgs = getSignatures(fl);
116
if (sgs.size() == 0) {
119
// test if the file is signed with passed alias
120
if (sgs.size() == 1 && sgs.contains(alias.toUpperCase())) {
121
alreadySigned.add(fl);
123
List lst = signersMap.get(sgs);
127
List<File> nlst = new ArrayList<File>();
129
signersMap.put(sgs, nlst);
133
} catch (IOException ex) {
134
throw new BuildException(ex, getLocation());
139
log("Files to be signed: " + mainJar.toString() + ", " + files2sign.toString(), Project.MSG_VERBOSE);
141
// for already signed files generate component jnlp file
142
log("Files already signed by requested alias: " + alreadySigned.toString(), Project.MSG_VERBOSE);
144
StringBuilder signedJarsBuilder = new StringBuilder();
145
SignJar signJar = (SignJar) getProject().createTask("signjar");
146
signJar.setLocation(getLocation());
147
signJar.setKeystore(keystore);
148
signJar.setStorepass(storepass);
149
signJar.setKeypass(keypass);
150
signJar.setAlias(alias);
153
// test main jar if its already signed with passed alias ??
154
log("Signing main jar file: " + mainJar, Project.MSG_VERBOSE);
155
signJar.setJar(mainJar);
158
if (files2sign.size() > 0) {
159
for (Iterator<File> iter = files2sign.iterator(); iter.hasNext(); ) {
160
File f = iter.next();
161
log("Signing file: " + f, Project.MSG_VERBOSE);
164
signedJarsBuilder.append("\n <jar href=\"lib/" + f.getName() + "\" download=\"eager\"/>"); // XXX lib ?
168
if (alreadySigned.size() > 0) {
169
for (Iterator<File> iter = alreadySigned.iterator(); iter.hasNext(); ) {
170
File f = iter.next();
171
log("Adding signed file: " + f, Project.MSG_VERBOSE);
172
signedJarsBuilder.append("\n <jar href=\"lib/" + f.getName() + "\" download=\"eager\"/>"); // XXX lib ?
176
getProject().setProperty(signedJarsProp, signedJarsBuilder.toString());
178
StringBuilder compsBuilder = new StringBuilder();
179
for (Iterator<Entry<Set<String>,List<File>>> iter = signersMap.entrySet().iterator(); iter.hasNext(); ) {
180
Entry<Set<String>,List<File>> entry = iter.next();
181
log("Already signed: keystore aliases = " + entry.getKey() + " -> signed jars = " + entry.getValue(), Project.MSG_VERBOSE);
183
String compName = "jnlpcomponent" + compIndex++;
184
createJNLPComponentFile(entry.getKey(), entry.getValue(), compName);
185
compsBuilder.append("\n <extension name=\"" + compName + "\" href=\"" + compName + ".jnlp\"/>");
188
getProject().setProperty(compProp, compsBuilder.toString());
193
* Returns set of signature aliases used to sign this file
195
private static Set<String> getSignatures(File f) throws IOException {
196
ZipFile jarFile = null;
197
Set<String> signatures = new HashSet<String>(3);
199
jarFile = new ZipFile(f);
200
for (Enumeration<ZipEntry> en = (Enumeration<ZipEntry>) jarFile.entries(); en.hasMoreElements(); ) {
201
ZipEntry je = en.nextElement();
202
if (!je.isDirectory() && je.getName().startsWith(SIG_START) && je.getName().endsWith(SIG_END)) {
203
// there is signature file, get the name
204
String sigName = je.getName().substring(SIG_START.length(), je.getName().indexOf(SIG_END));
205
signatures.add(sigName);
209
if (jarFile != null) jarFile.close();
215
* return filename of the JNLP component file ??
217
private String createJNLPComponentFile(Set<String> aliases, List<File> jars, String compName) {
219
File f = new File(destDir, compName + ".jnlp");
220
PrintWriter writer = null;
222
writer = new PrintWriter(f);
223
} catch (IOException ioe) {
224
throw new BuildException(ioe, getLocation());
226
writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
227
writer.println("<jnlp spec=\"1.0+\" codebase=\"" + codebase + "\">");
228
writer.println(" <information>");
229
writer.println(" <title>" + compName + "</title>");
230
writer.println(" <vendor>" + concatSet(aliases) + "</vendor>");
231
writer.println(" </information>");
232
writer.println(" <security>");
233
writer.println(" <all-permissions/>");
234
writer.println(" </security>");
235
writer.println(" <resources>");
236
for (Iterator<File> iter = jars.iterator(); iter.hasNext(); ) {
237
writer.println(" <jar href=\"" + getPath(destDir.getAbsolutePath(), iter.next().getAbsolutePath()) + "\" download=\"eager\"/>");
239
writer.println(" </resources>");
240
writer.println(" <component-desc/>");
241
writer.println("</jnlp>");
245
return f.getAbsolutePath();
249
/* Returns the result after subtraction of filePath - dirPath
251
private String getPath(String dirPath, String filePath) {
252
String retVal = null;
253
if (filePath.indexOf(dirPath) != -1) {
254
retVal = (filePath.substring(dirPath.length() + 1).replace('\\', '/'));
259
/* Returns the concatenation of set items, separated by commas
261
private String concatSet(Set<String> s) {
262
StringBuilder sb = new StringBuilder();
263
boolean first = true;
264
for (Iterator iter = s.iterator(); iter.hasNext(); ) {
266
sb.append(iter.next());
268
sb.append(", " + iter.next());
271
return sb.toString();