/*******************************************************************************
* Copyright (c) 2005, 2006 committers of openArchitectureWare and others.
* All rights reserved. This program and the accompanying materials
* are 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:
* committers of openArchitectureWare - initial API and implementation
*******************************************************************************/
package org.eclipse.emf.mwe.internal.core.ast.util;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.emf.mwe.core.customizer.CustomizationException;
import org.eclipse.emf.mwe.core.issues.Issues;
import org.eclipse.emf.mwe.core.issues.IssuesImpl;
import org.eclipse.emf.mwe.internal.core.ast.AbstractASTBase;
import org.eclipse.emf.mwe.internal.core.ast.ComponentAST;
import org.eclipse.emf.mwe.internal.core.ast.InclusionAST;
import org.eclipse.emf.mwe.internal.core.ast.ReferenceAST;
import org.eclipse.emf.mwe.internal.core.ast.SimpleParamAST;
import org.eclipse.emf.mwe.internal.core.ast.util.converter.Converter;
public class VisitorAnalyzer extends VisitorBase {
private VisitorAnalyzer cloneWithCurrentClass(final Class<?> c) {
final VisitorAnalyzer ana = new VisitorAnalyzer(issues, converter, c);
return ana;
}
private Map<Class<?>, Converter<?>> converter = new HashMap<Class<?>, Converter<?>>(); // <Class,
// Converter>
private Class<?> currentComponentClass = null;
private Issues issues = new IssuesImpl();
public VisitorAnalyzer(final Issues issues, final Map<Class<?>, Converter<?>> converter,
final Class<?> currentComponentClass) {
if (currentComponentClass == null)
throw new NullPointerException("currentComponentClass");
this.issues = issues;
this.converter = converter;
this.currentComponentClass = currentComponentClass;
}
@Override
public Object visitComponentAST(final ComponentAST componentAST) {
final String elementName = componentAST.getName();
Class<?> expected = null;
try {
expected = getTypeForProperty(elementName);
}
catch (final CustomizationException ex) {
issues.addError(ex.getMessage(), componentAST);
return null;
}
if (expected == null) {
issues.addError("No getter or adder method for property '" + elementName + "' in clazz '"
+ currentComponentClass.getName() + "' found. Forgot to customize?", componentAST);
}
else {
if (componentAST.getClazz() != null) {
final Class<?> actual = loader.loadClass(componentAST.getClazz());
if (actual == null) {
issues.addError("Class not found: '" + componentAST.getClazz() + "'", componentAST);
}
else if (!expected.isAssignableFrom(actual)) {
issues.addError("Incompatible Classes: '" + componentAST.getClazz()
+ "' is not a subclass of the expected class '" + expected.getName() + "'.", componentAST);
}
else {
expected = actual;
}
}
componentAST.setAnalyzedType(expected);
final VisitorAnalyzer v = cloneWithCurrentClass(expected);
for (final Iterator<?> iter = componentAST.getChildren().iterator(); iter.hasNext();) {
((AbstractASTBase) iter.next()).accept(v);
}
}
return expected;
}
@Override
public Object visitReferenceAST(final ReferenceAST ele) {
Class<?> expected = null;
try {
expected = getTypeForProperty(ele.getName());
}
catch (final CustomizationException ex) {
issues.addError(ex.getMessage(), ele);
return null;
}
if (expected == null) {
issues.addError("No setter or adder method for property '" + ele.getName() + "' in clazz '"
+ currentComponentClass.getName() + "' found", ele);
return ele;
}
if (ele.getReference() == null) {
issues.addError("Reference to bean with id " + ele.getIdRef() + " not resolved!", ele);
}
else {
final Class<?> c = (Class<?>) ele.getReference().getAnalyzedType();
if (c != null && !expected.isAssignableFrom(c)) {
issues.addWarning("The type of the referred bean (" + c.getName() + ") is not assignable to "
+ expected.getName());
}
return c;
}
return expected;
}
@Override
public Object visitSimpleParamAST(final SimpleParamAST ele) {
Class<?> expected = null;
try {
expected = getTypeForProperty(ele.getName());
}
catch (final CustomizationException ex) {
issues.addError(ex.getMessage(), ele);
return null;
}
if (expected == null) {
issues.addError("No getter or adder method for property '" + ele.getName() + "' in clazz '"
+ getCurrClassName() + "' found.", ele);
}
else if (!converter.containsKey(expected)) {
issues.addError("Cannot convert from String to '" + expected.getName()
+ "'. You need to register a corresponding Converter.", ele);
}
return expected;
}
private String getCurrClassName() {
return currentComponentClass != null ? currentComponentClass.getName() : "unknown";
}
private Class<?> getTypeForProperty(final String name) {
if (currentComponentClass != null) {
final Injector inj = InjectorFactory.getInjector(currentComponentClass, name);
if (inj != null)
return inj.getRequiredType();
}
return null;
}
@Override
public Object visitInclusionAST(final InclusionAST ele) {
if (ele.getImportedElement() != null)
return ele.getImportedElement().accept(cloneWithCurrentClass(WorkflowContainer.class));
else {
issues.addError("Cartridge " + ele.getFile() + " not resolved!", ele);
}
return Object.class;
}
}