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