View Javadoc

1   /*
2    * $Id$
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.construct;
12  
13  import org.mule.MessageExchangePattern;
14  import org.mule.api.MuleContext;
15  import org.mule.api.MuleException;
16  import org.mule.api.MuleRuntimeException;
17  import org.mule.api.component.Component;
18  import org.mule.api.component.JavaComponent;
19  import org.mule.api.construct.FlowConstructInvalidException;
20  import org.mule.api.context.MuleContextAware;
21  import org.mule.api.endpoint.InboundEndpoint;
22  import org.mule.api.processor.MessageProcessor;
23  import org.mule.api.processor.MessageProcessorBuilder;
24  import org.mule.api.source.MessageSource;
25  import org.mule.config.i18n.MessageFactory;
26  import org.mule.construct.processor.FlowConstructStatisticsMessageObserver;
27  import org.mule.interceptor.LoggingInterceptor;
28  import org.mule.processor.builder.InterceptingChainMessageProcessorBuilder;
29  import org.mule.util.ClassUtils;
30  
31  import java.lang.reflect.Method;
32  import java.util.List;
33  
34  import edu.emory.mathcs.backport.java.util.Collections;
35  
36  /**
37   * In-out SOA-style simple service, with no outbound router. Always fully
38   * synchronous.
39   */
40  public class SimpleService extends AbstractFlowConstruct
41  {
42      public enum Type
43      {
44          /**
45           * Expose a JAX-WS annoted component as a web service. The CXF module is
46           * required to have this working.
47           */
48          JAX_WS
49          {
50              @Override
51              public void validate(Component component) throws FlowConstructInvalidException
52              {
53                  if (!(component instanceof JavaComponent))
54                  {
55                      throw new FlowConstructInvalidException(
56                          MessageFactory.createStaticMessage("SimpleService can only expose instances of JAX-WS annotated JavaComponent instances. You provided a: "
57                                                             + component.getClass().getName()));
58                  }
59              }
60  
61              @Override
62              public void configureComponentMessageProcessor(MuleContext muleContext,
63                                                             InterceptingChainMessageProcessorBuilder builder,
64                                                             Component component)
65              {
66                  builder.chain(newJaxWsComponentMessageProcessor(muleContext, getComponentClass(component)));
67                  builder.chain(component);
68              }
69          },
70  
71          /**
72           * Expose a JAX-RS annoted component as a web service. The Jersey module is
73           * required to have this working.
74           */
75          JAX_RS
76          {
77              @Override
78              public void validate(Component component) throws FlowConstructInvalidException
79              {
80                  if (!(component instanceof JavaComponent))
81                  {
82                      throw new FlowConstructInvalidException(
83                          MessageFactory.createStaticMessage("SimpleService can only expose instances of JAX-RS annotated JavaComponent instances. You provided a: "
84                                                             + component.getClass().getName()));
85                  }
86              }
87  
88              @Override
89              public void configureComponentMessageProcessor(MuleContext muleContext,
90                                                             InterceptingChainMessageProcessorBuilder builder,
91                                                             Component component)
92              {
93                  builder.chain(newJaxRsComponentWrapper(muleContext, component));
94              }
95          },
96  
97          /**
98           * Pass the inbound messages unaltered to the component.
99           */
100         DIRECT
101         {
102             @Override
103             public void validate(Component component) throws FlowConstructInvalidException
104             {
105                 // NOOP
106             }
107 
108             @Override
109             public void configureComponentMessageProcessor(MuleContext muleContext,
110                                                            InterceptingChainMessageProcessorBuilder builder,
111                                                            Component component)
112             {
113                 builder.chain(component);
114             }
115         };
116 
117         public abstract void validate(Component component) throws FlowConstructInvalidException;
118 
119         public abstract void configureComponentMessageProcessor(MuleContext muleContext,
120                                                                 InterceptingChainMessageProcessorBuilder builder,
121                                                                 Component component);
122 
123         public static Type fromString(String string)
124         {
125             String mepString = string.toUpperCase().replace('-', '_');
126             return Type.valueOf(mepString);
127         }
128     }
129 
130     private final Component component;
131     private final Type type;
132 
133     public SimpleService(String name,
134                          MuleContext muleContext,
135                          MessageSource messageSource,
136                          Component component,
137                          Type type) throws MuleException
138     {
139         super(name, muleContext);
140 
141         if (messageSource == null)
142         {
143             throw new FlowConstructInvalidException(
144                 MessageFactory.createStaticMessage("messageSource can't be null on: " + this.toString()));
145         }
146 
147         if (component == null)
148         {
149             throw new FlowConstructInvalidException(
150                 MessageFactory.createStaticMessage("component can't be null on: " + this.toString()));
151         }
152 
153         if (type == null)
154         {
155             throw new FlowConstructInvalidException(
156                 MessageFactory.createStaticMessage("type can't be null on: " + this.toString()));
157         }
158 
159         this.messageSource = messageSource;
160         this.component = component;
161         this.type = type;
162     }
163 
164     public Component getComponent()
165     {
166         return component;
167     }
168 
169     @Override
170     protected void configureMessageProcessors(InterceptingChainMessageProcessorBuilder builder)
171     {
172         builder.chain(new LoggingInterceptor());
173         builder.chain(new FlowConstructStatisticsMessageObserver());
174         type.configureComponentMessageProcessor(muleContext, builder, component);
175     }
176 
177     @Override
178     protected void validateConstruct() throws FlowConstructInvalidException
179     {
180         super.validateConstruct();
181 
182         if ((messageSource instanceof InboundEndpoint)
183             && (!((InboundEndpoint) messageSource).getExchangePattern().equals(
184                 MessageExchangePattern.REQUEST_RESPONSE)))
185         {
186             throw new FlowConstructInvalidException(
187                 MessageFactory.createStaticMessage("SimpleService only works with a request-response inbound endpoint."),
188                 this);
189         }
190 
191         type.validate(component);
192     }
193 
194     private static Class<?> getComponentClass(Component component)
195     {
196         if (component instanceof JavaComponent)
197         {
198             return ((JavaComponent) component).getObjectFactory().getObjectClass();
199         }
200 
201         return component.getClass();
202     }
203 
204     private static MessageProcessor newJaxWsComponentMessageProcessor(MuleContext muleContext,
205                                                                       Class<?> componentClass)
206     {
207         try
208         {
209             MessageProcessorBuilder wsmpb = (MessageProcessorBuilder) ClassUtils.instanciateClass("org.mule.module.cxf.builder.WebServiceMessageProcessorBuilder");
210 
211             Method setServiceClassMethod = ClassUtils.getMethod(wsmpb.getClass(), "setServiceClass",
212                 new Class<?>[]{Class.class});
213 
214             setServiceClassMethod.invoke(wsmpb, new Object[]{componentClass});
215 
216             Method setFrontendMethod = ClassUtils.getMethod(wsmpb.getClass(), "setFrontend",
217                 new Class<?>[]{String.class});
218 
219             setFrontendMethod.invoke(wsmpb, new Object[]{"jaxws"});
220 
221             ((MuleContextAware) wsmpb).setMuleContext(muleContext);
222 
223             return wsmpb.build();
224         }
225         catch (Exception e)
226         {
227             throw new MuleRuntimeException(
228                 MessageFactory.createStaticMessage("Failed to configure the required web service infrastructure: are you missing the Mule CXF Module?"),
229                 e);
230         }
231     }
232 
233     private static Component newJaxRsComponentWrapper(MuleContext muleContext, Component component)
234     {
235         try
236         {
237             Component jrc = (Component) ClassUtils.instanciateClass("org.mule.module.jersey.JerseyResourcesComponent");
238 
239             Method setComponentsMethod = ClassUtils.getMethod(jrc.getClass(), "setComponents",
240                 new Class<?>[]{List.class});
241 
242             setComponentsMethod.invoke(jrc, new Object[]{Collections.singletonList(component)});
243 
244             ((MuleContextAware) jrc).setMuleContext(muleContext);
245 
246             return jrc;
247         }
248         catch (Exception e)
249         {
250             throw new MuleRuntimeException(
251                 MessageFactory.createStaticMessage("Failed to configure the required web service infrastructure: are you missing the Mule Jersey Module?"),
252                 e);
253         }
254     }
255 }