/** * 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.dynamic.api.loader; import org.mule.api.Capabilities; import org.mule.api.ConnectionManager; import org.mule.api.annotations.Configurable; import org.mule.api.annotations.Processor; import org.mule.api.annotations.Source; import org.mule.api.annotations.Transformer; import org.mule.api.annotations.param.Default; import org.mule.api.annotations.param.Optional; import org.mule.api.callback.SourceCallback; import org.mule.api.processor.MessageProcessor; import org.mule.api.source.MessageSource; import org.mule.devkit.dynamic.api.helper.Classes; import org.mule.devkit.dynamic.api.helper.Reflections; import org.mule.devkit.dynamic.api.model.Module; import org.mule.util.StringUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.LinkedList; import java.util.List; public class Loader { 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"; protected final Class<?> findMessageProcessorClass(final Package modulePackage, final String processorName, final ClassLoader classLoader) { final String messageProcessorClassName = modulePackage.getName()+"."+StringUtils.capitalize(processorName)+Loader.MESSAGE_PROCESSOR_CLASS_SUFFIX; System.out.println(messageProcessorClassName); return Classes.loadClass(classLoader, messageProcessorClassName); } protected final Class<?> findMessageSourceClass(final Package modulePackage, final String sourceName, final ClassLoader classLoader) { final String messageSourceName = modulePackage.getName()+"."+StringUtils.capitalize(sourceName)+Loader.MESSAGE_SOURCE_CLASS_SUFFIX; return Classes.loadClass(classLoader, messageSourceName); } protected final Class<?> findTransformerClass(final Package modulePackage, final String transformerName, final ClassLoader classLoader) { final String transformerClassName = modulePackage.getName()+"."+StringUtils.capitalize(transformerName)+Loader.TRANSFORMER_CLASS_SUFFIX; return Classes.loadClass(classLoader, transformerClassName); } protected final Object extractAnnotation(final Class<?> moduleClass) { final org.mule.api.annotations.Module moduleAnnotation = Classes.getDeclaredAnnotation(moduleClass, org.mule.api.annotations.Module.class); if (moduleAnnotation != null) { return moduleAnnotation; } else { return Classes.getDeclaredAnnotation(moduleClass, org.mule.api.annotations.Connector.class); } } public final Module load(final Capabilities module, final ConnectionManager<?, ?> connectionManager) { return load(module, connectionManager, module.getClass().getPackage(), module.getClass().getClassLoader()); } public final Module load(final Capabilities module, final ConnectionManager<?, ?> connectionManager, final Package modulePackage, final ClassLoader classLoader) { if (module == null) { throw new IllegalArgumentException("null module"); } final Class<?> moduleClass = module.getClass(); final Object annotation = extractAnnotation(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<Module.Parameter> parameters = listParameters(moduleClass); final List<Module.Processor> processors = listProcessors(modulePackage, moduleClass, classLoader); final List<Module.Source> sources = listSources(modulePackage, moduleClass, classLoader); final List<Module.Transformer> transformers = listTransformers(modulePackage, moduleClass, classLoader); return new Module(name, minMuleVersion, module, parameters, processors, sources, transformers, connectionManager, classLoader); } protected final String extractClassName(final String name) { final String strippedClassName = name.substring(0, name.lastIndexOf(".")); return strippedClassName.replace('/', '.'); } protected final String extractAnnotationName(final Object annotation) { return Reflections.invoke(annotation, "name"); } protected final String extractMinMuleVersion(final Object annotation) { return Reflections.invoke(annotation, "minMuleVersion"); } protected final List<Module.Parameter> listParameters(final Class<?> moduleClass) { final List<Module.Parameter> parameters = new LinkedList<Module.Parameter>(); for (final Field field : Classes.allDeclaredFields(moduleClass)) { if (field.getAnnotation(Configurable.class) != null) { final boolean optional = field.getAnnotation(Optional.class) != null; final String defaultValue = field.getAnnotation(Default.class) != null ? field.getAnnotation(Default.class).value() : null; parameters.add(new Module.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 Classes.methodNameToDashBased(method); } 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(Loader.PARAMETER_TYPE_FIELD_PREFIX) && fieldName.endsWith(Loader.PARAMETER_TYPE_FIELD_SUFFIX))) { continue; } final String parameterName = StringUtils.uncapitalize(fieldName.substring(Loader.PARAMETER_TYPE_FIELD_PREFIX.length(), fieldName.length()-Loader.PARAMETER_TYPE_FIELD_SUFFIX.length())); 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 (SourceCallback.class.equals(type)) { continue; } parameterTypes.add(type); } return parameterTypes.toArray(new Class<?>[parameterTypes.size()]); } protected final List<Module.Parameter> listMethodParameters(final Class<?> moduleClass, final Method method, final Class<?> generatedClass) { final List<Module.Parameter> parameters = new LinkedList<Module.Parameter>(); //Rely on the fact that parameters are added first in generated MessageProcessor/MessageSource. //TODO Pretty fragile. Replace with stronger alternative. final String[] parameterNames = extractMethodParameterNames(generatedClass); final Class<?>[] parameterTypes = extractMethodParameterTypes(method); final Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int i = 0; i < parameterTypes.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 (annotation instanceof Optional) { optional = true; } if (annotation instanceof Default) { defaultValue = Default.class.cast(annotation).value(); } } parameters.add(new Module.Parameter(name, type, optional, defaultValue)); } return parameters; } protected final List<Module.Processor> listProcessors(final Package modulePackage, final Class<?> moduleClass, final ClassLoader classLoader) { final List<Module.Processor> processors = new LinkedList<Module.Processor>(); for (final Method method : moduleClass.getMethods()) { final Processor annotation = method.getAnnotation(Processor.class); if (annotation != null) { final Class<?> messageProcessorClass = findMessageProcessorClass(modulePackage, method.getName(), classLoader); if (messageProcessorClass == null) { throw new IllegalArgumentException("Failed to find MessageProcessor class for processor <"+method.getName()+">"); } final MessageProcessor messageProcessor = Classes.newInstance(messageProcessorClass); if (messageProcessor == null) { throw new IllegalArgumentException("Failed to instantiate MessageProcessor class <"+messageProcessorClass.getCanonicalName()+">"); } processors.add(new Module.Processor(extractName(annotation, method), messageProcessor, listMethodParameters(moduleClass, method, messageProcessorClass), annotation.intercepting())); } } return processors; } protected final List<Module.Source> listSources(final Package modulePackage, final Class<?> moduleClass, final ClassLoader classLoader) { final List<Module.Source> sources = new LinkedList<Module.Source>(); for (final Method method : moduleClass.getMethods()) { final Source annotation = method.getAnnotation(Source.class); if (annotation != null) { final Class<?> messageSourceClass = findMessageSourceClass(modulePackage, method.getName(), classLoader); if (messageSourceClass == null) { throw new IllegalArgumentException("Failed to find MessageSource class for processor <"+method.getName()+">"); } final MessageSource messageSource = Classes.newInstance(messageSourceClass); if (messageSource == null) { throw new IllegalArgumentException("Failed to instantiate MessageSource class <"+messageSourceClass.getCanonicalName()+">"); } sources.add(new Module.Source(extractName(annotation, method), messageSource, listMethodParameters(moduleClass, method, messageSourceClass))); } } return sources; } protected final List<Module.Transformer> listTransformers(final Package modulePackage, final Class<?> moduleClass, final ClassLoader classLoader) { final List<Module.Transformer> transformers = new LinkedList<Module.Transformer>(); for (final Method method : moduleClass.getMethods()) { final Transformer annotation = method.getAnnotation(Transformer.class); if (annotation != null) { final Class<?> transformerClass = findTransformerClass(modulePackage, method.getName(), classLoader); if (transformerClass == null) { throw new IllegalArgumentException("Failed to find Transformer class for processor <"+method.getName()+">"); } final org.mule.api.transformer.Transformer transformer = Classes.newInstance(transformerClass); if (transformer == null) { throw new IllegalArgumentException("Failed to instantiate Transformer class <"+transformerClass.getCanonicalName()+">"); } transformers.add(new Module.Transformer(transformer, annotation.priorityWeighting(), annotation.sourceTypes())); } } return transformers; } }