/*******************************************************************************
* Copyright (c) 2011 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.cdi.seam.solder.core.generic;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IAnnotatable;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.osgi.util.NLS;
import org.jboss.tools.cdi.core.CDICoreNature;
import org.jboss.tools.cdi.core.CDIUtil;
import org.jboss.tools.cdi.core.IBean;
import org.jboss.tools.cdi.core.IClassBean;
import org.jboss.tools.cdi.core.IProducer;
import org.jboss.tools.cdi.core.IQualifierDeclaration;
import org.jboss.tools.cdi.internal.core.impl.CDIProject;
import org.jboss.tools.cdi.internal.core.impl.definition.AbstractMemberDefinition;
import org.jboss.tools.cdi.internal.core.impl.definition.AnnotationDefinition;
import org.jboss.tools.cdi.internal.core.impl.definition.TypeDefinition;
import org.jboss.tools.cdi.internal.core.validation.CDICoreValidator;
import org.jboss.tools.cdi.seam.solder.core.CDISeamSolderCorePlugin;
import org.jboss.tools.cdi.seam.solder.core.CDISeamSolderPreferences;
import org.jboss.tools.cdi.seam.solder.core.Version;
import org.jboss.tools.cdi.seam.solder.core.validation.SeamSolderValidationMessages;
import org.jboss.tools.common.java.IAnnotationDeclaration;
import org.jboss.tools.common.java.IParametedType;
import org.jboss.tools.common.text.ITextSourceReference;
/**
*
* @author Viacheslav Kabanovich
*
*/
public class GenericBeanValidator {
Version version;
public GenericBeanValidator(Version version) {
this.version = version;
}
public void validateResource(IFile file, CDICoreValidator validator, CDICoreNature project, GenericBeanDefinitionContext context) {
Map<String, GenericConfiguration> cs = context.getGenericConfigurations();
for (GenericConfiguration c: cs.values()) {
if(c.getInvolvedTypes().contains(file.getFullPath())) {
try {
validateConfiguration(file, c, validator, project, context);
} catch (CoreException e) {
CDISeamSolderCorePlugin.getDefault().logError(e);
}
}
}
}
public void validateConfiguration(IFile file, GenericConfiguration c, CDICoreValidator validator, CDICoreNature project, GenericBeanDefinitionContext context) throws CoreException {
IParametedType t = c.getConfigType();
AnnotationDefinition genericType = c.getGenericTypeDefinition();
if(genericType == null) {
String n = c.getGenericTypeName();
for (TypeDefinition d: c.getGenericBeans()) {
if(d.getResource() != null && d.getResource().equals(file)) {
IAnnotationDeclaration a = d.getAnnotation(version.getGenericConfigurationAnnotationTypeName());
validator.addError(SeamSolderValidationMessages.WRONG_GENERIC_CONFIGURATION_ANNOTATION_REFERENCE,
CDISeamSolderPreferences.WRONG_GENERIC_CONFIGURATION_ANNOTATION_REFERENCE, new String[]{n}, a, file);
}
}
} else if(file.equals(genericType.getResource())) {
if(t != null && context.isGenericBean(t.getType().getFullyQualifiedName())) {
IAnnotationDeclaration a = genericType.getAnnotation(version.getGenericTypeAnnotationTypeName());
validator.addError(SeamSolderValidationMessages.GENERIC_CONFIGURATION_TYPE_IS_A_GENERIC_BEAN,
CDISeamSolderPreferences.GENERIC_CONFIGURATION_TYPE_IS_A_GENERIC_BEAN, new String[0], a, file);
}
}
Map<AbstractMemberDefinition, List<IQualifierDeclaration>> bs = c.getGenericConfigurationPoints();
for (AbstractMemberDefinition d: bs.keySet()) {
if(d.getResource() != null && d.getResource().equals(file) && !d.getTypeDefinition().isVetoed()) {
ITextSourceReference reference = CDIUtil.convertToSourceReference(((IMember)d.getMember()).getNameRange(), file, (IMember)d.getMember());
/*
* If several generic configuration points have the same set of qualifiers,
* than respective generic beans will result in ambiguous beans for injections
* with that set of qualifiers.
*/
StringBuffer duplicates = new StringBuffer();
List<IQualifierDeclaration> ds = bs.get(d);
for (AbstractMemberDefinition d1: bs.keySet()) {
List<IQualifierDeclaration> ds2 = bs.get(d1);
if(ds2 != ds && !d1.getTypeDefinition().isVetoed()
&& CDIProject.areMatchingQualifiers(ds, ds2)
&& CDIProject.areMatchingQualifiers(ds2, ds)) {
duplicates.append(", ").append(definitionToString(d1));
}
}
if(duplicates.length() > 0) {
duplicates.insert(0, definitionToString(d));
String message = NLS.bind(SeamSolderValidationMessages.AMBIGUOUS_GENERIC_CONFIGURATION_POINT, duplicates.toString());
validator.addError(message,
CDISeamSolderPreferences.AMBIGUOUS_GENERIC_CONFIGURATION_POINT, new String[0], reference, file);
}
/*
* Type of generic configuration point must be assignable to the configuration type.
*/
IBean b = findGenericBean(file, (IMember)d.getMember(), project);
if(t == null || b == null || !CDIProject.containsType(b.getAllTypes(), t)) {
validator.addError(SeamSolderValidationMessages.WRONG_TYPE_OF_GENERIC_CONFIGURATION_POINT,
CDISeamSolderPreferences.WRONG_TYPE_OF_GENERIC_CONFIGURATION_POINT, new String[0], reference, file);
}
}
}
//TODO check`
}
private String definitionToString(AbstractMemberDefinition d) {
IAnnotatable e = d.getMember();
String result = "";
if(e instanceof IType) {
result = ((IType)e).getElementName();
} else if(e instanceof IMember) {
IMember m = (IMember)e;
result = m.getDeclaringType().getElementName() + "." + m.getElementName();
if(e instanceof IMethod) {
result += "()";
}
}
return result;
}
private IBean findGenericBean(IFile file, IMember member, CDICoreNature project) {
for (IBean b: project.getDelegate().getBeans(file.getFullPath())) {
if(b instanceof IClassBean) {
if(member.equals(((IClassBean)b).getBeanClass())) return b;
} else if(b instanceof IProducer) {
if(member.equals(((IProducer)b).getSourceMember())) return b;
}
}
return null;
}
}