1 package com.atlassian.plugin.osgi.factory.transform;
2
3 import com.atlassian.plugin.PluginAccessor;
4 import com.atlassian.plugin.JarPluginArtifact;
5 import com.atlassian.plugin.osgi.factory.transform.stage.ComponentImportSpringStage;
6 import com.atlassian.plugin.osgi.factory.transform.stage.ComponentSpringStage;
7 import com.atlassian.plugin.osgi.factory.transform.stage.HostComponentSpringStage;
8 import com.atlassian.plugin.osgi.hostcomponents.HostComponentRegistration;
9 import com.atlassian.plugin.osgi.container.impl.DefaultOsgiPersistentCache;
10 import com.atlassian.plugin.osgi.container.OsgiContainerManager;
11 import com.atlassian.plugin.osgi.factory.transform.model.SystemExports;
12 import com.atlassian.plugin.osgi.hostcomponents.PropertyBuilder;
13 import com.atlassian.plugin.osgi.hostcomponents.impl.MockRegistration;
14 import com.atlassian.plugin.test.PluginJarBuilder;
15 import com.atlassian.plugin.test.PluginTestUtils;
16
17 import com.google.common.collect.ImmutableMap;
18 import com.google.common.collect.Sets;
19 import org.dom4j.Document;
20 import org.dom4j.Element;
21 import org.dom4j.io.SAXReader;
22 import org.jaxen.SimpleNamespaceContext;
23 import org.jaxen.XPath;
24 import org.jaxen.dom4j.Dom4jXPath;
25 import org.osgi.framework.Constants;
26 import org.osgi.framework.ServiceReference;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.when;
29
30 import java.io.File;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.net.URISyntaxException;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.jar.Attributes;
42 import java.util.jar.JarFile;
43 import java.util.zip.ZipEntry;
44 import java.util.zip.ZipFile;
45
46 import junit.framework.TestCase;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 public class TestDefaultPluginTransformer extends TestCase
51 {
52 private static final Logger LOG = LoggerFactory.getLogger(TestDefaultPluginTransformer.class);
53
54 private DefaultPluginTransformer transformer;
55 private File tmpDir;
56
57 @Override
58 protected void setUp() throws Exception
59 {
60 super.setUp();
61 OsgiContainerManager osgiContainerManager = mock(OsgiContainerManager.class);
62 when(osgiContainerManager.getRegisteredServices()).thenReturn(new ServiceReference[0]);
63 tmpDir = PluginTestUtils.createTempDirectory("plugin-transformer");
64 transformer = new DefaultPluginTransformer(new DefaultOsgiPersistentCache(tmpDir), SystemExports.NONE, null, PluginAccessor.Descriptor.FILENAME, osgiContainerManager);
65 }
66
67 @Override
68 protected void tearDown() throws Exception
69 {
70 super.tearDown();
71 tmpDir = null;
72 transformer = null;
73 }
74
75 public void testAddFilesToZip() throws URISyntaxException, IOException
76 {
77 final File file = PluginTestUtils.getFileForResource("myapp-1.0-plugin.jar");
78
79 final Map<String, byte[]> files = new HashMap<String, byte[]>()
80 {
81 {
82 put("foo", "bar".getBytes());
83 }
84 };
85 final File copy = transformer.addFilesToExistingZip(file, files);
86 assertNotNull(copy);
87 assertTrue(!copy.getName().equals(file.getName()));
88 assertTrue(copy.length() != file.length());
89
90 final ZipFile zip = new ZipFile(copy);
91 try
92 {
93 final ZipEntry entry = zip.getEntry("foo");
94 assertNotNull(entry);
95 }
96 finally
97 {
98 closeQuietly(zip);
99 }
100 }
101
102 public void testTransform() throws Exception
103 {
104 final File file = new PluginJarBuilder()
105 .addFormattedJava("my.Foo",
106 "package my;",
107 "public class Foo {",
108 " com.atlassian.plugin.osgi.factory.transform.Fooable bar;",
109 "}")
110 .addPluginInformation("foo", "foo", "1.1")
111 .build();
112
113 final File copy = transformer.transform(new JarPluginArtifact(file), new ArrayList<HostComponentRegistration>()
114 {
115 {
116 add(new StubHostComponentRegistration(Fooable.class));
117 }
118 });
119
120 assertNotNull(copy);
121 assertTrue(copy.getName().contains(String.valueOf(file.lastModified())));
122 assertTrue(copy.getName().endsWith(".jar"));
123 assertEquals(tmpDir.getAbsolutePath(), copy.getParentFile().getParentFile().getAbsolutePath());
124 final JarFile jar = new JarFile(copy);
125 try
126 {
127 final Attributes attrs = jar.getManifest().getMainAttributes();
128 assertEquals("1.1", attrs.getValue(Constants.BUNDLE_VERSION));
129 assertNotNull(jar.getEntry("META-INF/spring/atlassian-plugins-host-components.xml"));
130 }
131 finally
132 {
133 closeQuietly(jar);
134 }
135 }
136
137
138 public void notTestTransformWithBeanConflictBetweenComponentAndHostComponent() throws Exception
139 {
140 final File file = new PluginJarBuilder()
141 .addFormattedJava("my.Foo",
142 "package my;",
143 "public class Foo {",
144 " com.atlassian.plugin.osgi.factory.transform.Fooable bar;",
145 "}")
146 .addFormattedResource("atlassian-plugin.xml",
147 "<atlassian-plugin name='plugin1' key='first' pluginsVersion='2'>",
148 " <plugin-info>",
149 " <version>1.0</version>",
150 " </plugin-info>",
151 "<component key='host_component1' class='my.Foo'/>",
152 "</atlassian-plugin>")
153 .build();
154
155 try
156 {
157 transformer.transform(new JarPluginArtifact(file), new ArrayList<HostComponentRegistration>()
158 {
159 {
160 HostComponentRegistration reg = new StubHostComponentRegistration(Fooable.class);
161 reg.getProperties().put(PropertyBuilder.BEAN_NAME, "host_component1");
162 add(reg);
163 }
164 });
165
166 fail(PluginTransformationException.class.getSimpleName() + " expected");
167 }
168 catch (PluginTransformationException e)
169 {
170
171
172
173
174 LOG.info(e.toString());
175 e.getMessage().contains("host_component1");
176 e.getMessage().contains(ComponentSpringStage.BEAN_SOURCE);
177 e.getMessage().contains(HostComponentSpringStage.BEAN_SOURCE);
178 }
179 }
180
181
182 public void notTestTransformWithBeanConflictBetweenComponentAndImportComponent() throws Exception
183 {
184 final File file = new PluginJarBuilder()
185 .addFormattedJava("my.Foo",
186 "package my;",
187 "public class Foo {",
188 " com.atlassian.plugin.osgi.factory.transform.Fooable bar;",
189 "}")
190 .addFormattedJava("com.atlassian.plugin.osgi.SomeInterface",
191 "package com.atlassian.plugin.osgi;",
192 "public interface SomeInterface {}")
193 .addFormattedResource("atlassian-plugin.xml",
194 "<atlassian-plugin name='plugin1' key='first' pluginsVersion='2'>",
195 " <plugin-info>",
196 " <version>1.0</version>",
197 " </plugin-info>",
198 "<component key='component1' class='my.Foo'/>",
199 "<component-import key='component1'>",
200 " <interface>com.atlassian.plugin.osgi.SomeInterface</interface>",
201 "</component-import>",
202 "</atlassian-plugin>")
203 .build();
204
205 try
206 {
207 transformer.transform(new JarPluginArtifact(file), new ArrayList<HostComponentRegistration>());
208 fail(PluginTransformationException.class.getSimpleName() + " expected");
209 }
210 catch (PluginTransformationException e)
211 {
212
213
214
215
216 LOG.info(e.toString());
217 e.getMessage().contains("component1");
218 e.getMessage().contains(ComponentSpringStage.BEAN_SOURCE);
219 e.getMessage().contains(ComponentImportSpringStage.BEAN_SOURCE);
220 }
221 }
222
223 public void testImportManifestGenerationOnInterfaces() throws Exception
224 {
225 final File innerJar = new PluginJarBuilder()
226 .addFormattedJava("my.innerpackage.InnerPackageInterface1",
227 "package my.innerpackage;",
228 "public interface InnerPackageInterface1 {}")
229 .build();
230
231 final File pluginJar = new PluginJarBuilder()
232 .addFormattedJava("my.MyFooChild",
233 "package my;",
234 "public class MyFooChild extends com.atlassian.plugin.osgi.factory.transform.dummypackage2.DummyClass2 {",
235 "}")
236 .addFormattedJava("my2.MyFooInterface",
237 "package my2;",
238 "public interface MyFooInterface {}")
239 .addFormattedResource("atlassian-plugin.xml",
240 "<atlassian-plugin name='plugin1' key='first' pluginsVersion='2'>",
241 " <plugin-info>",
242 " <version>1.0</version>",
243 " </plugin-info>",
244 " <component key='component1' class='my.MyFooChild' public='true'>",
245 " <interface>com.atlassian.plugin.osgi.factory.transform.dummypackage0.DummyInterface0</interface>",
246 " <interface>com.atlassian.plugin.osgi.factory.transform.dummypackage1.DummyInterface1</interface>",
247 " <interface>my.innerpackage.InnerPackageInterface1</interface>",
248 " <interface>my2.MyFooInterface</interface>",
249 " </component>",
250 "</atlassian-plugin>")
251 .addFile("META-INF/lib/mylib.jar", innerJar)
252 .build();
253
254 File outputFile = transformer.transform(new JarPluginArtifact(pluginJar), new ArrayList<HostComponentRegistration>());
255
256 JarFile outputJar = new JarFile(outputFile);
257 String importString;
258 try
259 {
260 importString = outputJar.getManifest().getMainAttributes().getValue(Constants.IMPORT_PACKAGE);
261 }
262 finally
263 {
264 closeQuietly(outputJar);
265 }
266
267
268 assertTrue(importString.contains("com.atlassian.plugin.osgi.factory.transform.dummypackage2"));
269
270
271 assertTrue(importString.contains("com.atlassian.plugin.osgi.factory.transform.dummypackage1"));
272
273
274 assertTrue(importString.contains("com.atlassian.plugin.osgi.factory.transform.dummypackage0"));
275
276
277 assertFalse(importString.contains("my2.MyFooInterface"));
278
279
280 assertFalse(importString.contains("my.innerpackage"));
281 }
282
283 public void testGenerateCacheName() throws IOException
284 {
285 File tmp = File.createTempFile("asdf", ".jar", tmpDir);
286 assertTrue(DefaultPluginTransformer.generateCacheName(tmp).endsWith(".jar"));
287 tmp = File.createTempFile("asdf", "asdf", tmpDir);
288 assertTrue(DefaultPluginTransformer.generateCacheName(tmp).endsWith(String.valueOf(tmp.lastModified())));
289
290 tmp = File.createTempFile("asdf", "asdf.", tmpDir);
291 assertTrue(DefaultPluginTransformer.generateCacheName(tmp).endsWith(String.valueOf(tmp.lastModified())));
292
293 tmp = File.createTempFile("asdf", "asdf.s", tmpDir);
294 assertTrue(DefaultPluginTransformer.generateCacheName(tmp).endsWith(String.valueOf(".s")));
295 }
296
297 public void testTransformComponentMustNotPerformKeyConversion() throws Exception
298 {
299 File outputJarFile = runTransform();
300
301 assertBeanNames(outputJarFile, "META-INF/spring/atlassian-plugins-components.xml",
302 ImmutableMap.<String, String>builder().put("beans", "http://www.springframework.org/schema/beans").build(),
303 "//beans:bean",
304 Sets.newHashSet("TESTING1", "testing2"));
305 }
306
307 public void testTransformImportMustNotPerformKeyConversion() throws Exception
308 {
309 File outputJarFile = runTransform();
310
311 assertBeanNames(outputJarFile, "META-INF/spring/atlassian-plugins-component-imports.xml",
312 ImmutableMap.<String, String>builder().put("osgi", "http://www.springframework.org/schema/osgi").build(),
313 "//osgi:reference",
314 Sets.newHashSet("TESTING3", "testing4"));
315 }
316
317 public void testTransformHostComponentMustNotPerformKeyConversion() throws Exception
318 {
319 File outputJarFile = runTransform();
320
321 assertBeanNames(outputJarFile, "META-INF/spring/atlassian-plugins-host-components.xml",
322 ImmutableMap.<String, String>builder().put("beans", "http://www.springframework.org/schema/beans").build(),
323 "//beans:bean",
324 Sets.newHashSet("TESTING5", "testing6"));
325 }
326
327 private File runTransform() throws Exception
328 {
329 final File file = new PluginJarBuilder()
330 .addFormattedJava("my.Foo",
331 "package my;",
332 "import com.atlassian.plugin.osgi.factory.transform.Fooable;",
333 "import com.atlassian.plugin.osgi.factory.transform.FooChild;",
334 "public class Foo {",
335 " private Fooable bar;",
336 " public Foo(Fooable bar, FooChild child) { this.bar = bar;} ",
337 "}")
338 .addFormattedJava("com.atlassian.plugin.osgi.SomeInterface",
339 "package com.atlassian.plugin.osgi;",
340 "public interface SomeInterface {}")
341 .addFormattedResource("atlassian-plugin.xml",
342 "<atlassian-plugin name='plugin1' key='first' pluginsVersion='2'>",
343 " <plugin-info>",
344 " <version>1.0</version>",
345 " </plugin-info>",
346 " <component key='TESTING1' class='my.Foo'/>",
347 " <component key='testing2' class='my.Foo'/>",
348 " <component-import key='TESTING3'>",
349 " <interface>com.atlassian.plugin.osgi.SomeInterface</interface>",
350 " </component-import>",
351 " <component-import key='testing4'>",
352 " <interface>com.atlassian.plugin.osgi.SomeInterface</interface>",
353 " </component-import>",
354 "</atlassian-plugin>")
355 .build();
356
357 MockRegistration mockReg1 = new MockRegistration(new Foo(), Fooable.class);
358 mockReg1.getProperties().put(PropertyBuilder.BEAN_NAME, "TESTING5");
359 MockRegistration mockReg2 = new MockRegistration(new FooChild(), FooChild.class);
360 mockReg2.getProperties().put(PropertyBuilder.BEAN_NAME, "testing6");
361
362 return transformer.transform(new JarPluginArtifact(file), Arrays.<HostComponentRegistration>asList(mockReg1, mockReg2));
363 }
364
365 private void assertBeanNames(File outputJarFile, String springFileLocation,
366 Map<String, String> namespaces, String xpathQuery,
367 Set<String> expectedIds) throws Exception
368 {
369 JarFile jarFile = new JarFile(outputJarFile);
370 Set<String> foundBeanNames = new HashSet<String>();
371 try
372 {
373 InputStream inputStream = jarFile.getInputStream(jarFile.getEntry(springFileLocation));
374
375 SAXReader saxReader = new SAXReader();
376 Document document = saxReader.read(inputStream);
377
378 XPath xpath = new Dom4jXPath(xpathQuery);
379 xpath.setNamespaceContext(new SimpleNamespaceContext(namespaces));
380 List<Element> elems = xpath.selectNodes(document);
381 for(Element elem : elems)
382 {
383 foundBeanNames.add(elem.attribute("id").getValue());
384 }
385 }
386 finally
387 {
388 closeQuietly(jarFile);
389 }
390
391 assertEquals(expectedIds, foundBeanNames);
392 }
393
394
395 private static void closeQuietly(ZipFile zipFile)
396 {
397 try
398 {
399 zipFile.close();
400 }
401 catch (IOException e)
402 {
403 LOG.debug("Error closing zipFile: {}", zipFile.getName(), e);
404 }
405 }
406 }