Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 127375 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/update/core/FeatureContentProvider.java (-25 / +5 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2004 IBM Corporation and others.
2
 * Copyright (c) 2000, 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 11-26 Link Here
11
package org.eclipse.update.core;
11
package org.eclipse.update.core;
12
12
13
import java.io.*;
13
import java.io.*;
14
import java.net.*;
14
import java.net.URL;
15
import java.util.Date;
15
import java.util.*;
16
import java.util.HashMap;
17
import java.util.Hashtable;
18
import java.util.Iterator;
19
import java.util.Map;
20
import java.util.Properties;
21
import java.util.Set;
22
import java.util.StringTokenizer;
23
24
import org.eclipse.core.runtime.*;
16
import org.eclipse.core.runtime.*;
25
import org.eclipse.osgi.util.NLS;
17
import org.eclipse.osgi.util.NLS;
26
import org.eclipse.update.core.model.*;
18
import org.eclipse.update.core.model.*;
Lines 111-122 Link Here
111
	private static final String DOT_PERMISSIONS = "permissions.properties"; //$NON-NLS-1$
103
	private static final String DOT_PERMISSIONS = "permissions.properties"; //$NON-NLS-1$
112
	private static final String EXECUTABLES = "permissions.executable"; //$NON-NLS-1$
104
	private static final String EXECUTABLES = "permissions.executable"; //$NON-NLS-1$
113
105
114
	// lock
115
	private final static Object lock = new Object();
116
117
	// hashtable of locks
118
	private static Hashtable locks = new Hashtable();
119
120
	/**
106
	/**
121
	 * Feature content provider constructor
107
	 * Feature content provider constructor
122
	 * 
108
	 * 
Lines 186-198 Link Here
186
		// is still copying into it
172
		// is still copying into it
187
		File localFile = null;
173
		File localFile = null;
188
		FileFragment localFileFragment = null;
174
		FileFragment localFileFragment = null;
189
		Object keyLock = null;
175
		Object keyLock = LockManager.getLock(key);
190
		synchronized (lock) {
191
			if (locks.get(key) == null)
192
				locks.put(key, key);
193
			keyLock = locks.get(key);
194
		}
195
196
		synchronized (keyLock) {
176
		synchronized (keyLock) {
197
			localFile = Utilities.lookupLocalFile(key);
177
			localFile = Utilities.lookupLocalFile(key);
198
			if (localFile != null) {
178
			if (localFile != null) {
Lines 351-357 Link Here
351
				if (monitor != null)
331
				if (monitor != null)
352
					monitor.restoreState();
332
					monitor.restoreState();
353
			}
333
			}
354
			locks.remove(key);
334
			LockManager.returnLock(key);
355
		} // end lock
335
		} // end lock
356
		ContentReference reference =
336
		ContentReference reference =
357
			ref.createContentReference(ref.getIdentifier(), localFile);
337
			ref.createContentReference(ref.getIdentifier(), localFile);
(-)src/org/eclipse/update/internal/core/FeaturePackagedContentProvider.java (-9 / +74 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
2
 * Copyright (c) 2000, 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 10-24 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.update.internal.core;
11
package org.eclipse.update.internal.core;
12
import java.io.*;
12
import java.io.*;
13
import java.net.*;
13
import java.net.URL;
14
import java.util.ArrayList;
14
import java.util.*;
15
import java.util.Arrays;
15
import org.eclipse.core.runtime.CoreException;
16
import java.util.List;
17
18
import org.eclipse.core.runtime.*;
19
import org.eclipse.osgi.internal.provisional.verifier.CertificateVerifierFactory;
16
import org.eclipse.osgi.internal.provisional.verifier.CertificateVerifierFactory;
20
import org.eclipse.osgi.util.NLS;
17
import org.eclipse.osgi.util.NLS;
21
import org.eclipse.update.core.*;
18
import org.eclipse.update.core.*;
19
import org.eclipse.update.internal.jarprocessor.JarProcessor;
22
import org.eclipse.update.internal.security.JarVerifier;
20
import org.eclipse.update.internal.security.JarVerifier;
23
import org.eclipse.update.internal.verifier.CertVerifier;
21
import org.eclipse.update.internal.verifier.CertVerifier;
24
22
Lines 30-36 Link Here
30
	private ContentReference localManifest = null;
28
	private ContentReference localManifest = null;
31
	private ContentReference[] localFeatureFiles = new ContentReference[0];
29
	private ContentReference[] localFeatureFiles = new ContentReference[0];
32
	private IVerifier jarVerifier = null;
30
	private IVerifier jarVerifier = null;
33
31
	private ExtendedSite siteModel = null;
34
	/*
32
	/*
35
	 * filter for file with .jar
33
	 * filter for file with .jar
36
	 */
34
	 */
Lines 66-71 Link Here
66
		return jarVerifier;
64
		return jarVerifier;
67
	}
65
	}
68
66
67
	public void setFeature(IFeature feature) {
68
		super.setFeature(feature);
69
		ISite featureSite = feature.getSite();
70
		if(featureSite instanceof ExtendedSite){
71
			siteModel = (ExtendedSite) featureSite;
72
		}
73
	}
69
	/*
74
	/*
70
	 * @see IFeatureContentProvider#getFeatureManifestReference()
75
	 * @see IFeatureContentProvider#getFeatureManifestReference()
71
	 */
76
	 */
Lines 170-182 Link Here
170
		URL url = (siteContentProvider == null) ? null : siteContentProvider.getArchiveReference(archiveID);
175
		URL url = (siteContentProvider == null) ? null : siteContentProvider.getArchiveReference(archiveID);
171
176
172
		try {
177
		try {
173
			references[0] = asLocalReference(new JarContentReference(archiveID, url), monitor);
178
			references[0] = retrieveLocalJar(new JarContentReference(archiveID, url), monitor);
174
		} catch (IOException e) {
179
		} catch (IOException e) {
175
			throw errorRetrieving(archiveID, references[0], e);
180
			throw errorRetrieving(archiveID, references[0], e);
176
		}
181
		}
177
		return references;
182
		return references;
178
	}
183
	}
