001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.event;
020:
021: import java.io.Externalizable;
022: import java.io.IOException;
023: import java.io.ObjectInput;
024: import java.io.ObjectOutput;
025: import java.lang.reflect.Method;
026: import java.security.AccessController;
027: import java.util.Arrays;
028:
029: import org.apache.openjpa.lib.util.J2DoPrivHelper;
030: import org.apache.openjpa.lib.util.Localizer;
031: import org.apache.openjpa.util.UserException;
032:
033: /**
034: * Callback adapter that invokes a callback method via reflection.
035: *
036: * @author Steve Kim
037: */
038: public class MethodLifecycleCallbacks implements LifecycleCallbacks,
039: Externalizable {
040:
041: private static final Localizer _loc = Localizer
042: .forPackage(MethodLifecycleCallbacks.class);
043:
044: private transient Method _callback;
045: private boolean _arg;
046:
047: /**
048: * Constructor. Supply callback class and its callback method name.
049: *
050: * @arg Whether we expect a further argument such as in AfterDetach
051: */
052: public MethodLifecycleCallbacks(Class cls, String method,
053: boolean arg) {
054: Class[] args = arg ? new Class[] { Object.class } : null;
055: _callback = getMethod(cls, method, args);
056: _arg = arg;
057: }
058:
059: /**
060: * Constructor. Supply callback method.
061: */
062: public MethodLifecycleCallbacks(Method method, boolean arg) {
063: _callback = method;
064: _arg = arg;
065: }
066:
067: /**
068: * The callback method.
069: */
070: public Method getCallbackMethod() {
071: return _callback;
072: }
073:
074: /**
075: * Returns if this callback expects another argument
076: */
077: public boolean requiresArgument() {
078: return _arg;
079: }
080:
081: public boolean hasCallback(Object obj, int eventType) {
082: return true;
083: }
084:
085: public void makeCallback(Object obj, Object arg, int eventType)
086: throws Exception {
087: if (!_callback.isAccessible())
088: AccessController.doPrivileged(J2DoPrivHelper
089: .setAccessibleAction(_callback, true));
090:
091: if (_arg)
092: _callback.invoke(obj, new Object[] { arg });
093: else
094: _callback.invoke(obj, (Object[]) null);
095: }
096:
097: public String toString() {
098: return getClass().getName() + ":" + _callback;
099: }
100:
101: /**
102: * Helper method to return the named method of the given class, throwing
103: * the proper exception on error.
104: */
105: protected static Method getMethod(Class cls, String method,
106: Class[] args) {
107: Class currentClass = cls;
108: do {
109: Method[] methods = (Method[]) AccessController
110: .doPrivileged(J2DoPrivHelper
111: .getDeclaredMethodsAction(currentClass));
112: for (int i = 0; i < methods.length; i++) {
113: if (!method.equals(methods[i].getName()))
114: continue;
115:
116: if (isAssignable(methods[i].getParameterTypes(), args))
117: return methods[i];
118: }
119: } while ((currentClass = currentClass.getSuperclass()) != null);
120:
121: // if we get here, no suitable method was found
122: throw new UserException(_loc.get("method-notfound", cls
123: .getName(), method, args == null ? null : Arrays
124: .asList(args)));
125: }
126:
127: /**
128: * Returns true if all parameters in the from array are assignable
129: * from the corresponding parameters of the to array.
130: */
131: private static boolean isAssignable(Class[] from, Class[] to) {
132: if (from == null)
133: return to == null || to.length == 0;
134: if (to == null)
135: return from == null || from.length == 0;
136:
137: if (from.length != to.length)
138: return false;
139:
140: for (int i = 0; i < from.length; i++) {
141: if (from[i] != null && !from[i].isAssignableFrom(to[i]))
142: return false;
143: }
144:
145: return true;
146: }
147:
148: public void readExternal(ObjectInput in) throws IOException,
149: ClassNotFoundException {
150: Class cls = (Class) in.readObject();
151: String methName = (String) in.readObject();
152: _arg = in.readBoolean();
153:
154: Class[] args = _arg ? new Class[] { Object.class } : null;
155: _callback = getMethod(cls, methName, args);
156: }
157:
158: public void writeExternal(ObjectOutput out) throws IOException {
159: out.writeObject(_callback.getClass());
160: out.writeObject(_callback.getName());
161: out.writeBoolean(_arg);
162: }
163: }
|