1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.servlet.jetty;
12
13 import org.mule.api.MuleContext;
14 import org.mule.api.MuleException;
15 import org.mule.api.MuleRuntimeException;
16 import org.mule.api.config.MuleProperties;
17 import org.mule.api.construct.FlowConstruct;
18 import org.mule.api.context.notification.MuleContextNotificationListener;
19 import org.mule.api.endpoint.ImmutableEndpoint;
20 import org.mule.api.endpoint.InboundEndpoint;
21 import org.mule.api.lifecycle.InitialisationException;
22 import org.mule.api.lifecycle.LifecycleException;
23 import org.mule.api.transport.MessageReceiver;
24 import org.mule.api.transport.ReplyToHandler;
25 import org.mule.config.i18n.CoreMessages;
26 import org.mule.context.notification.MuleContextNotification;
27 import org.mule.context.notification.NotificationException;
28 import org.mule.transport.AbstractConnector;
29 import org.mule.transport.servlet.JarResourceServlet;
30 import org.mule.transport.servlet.MuleReceiverServlet;
31 import org.mule.transport.servlet.MuleServletContextListener;
32 import org.mule.util.IOUtils;
33 import org.mule.util.StringUtils;
34
35 import java.io.InputStream;
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.List;
39
40 import javax.servlet.Servlet;
41 import javax.servlet.http.HttpServlet;
42
43 import org.mortbay.jetty.Connector;
44 import org.mortbay.jetty.Server;
45 import org.mortbay.jetty.handler.ContextHandlerCollection;
46 import org.mortbay.jetty.nio.SelectChannelConnector;
47 import org.mortbay.jetty.servlet.Context;
48 import org.mortbay.jetty.servlet.ServletHolder;
49 import org.mortbay.xml.XmlConfiguration;
50
51
52
53
54
55
56 public class JettyHttpConnector extends AbstractConnector
57 {
58 public static final String RESOURCE_BASE_PROPERTY = "resourceBase";
59
60 public static final String ROOT = "/";
61
62 public static final String JETTY = "jetty";
63
64 private Server httpServer;
65
66 private String configFile;
67
68 private JettyReceiverServlet receiverServlet;
69
70 private boolean useContinuations = false;
71
72 protected HashMap<String, ConnectorHolder> holders = new HashMap<String, ConnectorHolder>();
73
74 public JettyHttpConnector(MuleContext context)
75 {
76 super(context);
77 registerSupportedProtocol("http");
78 registerSupportedProtocol(JETTY);
79 setInitialStateStopped(true);
80 }
81
82 public String getProtocol()
83 {
84 return JETTY;
85 }
86
87 @Override
88 protected void doInitialise() throws InitialisationException
89 {
90 httpServer = new Server();
91 initialiseFromConfigFile();
92
93 try
94 {
95 muleContext.registerListener(new MuleContextNotificationListener<MuleContextNotification>(){
96 public void onNotification(MuleContextNotification notification)
97 {
98 if (notification.getAction() == MuleContextNotification.CONTEXT_STARTED)
99 {
100
101 setInitialStateStopped(false);
102 try
103 {
104 start();
105 }
106 catch (MuleException e)
107 {
108 throw new MuleRuntimeException(CoreMessages.failedToStart(getName()), e);
109 }
110 }
111 }
112 });
113 }
114 catch (NotificationException e)
115 {
116 throw new InitialisationException(e, this);
117 }
118 }
119
120 @SuppressWarnings("unchecked")
121 protected void initialiseFromConfigFile() throws InitialisationException
122 {
123 if (configFile != null)
124 {
125 try
126 {
127 InputStream is = IOUtils.getResourceAsStream(configFile, getClass());
128 XmlConfiguration config = new XmlConfiguration(is);
129
130 String appHome =
131 muleContext.getRegistry().lookupObject(MuleProperties.APP_HOME_DIRECTORY_PROPERTY);
132 if (appHome == null)
133 {
134
135 appHome = System.getProperty(MuleProperties.APP_HOME_DIRECTORY_PROPERTY);
136 }
137
138 if (appHome != null)
139 {
140 config.getProperties().put(MuleProperties.APP_HOME_DIRECTORY_PROPERTY, appHome);
141 }
142
143 config.configure(httpServer);
144 }
145 catch (Exception e)
146 {
147 throw new InitialisationException(e, this);
148 }
149 }
150 }
151
152
153
154
155
156 @Override
157 protected void doDispose()
158 {
159 holders.clear();
160 }
161
162 @Override
163 protected void doStart() throws MuleException
164 {
165 try
166 {
167 httpServer.start();
168 for (ConnectorHolder<?, ?> contextHolder : holders.values())
169 {
170 contextHolder.start();
171 }
172 }
173 catch (Exception e)
174 {
175 throw new LifecycleException(CoreMessages.failedToStart("Jetty Http Receiver"), e, this);
176 }
177 }
178
179 @Override
180 protected void doStop() throws MuleException
181 {
182 try
183 {
184 httpServer.stop();
185 for (ConnectorHolder<?, ?> connectorRef : holders.values())
186 {
187 connectorRef.stop();
188 }
189 }
190 catch (Exception e)
191 {
192 throw new LifecycleException(CoreMessages.failedToStop("Jetty Http Receiver"), e, this);
193 }
194 }
195
196
197
198
199
200
201 @Override
202 protected void doConnect() throws Exception
203 {
204
205 }
206
207
208
209
210
211
212
213 @Override
214 protected void doDisconnect() throws Exception
215 {
216
217 }
218
219 @Override
220 protected MessageReceiver createReceiver(FlowConstruct flowConstruct, InboundEndpoint endpoint) throws Exception
221 {
222 MessageReceiver receiver = super.createReceiver(flowConstruct, endpoint);
223 registerJettyEndpoint(receiver, endpoint);
224 return receiver;
225 }
226
227 protected org.mortbay.jetty.AbstractConnector createJettyConnector()
228 {
229 return new SelectChannelConnector();
230 }
231
232 public void unregisterListener(MessageReceiver receiver) throws MuleException
233 {
234 String connectorKey = getHolderKey(receiver.getEndpoint());
235
236 synchronized (this)
237 {
238 ConnectorHolder connectorRef = holders.get(connectorKey);
239 if (connectorRef != null)
240 {
241 if (!connectorRef.isReferenced())
242 {
243 getHttpServer().removeConnector(connectorRef.getConnector());
244 holders.remove(connectorKey);
245 connectorRef.stop();
246 }
247 }
248 }
249 }
250
251 public Server getHttpServer()
252 {
253 return httpServer;
254 }
255
256 public String getConfigFile()
257 {
258 return configFile;
259 }
260
261 public void setConfigFile(String configFile)
262 {
263 this.configFile = configFile;
264 }
265
266 public JettyReceiverServlet getReceiverServlet()
267 {
268 return receiverServlet;
269 }
270
271 public void setReceiverServlet(JettyReceiverServlet receiverServlet)
272 {
273 this.receiverServlet = receiverServlet;
274 }
275
276 @Override
277 public ReplyToHandler getReplyToHandler(ImmutableEndpoint endpoint)
278 {
279 if (isUseContinuations())
280 {
281 return new JettyContinuationsReplyToHandler(getDefaultResponseTransformers(endpoint), muleContext);
282 }
283 return super.getReplyToHandler(endpoint);
284 }
285
286 public boolean isUseContinuations()
287 {
288 return useContinuations;
289 }
290
291 public void setUseContinuations(boolean useContinuations)
292 {
293 this.useContinuations = useContinuations;
294 }
295
296 ConnectorHolder<? extends MuleReceiverServlet, ? extends JettyHttpMessageReceiver> registerJettyEndpoint(MessageReceiver receiver, InboundEndpoint endpoint) throws MuleException
297 {
298
299 String connectorKey = getHolderKey(endpoint);
300
301 ConnectorHolder holder;
302
303 synchronized (this)
304 {
305 holder = holders.get(connectorKey);
306 if (holder == null)
307 {
308 Connector connector = createJettyConnector();
309
310 connector.setPort(endpoint.getEndpointURI().getPort());
311 connector.setHost(endpoint.getEndpointURI().getHost());
312 if ("localhost".equalsIgnoreCase(endpoint.getEndpointURI().getHost()))
313 {
314 logger.warn("You use localhost interface! It means that no external connections will be available."
315 + " Don't you want to use 0.0.0.0 instead (all network interfaces)?");
316 }
317 getHttpServer().addConnector(connector);
318
319 holder = createContextHolder(connector, receiver.getEndpoint(), receiver);
320 holders.put(connectorKey, holder);
321 if(isStarted())
322 {
323 holder.start();
324 }
325 }
326 else
327 {
328 holder.addReceiver(receiver);
329 }
330 }
331 return holder;
332 }
333
334 protected ConnectorHolder createContextHolder(Connector connector, InboundEndpoint endpoint, MessageReceiver receiver)
335 {
336 return new MuleReceiverConnectorHolder(connector, (JettyReceiverServlet) createServlet(connector, endpoint), (JettyHttpMessageReceiver)receiver);
337 }
338
339 protected Servlet createServlet(Connector connector, ImmutableEndpoint endpoint)
340 {
341 HttpServlet servlet;
342 if (getReceiverServlet() == null)
343 {
344 if(isUseContinuations())
345 {
346 servlet = new JettyContinuationsReceiverServlet();
347 }
348 else
349 {
350 servlet = new JettyReceiverServlet();
351 }
352 }
353 else
354 {
355 servlet = getReceiverServlet();
356 }
357
358 String path = endpoint.getEndpointURI().getPath();
359 if(StringUtils.isBlank(path))
360 {
361 path = ROOT;
362 }
363
364 ContextHandlerCollection handlerCollection = new ContextHandlerCollection();
365 Context context = new Context(handlerCollection, ROOT, Context.NO_SECURITY);
366 context.setConnectorNames(new String[]{connector.getName()});
367 context.addEventListener(new MuleServletContextListener(muleContext, getName()));
368
369 String resourceBase = (String)endpoint.getProperty(RESOURCE_BASE_PROPERTY);
370 if(resourceBase!=null)
371 {
372
373 Context resourceContext = new Context(handlerCollection, path, Context.NO_SECURITY);
374 resourceContext.setResourceBase(resourceBase);
375 }
376
377 context.addServlet(JarResourceServlet.class, JarResourceServlet.DEFAULT_PATH_SPEC);
378
379 ServletHolder holder = new ServletHolder();
380 holder.setServlet(servlet);
381 context.addServlet(holder, "/*");
382 getHttpServer().addHandler(handlerCollection);
383 return servlet;
384 }
385
386 protected String getHolderKey(ImmutableEndpoint endpoint)
387 {
388 return endpoint.getProtocol() + ":" + endpoint.getEndpointURI().getHost() + ":" + endpoint.getEndpointURI().getPort();
389 }
390
391 public class MuleReceiverConnectorHolder extends AbstractConnectorHolder<JettyReceiverServlet, JettyHttpMessageReceiver>
392 {
393 List<MessageReceiver> messageReceivers = new ArrayList<MessageReceiver>();
394
395 public MuleReceiverConnectorHolder(Connector connector, JettyReceiverServlet servlet, JettyHttpMessageReceiver receiver)
396 {
397 super(connector, servlet, receiver);
398 addReceiver(receiver);
399 }
400
401 public boolean isReferenced()
402 {
403 return messageReceivers.size() > 0;
404 }
405
406 public void addReceiver(JettyHttpMessageReceiver receiver)
407 {
408 messageReceivers.add(receiver);
409 if(started)
410 {
411 getServlet().addReceiver(receiver);
412 }
413 }
414
415 public void removeReceiver(JettyHttpMessageReceiver receiver)
416 {
417 messageReceivers.remove(receiver);
418 getServlet().removeReceiver(receiver);
419 }
420
421 @Override
422 public void start() throws MuleException
423 {
424 super.start();
425
426 for (MessageReceiver receiver : messageReceivers)
427 {
428 servlet.addReceiver(receiver);
429 }
430 }
431
432 @Override
433 public void stop() throws MuleException
434 {
435 super.stop();
436
437 for (MessageReceiver receiver : messageReceivers)
438 {
439 servlet.removeReceiver(receiver);
440 }
441 }
442 }
443 }