| /* |
| * 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.openjpa.event; |
| |
| import java.io.Externalizable; |
| import java.io.IOException; |
| import java.io.ObjectInput; |
| import java.io.ObjectOutput; |
| import java.lang.reflect.Method; |
| import java.security.AccessController; |
| import java.util.Arrays; |
| |
| import org.apache.openjpa.lib.util.J2DoPrivHelper; |
| import org.apache.openjpa.lib.util.Localizer; |
| import org.apache.openjpa.util.UserException; |
| |
| /** |
| * Callback adapter that invokes a callback method via reflection. |
| * |
| * @author Steve Kim |
| */ |
| public class MethodLifecycleCallbacks |
| implements LifecycleCallbacks, Externalizable { |
| |
| private static final Localizer _loc = Localizer.forPackage |
| (MethodLifecycleCallbacks.class); |
| |
| private transient Method _callback; |
| private boolean _arg; |
| |
| /** |
| * Constructor. Supply callback class and its callback method name. |
| * |
| * @param arg Whether we expect a further argument such as in AfterDetach |
| */ |
| public MethodLifecycleCallbacks(Class cls, String method, boolean arg) { |
| Class[] args = arg ? new Class[]{ Object.class } : null; |
| _callback = getMethod(cls, method, args); |
| _arg = arg; |
| } |
| |
| /** |
| * Constructor. Supply callback method. |
| */ |
| public MethodLifecycleCallbacks(Method method, boolean arg) { |
| _callback = method; |
| _arg = arg; |
| } |
| |
| /** |
| * The callback method. |
| */ |
| public Method getCallbackMethod() { |
| return _callback; |
| } |
| |
| /** |
| * Returns if this callback expects another argument |
| */ |
| public boolean requiresArgument() { |
| return _arg; |
| } |
| |
| @Override |
| public boolean hasCallback(Object obj, int eventType) { |
| return true; |
| } |
| |
| @Override |
| public void makeCallback(Object obj, Object arg, int eventType) |
| throws Exception { |
| if (!_callback.isAccessible()) |
| AccessController.doPrivileged(J2DoPrivHelper.setAccessibleAction( |
| _callback, true)); |
| |
| if (_arg) |
| _callback.invoke(obj, new Object[]{ arg }); |
| else |
| _callback.invoke(obj, (Object[]) null); |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getName() + ":" + _callback; |
| } |
| |
| /** |
| * Helper method to return the named method of the given class, throwing |
| * the proper exception on error. |
| */ |
| protected static Method getMethod(Class cls, String method, Class[] args) { |
| Class currentClass = cls; |
| do { |
| Method[] methods = (Method[]) AccessController.doPrivileged( |
| J2DoPrivHelper.getDeclaredMethodsAction(currentClass)); |
| for (Method value : methods) { |
| if (!method.equals(value.getName())) |
| continue; |
| |
| if (isAssignable(value.getParameterTypes(), args)) |
| return value; |
| } |
| } while ((currentClass = currentClass.getSuperclass()) != null); |
| |
| // if we get here, no suitable method was found |
| throw new UserException(_loc.get("method-notfound", cls.getName(), |
| method, args == null ? null : Arrays.asList(args))); |
| } |
| |
| /** |
| * Returns true if all parameters in the from array are assignable |
| * from the corresponding parameters of the to array. |
| */ |
| private static boolean isAssignable(Class[] from, Class[] to) { |
| if (from == null) |
| return to == null || to.length == 0; |
| if (to == null) |
| return from == null || from.length == 0; |
| |
| if (from.length != to.length) |
| return false; |
| |
| for (int i = 0; i < from.length; i++) { |
| if (from[i] != null && !from[i].isAssignableFrom(to[i])) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public void readExternal(ObjectInput in) |
| throws IOException, ClassNotFoundException { |
| Class cls = (Class) in.readObject(); |
| String methName = (String) in.readObject(); |
| _arg = in.readBoolean(); |
| |
| Class[] args = _arg ? new Class[]{ Object.class } : null; |
| _callback = getMethod(cls, methName, args); |
| } |
| |
| @Override |
| public void writeExternal(ObjectOutput out) |
| throws IOException { |
| out.writeObject(_callback.getClass()); |
| out.writeObject(_callback.getName()); |
| out.writeBoolean(_arg); |
| } |
| } |