View Javadoc

1   package org.vafer.minijar;
2   
3   import java.io.FileOutputStream;
4   import java.io.IOException;
5   import java.util.HashSet;
6   import java.util.Set;
7   import java.util.jar.JarEntry;
8   
9   import org.vafer.dependency.Clazz;
10  import org.vafer.dependency.Clazzpath;
11  import org.vafer.dependency.ClazzpathUnit;
12  import org.vafer.jar.Jar;
13  import org.vafer.jar.handler.FilteringJarHandler.JarEntryFilter;
14  import org.vafer.jar.handler.RenamingJarHandler.Mapper;
15  import org.vafer.jar.merging.JarMerger;
16  import org.vafer.jar.merging.MergeStrategy;
17  import org.vafer.jar.merging.PickFirstStrategy;
18  
19  public final class MiniJarProcessor {
20  	
21  	public interface Console {
22  		void info( String message );
23  		void error( String error );
24  	}
25  	
26  	public interface JarFilter {
27  		boolean accept( final Jar jar );
28  	}
29  
30  	
31  	private final Console console;
32  	
33  	public MiniJarProcessor( final Console pConsole ) {
34  		console = pConsole;
35  	}
36  	
37  	public void minijars( final Jar project, final Jar[] dependencies ) throws IOException {
38  		
39  		
40  		final Clazzpath clazzpath = new Clazzpath();            	
41          final ClazzpathUnit jar = clazzpath.addClazzpathUnit(project.getInputStream(), project.getName(), null);
42  
43          for (int i = 0; i < dependencies.length; i++) {
44  			final Jar dependency = dependencies[i];
45  
46  			clazzpath.addClazzpathUnit(dependency.getInputStream(), dependency.getName(), null);			
47  		}
48          
49          final Set removable = clazzpath.getClazzes();
50      
51          final int total = removable.size();
52          
53          removable.removeAll(jar.getClazzes());
54          removable.removeAll(jar.getTransitiveDependencies());
55  
56          console.info("Can remove " + removable.size() + " of " + total + " classes (" + (int) ( 100 * removable.size() / total ) + "%).");
57  
58          
59  
60  		for (int i = 0; i < dependencies.length; i++) {
61  	        final Jar dependency = dependencies[i];
62  
63  			final MergeStrategy strategy = new PickFirstStrategy();
64  	    	
65  	    	final JarMerger merger = new JarMerger(
66  	    		new JarEntryFilter() {
67  					public boolean accept( final JarEntry entry ) {
68  						if (removable.contains(new Clazz (resourceToClass(entry.getName())))) {
69  							console.info( "removing unused " + entry.getName());
70  							return false;
71  						}
72  						return true;
73  					}	    		
74  	    		}, null);
75  	    	
76  	    	merger.merge(new Jar[] { dependency }, null, strategy, null);			
77  		}
78  	}
79  	
80  	public void ueberjar( final Jar project, final Jar[] dependencies, final JarFilter dependenciesToMergeFilter, final JarFilter dependenciesToRelocateFilter ) throws IOException {
81  
82  		final Clazzpath clazzpath = new Clazzpath();            	
83          final ClazzpathUnit jar = clazzpath.addClazzpathUnit(project.getInputStream(), project.getName(), null);
84  
85          for (int i = 0; i < dependencies.length; i++) {
86  			final Jar dependency = dependencies[i];
87  
88  			clazzpath.addClazzpathUnit(dependency.getInputStream(), dependency.getName(), null);			
89  		}
90          
91          final Set removable = clazzpath.getClazzes();
92      
93          final int total = removable.size();
94          
95          removable.removeAll(jar.getClazzes());
96          removable.removeAll(jar.getTransitiveDependencies());
97  
98          console.info("Can remove " + removable.size() + " of " + total + " classes (" + (int) ( 100 * removable.size() / total ) + "%).");
99  		
100         
101         final Set jarsToMergeSet = new HashSet();
102         jarsToMergeSet.add(project);
103         for (int i = 0; i < dependencies.length; i++) {
104         	if (dependenciesToMergeFilter.accept(dependencies[i])) {
105         		jarsToMergeSet.add(dependencies[i]);
106         	}
107 		}
108         final Jar[] jarsToMerge = new Jar[jarsToMergeSet.size()];
109         jarsToMergeSet.toArray(jarsToMerge);
110 		
111 		
112 		
113 		final MergeStrategy strategy = new PickFirstStrategy();
114 
115     	
116     	
117     	final JarMerger merger = new JarMerger(
118     		new JarEntryFilter() {
119 				public boolean accept( final JarEntry entry ) {
120 					if (removable.contains(new Clazz (resourceToClass(entry.getName())))) {
121 						console.info( "removing unused " + entry.getName());
122 						return false;
123 					}
124 					return true;
125 				}
126     		
127     		}, new Mapper() {
128 				public String getNameFor( final Jar jar, final String name ) {
129 					
130 					if (jar == project) {
131 						return name;
132 					}
133 					
134 					
135             		if (dependenciesToRelocateFilter.accept(jar)) {
136 		            	final String prefix = prefixFromJar(jar);
137 		            	return prefix + name;
138             		}
139 
140 					return name;
141 				}        			
142     		});
143     	
144     	merger.merge(jarsToMerge, null, strategy, new FileOutputStream("/Users/tcurdt/Desktop/test.jar"));
145 		
146 	}
147 	
148 	private static String resourceToClass( final String oldName ) {
149 		return oldName.replace( '/' , '.' ).substring( 0, oldName.length() - ".class".length());
150 	}
151 	
152 	private static String prefixFromJar( final Jar jar ) {
153     	final String name = jar.getName();
154     	final char[] chars = name.toCharArray();
155     	final StringBuffer sb = new StringBuffer();
156 
157     	if ( chars.length > 0 ) {
158     		final char c = chars[0];
159     		if ( Character.isJavaIdentifierStart( c ) ) {
160     			sb.append( c );
161     		} else {
162     			sb.append( "C" );
163     		}
164     	}
165 
166     	for ( int i = 1; i < chars.length; i++ ) {
167     		final char c = chars[i];
168     		if (Character.isJavaIdentifierPart(c)) {
169     			sb.append( c );
170     		}
171     	}
172     	
173     	sb.append("/");
174 
175     	return sb.toString();
176 	}
177 }