001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs;
020:
021: import java.io.File;
022: import java.util.Enumeration;
023: import java.util.Vector;
024:
025: import org.apache.tools.ant.BuildException;
026: import org.apache.tools.ant.Task;
027: import org.apache.tools.ant.types.Environment;
028: import org.apache.tools.ant.types.FileSet;
029: import org.apache.tools.ant.types.Path;
030: import org.apache.tools.ant.types.RedirectorElement;
031: import org.apache.tools.ant.util.JavaEnvUtils;
032:
033: /**
034: * This is factored out from {@link SignJar}; a base class that can be used
035: * for both signing and verifying JAR files using jarsigner
036: */
037:
038: public abstract class AbstractJarSignerTask extends Task {
039: // CheckStyle:VisibilityModifier OFF - bc
040: /**
041: * The name of the jar file.
042: */
043: protected File jar;
044: /**
045: * The alias of signer.
046: */
047: protected String alias;
048: /**
049: * The url or path of keystore file.
050: */
051: protected String keystore;
052: /**
053: * password for the store
054: */
055: protected String storepass;
056: /**
057: * type of store,-storetype param
058: */
059: protected String storetype;
060: /**
061: * password for the key in the store
062: */
063: protected String keypass;
064: /**
065: * verbose output
066: */
067: protected boolean verbose;
068: /**
069: * The maximum amount of memory to use for Jar signer
070: */
071: protected String maxMemory;
072: /**
073: * the filesets of the jars to sign
074: */
075: protected Vector filesets = new Vector();
076: /**
077: * name of JDK program we are looking for
078: */
079: protected static final String JARSIGNER_COMMAND = "jarsigner";
080:
081: // CheckStyle:VisibilityModifier ON
082:
083: /**
084: * redirector used to talk to the jarsigner program
085: */
086: private RedirectorElement redirector;
087:
088: /**
089: * Java declarations -J-Dname=value
090: */
091: private Environment sysProperties = new Environment();
092:
093: /**
094: * error string for unit test verification: {@value}
095: */
096: public static final String ERROR_NO_SOURCE = "jar must be set through jar attribute "
097: + "or nested filesets";
098:
099: /**
100: * Path holding all non-filesets of filesystem resources we want to sign.
101: *
102: * @since Ant 1.7
103: */
104: private Path path = null;
105:
106: /**
107: * Set the maximum memory to be used by the jarsigner process
108: *
109: * @param max a string indicating the maximum memory according to the JVM
110: * conventions (e.g. 128m is 128 Megabytes)
111: */
112: public void setMaxmemory(String max) {
113: maxMemory = max;
114: }
115:
116: /**
117: * the jar file to sign; required
118: *
119: * @param jar the jar file to sign
120: */
121: public void setJar(final File jar) {
122: this .jar = jar;
123: }
124:
125: /**
126: * the alias to sign under; required
127: *
128: * @param alias the alias to sign under
129: */
130: public void setAlias(final String alias) {
131: this .alias = alias;
132: }
133:
134: /**
135: * keystore location; required
136: *
137: * @param keystore the keystore location
138: */
139: public void setKeystore(final String keystore) {
140: this .keystore = keystore;
141: }
142:
143: /**
144: * password for keystore integrity; required
145: *
146: * @param storepass the password for the keystore
147: */
148: public void setStorepass(final String storepass) {
149: this .storepass = storepass;
150: }
151:
152: /**
153: * keystore type; optional
154: *
155: * @param storetype the keystore type
156: */
157: public void setStoretype(final String storetype) {
158: this .storetype = storetype;
159: }
160:
161: /**
162: * password for private key (if different); optional
163: *
164: * @param keypass the password for the key (if different)
165: */
166: public void setKeypass(final String keypass) {
167: this .keypass = keypass;
168: }
169:
170: /**
171: * Enable verbose output when signing ; optional: default false
172: *
173: * @param verbose if true enable verbose output
174: */
175: public void setVerbose(final boolean verbose) {
176: this .verbose = verbose;
177: }
178:
179: /**
180: * Adds a set of files to sign
181: *
182: * @param set a set of files to sign
183: * @since Ant 1.4
184: */
185: public void addFileset(final FileSet set) {
186: filesets.addElement(set);
187: }
188:
189: /**
190: * Add a system property.
191: *
192: * @param sysp system property.
193: */
194: public void addSysproperty(Environment.Variable sysp) {
195: sysProperties.addVariable(sysp);
196: }
197:
198: /**
199: * Adds a path of files to sign.
200: *
201: * @return a path of files to sign.
202: * @since Ant 1.7
203: */
204: public Path createPath() {
205: if (path == null) {
206: path = new Path(getProject());
207: }
208: return path.createPath();
209: }
210:
211: /**
212: * init processing logic; this is retained through our execution(s)
213: */
214: protected void beginExecution() {
215:
216: redirector = createRedirector();
217: }
218:
219: /**
220: * any cleanup logic
221: */
222: protected void endExecution() {
223: redirector = null;
224: }
225:
226: /**
227: * Create the redirector to use, if any.
228: *
229: * @return a configured RedirectorElement.
230: */
231: private RedirectorElement createRedirector() {
232: RedirectorElement result = new RedirectorElement();
233: if (storepass != null) {
234: StringBuffer input = new StringBuffer(storepass)
235: .append('\n');
236: if (keypass != null) {
237: input.append(keypass).append('\n');
238: }
239: result.setInputString(input.toString());
240: result.setLogInputString(false);
241: }
242: return result;
243: }
244:
245: /**
246: * get the redirector. Non-null between invocations of
247: * {@link #beginExecution()} and {@link #endExecution()}
248: * @return a redirector or null
249: */
250: public RedirectorElement getRedirector() {
251: return redirector;
252: }
253:
254: /**
255: * these are options common to signing and verifying
256: * @param cmd command to configure
257: */
258: protected void setCommonOptions(final ExecTask cmd) {
259: if (maxMemory != null) {
260: addValue(cmd, "-J-Xmx" + maxMemory);
261: }
262:
263: if (verbose) {
264: addValue(cmd, "-verbose");
265: }
266:
267: //now patch in all system properties
268: Vector props = sysProperties.getVariablesVector();
269: Enumeration e = props.elements();
270: while (e.hasMoreElements()) {
271: Environment.Variable variable = (Environment.Variable) e
272: .nextElement();
273: declareSysProperty(cmd, variable);
274: }
275: }
276:
277: /**
278: *
279: * @param cmd command to configure
280: * @param property property to set
281: * @throws BuildException if the property is not correctly defined.
282: */
283: protected void declareSysProperty(ExecTask cmd,
284: Environment.Variable property) throws BuildException {
285: addValue(cmd, "-J-D" + property.getContent());
286: }
287:
288: /**
289: * bind to a keystore if the attributes are there
290: * @param cmd command to configure
291: */
292: protected void bindToKeystore(final ExecTask cmd) {
293: if (null != keystore) {
294: // is the keystore a file
295: addValue(cmd, "-keystore");
296: String loc;
297: File keystoreFile = getProject().resolveFile(keystore);
298: if (keystoreFile.exists()) {
299: loc = keystoreFile.getPath();
300: } else {
301: // must be a URL - just pass as is
302: loc = keystore;
303: }
304: addValue(cmd, loc);
305: }
306: if (null != storetype) {
307: addValue(cmd, "-storetype");
308: addValue(cmd, storetype);
309: }
310: }
311:
312: /**
313: * create the jarsigner executable task
314: * @return a task set up with the executable of jarsigner, failonerror=true
315: * and bound to our redirector
316: */
317: protected ExecTask createJarSigner() {
318: final ExecTask cmd = new ExecTask(this );
319: cmd.setExecutable(JavaEnvUtils
320: .getJdkExecutable(JARSIGNER_COMMAND));
321: cmd.setTaskType(JARSIGNER_COMMAND);
322: cmd.setFailonerror(true);
323: cmd.addConfiguredRedirector(redirector);
324: return cmd;
325: }
326:
327: /**
328: * clone our filesets vector, and patch in the jar attribute as a new
329: * fileset, if is defined
330: * @return a vector of FileSet instances
331: */
332: protected Vector createUnifiedSources() {
333: Vector sources = (Vector) filesets.clone();
334: if (jar != null) {
335: //we create a fileset with the source file.
336: //this lets us combine our logic for handling output directories,
337: //mapping etc.
338: FileSet sourceJar = new FileSet();
339: sourceJar.setProject(getProject());
340: sourceJar.setFile(jar);
341: sourceJar.setDir(jar.getParentFile());
342: sources.add(sourceJar);
343: }
344: return sources;
345: }
346:
347: /**
348: * clone our path and add all explicitly specified FileSets as
349: * well, patch in the jar attribute as a new fileset if it is
350: * defined.
351: * @return a path that contains all files to sign
352: * @since Ant 1.7
353: */
354: protected Path createUnifiedSourcePath() {
355: Path p = path == null ? new Path(getProject()) : (Path) path
356: .clone();
357: Vector s = createUnifiedSources();
358: Enumeration e = s.elements();
359: while (e.hasMoreElements()) {
360: p.add((FileSet) e.nextElement());
361: }
362: return p;
363: }
364:
365: /**
366: * Has either a path or a fileset been specified?
367: * @return true if a path or fileset has been specified.
368: * @since Ant 1.7
369: */
370: protected boolean hasResources() {
371: return path != null || filesets.size() > 0;
372: }
373:
374: /**
375: * add a value argument to a command
376: * @param cmd command to manipulate
377: * @param value value to add
378: */
379: protected void addValue(final ExecTask cmd, String value) {
380: cmd.createArg().setValue(value);
381: }
382: }
|