1 package org.apache.maven.plugins.shade.filter;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.Artifact;
23 import org.apache.maven.plugin.logging.Log;
24 import org.apache.maven.project.MavenProject;
25 import org.codehaus.plexus.util.IOUtil;
26 import org.vafer.jdependency.Clazz;
27 import org.vafer.jdependency.Clazzpath;
28 import org.vafer.jdependency.ClazzpathUnit;
29
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.util.Collections;
35 import java.util.HashSet;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Set;
39
40
41
42
43
44
45 public class MinijarFilter
46 implements Filter
47 {
48
49 private Log log;
50
51 private Set removable;
52
53 private int classesKept;
54
55 private int classesRemoved;
56
57 public MinijarFilter( MavenProject project, Log log )
58 throws IOException
59 {
60 this( project, log, Collections.<SimpleFilter>emptyList() );
61 }
62
63
64
65
66
67 public MinijarFilter( MavenProject project, Log log, List<SimpleFilter> simpleFilters )
68 throws IOException
69 {
70
71 this.log = log;
72
73 Clazzpath cp = new Clazzpath();
74
75 ClazzpathUnit artifactUnit =
76 cp.addClazzpathUnit( new FileInputStream( project.getArtifact().getFile() ), project.toString() );
77
78 for ( Iterator it = project.getArtifacts().iterator(); it.hasNext(); )
79 {
80 Artifact dependency = (Artifact) it.next();
81
82 InputStream is = null;
83 try
84 {
85 is = new FileInputStream( dependency.getFile() );
86 cp.addClazzpathUnit( is, dependency.toString() );
87 }
88 finally
89 {
90 IOUtil.close( is );
91 }
92 }
93
94 removable = cp.getClazzes();
95 removePackages( artifactUnit );
96 removable.removeAll( artifactUnit.getClazzes() );
97 removable.removeAll( artifactUnit.getTransitiveDependencies() );
98 removeSpecificallyIncludedClasses( project, simpleFilters == null
99 ? Collections.<SimpleFilter>emptyList()
100 : simpleFilters );
101 }
102
103 private void removePackages( ClazzpathUnit artifactUnit )
104 {
105 Set packageNames = new HashSet();
106 removePackages( artifactUnit.getClazzes(), packageNames );
107 removePackages( artifactUnit.getTransitiveDependencies(), packageNames );
108 }
109
110 private void removePackages( Set clazzes, Set packageNames )
111 {
112 Iterator it = clazzes.iterator();
113 while ( it.hasNext() )
114 {
115 Clazz clazz = (Clazz) it.next();
116 String name = clazz.getName();
117 while ( name.contains( "." ) )
118 {
119 name = name.substring( 0, name.lastIndexOf( '.' ) );
120 if ( packageNames.add( name ) )
121 {
122 removable.remove( new Clazz( name + ".package-info" ) );
123 }
124 }
125 }
126 }
127
128 private void removeSpecificallyIncludedClasses( MavenProject project, List<SimpleFilter> simpleFilters )
129 throws IOException
130 {
131
132 Clazzpath checkCp = new Clazzpath();
133 for ( Iterator it = project.getArtifacts().iterator(); it.hasNext(); )
134 {
135 Artifact dependency = (Artifact) it.next();
136 File jar = dependency.getFile();
137
138 for ( Iterator<SimpleFilter> i = simpleFilters.iterator(); i.hasNext(); )
139 {
140 SimpleFilter simpleFilter = i.next();
141 if ( simpleFilter.canFilter( jar ) )
142 {
143 InputStream is = null;
144 ClazzpathUnit depClazzpathUnit = null;
145 try
146 {
147 is = new FileInputStream( dependency.getFile() );
148 depClazzpathUnit = checkCp.addClazzpathUnit( is, dependency.toString() );
149 }
150 finally
151 {
152 IOUtil.close( is );
153 }
154
155 if ( depClazzpathUnit != null )
156 {
157 Iterator<Clazz> j = removable.iterator();
158 while ( j.hasNext() )
159 {
160 Clazz clazz = j.next();
161
162 if ( depClazzpathUnit.getClazzes().contains( clazz ) && simpleFilter.isSpecificallyIncluded(
163 clazz.getName().replace( '.', '/' ) ) )
164 {
165 log.info( clazz.getName() + " not removed because it was specifically included" );
166 j.remove();
167 }
168 }
169 }
170 }
171 }
172 }
173 }
174
175 public boolean canFilter( File jar )
176 {
177 return true;
178 }
179
180 public boolean isFiltered( String classFile )
181 {
182 String className = classFile.replace( '/', '.' ).replaceFirst( "\\.class$", "" );
183 Clazz clazz = new Clazz( className );
184
185 if ( removable.contains( clazz ) )
186 {
187 log.debug( "Removing " + className );
188 classesRemoved += 1;
189 return true;
190 }
191
192 classesKept += 1;
193 return false;
194 }
195
196 public void finished()
197 {
198 int classes_total = classesRemoved + classesKept;
199 log.info(
200 "Minimized " + classes_total + " -> " + classesKept + " (" + (int) ( 100 * classesKept / classes_total )
201 + "%)" );
202 }
203 }