blob: 8dbae59e8e434fd8862b7b30f12f2c83155263bf [file] [log] [blame]
/*
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package nsk.share.jdi;
import java.lang.reflect.*;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
import nsk.share.TestBug;
/*
* EventFilters class just contain all filter classes
*/
public class EventFilters
{
/*
* Class is intended for testing event filters.
*
* Since different request classes have identical methods for adding filters(e.g. addInstanceFilter(),addClassFilter())
* but this classes don't have common superclass reflection is used for filter adding.
* Subclasses should implement following methods:
* - getMethodName(), provide filter adding method's name
* - getParametersTypes(), provide filter adding method's parameters types
* - getFilterParameters(), provide parameters to be passed in filter adding method
*
* Also to check is generated event was really filtered subclasses should implement method 'isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)',
* this method should check is event generated by given object in given thread accepted by filter.
*/
public abstract static class DebugEventFilter
{
// eventObject - object which generate event
// eventThread - thread where event was generated
abstract public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread);
// call corresponding request's method to set event filter
public void addFilter(EventRequest request)
throws Throwable
{
java.lang.reflect.Method method;
try
{
method = request.getClass().getMethod(getMethodName(), getParametersTypes());
}
catch(Exception e)
{
throw new TestBug("Can't get method '" + getMethodName() + "'");
}
try
{
method.setAccessible(true);
method.invoke(request, getFilterParameters());
}
catch(IllegalAccessException e)
{
TestBug testBug = new TestBug("Can't call method '" + getMethodName() + "'");
testBug.initCause(e);
throw testBug;
}
catch(InvocationTargetException e)
{
throw e.getCause();
}
}
public boolean isSupported(VirtualMachine vm)
{
return true;
}
abstract protected String getMethodName();
abstract protected Class[] getParametersTypes();
abstract protected Object[] getFilterParameters();
}
/*
* Restricts the events to those whose method is in a class whose name matches this
* restricted regular expression. Only simple regular expressions that begin with '*' or end with '*' are supported
*/
public static class ClassFilter
extends DebugEventFilter
{
protected String classPattern;
private String startsWithPattern;
private String endsWithPattern;
public ClassFilter(String classPattern)
{
this.classPattern = classPattern;
if(classPattern.startsWith("*"))
endsWithPattern = classPattern.substring(1);
else
if(classPattern.endsWith("*"))
startsWithPattern = classPattern.substring(0, classPattern.length() - 1);
}
public String toString()
{
return "ClassFilter: classes should match pattern: " + classPattern;
}
protected String getMethodName()
{
return "addClassFilter";
}
protected Class[] getParametersTypes()
{
return new Class[]{String.class};
}
protected Object[] getFilterParameters()
{
return new Object[]{classPattern};
}
public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
{
if(!isNameMatch(eventObject.referenceType().name()))
return false;
else
return true;
}
protected boolean isNameMatch(String className)
{
if(startsWithPattern != null)
return className.startsWith(startsWithPattern);
else
if(endsWithPattern != null)
return className.endsWith(endsWithPattern);
else
return className.equals(classPattern);
}
}
/*
* Restricts the events to those whose method is in a class whose name doesn't matches
* restricted regular expression. Only simple regular expressions that begin with '*' or end with '*' are supported
*/
public static class ClassExclusionFilter
extends ClassFilter
{
public ClassExclusionFilter(String classPattern)
{
super(classPattern);
}
public String toString()
{
return "ClassExclusionFilter: classes match follows pattern should be excluded: " + classPattern;
}
protected String getMethodName()
{
return "addClassExclusionFilter";
}
public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
{
if(isNameMatch(eventObject.referenceType().name()))
return false;
else
return true;
}
}
/*
* Restricts the events to those whose method is in the given reference type or any of its subtypes
*/
public static class ClassReferenceFilter
extends DebugEventFilter
{
private Class<?> filterClass;
private ReferenceType referenceType;
public ClassReferenceFilter(ReferenceType referenceType)
{
this.referenceType = referenceType;
filterClass = findClass(referenceType);
}
public String toString()
{
return "ClassReferenceFilter: expect only " + filterClass.getName() + " and its subclasses";
}
protected String getMethodName()
{
return "addClassFilter";
}
protected Class[] getParametersTypes()
{
return new Class[]{ReferenceType.class};
}
protected Object[] getFilterParameters()
{
return new Object[]{referenceType};
}
public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
{
Class<?> eventObjectClass = findClass(eventObject.referenceType());
if(!filterClass.isAssignableFrom(eventObjectClass))
return false;
else
return true;
}
// find class represented by given referenceType
private Class<?> findClass(ReferenceType referenceType)
{
try
{
return Class.forName(referenceType.name());
}
catch(ClassNotFoundException e)
{
throw new TestBug("Can't find class: " + referenceType.name());
}
}
}
/*
* Restricts the events to those in which the currently executing instance ("this") is the given object
*/
public static class ObjectReferenceFilter
extends DebugEventFilter
{
private ObjectReference objectReference;
public ObjectReferenceFilter(ObjectReference objectReference)
{
this.objectReference = objectReference;
}
public String toString()
{
return "ObjectReferenceFilter: expect only object " + objectReference;
}
protected String getMethodName()
{
return "addInstanceFilter";
}
protected Class[] getParametersTypes()
{
return new Class[]{ObjectReference.class};
}
protected Object[] getFilterParameters()
{
return new Object[]{objectReference};
}
public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
{
return objectReference.equals(eventObject);
}
public boolean isSupported(VirtualMachine vm)
{
return vm.canUseInstanceFilters();
}
}
/*
* Restricts the events to those in the given thread
*/
public static class ThreadFilter
extends DebugEventFilter
{
private ThreadReference threadReference;
public ThreadFilter(ThreadReference threadReference)
{
this.threadReference = threadReference;
}
public String toString()
{
return "ThreadReferenceFilter: expect only thread " + threadReference;
}
protected String getMethodName()
{
return "addThreadFilter";
}
protected Class[] getParametersTypes()
{
return new Class[]{ThreadReference.class};
}
protected Object[] getFilterParameters()
{
return new Object[]{threadReference};
}
public boolean isObjectMatch(ObjectReference eventObject, ThreadReference eventThread)
{
return threadReference.equals(eventThread);
}
}
public static boolean filtered(Event event) {
if (event.toString().contains("VM JFR Buffer Thread"))
return true;
if (event.toString().contains("JFR request timer"))
return true;
return false;
}
// Filters out events with location not matching the given type.
public static boolean filtered(Event event, String typeName) {
if (event instanceof Locatable) {
Location location = ((Locatable) event).location();
if (location != null) {
ReferenceType declaringType = location.declaringType();
if (declaringType != null && typeName.equals(declaringType.name())) {
return false;
}
}
}
return true;
}
}