• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package org.apache.bcel.generic;
19 
20 import static com.sun.jna.platform.win32.WinReg.HKEY_LOCAL_MACHINE;
21 import static org.junit.Assert.assertArrayEquals;
22 import static org.junit.Assert.fail;
23 
24 import java.io.File;
25 import java.io.FileFilter;
26 import java.io.InputStream;
27 import java.util.Collection;
28 import java.util.Enumeration;
29 import java.util.HashSet;
30 import java.util.Set;
31 import java.util.jar.JarEntry;
32 import java.util.jar.JarFile;
33 
34 import org.apache.bcel.classfile.ClassParser;
35 import org.apache.bcel.classfile.Code;
36 import org.apache.bcel.classfile.JavaClass;
37 import org.apache.bcel.classfile.Method;
38 import org.apache.commons.lang3.StringUtils;
39 import org.apache.commons.lang3.SystemUtils;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 import org.junit.runners.Parameterized;
43 import org.junit.runners.Parameterized.Parameters;
44 
45 import com.sun.jna.platform.win32.Advapi32Util;
46 
47 /**
48  * Test that the generic dump() methods work on the JDK classes Reads each class into an instruction list and then dumps
49  * the instructions. The output bytes should be the same as the input.
50  */
51 @RunWith(Parameterized.class)
52 public class JDKGenericDumpTestCase {
53 
54     private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
55 
56     private static final String KEY_JDK = "SOFTWARE\\JavaSoft\\Java Development Kit";
57 
58     private static final String KEY_JDK_9 = "SOFTWARE\\JavaSoft\\JDK";
59 
60     private static final String KEY_JRE = "SOFTWARE\\JavaSoft\\Java Runtime Environment";
61 
62     private static final String KEY_JRE_9 = "SOFTWARE\\JavaSoft\\JRE";
63 
addAllJavaHomesOnWindows(final String keyJre, final Set<String> javaHomes)64     private static void addAllJavaHomesOnWindows(final String keyJre, final Set<String> javaHomes) {
65         javaHomes.addAll(findJavaHomesOnWindows(keyJre, Advapi32Util.registryGetKeys(HKEY_LOCAL_MACHINE, keyJre)));
66     }
67 
bytesToHex(final byte[] bytes)68     private static String bytesToHex(final byte[] bytes) {
69         final char[] hexChars = new char[bytes.length * 3];
70         int i = 0;
71         for (final byte b : bytes) {
72             final int v = b & 0xFF;
73             hexChars[i++] = hexArray[v >>> 4];
74             hexChars[i++] = hexArray[v & 0x0F];
75             hexChars[i++] = ' ';
76         }
77         return new String(hexChars);
78     }
79 
80     @Parameters(name = "{0}")
data()81     public static Collection<String> data() {
82         return findJavaHomes();
83     }
84 
findJavaHomes()85     private static Set<String> findJavaHomes() {
86         if (SystemUtils.IS_OS_WINDOWS) {
87             return findJavaHomesOnWindows();
88         }
89         final Set<String> javaHomes = new HashSet<>(1);
90         javaHomes.add(SystemUtils.JAVA_HOME);
91         return javaHomes;
92     }
93 
findJavaHomesOnWindows()94     private static Set<String> findJavaHomesOnWindows() {
95         final Set<String> javaHomes = new HashSet<>();
96         addAllJavaHomesOnWindows(KEY_JRE, javaHomes);
97         addAllJavaHomesOnWindows(KEY_JRE_9, javaHomes);
98         addAllJavaHomesOnWindows(KEY_JDK, javaHomes);
99         addAllJavaHomesOnWindows(KEY_JDK_9, javaHomes);
100         return javaHomes;
101     }
102 
findJavaHomesOnWindows(final String keyJavaHome, final String[] keys)103     private static Set<String> findJavaHomesOnWindows(final String keyJavaHome, final String[] keys) {
104         final Set<String> javaHomes = new HashSet<>(keys.length);
105         for (final String key : keys) {
106             if (Advapi32Util.registryKeyExists(HKEY_LOCAL_MACHINE, keyJavaHome + "\\" + key)) {
107                 final String javaHome = Advapi32Util.registryGetStringValue(HKEY_LOCAL_MACHINE,
108                         keyJavaHome + "\\" + key, "JavaHome");
109                 if (StringUtils.isNoneBlank(javaHome)) {
110                     if (new File(javaHome).exists()) {
111                         javaHomes.add(javaHome);
112                     }
113                 }
114             }
115         }
116         return javaHomes;
117     }
118 
119     private final String javaHome;
120 
JDKGenericDumpTestCase(final String javaHome)121     public JDKGenericDumpTestCase(final String javaHome) {
122         this.javaHome = javaHome;
123     }
124 
compare(final String name, final Method m)125     private void compare(final String name, final Method m) {
126         // System.out.println("Method: " + m);
127         final Code c = m.getCode();
128         if (c == null) {
129             return; // e.g. abstract method
130         }
131         final byte[] src = c.getCode();
132         final InstructionList il = new InstructionList(src);
133         final byte[] out = il.getByteCode();
134         if (src.length == out.length) {
135             assertArrayEquals(name + ": " + m.toString(), src, out);
136         } else {
137             System.out.println(name + ": " + m.toString() + " " + src.length + " " + out.length);
138             System.out.println(bytesToHex(src));
139             System.out.println(bytesToHex(out));
140             for (final InstructionHandle ih : il) {
141                 System.out.println(ih.toString(false));
142             }
143             fail("Array comparison failure");
144         }
145     }
146 
listJDKjars()147     private File[] listJDKjars() throws Exception {
148         final File javaLib = new File(javaHome, "lib");
149         return javaLib.listFiles(new FileFilter() {
150             @Override
151             public boolean accept(final File file) {
152                 return file.getName().endsWith(".jar");
153             }
154         });
155     }
156 
157     private void testJar(final File file) throws Exception {
158         System.out.println(file);
159         try (JarFile jar = new JarFile(file)) {
160             final Enumeration<JarEntry> en = jar.entries();
161             while (en.hasMoreElements()) {
162                 final JarEntry e = en.nextElement();
163                 final String name = e.getName();
164                 if (name.endsWith(".class")) {
165                     // System.out.println("- " + name);
166                     try (InputStream in = jar.getInputStream(e)) {
167                         final ClassParser parser = new ClassParser(in, name);
168                         final JavaClass jc = parser.parse();
169                         for (final Method m : jc.getMethods()) {
170                             compare(name, m);
171                         }
172                     }
173                 }
174             }
175         }
176     }
177 
178     @Test
179     public void testJDKjars() throws Exception {
180         final File[] jars = listJDKjars();
181         if (jars != null) {
182             for (final File file : jars) {
183                 testJar(file);
184             }
185         }
186     }
187 }
188