View Javadoc

1   /*
2    * $Id: SimpleService.java 21939 2011-05-18 13:32:09Z aperepel $
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.util.ClassUtils;
28  
29  import java.lang.reflect.Method;
30  import java.util.Collections;
31  import java.util.List;
32  
33  /**
34   * In-out SOA-style simple service, with no outbound router. Always fully synchronous.
35   */
36  public class SimpleService extends AbstractConfigurationPattern
37  {
38      public enum Type
39      {
40          /**
41           * Expose a JAX-WS annoted component as a web service. The CXF module is required to have this working.
42           */
43          JAX_WS
44          {
45              @Override
46              public void validate(Component component) throws FlowConstructInvalidException
47              {
48                  if (!(component instanceof JavaComponent))
49                  {
50                      throw new FlowConstructInvalidException(
51                          MessageFactory.createStaticMessage("SimpleService can only expose instances of JAX-WS annotated JavaComponent instances. You provided a: "
52                                                             + component.getClass().getName()));
53                  }
54              }
55  
56              @Override
57              public void configureComponentMessageProcessor(MuleContext muleContext,
58                                                             MessageProcessorChainBuilder builder,
59                                                             Component component)
60              {
61                  builder.chain(newJaxWsComponentMessageProcessor(muleContext, getComponentClass(component)));
62                  builder.chain(component);
63              }
64          },
65  
66          /**
67           * Expose a JAX-RS annoted component as a web service. The Jersey module is required to have this working.
68           */
69          JAX_RS
70          {
71              @Override
72              public void validate(Component component) throws FlowConstructInvalidException
73              {
74                  if (!(component instanceof JavaComponent))
75                  {
76                      throw new FlowConstructInvalidException(
77                          MessageFactory.createStaticMessage("SimpleService can only expose instances of JAX-RS annotated JavaComponent instances. You provided a: "
78                                                             + component.getClass().getName()));
79                  }
80              }
81  
82              @Override
83              public void configureComponentMessageProcessor(MuleContext muleContext,
84                                                             MessageProcessorChainBuilder builder,
85                                                             Component component)
86              {
87                  builder.chain(newJaxRsComponentWrapper(muleContext, component));
88              }
89          },
90  
91          /**
92           * Pass the inbound messages unaltered to the component.
93           */
94          DIRECT
95          {
96              @Override
97              public void validate(Component component) throws FlowConstructInvalidException
98              {
99                  // NOOP
100             }
101 
102             @Override
103             public void configureComponentMessageProcessor(MuleContext muleContext,
104                                                            MessageProcessorChainBuilder builder,
105                                                            Component component)
106             {
107                 builder.chain(component);
108             }
109         };
110 
111         public abstract void validate(Component component) throws FlowConstructInvalidException;
112 
113         public abstract void configureComponentMessageProcessor(MuleContext muleContext,
114                                                                 MessageProcessorChainBuilder builder,
115                                                                 Component component);
116 
117         public static Type fromString(String string)
118         {
119             String mepString = string.toUpperCase().replace('-', '_');
120             return Type.valueOf(mepString);
121         }
122     }
123 
124     private final Component component;
125     private final Type type;
126 
127     public SimpleService(String name,
128                          MuleContext muleContext,
129                          MessageSource messageSource,
130                          List<MessageProcessor> transformers,
131                          List<MessageProcessor> responseTransformers,
132                          Component component,
133                          Type type) throws MuleException
134     {
135         super(name, muleContext, transformers, responseTransformers);
136 
137         if (messageSource == null)
138         {
139             throw new FlowConstructInvalidException(
140                 MessageFactory.createStaticMessage("messageSource can't be null on: " + this.toString()));
141         }
142 
143         if (component == null)
144         {
145             throw new FlowConstructInvalidException(
146                 MessageFactory.createStaticMessage("component can't be null on: " + this.toString()));
147         }
148 
149         if (type == null)
150         {
151             throw new FlowConstructInvalidException(
152                 MessageFactory.createStaticMessage("type can't be null on: " + this.toString()));
153         }
154 
155         this.messageSource = messageSource;
156         this.component = component;
157         this.type = type;
158     }
159 
160     public Component getComponent()
161     {
162         return component;
163     }
164 
165     @Override
166     protected void configureMessageProcessorsBeforeTransformation(MessageProcessorChainBuilder builder)
167     {
168         // NOOP
169     }
170 
171     @Override
172     protected void configureMessageProcessorsAfterTransformation(MessageProcessorChainBuilder builder)
173     {
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, componentClass);
215 
216             Method setFrontendMethod = ClassUtils.getMethod(wsmpb.getClass(), "setFrontend",
217                 new Class<?>[]{String.class});
218 
219             setFrontendMethod.invoke(wsmpb, "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, 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 
256     @Override
257     public String getConstructType()
258     {
259         return "Simple-Service";
260     }
261 }