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