View Javadoc

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