| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.felix.ipojo.manipulation; |
| |
| import java.io.*; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.util.Arrays; |
| |
| import junit.framework.Assert; |
| import junit.framework.TestCase; |
| |
| import org.apache.felix.ipojo.InstanceManager; |
| import org.apache.felix.ipojo.Pojo; |
| import org.junit.Ignore; |
| import org.mockito.Mockito; |
| import org.objectweb.asm.ClassReader; |
| import org.objectweb.asm.util.CheckClassAdapter; |
| |
| public class ManipulatorTest extends TestCase { |
| |
| public void testClusterDaemon() throws Exception { |
| Manipulator manipulator = new Manipulator(this.getClass().getClassLoader()); |
| byte[] origin = getBytesFromFile(new File("target/test-classes/test/ClusterDaemon.class")); |
| manipulator.prepare(origin); |
| byte[] clazz = manipulator.manipulate(origin); |
| |
| ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.ClusterDaemon", clazz); |
| |
| //Assert.assertNotNull(manipulator.getManipulationMetadata()); |
| |
| //System.out.println(manipulator.getManipulationMetadata()); |
| |
| |
| ClassReader reader = new ClassReader(clazz); |
| CheckClassAdapter.verify(reader, false, new PrintWriter(new File("/tmp/class_dump"))); |
| |
| Class cl = classloader.findClass("test.ClusterDaemon"); |
| //Assert.assertNotNull(cl); |
| |
| // The manipulation add stuff to the class. |
| //Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/ClusterDaemon.class")).length); |
| |
| //Assert.assertNotNull(cl.newInstance()); |
| |
| } |
| |
| public void testCrypto() throws Exception { |
| Manipulator manipulator = new Manipulator(this.getClass().getClassLoader()); |
| byte[] origin = getBytesFromFile(new File("target/test-classes/test/frames/CryptoServiceSingleton.class")); |
| manipulator.prepare(origin); |
| byte[] clazz = manipulator.manipulate(origin); |
| |
| ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.frames.CryptoServiceSingleton", clazz); |
| |
| //Assert.assertNotNull(manipulator.getManipulationMetadata()); |
| |
| //System.out.println(manipulator.getManipulationMetadata()); |
| |
| |
| ClassReader reader = new ClassReader(clazz); |
| CheckClassAdapter.verify(reader, false, new PrintWriter(new File("/tmp/class_dump"))); |
| |
| Class cl = classloader.findClass("test.frames.CryptoServiceSingleton"); |
| Assert.assertNotNull(cl); |
| |
| Object instance = cl.newInstance(); |
| |
| Method method = cl.getMethod("encryptAESWithCBC", String.class, String.class); |
| final String salt = "0000000000000000"; |
| String result = (String) method.invoke(instance, "hello", salt); |
| assertNotNull(result); |
| |
| // The manipulation add stuff to the class. |
| //Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/ClusterDaemon.class")).length); |
| |
| //Assert.assertNotNull(cl.newInstance()); |
| |
| } |
| |
| public void testManipulatingTheSimplePojo() throws Exception { |
| Manipulator manipulator = new Manipulator(this.getClass().getClassLoader()); |
| byte[] origin = getBytesFromFile(new File("target/test-classes/test/SimplePojo.class")); |
| manipulator.prepare(origin); |
| byte[] clazz = manipulator.manipulate(origin); |
| ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.SimplePojo", clazz); |
| Class cl = classloader.findClass("test.SimplePojo"); |
| Assert.assertNotNull(cl); |
| Assert.assertNotNull(manipulator.getManipulationMetadata()); |
| |
| System.out.println(manipulator.getManipulationMetadata()); |
| |
| // The manipulation add stuff to the class. |
| Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/SimplePojo.class")).length); |
| |
| |
| boolean found = false; |
| Constructor cst = null; |
| Constructor[] csts = cl.getDeclaredConstructors(); |
| for (int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 1 && |
| csts[i].getParameterTypes()[0].equals(InstanceManager.class)) { |
| found = true; |
| cst = csts[i]; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // We still have the empty constructor |
| found = false; |
| csts = cl.getDeclaredConstructors(); |
| for (int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 0) { |
| found = true; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // Check the POJO interface |
| Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class)); |
| |
| cst.setAccessible(true); |
| Object pojo = cst.newInstance(new Object[] {new InstanceManager()}); |
| Assert.assertNotNull(pojo); |
| Assert.assertTrue(pojo instanceof Pojo); |
| |
| Method method = cl.getMethod("doSomething", new Class[0]); |
| Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue()); |
| |
| } |
| |
| public void testManipulatingTheNonSunPOJO() throws Exception { |
| Manipulator manipulator = new Manipulator(this.getClass().getClassLoader()); |
| byte[] origin = getBytesFromFile(new File("target/test-classes/test/NonSunClass.class")); |
| manipulator.prepare(origin); |
| byte[] clazz = manipulator.manipulate(origin); |
| |
| ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.NonSunClass", clazz); |
| Class cl = classloader.findClass("test.NonSunClass"); |
| Assert.assertNotNull(cl); |
| Assert.assertNotNull(manipulator.getManipulationMetadata()); |
| |
| System.out.println(manipulator.getManipulationMetadata()); |
| |
| // The manipulation add stuff to the class. |
| Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/NonSunClass.class")).length); |
| |
| |
| boolean found = false; |
| Constructor cst = null; |
| Constructor[] csts = cl.getDeclaredConstructors(); |
| for (int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 1 && |
| csts[i].getParameterTypes()[0].equals(InstanceManager.class)) { |
| found = true; |
| cst = csts[i]; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // Check the POJO interface |
| Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class)); |
| |
| cst.setAccessible(true); |
| Object pojo = cst.newInstance(new Object[] {new InstanceManager()}); |
| Assert.assertNotNull(pojo); |
| Assert.assertTrue(pojo instanceof Pojo); |
| |
| Method method = cl.getMethod("getS1", new Class[0]); |
| Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue()); |
| |
| } |
| |
| public void testManipulatingChild() throws Exception { |
| Manipulator manipulator = new Manipulator(this.getClass().getClassLoader()); |
| byte[] origin = getBytesFromFile(new File("target/test-classes/test/Child.class")); |
| manipulator.prepare(origin); |
| byte[] clazz = manipulator.manipulate(origin); |
| |
| ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.Child", clazz); |
| Class cl = classloader.findClass("test.Child"); |
| Assert.assertNotNull(cl); |
| Assert.assertNotNull(manipulator.getManipulationMetadata()); |
| |
| boolean found = false; |
| Constructor cst = null; |
| Constructor[] csts = cl.getDeclaredConstructors(); |
| for (int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 1 && |
| csts[i].getParameterTypes()[0].equals(InstanceManager.class)) { |
| found = true; |
| cst = csts[i]; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // We still have the regular constructor |
| found = false; |
| csts = cl.getDeclaredConstructors(); |
| for (int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 2) { |
| found = true; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // Check the POJO interface |
| Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class)); |
| |
| InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class); |
| cst.setAccessible(true); |
| Object pojo = cst.newInstance(new Object[] {im}); |
| Assert.assertNotNull(pojo); |
| Assert.assertTrue(pojo instanceof Pojo); |
| |
| Method method = cl.getMethod("doSomething", new Class[0]); |
| Assert.assertEquals(9, ((Integer) method.invoke(pojo, new Object[0])).intValue()); |
| |
| } |
| |
| public void testManipulatingWithConstructorModification() throws Exception { |
| Manipulator manipulator = new Manipulator(this.getClass().getClassLoader()); |
| byte[] origin = getBytesFromFile(new File("target/test-classes/test/Child.class")); |
| manipulator.prepare(origin); |
| byte[] clazz = manipulator.manipulate(origin); |
| ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.Child", clazz); |
| Class cl = classloader.findClass("test.Child"); |
| Assert.assertNotNull(cl); |
| Assert.assertNotNull(manipulator.getManipulationMetadata()); |
| |
| boolean found = false; |
| Constructor cst = null; |
| Constructor[] csts = cl.getDeclaredConstructors(); |
| for (int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 1 && |
| csts[i].getParameterTypes()[0].equals(InstanceManager.class)) { |
| found = true; |
| cst = csts[i]; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // We still have the regular constructor |
| found = false; |
| csts = cl.getDeclaredConstructors(); |
| for (int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 2) { |
| found = true; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // Check that we have the IM, Integer, String constructor too |
| Constructor cst2 = cl.getDeclaredConstructor(new Class[] { InstanceManager.class, Integer.TYPE, String.class }); |
| Assert.assertNotNull(cst2); |
| |
| // Check the POJO interface |
| Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class)); |
| |
| |
| // Creation using cst |
| InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class); |
| cst.setAccessible(true); |
| Object pojo = cst.newInstance(new Object[] {im}); |
| Assert.assertNotNull(pojo); |
| Assert.assertTrue(pojo instanceof Pojo); |
| |
| Method method = cl.getMethod("doSomething", new Class[0]); |
| Assert.assertEquals(9, ((Integer) method.invoke(pojo, new Object[0])).intValue()); |
| |
| // Try to create using cst2 |
| im = (InstanceManager) Mockito.mock(InstanceManager.class); |
| cst2.setAccessible(true); |
| pojo = cst2.newInstance(new Object[] {im, new Integer(2), "bariton"}); |
| Assert.assertNotNull(pojo); |
| Assert.assertTrue(pojo instanceof Pojo); |
| |
| method = cl.getMethod("doSomething", new Class[0]); |
| Assert.assertEquals(10, ((Integer) method.invoke(pojo, new Object[0])).intValue()); |
| |
| |
| |
| } |
| |
| |
| public void testManipulatingWithNoValidConstructor() throws Exception { |
| Manipulator manipulator = new Manipulator(this.getClass().getClassLoader()); |
| byte[] origin = getBytesFromFile(new File("target/test-classes/test/NoValidConstructor.class")); |
| manipulator.prepare(origin); |
| byte[] clazz = manipulator.manipulate(origin); |
| ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.NoValidConstructor", clazz); |
| Class cl = classloader.findClass("test.NoValidConstructor"); |
| Assert.assertNotNull(cl); |
| Assert.assertNotNull(manipulator.getManipulationMetadata()); |
| |
| System.out.println(manipulator.getManipulationMetadata()); |
| |
| // The manipulation add stuff to the class. |
| Assert.assertTrue(clazz.length > origin.length); |
| |
| |
| boolean found = false; |
| Constructor cst = null; |
| Constructor[] csts = cl.getDeclaredConstructors(); |
| for (int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 1 && |
| csts[i].getParameterTypes()[0].equals(InstanceManager.class)) { |
| found = true; |
| cst = csts[i]; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // Check the POJO interface |
| Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class)); |
| |
| cst.setAccessible(true); |
| Object pojo = cst.newInstance(new Object[] {new InstanceManager()}); |
| Assert.assertNotNull(pojo); |
| Assert.assertTrue(pojo instanceof Pojo); |
| |
| } |
| |
| public void testConstructor() throws Exception { |
| Manipulator manipulator = new Manipulator(this.getClass().getClassLoader()); |
| byte[] origin = getBytesFromFile(new File("target/test-classes/test/ConstructorCheck.class")); |
| manipulator.prepare(origin); |
| byte[] clazz = manipulator.manipulate(origin); |
| |
| // File out = new File("target/ManipulatedConstructorCheck.class"); |
| // FileOutputStream fos = new FileOutputStream(out); |
| // fos.write(clazz); |
| // fos.close(); |
| |
| ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.ConstructorCheck", clazz); |
| Class cl = classloader.findClass("test.ConstructorCheck"); |
| Assert.assertNotNull(cl); |
| Assert.assertNotNull(manipulator.getManipulationMetadata()); |
| |
| System.out.println(manipulator.getManipulationMetadata()); |
| |
| Constructor c = cl.getConstructor(new Class[] {String.class }); |
| Assert.assertNotNull(c); |
| |
| Object o = c.newInstance("toto"); |
| Field f = o.getClass().getField("m_foo"); |
| Assert.assertEquals("toto", f.get(o)); |
| } |
| |
| /** |
| * https://issues.apache.org/jira/browse/FELIX-3621 |
| */ |
| public void testManipulatingDoubleArray() throws Exception { |
| Manipulator manipulator = new Manipulator(this.getClass().getClassLoader()); |
| byte[] origin = getBytesFromFile(new File("target/test-classes/test/DoubleArray.class")); |
| manipulator.prepare(origin); |
| byte[] clazz = manipulator.manipulate(origin); |
| ManipulatedClassLoader classloader = new ManipulatedClassLoader("test.DoubleArray", clazz); |
| Class cl = classloader.findClass("test.DoubleArray"); |
| Assert.assertNotNull(cl); |
| Assert.assertNotNull(manipulator.getManipulationMetadata()); |
| |
| System.out.println(manipulator.getManipulationMetadata()); |
| Assert.assertTrue(manipulator.getManipulationMetadata().toString().contains("arguments=\"{int[][]}\"")); |
| |
| // The manipulation add stuff to the class. |
| Assert.assertTrue(clazz.length > origin.length); |
| |
| |
| boolean found = false; |
| Constructor cst = null; |
| Constructor[] csts = cl.getDeclaredConstructors(); |
| for(int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 1 && |
| csts[i].getParameterTypes()[0].equals(InstanceManager.class)) { |
| found = true; |
| cst = csts[i]; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // We still have the empty constructor |
| found = false; |
| csts = cl.getDeclaredConstructors(); |
| for (int i = 0; i < csts.length; i++) { |
| System.out.println(Arrays.asList(csts[i].getParameterTypes())); |
| if (csts[i].getParameterTypes().length == 0) { |
| found = true; |
| } |
| } |
| Assert.assertTrue(found); |
| |
| // Check the POJO interface |
| Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class)); |
| |
| cst.setAccessible(true); |
| Object pojo = cst.newInstance(new Object[] {new InstanceManager()}); |
| Assert.assertNotNull(pojo); |
| Assert.assertTrue(pojo instanceof Pojo); |
| |
| Method method = cl.getMethod("start", new Class[0]); |
| Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue()); |
| |
| } |
| |
| |
| |
| public static byte[] getBytesFromFile(File file) throws IOException { |
| InputStream is = new FileInputStream(file); |
| long length = file.length(); |
| byte[] bytes = new byte[(int)length]; |
| |
| // Read in the bytes |
| int offset = 0; |
| int numRead = 0; |
| while (offset < bytes.length |
| && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) { |
| offset += numRead; |
| } |
| |
| // Ensure all the bytes have been read in |
| if (offset < bytes.length) { |
| throw new IOException("Could not completely read file "+file.getName()); |
| } |
| |
| // Close the input stream and return bytes |
| is.close(); |
| return bytes; |
| } |
| |
| |
| |
| } |