/*
* $Id: DecoratingAnnotatedServiceProcessor.java 20321 2010-11-24 15:21:24Z dfeist $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
*
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.config.processors;
import org.mule.api.AnnotationException;
import org.mule.api.EndpointAnnotationParser;
import org.mule.api.MessageProcessorAnnotationParser;
import org.mule.api.MuleContext;
import org.mule.api.MuleException;
import org.mule.api.MuleRuntimeException;
import org.mule.api.annotations.meta.Channel;
import org.mule.api.annotations.meta.ChannelType;
import org.mule.api.annotations.meta.Router;
import org.mule.api.annotations.meta.RouterType;
import org.mule.api.config.MuleProperties;
import org.mule.api.context.MuleContextAware;
import org.mule.api.endpoint.InboundEndpoint;
import org.mule.api.endpoint.OutboundEndpoint;
import org.mule.api.lifecycle.Initialisable;
import org.mule.api.processor.MessageProcessor;
import org.mule.api.registry.PreInitProcessor;
import org.mule.api.routing.OutboundRouter;
import org.mule.api.routing.OutboundRouterCollection;
import org.mule.api.service.Service;
import org.mule.api.source.CompositeMessageSource;
import org.mule.component.AbstractJavaComponent;
import org.mule.config.AnnotationsParserFactory;
import org.mule.config.endpoint.AnnotatedEndpointHelper;
import org.mule.config.i18n.AnnotationsMessages;
import org.mule.config.i18n.CoreMessages;
import org.mule.registry.RegistryMap;
import org.mule.routing.outbound.OutboundPassThroughRouter;
import org.mule.service.ServiceCompositeMessageSource;
import org.mule.util.TemplateParser;
import org.mule.util.annotation.AnnotationMetaData;
import org.mule.util.annotation.AnnotationUtils;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* This object processor allows users to register annotated services directly to the registry
* and have them configured correctly.
* It will look for a non-system {@link org.mule.api.model.Model} registered with the Registry.
* If one is not found a default SEDA Model will be created
* Finally, the processor will register the service with the Registry and return null.
*/
public class DecoratingAnnotatedServiceProcessor implements PreInitProcessor, MuleContextAware
{
/**
* logger used by this class
*/
protected transient final Log logger = LogFactory.getLog(DecoratingAnnotatedServiceProcessor.class);
protected MuleContext context;
private final TemplateParser parser = TemplateParser.createAntStyleParser();
protected RegistryMap regProps;
protected AnnotatedEndpointHelper helper;
protected AnnotationsParserFactory parserFactory;
public DecoratingAnnotatedServiceProcessor()
{
}
public DecoratingAnnotatedServiceProcessor(MuleContext context)
{
setMuleContext(context);
}
public void setMuleContext(MuleContext context)
{
try
{
this.context = context;
this.regProps = new RegistryMap(context.getRegistry());
this.helper = new AnnotatedEndpointHelper(context);
this.parserFactory = context.getRegistry().lookupObject(AnnotationsParserFactory.class);
if(parserFactory==null)
{
logger.info(AnnotationsParserFactory.class.getName() +" implementation not found in registry, annotations not enabled");
}
}
catch (MuleException e)
{
throw new MuleRuntimeException(CoreMessages.failedToCreate(getClass().getName()), e);
}
}
public Object process(Object object)
{
if (object == null || parserFactory == null)
{
return object;
}
if (object instanceof Service)
{
Service service = (Service) object;
//Annotations only supported on Java components
if (service.getComponent() instanceof AbstractJavaComponent)
{
try
{
AbstractJavaComponent component = (AbstractJavaComponent) service.getComponent();
if(AnnotationUtils.getMethodMetaAnnotations(component.getObjectType(), Channel.class).size()==0)
{
return object;
}
processInbound(component.getObjectType(), service);
processOutbound(component.getObjectType(), service);
//Check for Async reply Config
processReply(component.getObjectType(), service);
}
catch (MuleException e)
{
e.printStackTrace();
}
}
}
return object;
}
protected void processInbound(Class componentFactoryClass, org.mule.api.service.Service service) throws MuleException
{
InboundEndpoint inboundEndpoint;
List<AnnotationMetaData> annotations = AnnotationUtils.getClassAndMethodAnnotations(componentFactoryClass);
for (AnnotationMetaData annotation : annotations)
{
inboundEndpoint = tryInboundEndpointAnnotation(annotation, ChannelType.Inbound);
if (inboundEndpoint != null)
{
if (annotation.getType() == ElementType.METHOD)
{
inboundEndpoint.getProperties().put(MuleProperties.MULE_METHOD_PROPERTY, annotation.getElementName());
}
((CompositeMessageSource) service.getMessageSource()).addSource(inboundEndpoint);
}
}
//Lets process the inbound routers
processInboundRouters(componentFactoryClass, service);
}
protected void processInboundRouters(Class componentFactoryClass, org.mule.api.service.Service service) throws MuleException
{
for (int i = 0; i < componentFactoryClass.getAnnotations().length; i++)
{
Annotation annotation = componentFactoryClass.getAnnotations()[i];
Router routerAnnotation = annotation.annotationType().getAnnotation(Router.class);
if (routerAnnotation != null && routerAnnotation.type() == RouterType.Inbound)
{
MessageProcessorAnnotationParser parser = parserFactory.getRouterParser(annotation, componentFactoryClass, null);
if (parser != null)
{
((ServiceCompositeMessageSource) service.getMessageSource()).addMessageProcessor(parser.parseMessageProcessor(annotation));
}
else
{
//TODO i18n
throw new IllegalStateException("Cannot find parser for router annotation: " + annotation.toString());
}
}
}
}
protected void processReplyRouters(Class componentFactoryClass, org.mule.api.service.Service service) throws MuleException
{
List<AnnotationMetaData> annotations = AnnotationUtils.getClassAndMethodAnnotations(componentFactoryClass);
for (AnnotationMetaData metaData : annotations)
{
Router routerAnnotation = metaData.getAnnotation().annotationType().getAnnotation(Router.class);
if (routerAnnotation != null && routerAnnotation.type() == RouterType.ReplyTo)
{
MessageProcessorAnnotationParser parser = parserFactory.getRouterParser(metaData.getAnnotation(), metaData.getClazz(), metaData.getMember());
if (parser != null)
{
MessageProcessor router = parser.parseMessageProcessor(metaData.getAnnotation());
//Todo, wrap lifecycle
if (router instanceof MuleContextAware)
{
((MuleContextAware) router).setMuleContext(context);
}
if (router instanceof Initialisable)
{
((Initialisable) router).initialise();
}
// service.getResponseRouter().addRouter(router);
break;
}
else
{
//TODO i18n
throw new IllegalStateException("Cannot find parser for router annotation: " + metaData.getAnnotation().toString());
}
}
}
}
protected OutboundRouter processOutboundRouter(Class componentFactoryClass) throws MuleException
{
Collection routerParsers = context.getRegistry().lookupObjects(MessageProcessorAnnotationParser.class);
OutboundRouter router = null;
List<AnnotationMetaData> annotations = AnnotationUtils.getClassAndMethodAnnotations(componentFactoryClass);
for (AnnotationMetaData metaData : annotations)
{
Router routerAnnotation = metaData.getAnnotation().annotationType().getAnnotation(Router.class);
if (routerAnnotation != null && routerAnnotation.type() == RouterType.Outbound)
{
if (router != null)
{
//TODO i18n
throw new IllegalStateException("You can only configure one outbound router on a service");
}
MessageProcessorAnnotationParser parser = parserFactory.getRouterParser(metaData.getAnnotation(), metaData.getClazz(), metaData.getMember());
if (parser != null)
{
router = (OutboundRouter) parser.parseMessageProcessor(metaData.getAnnotation());
}
else
{
//TODO i18n
throw new IllegalStateException("Cannot find parser for router annotation: " + metaData.getAnnotation().toString());
}
}
}
if (router == null)
{
router = new OutboundPassThroughRouter();
}
//Todo, wrap lifecycle
if (router instanceof MuleContextAware)
{
((MuleContextAware) router).setMuleContext(context);
}
router.initialise();
return router;
}
protected void processOutbound(Class componentFactoryClass, org.mule.api.service.Service service) throws MuleException
{
OutboundRouter router = processOutboundRouter(componentFactoryClass);
OutboundEndpoint outboundEndpoint;
List<AnnotationMetaData> annotations = AnnotationUtils.getClassAndMethodAnnotations(componentFactoryClass);
for (AnnotationMetaData annotation : annotations)
{
outboundEndpoint = tryOutboundEndpointAnnotation(annotation, ChannelType.Outbound);
if (outboundEndpoint != null)
{
router.addRoute(outboundEndpoint);
}
}
if (router instanceof MuleContextAware)
{
((MuleContextAware) router).setMuleContext(context);
}
router.initialise();
((OutboundRouterCollection) service.getOutboundMessageProcessor()).addRoute(router);
}
protected InboundEndpoint tryInboundEndpointAnnotation(AnnotationMetaData metaData, ChannelType channelType) throws MuleException
{
Channel channelAnno = metaData.getAnnotation().annotationType().getAnnotation(Channel.class);
if (channelAnno != null && channelAnno.type() == channelType)
{
EndpointAnnotationParser parser = parserFactory.getEndpointParser(metaData.getAnnotation(), metaData.getClazz(), metaData.getMember());
if (parser == null)
{
//TODO i18n
throw new AnnotationException(AnnotationsMessages.createStaticMessage("No parser found for annotation: " + metaData));
}
else
{
return parser.parseInboundEndpoint(metaData.getAnnotation(), Collections.EMPTY_MAP);
}
}
return null;
}
protected OutboundEndpoint tryOutboundEndpointAnnotation(AnnotationMetaData metaData, ChannelType channelType) throws MuleException
{
Channel channelAnno = metaData.getAnnotation().annotationType().getAnnotation(Channel.class);
if (channelAnno != null && channelAnno.type() == channelType)
{
EndpointAnnotationParser parser = parserFactory.getEndpointParser(metaData.getAnnotation(), metaData.getClazz(), metaData.getMember());
if (parser == null)
{
//TODO i18n
throw new AnnotationException(AnnotationsMessages.createStaticMessage("No parser found for annotation: " + metaData));
}
else
{
return parser.parseOutboundEndpoint(metaData.getAnnotation(), Collections.EMPTY_MAP);
}
}
return null;
}
protected void processReply(Class componentFactoryClass, org.mule.api.service.Service service) throws MuleException
{
InboundEndpoint inboundEndpoint;
for (int i = 0; i < componentFactoryClass.getAnnotations().length; i++)
{
Annotation annotation = componentFactoryClass.getAnnotations()[i];
inboundEndpoint = tryInboundEndpointAnnotation(
new AnnotationMetaData(componentFactoryClass, null, ElementType.TYPE, annotation), ChannelType.Reply);
if (inboundEndpoint != null)
{
service.getAsyncReplyMessageSource().addSource(inboundEndpoint);
}
}
//Lets process the reply routers
processReplyRouters(componentFactoryClass, service);
}
protected String getValue(String key)
{
return parser.parse(regProps, key);
}
}