org.apache.cayenne.util.Invocation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cayenne-client-nodeps
Show all versions of cayenne-client-nodeps
Cayenne Object Persistence Framework
/*****************************************************************
* 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.cayenne.util;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.cayenne.CayenneRuntimeException;
/**
* Invocation represents a dynamic method invocation bound to a specific target. The
* target is kept with a WeakReference and can therefore be reclaimed by the Garbage
* Collector.
*
* @author Holger Hoffstaette
* @author Dirk Olmes
*/
public class Invocation extends Object {
private WeakReference _target;
private Method _method;
private Class[] _parameterTypes;
/**
* Prevent use of empty default constructor
*/
private Invocation() {
}
/**
* Constructor for an Invocation without arguments in the target's method.
*
* @see #Invocation(Object, String, Class[])
*/
public Invocation(Object target, String methodName) throws NoSuchMethodException {
this(target, methodName, (Class[]) null);
}
/**
* Constructor for an Invocation with a single argument in the target's method.
*
* @see #Invocation(Object, String, Class[])
*/
public Invocation(Object target, String methodName, Class parameterType)
throws NoSuchMethodException {
this(target, methodName, new Class[] {
parameterType
});
}
/**
* Constructor for an Invocation with arbitrary arguments in the target's method.
*
* @param target
* @param methodName
* @param parameterTypes
* @throws NoSuchMethodException if methodName
could not be found in
* the target
* @throws IllegalArgumentException if target or methodName are null
,
* or parameterTypes is empty or contains null
elements
*/
public Invocation(Object target, String methodName, Class[] parameterTypes)
throws NoSuchMethodException {
super();
if (target == null) {
throw new IllegalArgumentException("target argument must not be null");
}
if (methodName == null) {
throw new IllegalArgumentException("method name must not be null");
}
if (parameterTypes != null) {
if (parameterTypes.length > 0) {
for (int i = 0; i < parameterTypes.length; i++) {
if (parameterTypes[i] == null) {
throw new IllegalArgumentException("parameter type["
+ i
+ "] must not be null");
}
}
}
else {
throw new IllegalArgumentException("parameter types must not be empty");
}
}
// allow access to public methods of inaccessible classes, if such methods were
// declared in a public interface
_method = lookupMethodInHierarchy(target.getClass(), methodName, parameterTypes);
if (_method == null) {
throw new NoSuchMethodException("No such method: "
+ target.getClass().getName()
+ "."
+ methodName);
}
if (!Util.isAccessible(_method)) {
_method.setAccessible(true);
}
_parameterTypes = parameterTypes;
_target = new WeakReference(target);
}
Method lookupMethodInHierarchy(
Class objectClass,
String methodName,
Class[] parameterTypes) throws SecurityException, NoSuchMethodException {
try {
return objectClass.getDeclaredMethod(methodName, parameterTypes);
}
catch (NoSuchMethodException e) {
Class superClass = objectClass.getSuperclass();
if (superClass == null || superClass.getName().equals(Object.class.getName())) {
throw e;
}
return lookupMethodInHierarchy(superClass, methodName, parameterTypes);
}
}
/**
* Invoke the target's method without any arguments.
*
* @see #fire(Object[])
*/
public boolean fire() {
return this.fire(null);
}
/**
* Invoke the target's method with a single argument.
*
* @param argument an object passed to the target's method
* @see #fire(Object[])
*/
public boolean fire(Object argument) {
return this.fire(new Object[] {
argument
});
}
/**
* Invoke the target's method with an arbitrary number of arguments. The number of
* arguments must be consistent with the arguments given at construction time of this
* Invocation.
*
* @param arguments an array of objects passed to the target's method
* @return true
if invocation of the method succeeded, otherwise
* false
.
* @throws IllegalArgumentException if the passed arguments are inconsistent with the
* arguments passed to this instance's constructor
* @see #fire(Object[])
*/
public boolean fire(Object[] arguments) {
if (_parameterTypes == null) {
if (arguments != null) {
throw new IllegalArgumentException("arguments unexpectedly != null");
}
}
else if (arguments == null) {
throw new IllegalArgumentException("arguments must not be null");
}
else if (_parameterTypes.length != arguments.length) {
throw new IllegalArgumentException(
"inconsistent number of arguments: expected"
+ _parameterTypes.length
+ ", got "
+ arguments.length);
}
Object currentTarget = _target.get();
if (currentTarget == null) {
return false;
}
try {
_method.invoke(currentTarget, arguments);
return true;
}
catch (InvocationTargetException ite) {
// this is the only type of exception that can be rethrown, since
// listener can have a valid need to respond to an event with exception,
// and this does not indicate that it is being in invalid state
Throwable cause = ite.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
else {
throw new CayenneRuntimeException(cause);
}
}
catch (Exception ex) {
// all other exceptions indicate propblems with the listener,
// so return invalid status
return false;
}
}
/**
* @see Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if ((obj != null) && (obj.getClass().equals(this.getClass()))) {
Invocation otherInvocation = (Invocation) obj;
if (_method.equals(otherInvocation.getMethod())) {
Object otherTarget = otherInvocation.getTarget();
Object target = _target.get();
if ((target == null) && (otherTarget == null)) {
return true;
}
if ((target == null) && (otherTarget != null)) {
return false;
}
if (target != null) {
return target.equals(otherTarget);
}
}
return false;
}
else {
return super.equals(obj);
}
}
/**
* @see Object#hashCode()
*/
public int hashCode() {
// IMPORTANT: DO NOT include Invocation target into whatever
// algorithm is used to compute hashCode, since it is using a
// WeakReference and can be released at a later time, altering
// hashCode, and breaking collections using Invocation as a key
// (e.g. event DispatchQueue)
// TODO: use Jakarta commons HashBuilder
int hash = 42, hashMultiplier = 59;
return hash * hashMultiplier + _method.hashCode();
}
/**
* @return the method to be invoked on the target
*/
public Method getMethod() {
return _method;
}
/**
* @return the target object of this Invocation
*/
public Object getTarget() {
return _target.get();
}
/**
* @return an array of Classes describing the target method's parameters
*/
public Class[] getParameterTypes() {
return _parameterTypes;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy