/*
* Copyright 2009-2014 Jose Luis Martin.
*
* Licensed 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.jdal.aop;
import java.util.Map;
import java.util.WeakHashMap;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.IntroductionInterceptor;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.IntroductionInfoSupport;
/**
* DelegatingIntroductionInterceptor that use a Factory to create delegates.
* <p>
* Note: this class include code from {@link org.springframework.aop.support.DelegatePerTargetObjectIntroductionInterceptor}
* </p>
* @author Jose Luis Martin
* @since 2.0
*/
@SuppressWarnings({"serial" })
public class DelegateFactoryIntroductionInterceptor extends IntroductionInfoSupport
implements IntroductionInterceptor {
private DelegateFactory delegateFactory;
private Class<?> interfaceType;
/**
* Hold weak references to keys as we don't want to interfere with garbage collection..
*/
private final Map<Object, Object> delegateMap = new WeakHashMap<Object, Object>();
public DelegateFactoryIntroductionInterceptor(DelegateFactory delegateFactory, Class<?> interfaceType) {
this.delegateFactory = delegateFactory;
this.interfaceType = interfaceType;
this.publishedInterfaces.add(interfaceType);
}
public Object invoke(MethodInvocation mi) throws Throwable {
if (isMethodOnIntroducedInterface(mi)) {
Object delegate = getIntroductionDelegateFor(mi.getThis());
Object retVal = AopUtils.invokeJoinpointUsingReflection(delegate, mi.getMethod(), mi.getArguments());
if (retVal == delegate && mi instanceof ProxyMethodInvocation) {
retVal = ((ProxyMethodInvocation) mi).getProxy();
}
return retVal;
}
return doProceed(mi);
}
protected Object doProceed(MethodInvocation mi) throws Throwable {
return mi.proceed();
}
private Object getIntroductionDelegateFor(Object targetObject) {
synchronized (this.delegateMap) {
if (this.delegateMap.containsKey(targetObject)) {
return this.delegateMap.get(targetObject);
}
else {
Object delegate = createNewDelegate(targetObject);
this.delegateMap.put(targetObject, delegate);
return delegate;
}
}
}
protected Object createNewDelegate(Object targetObject) {
try {
return delegateFactory.createNewDelegate(targetObject);
}
catch(Exception e) {
throw new IllegalStateException("Cant create delegate instance of type [" + this.interfaceType.getName() +
"] : " + e.getMessage());
}
}
public interface DelegateFactory {
Object createNewDelegate(Object target) throws Exception;
}
}