/*
* Copyright (c) 2012 3 Round Stones Inc., Some rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the openrdf.org nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.openrdf.repository.object.advice.behaviour;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.openrdf.annotations.ParameterTypes;
import org.openrdf.repository.object.advice.Advice;
import org.openrdf.repository.object.composition.BehaviourFactory;
/**
* Modifies composed classes to call Advice.
*/
public class AdviceBehaviourFactory implements BehaviourFactory {
private static final Method intercept = Advice.class.getMethods()[0];
private final Advice advice;
private final Method intercepting;
private final Class<?>[] parameterTypes;
private final Class<?> annotationType;
public AdviceBehaviourFactory(Advice advice, Method intercepting,
Class<?> annotationType) {
assert advice != null;
assert intercepting != null;
assert annotationType != null;
this.advice = advice;
this.intercepting = intercepting;
this.annotationType = annotationType;
if (intercepting.isAnnotationPresent(ParameterTypes.class)) {
parameterTypes = intercepting.getAnnotation(ParameterTypes.class)
.value();
} else {
parameterTypes = intercepting.getParameterTypes();
}
}
public String toString() {
return getName();
}
public String getName() {
return getBehaviourType().getSimpleName();
}
public Class<?> getBehaviourType() {
return Advice.class;
}
public Class<?>[] getInterfaces() {
return new Class<?>[0];
}
public Method[] getMethods() {
return new Method[] { intercepting };
}
public synchronized Method getInvocation(Method method) {
if (intercepting.equals(method))
return intercept;
if (intercepting.getName().equals(method.getName())) {
Class<?>[] ptypes = method.getParameterTypes();
if (Arrays.equals(ptypes, parameterTypes))
return intercept;
if (method.isAnnotationPresent(ParameterTypes.class)) {
Class<?>[] aptypes = method.getAnnotation(ParameterTypes.class)
.value();
if (Arrays.equals(aptypes, parameterTypes))
return intercept;
}
}
return null;
}
public boolean precedes(Method invocation, BehaviourFactory factory,
Method to) {
if (factory instanceof AdviceBehaviourFactory) {
AdviceBehaviourFactory o = (AdviceBehaviourFactory) factory;
Class<?> cls = intercepting.getDeclaringClass();
Class<?> ocls = o.intercepting.getDeclaringClass();
if (cls.isAssignableFrom(ocls))
return false;
if (ocls.isAssignableFrom(cls))
return true;
if (intercepting.equals(o.intercepting)) {
for (Annotation ann : intercepting.getAnnotations()) {
if (ann.annotationType().equals(o.annotationType))
return false;
if (ann.annotationType().equals(annotationType))
return true;
}
}
return false;
}
return !to.isAnnotationPresent(ParameterTypes.class);
}
public boolean isSingleton() {
return true;
}
public Object getSingleton() {
return advice;
}
public Object newInstance(Object proxy) throws Throwable {
return advice;
}
}