Coverage Report - org.mule.transport.servlet.jetty.JettyHttpConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
JettyHttpConnector
0%
0/115
0%
0/30
0
JettyHttpConnector$1
0%
0/8
0%
0/2
0
JettyHttpConnector$MuleReceiverConnectorHolder
0%
0/22
0%
0/8
0
 
 1  
 /*
 2  
  * $Id: JettyHttpConnector.java 19554 2010-09-10 13:39:43Z dirk.olmes $
 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.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  
  * The <code>JettyConnector</code> can be using to embed a Jetty server to receive requests on an
 53  
  * http inound endpoint. One server is created for each connector declared, many Jetty endpoints
 54  
  * can share the same connector.
 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  0
     private boolean useContinuations = false;
 71  
 
 72  0
     protected HashMap<String, ConnectorHolder> holders = new HashMap<String, ConnectorHolder>();
 73  
 
 74  
     public JettyHttpConnector(MuleContext context)
 75  
     {
 76  0
         super(context);
 77  0
         registerSupportedProtocol("http");
 78  0
         registerSupportedProtocol(JETTY);
 79  0
         setInitialStateStopped(true);
 80  0
     }
 81  
 
 82  
     public String getProtocol()
 83  
     {
 84  0
         return JETTY;
 85  
     }
 86  
 
 87  
     @Override
 88  
     protected void doInitialise() throws InitialisationException
 89  
     {
 90  0
         httpServer = new Server();
 91  0
         initialiseFromConfigFile();
 92  
 
 93  
         try
 94  
         {
 95  0
             muleContext.registerListener(new MuleContextNotificationListener<MuleContextNotification>(){
 96  
                 public void onNotification(MuleContextNotification notification)
 97  
                 {
 98  0
                     if (notification.getAction() == MuleContextNotification.CONTEXT_STARTED)
 99  
                     {
 100  
                         //We delay starting until the context has been started since we need the MuleAjaxServlet to initialise first
 101  0
                         setInitialStateStopped(false);
 102  
                         try
 103  
                         {
 104  0
                             start();
 105  
                         }
 106  0
                         catch (MuleException e)
 107  
                         {
 108  0
                             throw new MuleRuntimeException(CoreMessages.failedToStart(getName()), e);
 109  0
                         }
 110  
                     }
 111  0
                 }
 112  
             });
 113  
         }
 114  0
         catch (NotificationException e)
 115  
         {
 116  0
             throw new InitialisationException(e, this);
 117  0
         }
 118  0
     }
 119  
 
 120  
     @SuppressWarnings("unchecked")
 121  
     protected void initialiseFromConfigFile() throws InitialisationException
 122  
     {
 123  0
         if (configFile != null)
 124  
         {
 125  
             try
 126  
             {
 127  0
                 InputStream is = IOUtils.getResourceAsStream(configFile, getClass());
 128  0
                 XmlConfiguration config = new XmlConfiguration(is);
 129  
 
 130  0
                 String appHome =
 131  
                     muleContext.getRegistry().lookupObject(MuleProperties.APP_HOME_DIRECTORY_PROPERTY);
 132  0
                 if (appHome == null)
 133  
                 {
 134  
                     // Mule IDE sets app.home as part of the launch config it creates
 135  0
                     appHome = System.getProperty(MuleProperties.APP_HOME_DIRECTORY_PROPERTY);
 136  
                 }
 137  
 
 138  0
                 if (appHome != null)
 139  
                 {
 140  0
                     config.getProperties().put(MuleProperties.APP_HOME_DIRECTORY_PROPERTY, appHome);
 141  
                 }
 142  
                 
 143  0
                 config.configure(httpServer);
 144  
             }
 145  0
             catch (Exception e)
 146  
             {
 147  0
                 throw new InitialisationException(e, this);
 148  0
             }
 149  
         }
 150  0
     }
 151  
 
 152  
     /**
 153  
      * Template method to dispose any resources associated with this receiver. There
 154  
      * is not need to dispose the connector as this is already done by the framework
 155  
      */
 156  
     @Override
 157  
     protected void doDispose()
 158  
     {
 159  0
         holders.clear();
 160  0
     }
 161  
 
 162  
     @Override
 163  
     protected void doStart() throws MuleException
 164  
     {
 165  
         try
 166  
         {
 167  0
             httpServer.start();
 168  0
             for (ConnectorHolder<?, ?> contextHolder : holders.values())
 169  
             {
 170  0
                 contextHolder.start();
 171  
             }
 172  
         }
 173  0
         catch (Exception e)
 174  
         {
 175  0
             throw new LifecycleException(CoreMessages.failedToStart("Jetty Http Receiver"), e, this);
 176  0
         }
 177  0
     }
 178  
 
 179  
     @Override
 180  
     protected void doStop() throws MuleException
 181  
     {
 182  
         try
 183  
         {
 184  0
             httpServer.stop();
 185  0
             for (ConnectorHolder<?, ?> connectorRef : holders.values())
 186  
             {
 187  0
                 connectorRef.stop();
 188  
             }
 189  
         }
 190  0
         catch (Exception e)
 191  
         {
 192  0
             throw new LifecycleException(CoreMessages.failedToStop("Jetty Http Receiver"), e, this);
 193  0
         }
 194  0
     }
 195  
 
 196  
     /**
 197  
      * Template method where any connections should be made for the connector
 198  
      *
 199  
      * @throws Exception
 200  
      */
 201  
     @Override
 202  
     protected void doConnect() throws Exception
 203  
     {
 204  
         //do nothing
 205  0
     }
 206  
 
 207  
     /**
 208  
      * Template method where any connected resources used by the connector should be
 209  
      * disconnected
 210  
      *
 211  
      * @throws Exception
 212  
      */
 213  
     @Override
 214  
     protected void doDisconnect() throws Exception
 215  
     {
 216  
         //do nothing
 217  0
     }
 218  
 
 219  
      @Override
 220  
     protected MessageReceiver createReceiver(FlowConstruct flowConstruct, InboundEndpoint endpoint) throws Exception
 221  
     {
 222  0
         MessageReceiver receiver = super.createReceiver(flowConstruct, endpoint);
 223  0
         registerJettyEndpoint(receiver, endpoint);
 224  0
         return receiver;
 225  
     }
 226  
 
 227  
     protected org.mortbay.jetty.AbstractConnector createJettyConnector()
 228  
     {
 229  0
         return new SelectChannelConnector();
 230  
     }
 231  
 
 232  
     public void unregisterListener(MessageReceiver receiver) throws MuleException
 233  
     {
 234  0
         String connectorKey = getHolderKey(receiver.getEndpoint());
 235  
 
 236  0
         synchronized (this)
 237  
         {
 238  0
             ConnectorHolder connectorRef = holders.get(connectorKey);
 239  0
             if (connectorRef != null)
 240  
             {
 241  0
                 if (!connectorRef.isReferenced())
 242  
                 {
 243  0
                     getHttpServer().removeConnector(connectorRef.getConnector());
 244  0
                     holders.remove(connectorKey);
 245  0
                     connectorRef.stop();
 246  
                 }
 247  
             }
 248  0
         }
 249  0
     }
 250  
 
 251  
     public Server getHttpServer()
 252  
     {
 253  0
         return httpServer;
 254  
     }
 255  
 
 256  
     public String getConfigFile()
 257  
     {
 258  0
         return configFile;
 259  
     }
 260  
 
 261  
     public void setConfigFile(String configFile)
 262  
     {
 263  0
         this.configFile = configFile;
 264  0
     }
 265  
 
 266  
     public JettyReceiverServlet getReceiverServlet()
 267  
     {
 268  0
         return receiverServlet;
 269  
     }
 270  
 
 271  
     public void setReceiverServlet(JettyReceiverServlet receiverServlet)
 272  
     {
 273  0
         this.receiverServlet = receiverServlet;
 274  0
     }
 275  
 
 276  
     @Override
 277  
     public ReplyToHandler getReplyToHandler(ImmutableEndpoint endpoint)
 278  
     {
 279  0
         if (isUseContinuations())
 280  
         {
 281  0
             return new JettyContinuationsReplyToHandler(getDefaultResponseTransformers(endpoint), muleContext);
 282  
         }
 283  0
         return super.getReplyToHandler(endpoint);
 284  
     }
 285  
 
 286  
     public boolean isUseContinuations()
 287  
     {
 288  0
         return useContinuations;
 289  
     }
 290  
 
 291  
     public void setUseContinuations(boolean useContinuations)
 292  
     {
 293  0
         this.useContinuations = useContinuations;
 294  0
     }
 295  
 
 296  
     ConnectorHolder<? extends MuleReceiverServlet, ? extends JettyHttpMessageReceiver> registerJettyEndpoint(MessageReceiver receiver, InboundEndpoint endpoint) throws MuleException
 297  
     {
 298  
         // Make sure that there is a connector for the requested endpoint.
 299  0
         String connectorKey = getHolderKey(endpoint);
 300  
 
 301  
         ConnectorHolder holder;
 302  
 
 303  0
         synchronized (this)
 304  
         {
 305  0
             holder = holders.get(connectorKey);
 306  0
             if (holder == null)
 307  
             {
 308  0
                 Connector connector = createJettyConnector();
 309  
 
 310  0
                 connector.setPort(endpoint.getEndpointURI().getPort());
 311  0
                 connector.setHost(endpoint.getEndpointURI().getHost());
 312  0
                 if ("localhost".equalsIgnoreCase(endpoint.getEndpointURI().getHost()))
 313  
                 {
 314  0
                     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  0
                 getHttpServer().addConnector(connector);
 318  
 
 319  0
                 holder = createContextHolder(connector, receiver.getEndpoint(), receiver);
 320  0
                 holders.put(connectorKey, holder);
 321  0
                 if(isStarted())
 322  
                 {
 323  0
                     holder.start();
 324  
                 }
 325  0
             }
 326  
             else
 327  
             {
 328  0
                 holder.addReceiver(receiver);
 329  
             }
 330  0
         }
 331  0
         return holder;
 332  
     }
 333  
 
 334  
     protected ConnectorHolder createContextHolder(Connector connector, InboundEndpoint endpoint, MessageReceiver receiver)
 335  
     {
 336  0
         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  0
         if (getReceiverServlet() == null)
 343  
         {
 344  0
             if(isUseContinuations())
 345  
             {
 346  0
                 servlet = new JettyContinuationsReceiverServlet();
 347  
             }
 348  
             else
 349  
             {
 350  0
                 servlet = new JettyReceiverServlet();
 351  
             }
 352  
         }
 353  
         else
 354  
         {
 355  0
             servlet = getReceiverServlet();
 356  
         }
 357  
 
 358  0
         String path = endpoint.getEndpointURI().getPath();
 359  0
         if(StringUtils.isBlank(path))
 360  
         {
 361  0
             path = ROOT;
 362  
         }
 363  
 
 364  0
         ContextHandlerCollection handlerCollection = new ContextHandlerCollection();
 365  0
         Context context = new Context(handlerCollection, ROOT, Context.NO_SECURITY);
 366  0
         context.setConnectorNames(new String[]{connector.getName()});
 367  0
         context.addEventListener(new MuleServletContextListener(muleContext, getName()));
 368  
 
 369  0
         String resourceBase = (String)endpoint.getProperty(RESOURCE_BASE_PROPERTY);
 370  0
         if(resourceBase!=null)
 371  
         {
 372  
 
 373  0
             Context resourceContext = new Context(handlerCollection, path, Context.NO_SECURITY);
 374  0
             resourceContext.setResourceBase(resourceBase);
 375  
         }
 376  
 
 377  0
         context.addServlet(JarResourceServlet.class, JarResourceServlet.DEFAULT_PATH_SPEC);
 378  
 
 379  0
         ServletHolder holder = new ServletHolder();
 380  0
         holder.setServlet(servlet);
 381  0
         context.addServlet(holder, "/*");
 382  0
         getHttpServer().addHandler(handlerCollection);
 383  0
         return servlet;
 384  
     }
 385  
 
 386  
     protected String getHolderKey(ImmutableEndpoint endpoint)
 387  
     {
 388  0
         return endpoint.getProtocol() + ":" + endpoint.getEndpointURI().getHost() + ":" + endpoint.getEndpointURI().getPort();
 389  
     }
 390  
 
 391  0
     public class MuleReceiverConnectorHolder extends AbstractConnectorHolder<JettyReceiverServlet, JettyHttpMessageReceiver>
 392  
     {
 393  0
         List<MessageReceiver> messageReceivers = new ArrayList<MessageReceiver>();
 394  
 
 395  
         public MuleReceiverConnectorHolder(Connector connector, JettyReceiverServlet servlet, JettyHttpMessageReceiver receiver)
 396  0
         {
 397  0
             super(connector, servlet, receiver);
 398  0
             addReceiver(receiver);
 399  0
         }
 400  
 
 401  
         public boolean isReferenced()
 402  
         {
 403  0
             return messageReceivers.size() > 0;
 404  
         }
 405  
 
 406  
         public void addReceiver(JettyHttpMessageReceiver receiver)
 407  
         {
 408  0
             messageReceivers.add(receiver);
 409  0
             if(started)
 410  
             {
 411  0
                 getServlet().addReceiver(receiver);
 412  
             }
 413  0
         }
 414  
 
 415  
         public void removeReceiver(JettyHttpMessageReceiver receiver)
 416  
         {
 417  0
             messageReceivers.remove(receiver);
 418  0
             getServlet().removeReceiver(receiver);
 419  0
         }
 420  
 
 421  
         @Override
 422  
         public void start() throws MuleException
 423  
         {
 424  0
             super.start();
 425  
             
 426  0
             for (MessageReceiver receiver : messageReceivers)
 427  
             {
 428  0
                 servlet.addReceiver(receiver);
 429  
             }
 430  0
         }
 431  
 
 432  
         @Override
 433  
         public void stop() throws MuleException
 434  
         {
 435  0
             super.stop();
 436  
 
 437  0
             for (MessageReceiver receiver : messageReceivers)
 438  
             {
 439  0
                 servlet.removeReceiver(receiver);
 440  
             }
 441  0
         }
 442  
     }
 443  
 }