179
184
185
	private ContentReference retrieveLocalJar(JarContentReference reference, InstallMonitor monitor) throws IOException, CoreException {
186
		//If the site does not support pack200, just get the jar as normal
187
		if(siteModel == null || !siteModel.supportsPack200() || !JarProcessor.canPerformUnpack()) {
188
			return asLocalReference(reference, monitor);
189
		}
190
		
191
		ContentReference packedRef = null;
192
		String key = reference.toString();
193
		Object jarLock = LockManager.getLock(key);
194
		synchronized (jarLock) {
195
			//do we have this jar already?
196
			File localFile = Utilities.lookupLocalFile(key);
197
			if (localFile != null) {
198
				// check if the cached file is still valid (no newer version on server)
199
				if (UpdateManagerUtils.isSameTimestamp(reference.asURL(), localFile.lastModified())) {
200
					LockManager.returnLock(key);
201
					return reference.createContentReference(reference.getIdentifier(), localFile);
202
				}
203
			}
204
205
			try {
206
				//don't have jar, check for pack.gz
207
				URL packGZURL = new URL(reference.asURL().toExternalForm() + ".pack.gz"); //$NON-NLS-1$
208
				packedRef = asLocalReference(new JarContentReference(reference.getIdentifier(), packGZURL), monitor);
209
			} catch (IOException e) {
210
				//no pack.gz
211
			}
212
		}
213
		
214
		if (packedRef == null) {
215
			//no pack.gz on server, get normal jar
216
			return asLocalReference(reference, monitor);
217
		}
218
219
		synchronized (jarLock) {
220
			String packed = packedRef.toString();
221
			Object packedLock = LockManager.getLock(packed);
222
			synchronized (packedLock) {
223
				try {
224
					File tempFile = packedRef.asFile();
225
					long timeStamp = tempFile.lastModified();
226
	
227
					JarProcessor processor = JarProcessor.getUnpackProcessor(null);
228
					processor.setWorkingDirectory(tempFile.getParent());
229
	
230
					File packedFile = new File(tempFile.toString() + ".pack.gz"); //$NON-NLS-1$
231
					tempFile.renameTo(packedFile);
232
					//unpacking the jar will strip the ".pack.gz" and leave us back with the original filename
233
					processor.processJar(packedFile);
234
	
235
					tempFile.setLastModified(timeStamp);
236
					Utilities.mapLocalFile(key, tempFile);
237
				} finally {
238
					LockManager.returnLock(packed);
239
					LockManager.returnLock(key);
240
				}
241
			}
242
		}
243
		return packedRef;
244
	}
180
	/*
245
	/*
181
	 * @see IFeatureContentProvider#getNonPluginEntryArchiveReferences(INonPluginEntry)
246
	 * @see IFeatureContentProvider#getNonPluginEntryArchiveReferences(INonPluginEntry)
182
	 */
247
	 */
(-)src/org/eclipse/update/internal/core/ExtendedSite.java (-1 / +30 lines)
Lines 1-3 Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
1
package org.eclipse.update.internal.core;
11
package org.eclipse.update.internal.core;
2
12
3
import java.util.ArrayList;
13
import java.util.ArrayList;
Lines 12-18 Link Here
12
	private String[] availableLocals;
22
	private String[] availableLocals;
13
	private String digestURL;
23
	private String digestURL;
14
	private LiteFeature[] liteFeatures;
24
	private LiteFeature[] liteFeatures;
15
	
25
	private boolean pack200 = false;
16
	
26
	
17
	public String getDigestURL() {
27
	public String getDigestURL() {
18
		return digestURL;
28
		return digestURL;
Lines 55-60 Link Here
55
		this.liteFeatures = liteFeatures;
65
		this.liteFeatures = liteFeatures;
56
	}
66
	}
57
	
67
	
68
	
69
	/**
70
	 * Get whether or not this site may contain jars packed with pack200.
71
	 * The packed version of foo.jar, is expected to be foo.jar.pack.gz
72
	 * @return
73
	 */
74
	public boolean supportsPack200() {
75
		return pack200;
76
	}
77
	
78
	/**
79
	 * Set whether or not this site may contain jars packed with pack200
80
	 * The packed version of foo.jar is expected to be foo.jar.pack.gz
81
	 * @param pack
82
	 */
83
	public void setSupportsPack200(boolean pack){
84
		pack200 = pack;
85
	}
86
	
58
	/*
87
	/*
59
	 * Method filterFeatures.
88
	 * Method filterFeatures.
60
	 * Also implemented in Feature
89
	 * Also implemented in Feature
(-)src/org/eclipse/update/core/model/DefaultSiteParser.java (-1 / +6 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2005 IBM Corporation and others.
2
 * Copyright (c) 2000, 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 514-519 Link Here
514
				site.setMirrorsURLString(mirrorsURL);
514
				site.setMirrorsURLString(mirrorsURL);
515
		}
515
		}
516
		
516
		
517
		String pack200 = attributes.getValue("pack200"); //$NON-NLS-1$
518
		if(site instanceof ExtendedSite && pack200 != null && new Boolean(pack200).booleanValue()){
519
			((ExtendedSite) site).setSupportsPack200(true);
520
		}
521
		
517
		if ( (site instanceof ExtendedSite) && (attributes.getValue("digestURL") != null)) { //$NON-NLS-1$
522
		if ( (site instanceof ExtendedSite) && (attributes.getValue("digestURL") != null)) { //$NON-NLS-1$
518
			ExtendedSite extendedSite = (ExtendedSite) site;
523
			ExtendedSite extendedSite = (ExtendedSite) site;
519
			extendedSite.setDigestExist(true);
524
			extendedSite.setDigestExist(true);
(-)src/org/eclipse/update/internal/jarprocessor/PackStep.java (+101 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.File;
14
import java.io.IOException;
15
import java.util.*;
16
17
public class PackStep extends CommandStep {
18
19
	protected static String packCommand = null;
20
	private static Boolean canPack = null;
21
22
	private Set exclusions = Collections.EMPTY_SET;
23
24
	public static boolean canPack() {
25
		if (canPack != null)
26
			return canPack.booleanValue();
27
28
		String[] locations = Utils.getPack200Commands("pack200"); //$NON-NLS-1$
29
		if (locations == null) {
30
			canPack = Boolean.FALSE;
31
			packCommand = null;
32
			return false;
33
		}
34
35
		int result;
36
		for (int i = 0; i < locations.length; i++) {
37
			if (locations[i] == null)
38
				continue;
39
			try {
40
				result = execute(new String[] {locations[i], "-V"}); //$NON-NLS-1$
41
				if (result == 0) {
42
					packCommand = locations[i];
43
					canPack = Boolean.TRUE;
44
					return true;
45
				}
46
			} catch (IOException e) {
47
				//no good
48
			}
49
		}
50
51
		canPack = Boolean.FALSE;
52
		return false;
53
	}
54
55
	public PackStep(Properties options) {
56
		super(options, null, null);
57
		exclusions = Utils.getPackExclusions(options);
58
	}
59
60
	public String recursionEffect(String entryName) {
61
		if (canPack() && entryName.endsWith(".jar") && !exclusions.contains(entryName)) { //$NON-NLS-1$
62
			return entryName + Utils.PACKED_SUFFIX;
63
		}
64
		return null;
65
	}
66
67
	public File preProcess(File input, File workingDirectory) {
68
		return null;
69
	}
70
71
	public File postProcess(File input, File workingDirectory) {
72
		if (canPack() && packCommand != null) {
73
			File outputFile = new File(workingDirectory, input.getName() + Utils.PACKED_SUFFIX);
74
			try {
75
				String[] cmd = getCommand(input, outputFile);
76
				execute(cmd);
77
			} catch (IOException e) {
78
				//didn't work
79
				return null;
80
			}
81
			return outputFile;
82
		}
83
		return null;
84
	}
85
86
	protected String[] getCommand(File input, File outputFile) throws IOException {
87
		String[] cmd = null;
88
		String arguments = getOptions().getProperty(input.getName() + ".pack.args"); //$NON-NLS-1$
89
		if (arguments != null) {
90
			String[] args = arguments.split(",\\s*"); //$NON-NLS-1$
91
			cmd = new String[3 + args.length];
92
			cmd[0] = packCommand;
93
			System.arraycopy(args, 0, cmd, 1, args.length);
94
			cmd[cmd.length - 2] = outputFile.getCanonicalPath();
95
			cmd[cmd.length - 1] = input.getCanonicalPath();
96
		} else {
97
			cmd = new String[] {packCommand, outputFile.getCanonicalPath(), input.getCanonicalPath()};
98
		}
99
		return cmd;
100
	}
101
}
(-)src/org/eclipse/update/internal/jarprocessor/SignCommandStep.java (+94 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.*;
14
import java.util.*;
15
import java.util.jar.*;
16
17
/**
18
 * @author aniefer
19
 *
20
 */
