Coverage Report - org.mule.transport.ajax.embedded.AjaxConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
AjaxConnector
0%
0/113
0%
0/26
0
 
 1  
 /*
 2  
  * $Id: AjaxConnector.java 20385 2010-11-29 20:25:26Z 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  
 package org.mule.transport.ajax.embedded;
 11  
 
 12  
 import org.mule.api.MuleContext;
 13  
 import org.mule.api.MuleException;
 14  
 import org.mule.api.construct.FlowConstruct;
 15  
 import org.mule.api.endpoint.EndpointBuilder;
 16  
 import org.mule.api.endpoint.ImmutableEndpoint;
 17  
 import org.mule.api.endpoint.InboundEndpoint;
 18  
 import org.mule.api.lifecycle.InitialisationException;
 19  
 import org.mule.api.transport.MessageReceiver;
 20  
 import org.mule.api.transport.ReplyToHandler;
 21  
 import org.mule.transport.ajax.AjaxMessageReceiver;
 22  
 import org.mule.transport.ajax.AjaxMuleMessageFactory;
 23  
 import org.mule.transport.ajax.AjaxReplyToHandler;
 24  
 import org.mule.transport.ajax.BayeuxAware;
 25  
 import org.mule.transport.ajax.container.MuleAjaxServlet;
 26  
 import org.mule.transport.ajax.i18n.AjaxMessages;
 27  
 import org.mule.transport.servlet.JarResourceServlet;
 28  
 import org.mule.transport.servlet.MuleServletContextListener;
 29  
 import org.mule.transport.servlet.jetty.JettyHttpsConnector;
 30  
 import org.mule.util.StringUtils;
 31  
 
 32  
 import java.net.URL;
 33  
 import java.util.Map;
 34  
 
 35  
 import javax.servlet.Servlet;
 36  
 
 37  
 import org.mortbay.cometd.AbstractBayeux;
 38  
 import org.mortbay.cometd.continuation.ContinuationCometdServlet;
 39  
 import org.mortbay.jetty.AbstractConnector;
 40  
 import org.mortbay.jetty.Connector;
 41  
 import org.mortbay.jetty.handler.ContextHandlerCollection;
 42  
 import org.mortbay.jetty.nio.SelectChannelConnector;
 43  
 import org.mortbay.jetty.servlet.Context;
 44  
 import org.mortbay.jetty.servlet.DefaultServlet;
 45  
 import org.mortbay.jetty.servlet.ServletHolder;
 46  
 
 47  
 /**
 48  
  * Creates an 'embedded' Ajax server using Jetty and allows Mule to receiver and send events
 49  
  * to browsers. The browser will need to use the <pre>mule.js</pre> class to publish and
 50  
  * subscribe events.
 51  
  *
 52  
  * Note that a {@link @RESOURCE_BASE_PROPERTY} can be set on the ajax endpoint that provides the location of any web application resources such
 53  
  * as html pages
 54  
  */
 55  
 public class AjaxConnector extends JettyHttpsConnector implements BayeuxAware
 56  
 {
 57  
     public static final String PROTOCOL = "ajax";
 58  
 
 59  
     public static final String CHANNEL_PROPERTY = "channel";
 60  
 
 61  
     public static final String AJAX_PATH_SPEC = "/ajax/*";
 62  
 
 63  
     public static final String COMETD_CLIENT = "cometd.client";
 64  
 
 65  
     /**
 66  
      * This is the key that's used to retrieve the reply to destination from a {@link Map} that's
 67  
      * passed into {@link AjaxMuleMessageFactory}.
 68  
      */
 69  
     public static final String REPLYTO_PARAM = "replyTo";
 70  
 
 71  
     private URL serverUrl;
 72  
 
 73  
     /**
 74  
      * The client side poll timeout in milliseconds (default 0). How long a client
 75  
      * will wait between reconnects
 76  
      */
 77  0
     private int interval = INT_VALUE_NOT_SET;
 78  
 
 79  
     /**
 80  
      * The max client side poll timeout in milliseconds (default 30000). A client
 81  
      * will be removed if a connection is not received in this time.
 82  
      */
 83  0
     private int maxInterval = INT_VALUE_NOT_SET;
 84  
 
 85  
     /**
 86  
      * The client side poll timeout if multiple connections are detected from the
 87  
      * same browser (default 1500).
 88  
      */
 89  0
     private int multiFrameInterval = INT_VALUE_NOT_SET;
 90  
 
 91  
     /**
 92  
      * 0=none, 1=info, 2=debug
 93  
      */
 94  0
     private int logLevel = INT_VALUE_NOT_SET;
 95  
 
 96  
     /**
 97  
      * The server side poll timeout in milliseconds (default 250000). This is how long
 98  
      * the server will hold a reconnect request before responding.
 99  
      */
 100  0
     private int timeout = INT_VALUE_NOT_SET;
 101  
 
 102  
     /**
 103  
      * If "true" (default) then the server will accept JSON wrapped in a comment and
 104  
      * will generate JSON wrapped in a comment. This is a defence against Ajax Hijacking.
 105  
      */
 106  0
     private boolean jsonCommented = true;
 107  
 
 108  
     /**
 109  
      * TODO SUPPORT FILTERS
 110  
      * the location of a JSON file describing {@link org.cometd.DataFilter} instances to be installed
 111  
      */
 112  
     private String filters;
 113  
 
 114  
     /**
 115  
      * If true, the current request is made available via the
 116  
      * {@link AbstractBayeux#getCurrentRequest()} method
 117  
      */
 118  0
     private boolean requestAvailable = true;
 119  
 
 120  
     /**
 121  
      * true if published messages are delivered directly to subscribers (default).
 122  
      * If false, a message copy is created with only supported fields (default true).
 123  
      */
 124  0
     private boolean directDeliver = true;
 125  
 
 126  
     /**
 127  
      * The number of message refs at which the a single message response will be
 128  
      * cached instead of being generated for every client delivered to. Done to optimize
 129  
      * a single message being sent to multiple clients.
 130  
      */
 131  0
     private int refsThreshold = INT_VALUE_NOT_SET;
 132  
 
 133  
     private ContinuationCometdServlet servlet;
 134  
 
 135  
     public AjaxConnector(MuleContext context)
 136  
     {
 137  0
         super(context);
 138  0
         unregisterSupportedProtocol("http");
 139  0
         unregisterSupportedProtocol("https");
 140  0
         unregisterSupportedProtocol("jetty-ssl");
 141  0
         unregisterSupportedProtocol("jetty");
 142  0
         setInitialStateStopped(true);
 143  0
     }
 144  
 
 145  
     @Override
 146  
     public String getProtocol()
 147  
     {
 148  0
         return PROTOCOL;
 149  
     }
 150  
 
 151  
     public URL getServerUrl()
 152  
     {
 153  0
         return serverUrl;
 154  
     }
 155  
 
 156  
     public void setServerUrl(URL serverUrl)
 157  
     {
 158  0
         this.serverUrl = serverUrl;
 159  0
     }
 160  
 
 161  
     @Override
 162  
     protected void doInitialise() throws InitialisationException
 163  
     {
 164  0
         if (serverUrl==null)
 165  
         {
 166  0
             throw new InitialisationException(AjaxMessages.serverUrlNotDefined(), this);
 167  
         }
 168  0
         super.doInitialise();
 169  
         try
 170  
         {
 171  0
             createEmbeddedServer();
 172  
         }
 173  0
         catch (Exception e)
 174  
         {
 175  0
             throw new InitialisationException(e, this);
 176  0
         }
 177  0
     }
 178  
 
 179  
     @Override
 180  
     protected void doStart() throws MuleException
 181  
     {
 182  0
         super.doStart();
 183  0
         for (MessageReceiver receiver : receivers.values())
 184  
         {
 185  0
             ((AjaxMessageReceiver)receiver).setBayeux(getBayeux());
 186  
         }
 187  0
     }
 188  
 
 189  
     @Override
 190  
     protected void validateSslConfig() throws InitialisationException
 191  
     {
 192  0
         if (serverUrl.getProtocol().equals("https"))
 193  
         {
 194  0
             super.validateSslConfig();
 195  
         }
 196  0
     }
 197  
 
 198  
     @Override
 199  
     public ReplyToHandler getReplyToHandler(ImmutableEndpoint endpoint)
 200  
     {
 201  0
         return new AjaxReplyToHandler(getDefaultResponseTransformers(endpoint), this);
 202  
     }
 203  
 
 204  
     void createEmbeddedServer() throws MuleException
 205  
     {
 206  0
         Connector connector = createJettyConnector();
 207  
 
 208  0
         connector.setPort(serverUrl.getPort());
 209  0
         connector.setHost(serverUrl.getHost());
 210  
         
 211  0
         getHttpServer().addConnector(connector);
 212  0
         EndpointBuilder builder = muleContext.getEndpointFactory().getEndpointBuilder(serverUrl.toString());
 213  
 
 214  0
         servlet = (ContinuationCometdServlet)createServlet(connector, builder.buildInboundEndpoint());
 215  0
     }
 216  
 
 217  
     @Override
 218  
     public Servlet createServlet(Connector connector, ImmutableEndpoint endpoint)
 219  
     {
 220  0
         ContinuationCometdServlet ajaxServlet = new MuleAjaxServlet();
 221  
 
 222  0
         String path = endpoint.getEndpointURI().getPath();
 223  0
         if (StringUtils.isBlank(path))
 224  
         {
 225  0
             path = ROOT;
 226  
         }
 227  
 
 228  0
         ContextHandlerCollection handlerCollection = new ContextHandlerCollection();
 229  0
         Context root = new Context(handlerCollection, ROOT, Context.NO_SECURITY);
 230  0
         root.setConnectorNames(new String[]{connector.getName()});
 231  0
         root.addEventListener(new MuleServletContextListener(muleContext, getName()));
 232  
 
 233  0
         if (!ROOT.equals(path))
 234  
         {
 235  0
             Context resourceContext = new Context(handlerCollection, path, Context.NO_SECURITY);
 236  0
             populateContext(resourceContext);
 237  
 
 238  0
         }
 239  
         else
 240  
         {
 241  0
             populateContext(root);
 242  
         }
 243  
 
 244  
         //Add ajax to root
 245  0
         ServletHolder holder = new ServletHolder();
 246  0
         holder.setServlet(ajaxServlet);
 247  0
         root.addServlet(holder, AJAX_PATH_SPEC);
 248  
 
 249  0
         if (getInterval() != INT_VALUE_NOT_SET) holder.setInitParameter("interval", Integer.toString(getInterval()));
 250  0
         holder.setInitParameter("JSONCommented", Boolean.toString(isJsonCommented()));
 251  0
         if (getLogLevel() != INT_VALUE_NOT_SET) holder.setInitParameter("logLevel", Integer.toString(getLogLevel()));
 252  0
         if (getMaxInterval() != INT_VALUE_NOT_SET) holder.setInitParameter("maxInterval", Integer.toString(getMaxInterval()));
 253  0
         if (getMultiFrameInterval() != INT_VALUE_NOT_SET) holder.setInitParameter("multiFrameInterval", (Integer.toString(getMultiFrameInterval())));
 254  0
         if (getTimeout() != INT_VALUE_NOT_SET) holder.setInitParameter("timeout", Integer.toString(getTimeout()));
 255  0
         if (getRefsThreshold() != INT_VALUE_NOT_SET) holder.setInitParameter("refsThreshold", Integer.toString(getRefsThreshold()));
 256  0
         holder.setInitParameter("requestAvailable", Boolean.toString(isRequestAvailable()));
 257  
 
 258  
 
 259  0
         this.getHttpServer().addHandler(handlerCollection);
 260  0
         return ajaxServlet;
 261  
     }
 262  
 
 263  
     protected void populateContext(Context context)
 264  
     {
 265  0
         context.addServlet(DefaultServlet.class, ROOT);
 266  0
         context.addServlet(JarResourceServlet.class, JarResourceServlet.DEFAULT_PATH_SPEC);
 267  
 
 268  0
         String base = getResourceBase();
 269  0
         if (base != null)
 270  
         {
 271  0
             context.setResourceBase(base);
 272  
         }
 273  0
     }
 274  
 
 275  
     @Override
 276  
     protected AbstractConnector createJettyConnector()
 277  
     {
 278  0
         if (serverUrl.getProtocol().equals("https"))
 279  
         {
 280  0
             return super.createJettyConnector();
 281  
         }
 282  
         else
 283  
         {
 284  0
             return new SelectChannelConnector();
 285  
         }
 286  
     }
 287  
 
 288  
     public AbstractBayeux getBayeux( )
 289  
     {
 290  0
         return servlet.getBayeux();
 291  
     }
 292  
 
 293  
     public void setBayeux(AbstractBayeux bayeux)
 294  
     {
 295  
         //Ignore
 296  0
     }
 297  
 
 298  
     @Override
 299  
     protected MessageReceiver createReceiver(FlowConstruct flowConstruct, InboundEndpoint endpoint) throws Exception
 300  
     {
 301  0
         MessageReceiver receiver = getServiceDescriptor().createMessageReceiver(this, flowConstruct, endpoint);
 302  
         //If the connector has not started yet, the Bayeux object will still be null
 303  0
         ((AjaxMessageReceiver) receiver).setBayeux(getBayeux());
 304  0
         return receiver;
 305  
     }
 306  
 
 307  
 
 308  
     public int getInterval()
 309  
     {
 310  0
         return interval;
 311  
     }
 312  
 
 313  
     public void setInterval(int interval)
 314  
     {
 315  0
         this.interval = interval;
 316  0
     }
 317  
 
 318  
     public int getMaxInterval()
 319  
     {
 320  0
         return maxInterval;
 321  
     }
 322  
 
 323  
     public void setMaxInterval(int maxInterval)
 324  
     {
 325  0
         this.maxInterval = maxInterval;
 326  0
     }
 327  
 
 328  
     public int getMultiFrameInterval()
 329  
     {
 330  0
         return multiFrameInterval;
 331  
     }
 332  
 
 333  
     public void setMultiFrameInterval(int multiFrameInterval)
 334  
     {
 335  0
         this.multiFrameInterval = multiFrameInterval;
 336  0
     }
 337  
 
 338  
     public int getLogLevel()
 339  
     {
 340  0
         return logLevel;
 341  
     }
 342  
 
 343  
     public void setLogLevel(int logLevel)
 344  
     {
 345  0
         this.logLevel = logLevel;
 346  0
     }
 347  
 
 348  
     public int getTimeout()
 349  
     {
 350  0
         return timeout;
 351  
     }
 352  
 
 353  
     public void setTimeout(int timeout)
 354  
     {
 355  0
         this.timeout = timeout;
 356  0
     }
 357  
 
 358  
     public boolean isJsonCommented()
 359  
     {
 360  0
         return jsonCommented;
 361  
     }
 362  
 
 363  
     public void setJsonCommented(boolean jsonCommented)
 364  
     {
 365  0
         this.jsonCommented = jsonCommented;
 366  0
     }
 367  
 
 368  
     public String getFilters()
 369  
     {
 370  0
         return filters;
 371  
     }
 372  
 
 373  
     public void setFilters(String filters)
 374  
     {
 375  0
         this.filters = filters;
 376  0
     }
 377  
 
 378  
     public boolean isRequestAvailable()
 379  
     {
 380  0
         return requestAvailable;
 381  
     }
 382  
 
 383  
     public void setRequestAvailable(boolean requestAvailable)
 384  
     {
 385  0
         this.requestAvailable = requestAvailable;
 386  0
     }
 387  
 
 388  
     public boolean isDirectDeliver()
 389  
     {
 390  0
         return directDeliver;
 391  
     }
 392  
 
 393  
     public void setDirectDeliver(boolean directDeliver)
 394  
     {
 395  0
         this.directDeliver = directDeliver;
 396  0
     }
 397  
 
 398  
     public int getRefsThreshold()
 399  
     {
 400  0
         return refsThreshold;
 401  
     }
 402  
 
 403  
     public void setRefsThreshold(int refsThreshold)
 404  
     {
 405  0
         this.refsThreshold = refsThreshold;
 406  0
     }
 407  
 }