1 package com.atlassian.plugin;
2
3 import com.google.common.base.Predicate;
4 import org.apache.commons.io.IOUtils;
5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7
8 import java.io.BufferedInputStream;
9 import java.io.File;
10 import java.io.FileInputStream;
11 import java.io.FileNotFoundException;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.util.jar.JarEntry;
15 import java.util.jar.JarFile;
16 import java.util.jar.Manifest;
17 import java.util.zip.ZipEntry;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.collect.Iterators.any;
21 import static com.google.common.collect.Iterators.forEnumeration;
22
23
24
25
26
27
28
29 public final class JarPluginArtifact implements PluginArtifact
30 {
31 private final Logger logger = LoggerFactory.getLogger(this.getClass());
32
33 private final File jarFile;
34
35 public JarPluginArtifact(File jarFile)
36 {
37 this.jarFile = checkNotNull(jarFile);
38 }
39
40 public boolean doesResourceExist(String name)
41 {
42 InputStream in = null;
43 try
44 {
45 in = getResourceAsStream(name);
46 return (in != null);
47 }
48 finally
49 {
50 IOUtils.closeQuietly(in);
51 }
52 }
53
54
55
56
57 public InputStream getResourceAsStream(String fileName) throws PluginParseException
58 {
59 checkNotNull(fileName, "The file name must not be null");
60
61 final JarFile jar = open();
62 final ZipEntry entry = jar.getEntry(fileName);
63 if (entry == null)
64 {
65 closeJarQuietly(jar);
66 return null;
67 }
68
69 try
70 {
71 return new BufferedInputStream(jar.getInputStream(entry))
72 {
73
74
75 public void close() throws IOException
76 {
77 super.close();
78 jar.close();
79 }
80 };
81 }
82 catch (IOException e)
83 {
84 throw new PluginParseException("Cannot retrieve " + fileName + " from plugin JAR [" + jarFile + "]", e);
85 }
86 }
87
88 public String getName()
89 {
90 return jarFile.getName();
91 }
92
93 @Override
94 public String toString()
95 {
96 return getName();
97 }
98
99
100
101
102
103 public InputStream getInputStream()
104 {
105 try
106 {
107 return new BufferedInputStream(new FileInputStream(jarFile));
108 }
109 catch (FileNotFoundException e)
110 {
111 throw new PluginParseException("Could not open JAR file: " + jarFile, e);
112 }
113 }
114
115 public File toFile()
116 {
117 return jarFile;
118 }
119
120 @Override
121 public boolean containsJavaExecutableCode()
122 {
123 final JarFile jar = open();
124 try
125 {
126 final Manifest manifest = getManifest(jar);
127 return hasBundleActivator(manifest)
128 ||
129 hasSpringContext(manifest)
130 ||
131 any(forEnumeration(jar.entries()), new Predicate<JarEntry>()
132 {
133 @Override
134 public boolean apply(JarEntry entry)
135 {
136 return isJavaClass(entry) || isJavaLibrary(entry) || isSpringContext(entry);
137 }
138 });
139 }
140 finally
141 {
142 closeJarQuietly(jar);
143 }
144 }
145
146 private boolean isJavaClass(ZipEntry entry)
147 {
148 return entry.getName().endsWith(".class");
149 }
150
151 private boolean isJavaLibrary(ZipEntry entry)
152 {
153 return entry.getName().endsWith(".jar");
154 }
155
156 private boolean isSpringContext(ZipEntry entry)
157 {
158 final String entryName = entry.getName();
159 return entryName.startsWith("META-INF/spring/") && entryName.endsWith(".xml");
160 }
161
162 private boolean hasSpringContext(Manifest manifest)
163 {
164 return hasManifestEntry(manifest, "Spring-Context");
165 }
166
167 private boolean hasBundleActivator(Manifest manifest)
168 {
169 return hasManifestEntry(manifest, "Bundle-Activator");
170 }
171
172 private boolean hasManifestEntry(Manifest manifest, String manifestEntryName)
173 {
174 return manifest != null
175 && manifest.getMainAttributes() != null
176 && manifest.getMainAttributes().getValue(manifestEntryName) != null;
177 }
178
179 private JarFile open()
180 {
181 try
182 {
183 return new JarFile(jarFile);
184 }
185 catch (IOException e)
186 {
187 throw new PluginParseException("Cannot open JAR file: " + jarFile, e);
188 }
189 }
190
191 private Manifest getManifest(JarFile jar)
192 {
193 try
194 {
195 return jar.getManifest();
196 }
197 catch (IOException e)
198 {
199 throw new PluginParseException("Cannot get manifest for JAR file: " + jarFile, e);
200 }
201 }
202
203 private void closeJarQuietly(JarFile jar)
204 {
205 if (jar != null)
206 {
207 try
208 {
209 jar.close();
210 }
211 catch (IOException ignored)
212 {
213 logger.debug("Exception closing jar file " + jarFile + ".", ignored);
214 }
215 }
216 }
217 }