1 package com.atlassian.plugin.osgi.factory.transform.stage;
2
3 import static com.atlassian.plugin.osgi.factory.transform.JarUtils.withJar;
4 import static com.google.common.collect.Iterables.transform;
5
6 import com.atlassian.plugin.osgi.factory.transform.JarUtils;
7 import com.atlassian.plugin.osgi.factory.transform.PluginTransformationException;
8
9 import org.apache.commons.io.IOUtils;
10
11 import com.google.common.base.Function;
12 import com.google.common.collect.ImmutableSet;
13
14 import java.io.File;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.util.Collections;
18 import java.util.HashSet;
19 import java.util.Set;
20 import java.util.jar.JarEntry;
21 import java.util.jar.JarFile;
22 import java.util.jar.JarInputStream;
23
24
25
26
27
28
29 final class TransformStageUtils
30 {
31
32
33
34 private TransformStageUtils()
35 {}
36
37
38
39
40
41
42
43
44
45
46
47
48 static Set<String> scanJarForItems(final JarInputStream inputStream, final Set<String> expectedItems, final Function<JarEntry, String> mapper) throws IOException
49 {
50 final Set<String> matches = new HashSet<String>();
51
52 JarEntry entry;
53 while ((entry = inputStream.getNextJarEntry()) != null)
54 {
55 final String item = mapper.apply(entry);
56 if ((item != null) && expectedItems.contains(item))
57 {
58 matches.add(item);
59
60 if (matches.size() == expectedItems.size())
61 {
62 break;
63 }
64 }
65 }
66
67 return Collections.unmodifiableSet(matches);
68 }
69
70
71
72
73
74
75
76
77
78
79
80 static Set<String> scanInnerJars(final File pluginFile, final Set<String> innerJars, final Set<String> expectedClasses)
81 {
82 return withJar(pluginFile, new JarUtils.Extractor<Set<String>>()
83 {
84 public Set<String> get(final JarFile pluginJarFile)
85 {
86
87 final Set<String> matches = new HashSet<String>();
88
89
90 for (final String innerJar : innerJars)
91 {
92 JarInputStream innerJarStream = null;
93 try
94 {
95
96 innerJarStream = new JarInputStream(pluginJarFile.getInputStream(pluginJarFile.getEntry(innerJar)));
97 final Set<String> innerMatches = scanJarForItems(innerJarStream, expectedClasses, JarEntryToClassName.INSTANCE);
98
99 matches.addAll(innerMatches);
100 }
101 catch (final IOException ioe)
102 {
103 throw new PluginTransformationException("Error reading inner jar:" + innerJar + " in file: " + pluginFile, ioe);
104 }
105 finally
106 {
107 closeNestedStreamQuietly(innerJarStream);
108 }
109
110
111 if (matches.size() == expectedClasses.size())
112 {
113 break;
114 }
115 }
116 return Collections.unmodifiableSet(matches);
117 }
118 });
119 }
120
121
122
123
124
125
126
127 static void closeNestedStreamQuietly(final InputStream... streams)
128 {
129 for (final InputStream stream : streams)
130 {
131 if (stream != null)
132 {
133 IOUtils.closeQuietly(stream);
134 break;
135 }
136 }
137 }
138
139
140
141
142
143
144
145 static String getPackageName(final String fullClassName)
146 {
147 return PackageName.INSTANCE.apply(fullClassName);
148 }
149
150
151
152
153
154
155
156 static Set<String> getPackageNames(final Iterable<String> classes)
157 {
158 return ImmutableSet.copyOf(transform(classes, PackageName.INSTANCE));
159 }
160
161
162
163
164
165
166
167
168 static String jarPathToClassName(final String jarPath)
169 {
170 if ((jarPath == null) || !jarPath.contains(".class"))
171 {
172 return null;
173 }
174
175 return jarPath.replaceAll("/", ".").substring(0, jarPath.length() - ".class".length());
176 }
177
178
179
180
181 enum PackageName implements Function<String, String>
182 {
183 INSTANCE;
184
185 public String apply(final String fullClassName)
186 {
187
188 return fullClassName.substring(0, fullClassName.lastIndexOf("."));
189 }
190 }
191
192
193
194
195 enum JarEntryToClassName implements Function<JarEntry, String>
196 {
197 INSTANCE;
198
199 public String apply(final JarEntry entry)
200 {
201 final String jarPath = entry.getName();
202 if ((jarPath == null) || !jarPath.contains(".class"))
203 {
204 return null;
205 }
206
207 return jarPath.replaceAll("/", ".").substring(0, jarPath.length() - ".class".length());
208 }
209 }
210 }