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 }