21
public class SignCommandStep extends CommandStep {
22
	private Set exclusions = null;
23
24
	public SignCommandStep(Properties options, String command) {
25
		super(options, command, ".jar"); //$NON-NLS-1$
26
		exclusions = Utils.getSignExclusions(options);
27
	}
28
29
	/* (non-Javadoc)
30
	 * @see org.eclipse.update.jarprocessor.IProcessStep#recursionEffect(java.lang.String)
31
	 */
32
	public String recursionEffect(String entryName) {
33
		if (entryName.endsWith(extension) && !exclusions.contains(entryName))
34
			return entryName;
35
		return null;
36
	}
37
38
	/* (non-Javadoc)
39
	 * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
40
	 */
41
	public File preProcess(File input, File workingDirectory) {
42
		return null;
43
	}
44
45
	/* (non-Javadoc)
46
	 * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
47
	 */
48
	public File postProcess(File input, File workingDirectory) {
49
		if (command != null) {
50
			try {
51
				String[] cmd = new String[] {command, input.getCanonicalPath()};
52
				int result = execute(cmd);
53
				if (result == 0) {
54
					normalize(input, workingDirectory);
55
					return input;
56
				}
57
			} catch (IOException e) {
58
				//boo
59
				e.printStackTrace();
60
			}
61
		}
62
		return null;
63
	}
64
65
	private void normalize(File input, File workingDirectory) {
66
		try {
67
			File tempJar = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
68
			JarFile jar = new JarFile(input);
69
			JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(tempJar)));
70
			InputStream in = null;
71
			try {
72
				Enumeration entries = jar.entries();
73
				for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
74
					JarEntry newEntry = new JarEntry(entry.getName());
75
					newEntry.setTime(entry.getTime());
76
					in = new BufferedInputStream(jar.getInputStream(entry));
77
					jarOut.putNextEntry(newEntry);
78
					Utils.transferStreams(in, jarOut, false);
79
					jarOut.closeEntry();
80
					in.close();
81
				}
82
			} finally {
83
				Utils.close(jarOut);
84
				Utils.close(jar);
85
				Utils.close(in);
86
			}
87
			tempJar.setLastModified(input.lastModified());
88
			input.delete();
89
			tempJar.renameTo(input);
90
		} catch (IOException e) {
91
			//boo
92
		}
93
	}
