/*
* ============================================================================
* GNU Lesser General Public License
* ============================================================================
*
* Beanlet - JSE Application Container.
* Copyright (C) 2006 Leon van Zantvoort
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Leon van Zantvoort
* 243 Acalanes Drive #11
* Sunnyvale, CA 94086
* USA
*
* zantvoort@users.sourceforge.net
* http://beanlet.org
*/
package org.beanlet.impl;
import static java.lang.annotation.ElementType.*;
import java.lang.reflect.*;
import java.util.Set;
import org.beanlet.BeanletTypeMismatchException;
import org.beanlet.BeanletWiringException;
import org.beanlet.annotation.ConstructorElement;
import org.beanlet.annotation.ConstructorParameterElement;
import org.beanlet.annotation.Element;
import org.beanlet.annotation.FieldElement;
import org.beanlet.annotation.MethodElement;
import org.beanlet.annotation.MethodParameterElement;
import org.beanlet.annotation.ParameterElement;
import org.beanlet.plugin.DependencyInjection;
import org.beanlet.plugin.Injectant;
import org.jargo.ComponentConfiguration;
import org.jargo.ComponentContext;
/**
*
* @author Leon van Zantvoort
*/
public class ValidatingDependencyInjection implements DependencyInjection {
private final String beanletName;
private final DependencyInjection injection;
public ValidatingDependencyInjection(ComponentConfiguration<?> configuration,
DependencyInjection injection) {
this.beanletName = configuration.getComponentName();
this.injection = injection;
}
public Element getTarget() {
Element element = injection.getTarget();
assert element.getElementType() == FIELD ||
element.getElementType() == METHOD ||
element.getElementType() == CONSTRUCTOR ||
element.getElementType() == PARAMETER :
element.getElementType();
return element;
}
public boolean isOptional() {
return injection.isOptional();
}
public Set<String> getDependencies() throws BeanletWiringException {
return injection.getDependencies();
}
public Injectant<?> getInjectant(ComponentContext<?> ctx) throws
BeanletWiringException {
// Assertion errors are the result of incorrectly implemented dependency injection factories.
Injectant injectant = injection.getInjectant(ctx);
if (injectant != null) {
Object o = injectant.getObject();
Element target = getTarget();
if (injectant.isStatic()) {
switch (target.getElementType()) {
case CONSTRUCTOR:
Constructor c = ((ConstructorElement) target).getConstructor();
assert c.getParameterTypes().length == 0;
break;
case METHOD:
Method m = ((MethodElement) target).getMethod();
assert m.getParameterTypes().length == 0;
assert Modifier.isStatic(m.getModifiers());
assert !m.getReturnType().equals(Void.TYPE);
break;
case FIELD:
Field f = ((FieldElement) target).getField();
assert Modifier.isStatic(f.getModifiers());
break;
default:
assert false;
}
} else {
Class<?> type = getType(target);
if (o == null) {
if (type.isPrimitive()) {
throw new BeanletWiringException(beanletName,
getMember(target),
"Primitive cannot be injected with null value.");
}
} else {
final boolean match;
Class<?> injectantType = o.getClass();
if (type.isPrimitive()) {
if (Boolean.TYPE.equals(type)) {
match = injectantType.equals(Boolean.class);
} else if (Byte.TYPE.equals(type)) {
match = injectantType.equals(Byte.class);
} else if (Short.TYPE.equals(type)) {
match = injectantType.equals(Short.class);
} else if (Integer.TYPE.equals(type)) {
match = injectantType.equals(Integer.class);
} else if (Long.TYPE.equals(type)) {
match = injectantType.equals(Long.class);
} else if (Float.TYPE.equals(type)) {
match = injectantType.equals(Float.class);
} else if (Double.TYPE.equals(type)) {
match = injectantType.equals(Double.class);
} else {
assert false : type;
match = false;
}
} else {
match = type.isAssignableFrom(injectantType);
}
if (!match) {
throw new BeanletTypeMismatchException(beanletName,
getMember(target), type, injectantType);
}
}
}
}
return injectant;
}
private Class<?> getType(Element element) {
final Class<?> type;
switch (element.getElementType()) {
case FIELD:
type = ((FieldElement) element).getField().getType();
break;
case METHOD:
Method method = ((MethodElement) element).getMethod();
assert method.getParameterTypes().length > 0;
type = method.getParameterTypes()[0];
break;
case CONSTRUCTOR:
Constructor contructor = ((ConstructorElement) element).
getConstructor();
assert contructor.getParameterTypes().length > 0;
type = contructor.getParameterTypes()[0];
break;
case PARAMETER:
int parameter = ((ParameterElement) element).getParameter();
if (element instanceof MethodParameterElement) {
Method m = ((MethodParameterElement) element).getMethod();
assert parameter >= 0 && parameter < m.getParameterTypes().length;
type = m.getParameterTypes()[parameter];
} else if (element instanceof ConstructorParameterElement) {
Constructor c = ((ConstructorParameterElement) element).getConstructor();
assert parameter >= 0 && parameter < c.getParameterTypes().length;
type = c.getParameterTypes()[parameter];
} else {
assert false : element.getElementType();
type = null;
}
break;
default:
assert false;
type = null;
}
return type;
}
/**
* @return possibly {@code null}.
*/
public Member getMember(Element element) {
// PENDING: copied from AbstractDependencyInjectionFactory
final Member member;
switch (element.getElementType()) {
case ANNOTATION_TYPE:
member = null;
break;
case CONSTRUCTOR:
member = ((ConstructorElement) element).
getConstructor();
break;
case FIELD:
member = ((FieldElement) element).getField();
break;
case LOCAL_VARIABLE:
member = null;
break;
case METHOD:
member = ((MethodElement) element).getMethod();
break;
case PACKAGE:
member = null;
break;
case PARAMETER:
if (element instanceof ConstructorParameterElement) {
ConstructorParameterElement cpe = (ConstructorParameterElement) element;
member = cpe.getConstructor();
} else if (element instanceof MethodParameterElement) {
MethodParameterElement mpe = (MethodParameterElement) element;
member = mpe.getMethod();
} else {
member = null;
}
break;
case TYPE:
member = null;
break;
default:
member = null;
break;
}
return member;
}
}