View Javadoc

1   /*
2    * $Id: JerseyResourcesComponent.java 22439 2011-07-18 19:06:39Z 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.module.jersey;
12  
13  import org.mule.api.MuleEvent;
14  import org.mule.api.MuleMessage;
15  import org.mule.api.component.JavaComponent;
16  import org.mule.api.lifecycle.InitialisationException;
17  import org.mule.api.processor.MessageProcessor;
18  import org.mule.api.transformer.TransformerException;
19  import org.mule.component.AbstractComponent;
20  import org.mule.transport.http.HttpConnector;
21  
22  import com.sun.jersey.api.core.DefaultResourceConfig;
23  import com.sun.jersey.core.header.InBoundHeaders;
24  import com.sun.jersey.core.spi.component.ioc.IoCComponentProviderFactory;
25  import com.sun.jersey.spi.container.ContainerRequest;
26  import com.sun.jersey.spi.container.ContainerResponse;
27  import com.sun.jersey.spi.container.WebApplication;
28  import com.sun.jersey.spi.container.WebApplicationFactory;
29  
30  import java.io.InputStream;
31  import java.net.URI;
32  import java.net.URISyntaxException;
33  import java.util.ArrayList;
34  import java.util.HashSet;
35  import java.util.List;
36  import java.util.Set;
37  
38  import javax.ws.rs.ext.ExceptionMapper;
39  
40  import org.apache.commons.logging.Log;
41  import org.apache.commons.logging.LogFactory;
42  
43  /**
44   * Wraps a set of components which can get invoked by Jersey. This component will
45   * map the MuleMessage format to the internal Jersey format. Jersey will then select
46   * the appropriate component to invoke based on the request parameters/URI.
47   */
48  public class JerseyResourcesComponent extends AbstractComponent
49  {
50      public static String JERSEY_RESPONSE = "jersey_response";
51  
52      protected final Log logger = LogFactory.getLog(this.getClass());
53  
54      private List<JavaComponent> components;
55  
56      private WebApplication application;
57  
58      private List<ExceptionMapper<?>> exceptionMappers = new ArrayList<ExceptionMapper<?>>();
59  
60      @Override
61      protected void doInitialise() throws InitialisationException
62      {
63          super.doInitialise();
64  
65          final Set<Class<?>> resources = new HashSet<Class<?>>();
66  
67          if (components == null)
68          {
69              throw new IllegalStateException("There must be at least one component in the Jersey resources.");
70          }
71  
72          initializeResources(resources);
73          initializeExceptionMappers(resources);
74  
75          DefaultResourceConfig resourceConfig = createConfiguration(resources);
76  
77          application = WebApplicationFactory.createWebApplication();
78          application.initiate(resourceConfig, getComponentProvider());
79      }
80  
81      protected void initializeResources(Set<Class<?>> resources) throws InitialisationException
82      {
83          // Initialize the Jersey resources using the components
84          for (JavaComponent component : components)
85          {
86              Class<?> c;
87              try
88              {
89                  c = component.getObjectType();
90                  resources.add(c);
91              }
92              catch (Exception e)
93              {
94                  throw new InitialisationException(e, this);
95              }
96          }
97      }
98  
99      protected void initializeExceptionMappers(final Set<Class<?>> resources)
100     {
101         // Initialise Exception Mappers
102         for (ExceptionMapper<?> exceptionMapper : exceptionMappers)
103         {
104             resources.add(exceptionMapper.getClass());
105         }
106     }
107 
108     protected DefaultResourceConfig createConfiguration(final Set<Class<?>> resources)
109     {
110         return new DefaultResourceConfig(resources);
111     }
112 
113     @Override
114     protected Object doInvoke(MuleEvent event) throws Exception
115     {
116         MuleMessage message = event.getMessage();
117 
118         String path = (String) message.getInboundProperty(HttpConnector.HTTP_REQUEST_PROPERTY);
119         String contextPath = (String) message.getInboundProperty(HttpConnector.HTTP_CONTEXT_PATH_PROPERTY);
120         String query = null;
121         int queryIdx = path.indexOf('?');
122         if (queryIdx != -1)
123         {
124             query = path.substring(queryIdx + 1);
125             path = path.substring(0, queryIdx);
126         }
127 
128         URI endpointUri = event.getMessageSourceURI();
129         String host = message.getInboundProperty("Host", endpointUri.getHost());
130         String method = message.getInboundProperty(HttpConnector.HTTP_METHOD_PROPERTY);
131         InBoundHeaders headers = new InBoundHeaders();
132         for (Object prop : message.getInboundPropertyNames())
133         {
134             Object property = message.getInboundProperty(prop.toString());
135             if (property != null)
136             {
137                 headers.add(prop.toString(), property.toString());
138             }
139         }
140 
141         String scheme;
142         if ("servlet".equals(endpointUri.getScheme()))
143         {
144             scheme = "http";
145         }
146         else
147         {
148             scheme = endpointUri.getScheme();
149         }
150 
151         URI baseUri = getBaseUri(endpointUri, scheme, host, contextPath);
152         URI completeUri = getCompleteUri(endpointUri, scheme, host, path, query);
153         ContainerRequest req = new ContainerRequest(application, method, baseUri, completeUri, headers,
154             getInputStream(message));
155         if (logger.isDebugEnabled())
156         {
157             logger.debug("Base URI: " + baseUri);
158             logger.debug("Complete URI: " + completeUri);
159         }
160 
161         MuleResponseWriter writer = new MuleResponseWriter(message);
162         ContainerResponse res = new ContainerResponse(application, req, writer);
163 
164         application.handleRequest(req, res);
165 
166         return writer.getResponse();
167     }
168 
169     protected static InputStream getInputStream(MuleMessage message) throws TransformerException
170     {
171         return message.getPayload(InputStream.class);
172     }
173 
174     protected IoCComponentProviderFactory getComponentProvider()
175     {
176         return new MuleComponentProviderFactory(muleContext, components);
177     }
178 
179     protected static URI getCompleteUri(URI endpointUri,
180                                         String scheme,
181                                         String host,
182                                         String path,
183                                         String query) throws URISyntaxException
184     {
185         String uri = scheme + "://" + host + path;
186         if (query != null)
187         {
188             uri += "?" + query;
189         }
190 
191         return new URI(uri);
192     }
193 
194     protected static URI getBaseUri(URI endpointUri, String scheme, String host, String contextPath)
195         throws URISyntaxException
196     {
197         if (!contextPath.endsWith("/"))
198         {
199             contextPath += "/";
200         }
201 
202         return new URI(scheme + "://" + host + contextPath);
203     }
204 
205     public List<JavaComponent> getComponents()
206     {
207         return components;
208     }
209 
210     public void setComponents(List<JavaComponent> components)
211     {
212         this.components = components;
213     }
214 
215     public void setMessageProcessors(List<MessageProcessor> messageProcessors)
216     {
217         List<JavaComponent> javaComponents = new ArrayList<JavaComponent>();
218         for (MessageProcessor mp : messageProcessors)
219         {
220             if (mp instanceof JavaComponent)
221             {
222                 javaComponents.add((JavaComponent) mp);
223             }
224             else
225             {
226                 throw new IllegalStateException("Only JavaComponents are allowed as MessageProcessors. Type "
227                                                 + mp.getClass().getName() + " is not allowed.");
228             }
229         }
230         setComponents(javaComponents);
231     }
232 
233     public void setExceptionMapper(ExceptionMapper<?> exceptionMapper)
234     {
235         exceptionMappers.add(exceptionMapper);
236     }
237 }