| // | |
| // 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 com.cloud.utils; | |
| import java.lang.reflect.Method; | |
| import java.util.WeakHashMap; | |
| import net.sf.cglib.proxy.Callback; | |
| import net.sf.cglib.proxy.CallbackFilter; | |
| import net.sf.cglib.proxy.Enhancer; | |
| import net.sf.cglib.proxy.MethodInterceptor; | |
| import net.sf.cglib.proxy.MethodProxy; | |
| /* | |
| * This helper class provides a way to retrieve Method in a strong-type way. It takes advantage of power of | |
| * Intelligent IDE(Eclipse) in code-editing | |
| * | |
| * DummyImpl dummy = new DummyImpl(); | |
| * MethodCapturer<DummyImpl> capturer = MethodCapturer.capture(dummy); | |
| * Method method = capturer.get(capturer.instance().foo2()); | |
| * | |
| */ | |
| public class MethodCapturer<T> { | |
| private final static int CACHE_SIZE = 1024; | |
| private T _instance; | |
| private Method _method; | |
| private static WeakHashMap<Object, Object> s_cache = new WeakHashMap<Object, Object>(); | |
| private MethodCapturer() { | |
| } | |
| @SuppressWarnings("unchecked") | |
| public static <T> MethodCapturer<T> capture(T obj) { | |
| synchronized (s_cache) { | |
| MethodCapturer<T> capturer = (MethodCapturer<T>)s_cache.get(obj); | |
| if (capturer != null) { | |
| return capturer; | |
| } | |
| final MethodCapturer<T> capturerNew = new MethodCapturer<T>(); | |
| Enhancer en = new Enhancer(); | |
| en.setSuperclass(obj.getClass()); | |
| en.setCallbacks(new Callback[] {new MethodInterceptor() { | |
| @Override | |
| public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { | |
| capturerNew.setMethod(arg1); | |
| return null; | |
| } | |
| }, new MethodInterceptor() { | |
| @Override | |
| public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { | |
| return null; | |
| } | |
| }}); | |
| en.setCallbackFilter(new CallbackFilter() { | |
| @Override | |
| public int accept(Method method) { | |
| if (method.getParameterTypes().length == 0 && method.getName().equals("finalize")) { | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| }); | |
| capturerNew.setInstance((T)en.create()); | |
| // We expect MethodCapturer is only used for singleton objects here, so we only maintain a limited cache | |
| // here | |
| if (s_cache.size() < CACHE_SIZE) { | |
| s_cache.put(obj, capturerNew); | |
| } | |
| return capturerNew; | |
| } | |
| } | |
| public T instance() { | |
| return _instance; | |
| } | |
| private void setInstance(T instance) { | |
| _instance = instance; | |
| } | |
| public Method get(Object... useless) { | |
| return _method; | |
| } | |
| private void setMethod(Method method) { | |
| _method = method; | |
| } | |
| } |