/*******************************************************************************
* Licensed 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.kato.tck.scenario142.javaruntime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.tools.diagnostics.image.CorruptData;
import javax.tools.diagnostics.image.CorruptDataException;
import javax.tools.diagnostics.image.DataUnavailable;
import javax.tools.diagnostics.image.MemoryAccessException;
import javax.tools.diagnostics.runtime.java.JavaClass;
import javax.tools.diagnostics.runtime.java.JavaClassLoader;
import javax.tools.diagnostics.runtime.java.JavaField;
import javax.tools.diagnostics.runtime.java.JavaObject;
import javax.tools.diagnostics.runtime.java.JavaReference;
import javax.tools.diagnostics.runtime.java.JavaRuntime;
import javax.tools.diagnostics.runtime.java.JavaThread;
import org.apache.kato.tck.harness.TCKJavaRuntimeTestcase;
import org.apache.kato.tck.scenario142.javaruntime.SetupJavaRuntime_getHeapRoots;
import org.apache.kato.tck.scenario142.javaruntime.SetupJavaRuntime_getHeapRoots.HeapRoot;
public class TestJavaRuntime_getHeapRoots extends TCKJavaRuntimeTestcase {
private SetupJavaRuntime_getHeapRoots setup=new SetupJavaRuntime_getHeapRoots();
private static JavaClass javaLangString = null;
public static Map rootsCheckList = null;
public void testSystemClassRoots() {
if (rootsCheckList == null) {
rootsCheckList = getRootsCheckList();
}
assertTrue("Found system classes not reported as roots.", checkSystemClasses(rootsCheckList));
}
public void testThreadRoot() {
if (rootsCheckList == null) {
rootsCheckList = getRootsCheckList();
}
HeapRoot[] roots = searchRootByClassName(rootsCheckList, "HeapRootsTestThread", JavaReference.HEAP_ROOT_THREAD);
assertTrue("Found thread not reported as root.", roots.length != 0);
}
public void testClassloaderRoot() {
if (rootsCheckList == null) {
rootsCheckList = getRootsCheckList();
}
HeapRoot[] roots = searchRootByClassName(rootsCheckList, "HeapRootsTestClassLoader", JavaReference.HEAP_ROOT_CLASSLOADER);
assertTrue("Found classloader not reported as root.", roots.length != 0);
}
public void testUnfinalizedRoot() {
if (rootsCheckList == null) {
rootsCheckList = getRootsCheckList();
}
HeapRoot[] roots = searchRootByClassName(rootsCheckList, "HeapRootsTestUnfinalized", JavaReference.HEAP_ROOT_UNFINALIZED_OBJ);
assertTrue("Found unfinalized object not reported as root.", roots.length != 0);
}
public void testFinalizableRoot() {
if (rootsCheckList == null) {
rootsCheckList = getRootsCheckList();
}
HeapRoot[] roots = searchRootByClassName(rootsCheckList, "HeapRootsTestFinalizable", JavaReference.HEAP_ROOT_FINALIZABLE_OBJ);
assertTrue("Found finalizable object not reported as root.", roots.length != 0);
}
public void testStringTableRoot() {
if (rootsCheckList == null) {
rootsCheckList = getRootsCheckList();
}
HeapRoot[] roots = searchRootByClassName(rootsCheckList, "", JavaReference.HEAP_ROOT_STRINGTABLE);
HeapRoot currentRoot = null;
JavaField countField = null;
JavaField valueField = null;
Iterator fields = javaLangString.getDeclaredFields().iterator();
while (fields.hasNext()) {
Object next = fields.next();
if (next instanceof JavaField) {
JavaField field = (JavaField) next;
try {
if (field.getName().equals("value")) {
valueField = field;
} else if (field.getName().equals("count")) {
countField = field;
}
} catch (CorruptDataException e) {
assertNotNull(e.getCorruptData());
}
}
}
boolean found = false;
for (int i=0; i<roots.length; i++) {
currentRoot = roots[i];
Object rootObject = currentRoot.getRoot();
if (!(rootObject instanceof JavaObject)) {
continue;
}
JavaObject root = (JavaObject)rootObject;
try {
int length = countField.getInt(root);
char[] contents = new char[length];
Object valueObj = valueField.get(root);
if (valueObj instanceof JavaObject) {
JavaObject value = (JavaObject)valueObj;
value.arraycopy(0, contents, 0, length);
}
String currentString = new String(contents);
if (SetupJavaRuntime_getHeapRoots.DTFJ_STRING_TABLE_ROOT_TEST.equals(currentString)) {
found = true;
break;
}
} catch (CorruptDataException e) {
assertNotNull(e.getCorruptData());
e.printStackTrace();
} catch (MemoryAccessException e) {
assertNotNull(e.getPointer());
e.printStackTrace();
}
}
assertTrue("Found stringtable not reported as root.", found);
}
/* to be moved to the JavaStackFrame#getHeapRoots()
public void testJavaParameters() {
if (rootsCheckList == null) {
rootsCheckList = getRootsCheckList();
}
assertTrue("Found local variable not reported as root.", checkRoot(rootsCheckList, "HeapRootsTestLocalVariableClass"));
}
public void testJavaLocalVariables() {
if (rootsCheckList == null) {
rootsCheckList = getRootsCheckList();
}
assertTrue("Found local variable not reported as root.", checkRoot(rootsCheckList, "HeapRootsTestLocalVariableClass"));
}
*/
private Map getRootsCheckList() {
JavaRuntime runtime = getJavaRuntime();
Map rootsCheckList = new HashMap();
Iterator roots = runtime.getHeapRoots().iterator();
while (roots.hasNext()) {
Object next = roots.next();
if (next instanceof CorruptData) {
continue;
}
JavaReference r = (JavaReference)next;
try {
Object root = r.getTarget();
int type = r.getRootType();
HeapRoot rootObject = new HeapRoot(root, type);
rootsCheckList.put(rootObject, Boolean.FALSE);
//System.out.println("Adding " + rootObject + " to rootCheckList" );
} catch (DataUnavailable du) {
} catch (CorruptDataException cde) {
assertNotNull(cde.getCorruptData());
}
}
return rootsCheckList;
}
/** Tests whether all the system classes are correctly reported as roots */
// need to ignore primitive types
private boolean checkSystemClasses(Map rootsCheckList) {
JavaClassLoader systemClassLoader = getBootClassLoader();
Iterator systemClasses = systemClassLoader.getDefinedClasses().iterator();
boolean passed = true;
String systemClassName = null;
while (systemClasses.hasNext()) {
Object next = systemClasses.next();
if (next instanceof CorruptData) {
continue;
}
JavaClass systemClass = (JavaClass)next;
try {
systemClassName = systemClass.getName();
} catch (CorruptDataException e) {
assertNotNull(e.getCorruptData());
e.printStackTrace();
}
if (systemClassName.equals("java/lang/String")) {
javaLangString = systemClass; // to be used later on
}
// primitive types are reported as loaded by the System classloader,
// so they can be found, but they are not scanned as roots
if (!(systemClassName.equals("void")
|| systemClassName.equals("boolean")
|| systemClassName.equals("byte")
|| systemClassName.equals("char")
|| systemClassName.equals("short")
|| systemClassName.equals("int")
|| systemClassName.equals("long")
|| systemClassName.equals("float")
|| systemClassName.equals("double")))
{
Object rootClass = rootsCheckList.get(new HeapRoot(systemClass,JavaReference.HEAP_ROOT_SYSTEM_CLASS));
if (rootClass == null) {
System.out.println("Found a class loaded by the system classloader which is NOT a root:" + systemClassName);
passed = false;
} else {
//System.out.println("Found root object for system class: " + systemClassName);
rootsCheckList.put(rootClass, Boolean.TRUE);
}
}
}
return passed;
}
private HeapRoot[] searchRootByClassName(Map rootCheckList, String classNameToSearch) {
return searchRootByClassName(rootCheckList, classNameToSearch, 0);
}
private HeapRoot[] searchRootByClassName(Map rootCheckList, String classNameToSearch, int type) {
String className;
ArrayList roots = new ArrayList();
Iterator i = rootsCheckList.keySet().iterator();
while (i.hasNext()) {
Object next = i.next();
if (!(next instanceof HeapRoot)) {
continue;
}
HeapRoot rootObject = (HeapRoot)next;
Object root = rootObject.getRoot();
int rootType = rootObject.getType();
if (type != 0 && type != rootType) {
continue;
}
try {
if (root instanceof JavaObject) {
className = ((JavaObject)root).getJavaClass().getName();
} else if (root instanceof JavaClass) {
className = ((JavaClass)root).getName();
} else {
continue;
}
// System.out.println("Checking root object of class: "+ className + " root type: " + HeapRoot.getRootTypeDescription(rootType));
if (className.endsWith(classNameToSearch)) {
// System.out.println("Found root object of class: "+ className + " root type: " + HeapRoot.getRootTypeDescription(rootType));
roots.add(rootObject);
}
} catch (CorruptDataException e) {
assertNotNull(e.getCorruptData());
continue;
}
}
//System.out.println("Root object of type " + classNameToSearch + " not found.");
HeapRoot[] heapRoots = (HeapRoot[])roots.toArray(new HeapRoot[0]);
return heapRoots;
}
/**
* This test applies only to JVMs whose thread roots only appear with the rest of the roots,
* and not in JavaStackFrames because of conservative garbage collection.
*/
public void testJavaThreadRoots() throws Exception {
JavaThread thread = null;
// Find the thread to match as a root source.
Iterator threads = getJavaRuntime().getThreads().iterator();
while(threads.hasNext()) {
JavaThread candidateThread = (JavaThread) threads.next();
if (setup.javaLocalRootsthreadName.equals(candidateThread.getName())) {
thread = candidateThread;
break;
}
}
assertNotNull("Couldn't find thread "+setup.javaLocalRootsthreadName, thread);
// Set up a set of JavaObject class names to look for.
Set roots = new HashSet();
roots.add(SetupJavaStackFrame_getHeapRoots.HeapRootsTestLocalVariable.class.getName().replace('.', '/'));
roots.add(SetupJavaStackFrame_getHeapRoots.HeapRootsTestParam.class.getName().replace('.', '/'));
// Find all JavaObject heaproots that have our test thread as a source
// Remove their class names from our set of expected names.
Iterator rootIterator = getJavaRuntime().getHeapRoots().iterator();
while(rootIterator.hasNext()) {
JavaReference reference = (JavaReference) rootIterator.next();
if (thread.equals(reference.getSource())) {
if(reference.getTarget() instanceof JavaObject) {
JavaObject target = (JavaObject) reference.getTarget();
roots.remove(target.getJavaClass().getName());
}
}
}
// Create error string of missing object.
String remainingRoots="";
// uh-oh, we should have found all our roots
if(roots.size()>0) {
Iterator rootsLeft = roots.iterator();
while(rootsLeft.hasNext()) {
remainingRoots += " " + ((String) rootsLeft.next());
}
}
assertFalse("Thread roots not found: " + remainingRoots, roots.size() >0);
}
}