/**
* Mule Development Kit
* Copyright 2010-2011 (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
*
* 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.mule.devkit.generation.mule.transfomer;
import org.mule.api.annotations.Connector;
import org.mule.api.annotations.Module;
import org.mule.api.annotations.Processor;
import org.mule.api.annotations.Source;
import org.mule.api.context.MuleContextAware;
import org.mule.api.transformer.DiscoverableTransformer;
import org.mule.api.transformer.TransformerException;
import org.mule.devkit.generation.AbstractMessageGenerator;
import org.mule.devkit.generation.DevKitTypeElement;
import org.mule.devkit.generation.NamingContants;
import org.mule.devkit.model.code.DefinedClass;
import org.mule.devkit.model.code.ExpressionFactory;
import org.mule.devkit.model.code.FieldVariable;
import org.mule.devkit.model.code.Invocation;
import org.mule.devkit.model.code.Method;
import org.mule.devkit.model.code.Modifier;
import org.mule.devkit.model.code.TypeReference;
import org.mule.devkit.model.code.Variable;
import org.mule.transformer.AbstractTransformer;
import org.mule.transformer.types.DataTypeFactory;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
public class EnumTransformerGenerator extends AbstractMessageGenerator {
@Override
protected boolean shouldGenerate(DevKitTypeElement typeElement) {
return typeElement.hasAnnotation(Module.class) || typeElement.hasAnnotation(Connector.class);
}
@Override
protected void doGenerate(DevKitTypeElement typeElement) {
for (VariableElement field : typeElement.getFields()) {
if (context.getTypeMirrorUtils().isEnum(field.asType())) {
if (!context.isEnumRegistered(field.asType())) {
registerEnumTransformer(field);
context.registerEnum(field.asType());
}
}
}
for (ExecutableElement method : typeElement.getMethodsAnnotatedWith(Processor.class)) {
for (VariableElement variable : method.getParameters()) {
if (context.getTypeMirrorUtils().isEnum(variable.asType()) && !context.isEnumRegistered(variable.asType())) {
registerEnumTransformer(variable);
context.registerEnum(variable.asType());
} else if (context.getTypeMirrorUtils().isCollection(variable.asType())) {
DeclaredType variableType = (DeclaredType) variable.asType();
for (TypeMirror variableTypeParameter : variableType.getTypeArguments()) {
if (context.getTypeMirrorUtils().isEnum(variableTypeParameter) && !context.isEnumRegistered(variableTypeParameter)) {
Element enumElement = context.getTypeUtils().asElement(variableTypeParameter);
registerEnumTransformer(enumElement);
context.registerEnum(variableTypeParameter);
}
}
}
}
}
for (ExecutableElement method : typeElement.getMethodsAnnotatedWith(Source.class)) {
for (VariableElement variable : method.getParameters()) {
if (!context.getTypeMirrorUtils().isEnum(variable.asType())) {
continue;
}
if (!context.isEnumRegistered(variable.asType())) {
registerEnumTransformer(variable);
context.registerEnum(variable.asType());
}
}
}
}
private void registerEnumTransformer(Element variableElement) {
// get class
DefinedClass transformerClass = getEnumTransformerClass(variableElement);
// declare object
FieldVariable muleContext = generateFieldForMuleContext(transformerClass);
// declare weight
FieldVariable weighting = transformerClass.field(Modifier.PRIVATE, context.getCodeModel().INT, "weighting", ref(DiscoverableTransformer.class).staticRef("DEFAULT_PRIORITY_WEIGHTING"));
//generate constructor
generateConstructor(transformerClass, variableElement);
// add setmulecontext
generateSetMuleContextMethod(transformerClass, muleContext);
// doTransform
generateDoTransform(transformerClass, variableElement);
// set and get weight
generateGetPriorityWeighting(transformerClass, weighting);
generateSetPriorityWeighting(transformerClass, weighting);
context.registerAtBoot(transformerClass);
}
private void generateSetPriorityWeighting(DefinedClass jaxbTransformerClass, FieldVariable weighting) {
Method setPriorityWeighting = jaxbTransformerClass.method(Modifier.PUBLIC, context.getCodeModel().VOID, "setPriorityWeighting");
Variable localWeighting = setPriorityWeighting.param(context.getCodeModel().INT, "weighting");
setPriorityWeighting.body().assign(ExpressionFactory._this().ref(weighting), localWeighting);
}
private void generateGetPriorityWeighting(DefinedClass jaxbTransformerClass, FieldVariable weighting) {
Method getPriorityWeighting = jaxbTransformerClass.method(Modifier.PUBLIC, context.getCodeModel().INT, "getPriorityWeighting");
getPriorityWeighting.body()._return(weighting);
}
private void generateDoTransform(DefinedClass jaxbTransformerClass, Element variableElement) {
Method doTransform = jaxbTransformerClass.method(Modifier.PROTECTED, ref(Object.class), "doTransform");
doTransform._throws(TransformerException.class);
Variable src = doTransform.param(ref(Object.class), "src");
doTransform.param(ref(String.class), "encoding");
Variable result = doTransform.body().decl(ref(variableElement.asType()).boxify(), "result", ExpressionFactory._null());
Invocation valueOf = ref(Enum.class).staticInvoke("valueOf");
valueOf.arg(ref(variableElement.asType()).boxify().dotclass());
valueOf.arg(ExpressionFactory.cast(ref(String.class), src));
doTransform.body().assign(result, valueOf);
doTransform.body()._return(result);
}
private void generateConstructor(DefinedClass transformerClass, Element variableElement) {
// generate constructor
Method constructor = transformerClass.constructor(Modifier.PUBLIC);
// register source data type
registerSourceTypes(constructor);
// register destination data type
registerDestinationType(constructor, ref(variableElement.asType()).boxify());
constructor.body().invoke("setName").arg(transformerClass.name());
}
private void registerDestinationType(Method constructor, TypeReference clazz) {
Invocation setReturnClass = constructor.body().invoke("setReturnClass");
setReturnClass.arg(ExpressionFactory.dotclass(clazz));
}
private void registerSourceTypes(Method constructor) {
Invocation registerSourceType = constructor.body().invoke("registerSourceType");
registerSourceType.arg(ref(DataTypeFactory.class).staticInvoke("create").arg(ref(String.class).boxify().dotclass()));
}
private DefinedClass getEnumTransformerClass(Element variableElement) {
javax.lang.model.element.Element enumElement = context.getTypeUtils().asElement(variableElement.asType());
String transformerClassName = context.getNameUtils().generateClassNameInPackage(variableElement, enumElement.getSimpleName().toString() + NamingContants.ENUM_TRANSFORMER_CLASS_NAME_SUFFIX);
org.mule.devkit.model.code.Package pkg = context.getCodeModel()._package(context.getNameUtils().getPackageName(transformerClassName) + NamingContants.TRANSFORMERS_NAMESPACE);
DefinedClass transformer = pkg._class(context.getNameUtils().getClassName(transformerClassName), AbstractTransformer.class, new Class<?>[]{DiscoverableTransformer.class, MuleContextAware.class});
return transformer;
}
}