94
}
(-)src/org/eclipse/update/internal/core/LockManager.java (+39 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.core;
12
13
import java.util.Hashtable;
14
15
/**
16
 * @author aniefer
17
 *
18
 */
19
public class LockManager {
20
	// lock
21
	private final static Object lock = new Object();
22
23
	// hashtable of locks
24
	private static Hashtable locks = new Hashtable();
25
	
26
	public static Object getLock(String key) {
27
		synchronized (lock) {
28
			if (locks.get(key) == null)
29
				locks.put(key, key);
30
			return locks.get(key);
31
		}
32
	}
33
	
34
	public static void returnLock(String key) {
35
		synchronized (lock) {
36
			locks.remove(key);
37
		}
38
	}
39
}
(-)src/org/eclipse/update/internal/jarprocessor/CommandStep.java (+48 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.IOException;
14
import java.util.Properties;
15
16
/**
17
 * @author aniefer
18
 *
19
 */
20
public abstract class CommandStep implements IProcessStep {
21
	protected String command = null;
22
	protected String extension = null;
23
	private  Properties options = null;
24
	
25
	public CommandStep(Properties options, String command, String extension) {
26
		this.command = command;
27
		this.extension = extension;
28
		this.options = options;
29
	}
30
31
	protected static int execute(String[] cmd) throws IOException {
32
		Runtime runtime = Runtime.getRuntime();
33
		Process proc = runtime.exec(cmd);
34
		try {
35
			int result = proc.waitFor();
36
			return result;
37
		} catch (InterruptedException e) {
38
			//ignore
39
		}
40
		return -1;
41
	}
42
	
43
	public Properties getOptions() {
44
		if(options == null)
45
			options = new Properties();
46
		return options;
47
	}
48
}
(-)src/org/eclipse/update/internal/jarprocessor/Main.java (+151 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.*;
14
import java.util.zip.ZipException;
15
16
/**
17
 * @author aniefer
18
 *
19
 */
20
public class Main {
21
22
	public static class Options {
23
		public String outputDir = "."; //$NON-NLS-1$
24
		public String signCommand = null;
25
		public boolean pack = false;
26
		public boolean repack = false;
27
		public boolean unpack = false;
28
		public File input = null;
29
	}
30
31
	private static void printUsage() {
32
		System.out.println("[-option ...]... input"); //$NON-NLS-1$
33
		System.out.println("The following options are supported:"); //$NON-NLS-1$
34
		System.out.println("-repack         normalize jars "); //$NON-NLS-1$
35
		System.out.println("-sign <command> sign jars using <command>"); //$NON-NLS-1$
36
		System.out.println("-pack           pack the jars.  pack and repack are redundant unless"); //$NON-NLS-1$
37
		System.out.println("                sign is also specified."); //$NON-NLS-1$
38
		System.out.println("-unpack         unpack pack.gz files. Unpack is mutually exclusive"); //$NON-NLS-1$
39
		System.out.println("                with repack, sign and pack."); //$NON-NLS-1$
40
		System.out.println();
41
		System.out.println("-outputDir <dir>  the output directory"); //$NON-NLS-1$
42
	}
43
44
	public static Options processArguments(String[] args) {
45
		if (args.length == 0) {
46
			printUsage();
47
			return null;
48
		}
49
50
		Options options = new Options();
51
		int i = 0;
52
		for (; i < args.length - 1; i++) {
53
			if (args[i].equals("-pack")) {//$NON-NLS-1$
54
				options.pack = true;
55
			} else if (args[i].equals("-unpack")) { //$NON-NLS-1$
56
				options.unpack = true;
57
			} else if (args[i].equals("-sign") && i < args.length - 2) { //$NON-NLS-1$
58
				if (args[i + 1].startsWith("-")) { //$NON-NLS-1$
59
					printUsage();
60
					return null;
61
				}
62
				options.signCommand = args[++i];
63
			} else if (args[i].equals("-repack")) { //$NON-NLS-1$
64
				options.repack = true;
65
			} else if (args[i].equals("-outputDir") && i < args.length - 2) { //$NON-NLS-1$
66
				if (args[i + 1].startsWith("-")) { //$NON-NLS-1$
67
					printUsage();
68
					return null;
69
				}
70
				options.outputDir = args[++i];
71
			}
72
		}
73
74
		options.input = new File(args[i]);
75
76
		String problemMessage = null;
77
		if (options.unpack) {
78
			if (!JarProcessor.canPerformUnpack()) {
79
				problemMessage = "The unpack200 command cannot be found."; //$NON-NLS-1$
80
			} else 	if (options.input.isFile() && !args[i].endsWith(".zip") && !args[i].endsWith(".pack.gz")) { //$NON-NLS-1$ //$NON-NLS-2$
81
				problemMessage = "Input file is not a pack.gz file."; //$NON-NLS-1$
82
			} else 	if (options.pack || options.repack || options.signCommand != null) {
83
				problemMessage = "Pack, repack or sign cannot be specified with unpack."; //$NON-NLS-1$
84
			}
85
		} else {
86
			if (options.input.isFile() && !args[i].endsWith(".zip") && !args[i].endsWith(".jar")) { //$NON-NLS-1$ //$NON-NLS-2$
87
				problemMessage = "Input file is not a jar file."; //$NON-NLS-1$
88
			} else	if ((options.pack || options.repack) && !JarProcessor.canPerformPack()) {
89
				problemMessage = "The pack200 command can not be found."; //$NON-NLS-1$
90
			}
91
		}
92
		if(problemMessage != null){
93
			System.out.println(problemMessage);
94
			System.out.println();
95
			printUsage();
96
			return null;
97
		}
98
99
		return options;
100
	}
101
102
	/**
103
	 * @param args
104
	 * @throws FileNotFoundException 
105
	 */
106
	public static void main(String[] args) {
107
		Options options = processArguments(args);
108
		if (options == null)
109
			return;
110
111
		if (options.input.getName().endsWith(".zip")) { //$NON-NLS-1$
112
			ZipProcessor processor = new ZipProcessor();
113
			processor.setWorkingDirectory(options.outputDir);
114
			processor.setSignCommand(options.signCommand);
115
			processor.setPack(options.pack);
116
			processor.setRepack(options.repack || (options.pack && options.signCommand != null));
117
			processor.setUnpack(options.unpack);
118
			try {
119
				processor.processZip(options.input);
120
			} catch (ZipException e) {
121
				// TODO Auto-generated catch block
122
				e.printStackTrace();
123
			} catch (IOException e) {
124
				// TODO Auto-generated catch block
125
				e.printStackTrace();
126
			}
127
		} else {
128
			JarProcessor processor = new JarProcessor();
129
			processor.setWorkingDirectory(options.outputDir);
130
131
			if (options.repack || (options.pack && options.signCommand != null))
132
				processor.addProcessStep(new PackUnpackStep(null));
133
134
			if (options.signCommand != null)
135
				processor.addProcessStep(new SignCommandStep(null, options.signCommand));
136
137
			if (options.pack)
138
				processor.addProcessStep(new PackStep(null));
139
			else if (options.unpack)
140
				processor.addProcessStep(new UnpackStep(null));
141
142
			try {
143
				processor.process(options.input, options.unpack ? Utils.PACK_GZ_FILTER : Utils.JAR_FILTER);
144
			} catch (FileNotFoundException e) {
145
				// TODO Auto-generated catch block
146
				e.printStackTrace();
147
			}
148
		}
149
	}
150
151
}
(-)src/org/eclipse/update/internal/jarprocessor/pack-readme.html (+82 lines)
Added Link Here
1
<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
2
<html>
3
<head>
4
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5
  <title>Eclipse update packing tool readme</title>
6
</head>
7
<body>
8
<h1>Eclipse update packing tool</h1>
9
10
<h3>Overview</h3>
11
The update packing tool processes a hierarchy of arbitrarily nested
12
JARs and ZIP files.  It is a generic utility that performs a depth first traversal of 
13
a nested hierarchy of ZIPs and JARs, performs various commands on
14
each of the JARs in the hierarchy, and then rebuilds the same hierarchy
15
of ZIPs and JARs again.  Currently its main functions are:
16
<ul>
17
	<li>Packing JARs using the Java 1.5 <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/pack200.html">pack200</a>
18
	 command.</li>
19
	 <li>Unpacking PACK.GZs using the Java 1.5 <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/unpack200.html">unpack200</a>
20
	 command.</li>
21
	 <li>Normalizing JARs for future compression by pack200. This is accomplished
22
	 by running the pack200 command with the <tt>--repack</tt> command line argument.</li>
23
	 <li>Signing JARs to allow for authentication of the origin of JARs. This is accomplished by
24
	 running a supplied command (typically the command will just be a wrapper around
25
	 the Java <a href="http://java.sun.com/j2se/1.3/docs/tooldocs/win32/jarsigner.html">jarsigner</a> tool).</li>
26
</ul>
27
The packing tool is used in the following contexts:
28
<ul>
29
	<li>During a PDE build, to prepare JARs for uploading to an Eclipse
30
	update site.  In this usage, it is used to both nomalize JAR contents
31
	(pack200 -repack), and sign JARs.</li>
32
	<li>On an update site, to convert traditional JAR content into the 
33
	compressed pack200 format.</li>
34
	<li>From an Eclipse client application during update, to convert
35
	compressed pack200 format content into executable JAR files.</li>
36
</ul>
37
<h3>Tool usage</h3>
38
To run the packing tool, you need a 1.5 JRE installed. The tool is run
39
by invoking Java as follows:
40
41
<pre>
42
	java jarprocessor.jar [options] input
43
</pre>
44
45
Where <tt>input</tt> is either a zip file, a directory, or a JAR (or a pack.gz file). All files ending 
46
in ".jar" or ".pack.gz" in the provided zip or directory hierarchy
47
will be processed. 
48
The following additional command line arguments are supported:
49
<ul>
50
<li>-repack : Normalize the jars using pack200 <tt>--repack</tt></li>
51
<li>-sign &lt;cmd&gt; : signs the jars by executing the provided command.  
52
The command will be provided a single argument that will be the full path of the JAR to process.
53
</li>
54
<li>-pack : for each input in JAR form, produce a corresponding output
55
in packed form.  For an input "a.jar", the output is a.jar.pack.gz.  
56
</li>
57
<li>-unpack : for each input in packed form, produce a corresponding output
58
in unpacked form.  For an input "a.jar.pack.gz", the output is "a.jar". -unpack is mutually exclusive with -repack, -pack and -sign.</li>
59
<li>-outputDir &lt;dir&gt; : The directory to put the tool's output into.  If the input was a zip file, then an output zip file will be
60
created containg all the output files.  If the input was a directory, for each input file there is a corresponding output file in the output directory. By default the current working directory is used.  If the input is in the same
61
directory as the output, the input files may be overwritten.</li>
62
</ul>
63
64
Additionally, when the input is a zip file, it may contain a file called
65
<tt>pack.properties</tt>.  The pack.properties file supports the following values:
66
<ul>
67
<li>pack.excludes =  jarName[, jarName]* : A comma-delimited list of JARs that should not be packed or repacked.
68
</li>
69
<li>sign.excludes =  jarName[, jarName]* : A comma-delimited list of JARs that should not be signed.
70
</li>
71
<li>&lt;jarname&gt;.pack.args = option[, option]* : A comma-delimited list of additional arguments that should
72
be passed to pack200 when packing any jar with name &lt;jarname&gt;.
73
</ul>
74
</p>
75
<p>
76
<font size=-1>
77
Copyright (c) IBM Corporation and others 2006. All rights reserved. This program and the accompanying materials
78
are made available under the terms of the 
79
<a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License v1.0</a>.
80
</font>
81
</body>
82
</html>
(-)src/org/eclipse/update/internal/jarprocessor/Utils.java (+178 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.*;
14
import java.util.*;
15
import java.util.jar.JarFile;
16
17
/**
18
 * @author aniefer
19
 *
20
 */
21
public class Utils {
22
	public static final String PACK200_PROPERTY = "org.eclipse.update.jarprocessor.pack200"; //$NON-NLS-1$
23
	public static final String JRE = "@jre"; //$NON-NLS-1$
24
	public static final String PATH = "@path"; //$NON-NLS-1$
25
	public static final String NONE = "@none"; //$NON-NLS-1$
26
27
	public static final String PACKED_SUFFIX = ".pack.gz"; //$NON-NLS-1$
28
	public static final String JAR_SUFFIX = ".jar"; //$NON-NLS-1$
29
30
	public static final FileFilter JAR_FILTER = new FileFilter() {
31
		public boolean accept(File pathname) {
32
			return pathname.isFile() && pathname.getName().endsWith(".jar"); //$NON-NLS-1$
33
		}
34
	};
35
36
	public static final FileFilter PACK_GZ_FILTER = new FileFilter() {
37
		public boolean accept(File pathname) {
38
			return pathname.isFile() && pathname.getName().endsWith(PACKED_SUFFIX);
39
		}
40
	};
41
42
	public static void close(Object stream) {
43
		if (stream != null) {
44
			try {
45
				if (stream instanceof InputStream)
46
					((InputStream) stream).close();
47
				else if (stream instanceof OutputStream)
48
					((OutputStream) stream).close();
49
				else if (stream instanceof JarFile)
50
					((JarFile) stream).close();
51
			} catch (IOException e) {
52
				//ignore
53
			}
54
		}
55
	}
56
57
	/**
58
	 * get the set of commands to try to execute pack/unpack 
59
	 * @param cmd, the command, either "pack200" or "unpack200"
60
	 * @return String [] or null
61
	 */
62
	public static String[] getPack200Commands(String cmd) {
63
		String[] locations = null;
64
		String prop = System.getProperty(PACK200_PROPERTY);
65
		String javaHome = System.getProperty("java.home"); //$NON-NLS-1$
66
		if (NONE.equals(prop)) {
67
			return null;
68
		} else if (JRE.equals(prop)) {
69
			locations = new String[] {javaHome + "/bin/" + cmd}; //$NON-NLS-1$
70
		} else if (PATH.equals(prop)) {
71
			locations = new String[] {cmd};
72
		} else if (prop == null) {
73
			locations = new String[] {javaHome + "/bin/" + cmd, cmd}; //$NON-NLS-1$ 
74
		} else {
75
			locations = new String[] {prop + "/" + cmd}; //$NON-NLS-1$
76
		}
77
		return locations;
78
	}
79
80
	/**
81
	 * Transfers all available bytes from the given input stream to the given
82
	 * output stream. Closes both streams if close == true, regardless of failure. 
83
	 * Flushes the destination stream if close == false
84
	 * 
85
	 * @param source
86
	 * @param destination
87
	 * @param close 
88
	 * @throws IOException
89
	 */
90
	public static void transferStreams(InputStream source, OutputStream destination, boolean close) throws IOException {
91
		source = new BufferedInputStream(source);
92
		destination = new BufferedOutputStream(destination);
93
		try {
94
			byte[] buffer = new byte[8192];
95
			while (true) {
96
				int bytesRead = -1;
97
				if ((bytesRead = source.read(buffer)) == -1)
98
					break;
99
				destination.write(buffer, 0, bytesRead);
100
			}
101
		} finally {
102
			if (close) {
103
				close(source);
104
				close(destination);
105
			} else {
106
				destination.flush();
107
			}
108
		}
109
	}
110
111
	/**
112
	 * Deletes all the files and directories from the given root down (inclusive).
113
	 * Returns false if we could not delete some file or an exception occurred
114
	 * at any point in the deletion.
115
	 * Even if an exception occurs, a best effort is made to continue deleting.
116
	 */
117
	public static boolean clear(java.io.File root) {
118
		boolean result = clearChildren(root);
119
		try {
120
			if (root.exists())
121
				result &= root.delete();
122
		} catch (Exception e) {
123
			result = false;
124
		}
125
		return result;
126
	}
127
128
	/**
129
	 * Deletes all the files and directories from the given root down, except for 
130
	 * the root itself.
131
	 * Returns false if we could not delete some file or an exception occurred
132
	 * at any point in the deletion.
133
	 * Even if an exception occurs, a best effort is made to continue deleting.
134
	 */
135
	public static boolean clearChildren(java.io.File root) {
136
		boolean result = true;
137
		if (root.isDirectory()) {
138
			String[] list = root.list();
139
			// for some unknown reason, list() can return null.  
140
			// Just skip the children If it does.
141
			if (list != null)
142
				for (int i = 0; i < list.length; i++)
143
					result &= clear(new java.io.File(root, list[i]));
144
		}
145
		return result;
146
	}
147
148
	public static Set getPackExclusions(Properties properties) {
149
		if (properties == null)
150
			return Collections.EMPTY_SET;
151
152
		String packExcludes = properties.getProperty("pack.excludes"); //$NON-NLS-1$
153
		if (packExcludes != null) {
154
			String[] excludes = packExcludes.split(",\\s*"); //$NON-NLS-1$
155
			Set packExclusions = new HashSet();
156
			for (int i = 0; i < excludes.length; i++) {
157
				packExclusions.add(excludes[i]);
158
			}
159
			return packExclusions;
160
		}
161
		return Collections.EMPTY_SET;
162
	}
163
164
	public static Set getSignExclusions(Properties properties) {
165
		if (properties == null)
166
			return Collections.EMPTY_SET;
167
		String signExcludes = properties.getProperty("sign.excludes"); //$NON-NLS-1$
168
		if (signExcludes != null) {
169
			String[] excludes = signExcludes.split(",\\s*"); //$NON-NLS-1$
170
			Set signExclusions = new HashSet();
171
			for (int i = 0; i < excludes.length; i++) {
172
				signExclusions.add(excludes[i]);
173
			}
174
			return signExclusions;
175
		}
176
		return Collections.EMPTY_SET;
177
	}
178
}
(-)src/org/eclipse/update/internal/jarprocessor/UnpackStep.java (+109 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.File;
14
import java.io.IOException;
15
import java.util.Properties;
16
17
/**
18
 * @author aniefer
19
 *
20
 */
21
public class UnpackStep extends CommandStep {
22
	public static final String UNPACKER_PROPERTY = "org.eclipse.update.jarprocessor.Unpacker"; //$NON-NLS-1$
23
	private static Boolean canUnpack = null;
24
	private static String unpackCommand = null;
25
26
	public static boolean canUnpack() {
27
		if (canUnpack != null)
28
			return canUnpack.booleanValue();
29
30
		String[] locations = Utils.getPack200Commands("unpack200"); //$NON-NLS-1$
31
		if (locations == null) {
32
			canUnpack = Boolean.FALSE;
33
			unpackCommand = null;
34
			return false;
35
		}
36
37
		int result;
38
		for (int i = 0; i < locations.length; i++) {
39
			if (locations[i] == null)
40
				continue;
41
			try {
42
				result = execute(new String[] {locations[i], "-V"}); //$NON-NLS-1$
43
				if (result == 0) {
44
					unpackCommand = locations[i];
45
					canUnpack = Boolean.TRUE;
46
					return true;
47
				}
48
			} catch (IOException e) {
49
				//no good
50
			}
51
		}
52
53
		canUnpack = Boolean.FALSE;
54
		return false;
55
	}
56
57
	public UnpackStep(Properties options) {
58
		super(options, null, null);
59
	}
60
61
	/* (non-Javadoc)
62
	 * @see org.eclipse.update.jarprocessor.IProcessStep#recursionEffect(java.lang.String)
63
	 */
64
	public String recursionEffect(String entryName) {
65
		if (canUnpack() && entryName.endsWith(Utils.PACKED_SUFFIX)) {
66
			return entryName.substring(0, entryName.length() - Utils.PACKED_SUFFIX.length());
67
		}
68
		return null;
69
	}
70
71
	/* (non-Javadoc)
72
	 * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
73
	 */
74
	public File preProcess(File input, File workingDirectory) {
75
		if (canUnpack() && unpackCommand != null) {
76
			String name = input.getName();
77
			if (name.endsWith(Utils.PACKED_SUFFIX)) {
78
				name = name.substring(0, name.length() - Utils.PACKED_SUFFIX.length());
79
80
				File unpacked = new File(workingDirectory, name);
81
				File parent = unpacked.getParentFile();
82
				if (!parent.exists())
83
					parent.mkdirs();
84
				try {
85
					String options = getOptions().getProperty(input.getName() + ".unpack.args"); //$NON-NLS-1$
86
					String[] cmd = null;
87
					if (options != null) {
88
						cmd = new String[] {unpackCommand, options, input.getCanonicalPath(), unpacked.getCanonicalPath()};
89
					} else {
90
						cmd = new String[] {unpackCommand, input.getCanonicalPath(), unpacked.getCanonicalPath()};
91
					}
92
					execute(cmd);
93
				} catch (IOException e) {
94
					//didn't work
95
					return null;
96
				}
97
				return unpacked;
98
			}
99
		}
100
		return null;
101
	}
102
103
	/* (non-Javadoc)
104
	 * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
105
	 */
106
	public File postProcess(File input, File workingDirectory) {
107
		return null;
108
	}
109
}
(-)src/org/eclipse/update/internal/jarprocessor/jarprocessor.jardesc (+28 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<jardesc>
3
    <jar path="org.eclipse.update.core/jarprocessor.jar"/>
4
    <options overwrite="false" compress="true" exportErrors="true" exportWarnings="true" saveDescription="false" descriptionLocation="/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/jarprocessor.jardesc" useSourceFolders="false" buildIfNeeded="true" includeDirectoryEntries="false" storeRefactorings="false"/>
5
    <refactoring structuralOnly="false" deprecationInfo="true"/>
6
    <selectedProjects>
7
        <project name="org.eclipse.update.core"/>
8
    </selectedProjects>
9
    <manifest manifestVersion="1.0" usesManifest="true" reuseManifest="false" saveManifest="false" generateManifest="true" manifestLocation="" mainClassHandleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{Main.java[Main">
10
        <sealing sealJar="false">
11
            <packagesToSeal/>
12
            <packagesToUnSeal/>
13
        </sealing>
14
    </manifest>
15
    <selectedElements exportClassFiles="true" exportOutputFolder="false" exportJavaFiles="true">
16
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{JarProcessor.java"/>
17
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{PackUnpackStep.java"/>
18
        <file path="/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/pack-readme.html"/>
19
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{CommandStep.java"/>
20
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{IProcessStep.java"/>
21
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{ZipProcessor.java"/>
22
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{Main.java"/>
23
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{Utils.java"/>
24
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{UnpackStep.java"/>
25
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{PackStep.java"/>
26
        <javaElement handleIdentifier="=org.eclipse.update.core/src&lt;org.eclipse.update.internal.jarprocessor{SignCommandStep.java"/>
27
    </selectedElements>
28
</jardesc>
(-)src/org/eclipse/update/internal/jarprocessor/IProcessStep.java (+47 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.File;
14
15
/**
16
 * @author aniefer
17
 *
18
 */
19
public interface IProcessStep {
20
	
21
	/**
22
	 * The effect of this processing step if the JarProcessor was to recurse on this entry.
23
	 * Return null if this step will not do anything with this entry.
24
	 * Return the new entryName if this step will modify this entry on recursion.
25
	 * @param entryName
26
	 * @return
27
	 */
28
	String recursionEffect(String entryName);
29
	
30
	/**
31
	 * Perform some processing on the input file before the JarProcessor considers the entries for recursion.
32
	 *  return the file containing the result of the processing
33
	 * @param input
34
	 * @param workingDirectory
35
	 * @return
36
	 */
37
	File preProcess(File input, File workingDirectory);
38
	
39
	/**
40
	 * Perform some processing on the input file after the JarProcessor returns from recursion
41
	 * return the file containing the result of the processing
42
	 * @param input
43
	 * @param workingDirectory
44
	 * @return
45
	 */
46
	File postProcess(File input, File workingDirectory);
47
}
(-)src/org/eclipse/update/internal/jarprocessor/JarProcessor.java (+270 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.*;
14
import java.util.*;
15
import java.util.jar.*;
16
17
/**
18
 * @author aniefer
19
 *
20
 */
21
public class JarProcessor {
22
	private List steps = new ArrayList();
23
	private String workingDirectory = ""; //$NON-NLS-1$
24
	private int depth = -1;
25
26
	static public JarProcessor getUnpackProcessor(Properties properties) {
27
		if (!canPerformUnpack())
28
			throw new UnsupportedOperationException();
29
		JarProcessor processor = new JarProcessor();
30
		processor.addProcessStep(new UnpackStep(properties));
31
		return processor;
32
	}
33
34
	static public JarProcessor getPackProcessor(Properties properties) {
35
		if (!canPerformPack())
36
			throw new UnsupportedOperationException();
37
		JarProcessor processor = new JarProcessor();
38
		processor.addProcessStep(new PackStep(properties));
39
		return processor;
40
	}
41
42
	static public boolean canPerformPack() {
43
		return PackStep.canPack();
44
	}
45
46
	static public boolean canPerformUnpack() {
47
		return UnpackStep.canUnpack();
48
	}
49
50
	public String getWorkingDirectory() {
51
		return workingDirectory;
52
	}
53
54
	public void setWorkingDirectory(String dir) {
55
		workingDirectory = dir;
56
	}
57
58
	public void addProcessStep(IProcessStep step) {
59
		steps.add(step);
60
	}
61
62
	public void clearProcessSteps() {
63
		steps.clear();
64
	}
65
66
	public void process(File input, FileFilter filter) throws FileNotFoundException {
67
		if (!input.exists())
68
			throw new FileNotFoundException();
69
70
		File[] files = null;
71
		if (input.isDirectory()) {
72
			files = input.listFiles();
73
		} else if (filter.accept(input)) {
74
			files = new File[] {input};
75
		}
76
		for (int i = 0; i < files.length; i++) {
77
			System.out.println("Processing " + files[i].getName()); //$NON-NLS-1$
78
			if (files[i].isDirectory()) {
79
				String dir = getWorkingDirectory();
80
				setWorkingDirectory(dir + "/" + files[i].getName()); //$NON-NLS-1$
81
				process(files[i], filter);
82
				setWorkingDirectory(dir);
83
			} else if (filter.accept(files[i])) {
84
				try {
85
					processJar(files[i]);
86
				} catch (IOException e) {
87
					// TODO Auto-generated catch block
88
					e.printStackTrace();
89
				}
90
			}
91
		}
92
	}
93
94
	/**
95
	 * Recreate a jar file.  The replacements map specifies entry names to be replaced, the replacements are
96
	 * expected to be found in directory.
97
	 * 
98
	 * @param jar - The input jar
99
	 * @param outputJar - the output
100
	 * @param replacements - map of entryName -> new entryName
101
	 * @param directory - location to find file for new entryName
102
	 * @throws IOException
103
	 */
104
	private void recreateJar(JarFile jar, JarOutputStream outputJar, Map replacements, File directory) throws IOException {
105
		InputStream in = null;
106
		try {
107
			Enumeration entries = jar.entries();
108
			for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
109
				File replacement = null;
110
				JarEntry newEntry = null;
111
				if (replacements.containsKey(entry.getName())) {
112
					String name = (String) replacements.get(entry.getName());
113
					replacement = new File(directory, name);
114
					in = new BufferedInputStream(new FileInputStream(replacement));
115
					newEntry = new JarEntry(name);
116
				} else {
117
					in = new BufferedInputStream(jar.getInputStream(entry));
118
					newEntry = new JarEntry(entry.getName());
119
				}
120
				newEntry.setTime(entry.getTime());
121
				outputJar.putNextEntry(newEntry);
122
				Utils.transferStreams(in, outputJar, false);
123
				outputJar.closeEntry();
124
				in.close();
125
126
				//delete the nested jar file
127
				if (replacement != null) {
128
					replacement.delete();
129
				}
130
			}
131
		} finally {
132
			Utils.close(outputJar);
133
			Utils.close(jar);
134
			Utils.close(in);
135
		}
136
	}
137
138
	private String recursionEffect(String entryName) {
139
		String result = null;
140
		for (Iterator iter = steps.iterator(); iter.hasNext();) {
141
			IProcessStep step = (IProcessStep) iter.next();
142
143
			result = step.recursionEffect(entryName);
144
			if (result != null)
145
				entryName = result;
146
		}
147
		return result;
148
	}
149
150
	private void extractEntries(JarFile jar, File tempDir, Map data) throws IOException {
151
		Enumeration entries = jar.entries();
152
		if (entries.hasMoreElements()) {
153
			for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
154
				String name = entry.getName();
155
				String newName = recursionEffect(name);
156
				if (newName != null) {
157
					//extract entry to temp directory
158
					File extracted = new File(tempDir, name);
159
					File parentDir = extracted.getParentFile();
160
					if (!parentDir.exists())
161
						parentDir.mkdirs();
162
163
					InputStream in = null;
164
					OutputStream out = null;
165
					try {
166
						in = jar.getInputStream(entry);
167
						out = new BufferedOutputStream(new FileOutputStream(extracted));
168
						Utils.transferStreams(in, out, true); //this will close both streams
169
					} finally {
170
						Utils.close(in);
171
						Utils.close(out);
172
					}
173
					extracted.setLastModified(entry.getTime());
174
					data.put(name, newName);
175
176
					//recurse
177
					String dir = getWorkingDirectory();
178
					setWorkingDirectory(parentDir.getCanonicalPath());
179
					processJar(extracted);
180
					setWorkingDirectory(dir);
181
182
					//delete the extracted item leaving the recursion result
183
					if (!name.equals(newName))
184
						extracted.delete();
185
				}
186
			}
187
		}
188
	}
189
190
	private File preProcess(File input, File tempDir) {
191
		File result = null;
192
		for (Iterator iter = steps.iterator(); iter.hasNext();) {
193
			IProcessStep step = (IProcessStep) iter.next();
194
			result = step.preProcess(input, tempDir);
195
			if (result != null)
196
				input = result;
197
		}
198
		return input;
199
	}
200
201
	private File postProcess(File input, File tempDir) {
202
		File result = null;
203
		for (Iterator iter = steps.iterator(); iter.hasNext();) {
204
			IProcessStep step = (IProcessStep) iter.next();
205
			result = step.postProcess(input, tempDir);
206
			if (result != null)
207
				input = result;
208
		}
209
		return input;
210
	}
211
212
	public void processJar(File input) throws IOException {
213
		++depth;
214
		long lastModified = input.lastModified();
215
		File workingDir = new File(getWorkingDirectory());
216
		if (!workingDir.exists())
217
			workingDir.mkdirs();
218
219
		//pre
220
		File workingFile = preProcess(input, workingDir);
221
222
		//Extract entries from jar and recurse on them
223
		File tempDir = null;
224
		if (depth == 0) {
225
			tempDir = new File(workingDir, "temp." + workingFile.getName()); //$NON-NLS-1$
226
		} else {
227
			File parent = workingDir.getParentFile();
228
			tempDir = new File(parent, "temp_" + depth + '_' + workingFile.getName()); //$NON-NLS-1$
229
		}
230
231
		JarFile jar = new JarFile(workingFile, false);
232
		Map replacements = new HashMap();
233
		extractEntries(jar, tempDir, replacements);
234
235
		//Recreate the jar with replacements.  This also has the effect of normalizing the jar, so we want to do this even if
236
		//we aren't actually replacing anything
237
		File tempJar = null;
238
		tempJar = new File(tempDir, workingFile.getName());
239
		File parent = tempJar.getParentFile();
240
		if (!parent.exists())
241
			parent.mkdirs();
242
		JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(tempJar)));
243
		recreateJar(jar, jarOut, replacements, tempDir);
244
245
		jar.close();
246
		if (tempJar != null) {
247
			if (!workingFile.equals(input)) {
248
				workingFile.delete();
249
			}
250
			workingFile = tempJar;
251
		}
252
253
		//post
254
		File result = postProcess(workingFile, workingDir);
255
		if (!result.equals(workingFile) && !workingFile.equals(input))
256
			workingFile.delete();
257
		if (!result.getParentFile().equals(workingDir)) {
258
			File finalFile = new File(workingDir, result.getName());
259
			if (finalFile.exists())
260
				finalFile.delete();
261
			result.renameTo(finalFile);
262
		}
263
264
		if (tempDir.exists())
265
			Utils.clear(tempDir);
266
267
		result.setLastModified(lastModified);
268
		--depth;
269
	}
270
}
(-)src/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java (+73 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.File;
14
import java.io.IOException;
15
import java.util.Properties;
16
import java.util.Set;
17
18
/**
19
 * @author aniefer
20
 *
21
 */
22
public class PackUnpackStep extends PackStep {
23
	private Set exclusions = null;
24
	
25
	public PackUnpackStep(Properties options) {
26
		super(options);
27
		exclusions = Utils.getPackExclusions(options);
28
	}
29
30
	public String recursionEffect(String entryName) {
31
		if (canPack() && entryName.endsWith(".jar") &&  !exclusions.contains(entryName)) { //$NON-NLS-1$
32
			return entryName;
33
		}
34
		return null;
35
	}
36
37
	/* (non-Javadoc)
38
	 * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
39
	 */
40
	public File postProcess(File input, File workingDirectory) {
41
		if (canPack() && packCommand != null) {
42
			File tempFile = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
43
			try {
44
				String[] tmp = getCommand(input, tempFile);
45
				String[] cmd = new String[tmp.length + 1];
46
				cmd[0] = tmp[0];
47
				cmd[1] = "-r"; //$NON-NLS-1$
48
				System.arraycopy(tmp, 1, cmd, 2, tmp.length - 1);
49
50
				int result = execute(cmd);
51
				if (result == 0 && tempFile.exists()) {
52
					File finalFile = new File(workingDirectory, input.getName());
53
					if(finalFile.exists())
54
						finalFile.delete();
55
					tempFile.renameTo(finalFile);
56
					return finalFile;
57
				}
58
			} catch (IOException e) {
59
				//didn't work
60
				return null;
61
			}
62
		}
63
		return null;
64
	}
65
66
	/* (non-Javadoc)
67
	 * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
68
	 */
69
	public File preProcess(File input, File workingDirectory) {
70
		return null;
71
	}
72
73
}
(-)src/org/eclipse/update/internal/jarprocessor/ZipProcessor.java (+176 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM - Initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.update.internal.jarprocessor;
12
13
import java.io.*;
14
import java.util.*;
15
import java.util.zip.*;
16
17
/**
18
 * @author aniefer
19
 *
20
 */
21
public class ZipProcessor {
22
23
	private IProcessStep signStep = null;
24
	private IProcessStep packStep = null;
25
	private IProcessStep packUnpackStep = null;
26
	private IProcessStep unpackStep = null;
27
28
	private String workingDirectory = null;
29
	private Properties properties = null;
30
	private Set packExclusions = null;
31
	private Set signExclusions = null;
32
	private String command = null;
33
	private boolean packing = false;
34
	private boolean signing = false;
35
	private boolean repacking = false;
36
	private boolean unpacking = false;
37
38
	public void setWorkingDirectory(String dir) {
39
		workingDirectory = dir;
40
	}
41
42
	public String getWorkingDirectory() {
43
		if (workingDirectory == null)
44
			workingDirectory = "."; //$NON-NLS-1$
45
		return workingDirectory;
46
	}
47
48
	public void setSignCommand(String command) {
49
		this.command = command;
50
		this.signing = (command != null);
51
	}
52
53
	public void setPack(boolean pack) {
54
		this.packing = pack;
55
	}
56
57
	public void setRepack(boolean repack) {
58
		this.repacking = repack;
59
	}
60
61
	public void setUnpack(boolean unpack) {
62
		this.unpacking = unpack;
63
	}
64
65
	public void processZip(File zipFile) throws ZipException, IOException {
66
		ZipFile zip = new ZipFile(zipFile);
67
		initialize(zip);
68
69
		String extension = unpacking ? "pack.gz" : ".jar"; //$NON-NLS-1$ //$NON-NLS-2$
70
		File tempDir = new File(getWorkingDirectory(), "temp_" + zipFile.getName()); //$NON-NLS-1$
71
		JarProcessor processor = new JarProcessor();
72
		processor.setWorkingDirectory(tempDir.getCanonicalPath());
73
		if (unpacking) {
74
			processor.addProcessStep(unpackStep);
75
		}
76
77
		File outputFile = new File(getWorkingDirectory(), zipFile.getName() + ".temp"); //$NON-NLS-1$
78
		File parent = outputFile.getParentFile();
79
		if (!parent.exists())
80
			parent.mkdirs();
81
		ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(outputFile));
82
		Enumeration entries = zip.entries();
83
		if (entries.hasMoreElements()) {
84
			for (ZipEntry entry = (ZipEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (ZipEntry) entries.nextElement() : null) {
85
				String name = entry.getName();
86
87
				InputStream entryStream = zip.getInputStream(entry);
88
89
				boolean pack = packing && !packExclusions.contains(name);
90
				boolean sign = signing && !signExclusions.contains(name);
91
				boolean repack = repacking && !packExclusions.contains(name);
92
93
				File extractedFile = null;
94
95
				if (entry.getName().endsWith(extension) && (pack || sign || repack || unpacking)) {
96
					extractedFile = new File(tempDir, name);
97
					parent = extractedFile.getParentFile();
98
					if (!parent.exists())
99
						parent.mkdirs();
100
					FileOutputStream extracted = new FileOutputStream(extractedFile);
101
					Utils.transferStreams(entryStream, extracted, true);
102
103
					if (unpacking) {
104
						processor.processJar(extractedFile);
105
						name = name.substring(0, name.length() - Utils.PACKED_SUFFIX.length());
106
						extractedFile = new File(tempDir, name);
107
					} else {
108
						processor.clearProcessSteps();
109
						if (repack)
110
							processor.addProcessStep(packUnpackStep);
111
						if (sign)
112
							processor.addProcessStep(signStep);
113
						processor.processJar(extractedFile);
114
						extractedFile = new File(tempDir, extractedFile.getName());
115
						if (pack) {
116
							processor.clearProcessSteps();
117
							processor.addProcessStep(packStep);
118
							processor.processJar(extractedFile);
119
120
							File modifiedFile = new File(tempDir, extractedFile.getName() + Utils.PACKED_SUFFIX);
121
							ZipEntry zipEntry = new ZipEntry(name + Utils.PACKED_SUFFIX);
122
							entryStream = new FileInputStream(modifiedFile);
123
							zipOut.putNextEntry(zipEntry);
124
							Utils.transferStreams(entryStream, zipOut, false);
125
							entryStream.close();
126
							Utils.clear(modifiedFile);
127
						}
128
					}
129
					entryStream = new FileInputStream(extractedFile);
130
				}
131
				ZipEntry newEntry = new ZipEntry(name);
132
				zipOut.putNextEntry(newEntry);
133
				Utils.transferStreams(entryStream, zipOut, false);
134
				zipOut.closeEntry();
135
				entryStream.close();
136
137
				if (extractedFile != null)
138
					Utils.clear(extractedFile);
139
			}
140
141
		}
142
		zipOut.close();
143
		zip.close();
144
145
		File finalFile = new File(getWorkingDirectory(), zipFile.getName());
146
		if (finalFile.exists())
147
			finalFile.delete();
148
		outputFile.renameTo(finalFile);
149
		Utils.clear(tempDir);
150
	}
151
152
	private void initialize(ZipFile zip) {
153
		ZipEntry entry = zip.getEntry("pack.properties"); //$NON-NLS-1$
154
		properties = new Properties();
155
		if (entry != null) {
156
			InputStream stream = null;
157
			try {
158
				stream = zip.getInputStream(entry);
159
				properties.load(stream);
160
			} catch (IOException e) {
161
				// TODO Auto-generated catch block
162
				e.printStackTrace();
163
			} finally {
164
				Utils.close(stream);
165
			}
166
		}
167
168
		packExclusions = Utils.getPackExclusions(properties);
169
		signExclusions = Utils.getSignExclusions(properties);
170
171
		packUnpackStep = new PackUnpackStep(properties);
172
		packStep = new PackStep(properties);
173
		signStep = new SignCommandStep(properties, command);
174
		unpackStep = new UnpackStep(properties);
175
	}
176
}

Return to bug 127375