Java tutorial
/** * This software is licensed under the Apache 2 license, quoted below. * * Copyright 2012 Julien Eluard * * 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.tools.module.loader; import com.google.common.base.CaseFormat; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.mule.tools.module.helper.*; import org.mule.tools.module.model.Module; import org.mule.tools.module.model.Parameter; import org.mule.tools.module.model.Processor; import org.mule.tools.module.model.Source; import org.mule.tools.module.model.Transformer; public class Devkit42Loader implements Loader { //Add support for friendlyName private static final String MESSAGE_PROCESSOR_CLASS_SUFFIX = "MessageProcessor"; private static final String MESSAGE_SOURCE_CLASS_SUFFIX = "MessageSource"; private static final String TRANSFORMER_CLASS_SUFFIX = "Transformer"; private static final String PARAMETER_TYPE_FIELD_PREFIX = "_"; private static final String PARAMETER_TYPE_FIELD_SUFFIX = "Type"; private static final Set<String> TECHNICAL_FIELD_NAME = new HashSet<String>( Arrays.asList("username", "password", "securityToken", "accessKey", "secretKey")); protected final String findMessageProcessorClassName(final Package modulePackage, final String processorName) { return modulePackage.getName() + "." + Strings.capitalize(processorName) + Devkit42Loader.MESSAGE_PROCESSOR_CLASS_SUFFIX; } protected final String findMessageSourceClassName(final Package modulePackage, final String sourceName) { return modulePackage.getName() + "." + Strings.capitalize(sourceName) + Devkit42Loader.MESSAGE_SOURCE_CLASS_SUFFIX; } protected final String findTransformerClassName(final Package modulePackage, final String transformerName) { return modulePackage.getName() + "." + Strings.capitalize(transformerName) + Devkit42Loader.TRANSFORMER_CLASS_SUFFIX; } @Override public final Module load(final Class<?> moduleClass, final String connectionManagerClassName) { return load(moduleClass, connectionManagerClassName, moduleClass.getPackage()); } public final Module load(final Class<?> moduleClass, final String connectionManagerClassName, final Package modulePackage) { if (moduleClass == null) { throw new IllegalArgumentException("null moduleClass"); } final Object annotation = Annotations.getConnectorAnnotation(moduleClass); if (annotation == null) { throw new IllegalArgumentException( "Failed to find a Module annotation on <" + moduleClass.getCanonicalName() + ">"); } final String name = extractAnnotationName(annotation); final String minMuleVersion = extractMinMuleVersion(annotation); final List<Parameter> parameters = listParameters(moduleClass); final List<Processor> processors = listProcessors(modulePackage, moduleClass); final List<Source> sources = listSources(modulePackage, moduleClass); final List<Transformer> transformers = listTransformers(modulePackage, moduleClass); return new Module(name, minMuleVersion, moduleClass.getName(), parameters, processors, sources, transformers, connectionManagerClassName); } protected final String extractAnnotationName(final Object annotation) { return Reflections.invoke(annotation, "name"); } protected final String extractAnnotationFriendlyName(final Object annotation) { return Reflections.invoke(annotation, "friendlyName"); } protected final String extractMinMuleVersion(final Object annotation) { return Reflections.invoke(annotation, "minMuleVersion"); } protected final List<Parameter> listParameters(final Class<?> moduleClass) { final List<Parameter> parameters = new LinkedList<Parameter>(); for (final Field field : Classes.allDeclaredFields(moduleClass)) { if (Annotations.getAnnotation(field, Annotations.CONFIGURABLE_ANNOTATION_CLASS_NAME) != null) { final boolean optional = Annotations.getAnnotation(field, Annotations.OPTIONAL_ANNOTATION_CLASS_NAME) != null; final String defaultValue = Annotations.getDefaultAnnotationValue(field); parameters.add(new Parameter(field.getName(), field.getType(), optional, defaultValue)); } } return parameters; } protected final String extractName(final Object annotation, final Method method) { final String annotationName = extractAnnotationName(annotation); if (!"".equals(annotationName)) { return annotationName; } return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, method.getName()); } protected final String[] extractMethodParameterNames(final Class<?> generatedClass) { final List<String> parameterNames = new LinkedList<String>(); for (final Field field : generatedClass.getDeclaredFields()) { final String fieldName = field.getName(); if (!(fieldName.startsWith(Devkit42Loader.PARAMETER_TYPE_FIELD_PREFIX) && fieldName.endsWith(Devkit42Loader.PARAMETER_TYPE_FIELD_SUFFIX))) { continue; } final String parameterName = Strings .uncapitalize(fieldName.substring(Devkit42Loader.PARAMETER_TYPE_FIELD_PREFIX.length(), fieldName.length() - Devkit42Loader.PARAMETER_TYPE_FIELD_SUFFIX.length())); if (Devkit42Loader.TECHNICAL_FIELD_NAME.contains(parameterName)) { //Filter fields added by DevKit. //TODO What if user parameter have same name? continue; } parameterNames.add(parameterName); } return parameterNames.toArray(new String[parameterNames.size()]); } protected final Class<?>[] extractMethodParameterTypes(final Method method) { final List<Class<?>> parameterTypes = new LinkedList<Class<?>>(); for (final Class<?> type : method.getParameterTypes()) { //SourceCallback is not a user parameter. if (Modules.SOURCE_CALLBACK_CLASS_NAME.equals(type.getName())) { continue; } parameterTypes.add(type); } return parameterTypes.toArray(new Class<?>[parameterTypes.size()]); } protected final List<Parameter> listMethodParameters(final Class<?> moduleClass, final Method method, final String generatedClassName) { final List<Parameter> parameters = new LinkedList<Parameter>(); //Rely on the fact that parameters are added first in generated MessageProcessor/MessageSource. //TODO Pretty fragile. Replace with stronger alternative. final Class<?> generatedClass = Classes.loadClass(generatedClassName); if (generatedClass == null) { throw new IllegalArgumentException("Failed to load <" + generatedClassName + ">"); } final String[] parameterNames = extractMethodParameterNames(generatedClass); final Class<?>[] parameterTypes = extractMethodParameterTypes(method); final Annotation[][] parameterAnnotations = method.getParameterAnnotations(); if (parameterTypes.length < parameterNames.length || parameterAnnotations.length < parameterNames.length) { throw new IllegalArgumentException( "Failed to match method <" + method.getName() + "> parameters:\nnames <" + Arrays.toString(parameterNames) + ">\ntypes <" + Arrays.toString(parameterTypes) + ">\nannotations <" + Arrays.deepToString(parameterAnnotations) + ">"); } for (int i = 0; i < parameterNames.length; i++) { final String name = parameterNames[i]; final Class<?> type = parameterTypes[i]; final List<Annotation> annotations = Arrays.asList(parameterAnnotations[i]); boolean optional = false; String defaultValue = null; for (final Annotation annotation : annotations) { if (Annotations.OPTIONAL_ANNOTATION_CLASS_NAME.equals(annotation.annotationType().getName())) { optional = true; } if (Annotations.DEFAULT_ANNOTATION_CLASS_NAME.equals(annotation.annotationType().getName())) { defaultValue = Reflections.invoke(annotation, "value"); } } parameters.add(new Parameter(name, type, optional, defaultValue)); } return parameters; } protected final List<Processor> listProcessors(final Package modulePackage, final Class<?> moduleClass) { final List<Processor> processors = new LinkedList<Processor>(); for (final Method method : moduleClass.getMethods()) { final Object annotation = Annotations.getAnnotation(method, Annotations.PROCESSOR_ANNOTATION_CLASS_NAME); if (annotation != null) { final String messageProcessorClassName = findMessageProcessorClassName(modulePackage, method.getName()); processors.add(new Processor(extractName(annotation, method), extractAnnotationFriendlyName(annotation), messageProcessorClassName, listMethodParameters(moduleClass, method, messageProcessorClassName), method.getReturnType().getName(), Reflections.<Boolean>invoke(annotation, "intercepting"))); } } return processors; } protected final List<Source> listSources(final Package modulePackage, final Class<?> moduleClass) { final List<Source> sources = new LinkedList<Source>(); for (final Method method : moduleClass.getMethods()) { final Object annotation = Annotations.getAnnotation(method, Annotations.SOURCE_ANNOTATION_CLASS_NAME); if (annotation != null) { final String messageSourceClassName = findMessageSourceClassName(modulePackage, method.getName()); sources.add(new Source(extractName(annotation, method), extractAnnotationFriendlyName(annotation), messageSourceClassName, listMethodParameters(moduleClass, method, messageSourceClassName))); } } return sources; } protected final List<Transformer> listTransformers(final Package modulePackage, final Class<?> moduleClass) { final List<Transformer> transformers = new LinkedList<Transformer>(); for (final Method method : moduleClass.getMethods()) { final Object annotation = Annotations.getAnnotation(method, Annotations.TRANSFORMER_ANNOTATION_CLASS_NAME); if (annotation != null) { final String transformerClassName = findTransformerClassName(modulePackage, method.getName()); transformers.add(new Transformer(transformerClassName, Reflections.<Integer>invoke(annotation, "priorityWeighting"), Reflections.<Class[]>invoke(annotation, "sourceTypes"))); } } return transformers; } }