public ConfigurationContext getClientCfgCtx() throws Exception {
    ConfigurationContext cfgCtx =
        ConfigurationContextFactory.createConfigurationContext(new CustomAxisConfigurator());
    AxisConfiguration axisCfg = cfgCtx.getAxisConfiguration();
    axisCfg.engageModule("addressing");

    TransportInDescription trpInDesc = new TransportInDescription("udp");
    trpInDesc.setReceiver(new UDPListener());
    axisCfg.addTransportIn(trpInDesc);

    TransportOutDescription trpOutDesc = new TransportOutDescription("udp");
    trpOutDesc.setSender(new UDPSender());
    axisCfg.addTransportOut(trpOutDesc);

    return cfgCtx;
  }
  /**
   * Create Tenant Axis2 ConfigurationContexts & add them to the main Axis2 ConfigurationContext
   *
   * @param mainConfigCtx Super-tenant Axis2 ConfigurationContext
   * @param tenantDomain Tenant domain (e.g. foo.com)
   * @return The newly created Tenant ConfigurationContext
   * @throws Exception If an error occurs while creating tenant ConfigurationContext
   */
  private static ConfigurationContext createTenantConfigurationContext(
      ConfigurationContext mainConfigCtx, String tenantDomain) throws Exception {
    synchronized (tenantDomain.intern()) { // lock based on tenant domain
      Map<String, ConfigurationContext> tenantConfigContexts =
          getTenantConfigurationContexts(mainConfigCtx);
      ConfigurationContext tenantConfigCtx = tenantConfigContexts.get(tenantDomain);
      if (tenantConfigCtx != null) {
        return tenantConfigCtx;
      }
      long tenantLoadingStartTime = System.currentTimeMillis();
      int tenantId = getTenantId(tenantDomain);
      if (tenantId == MultitenantConstants.SUPER_TENANT_ID
          || tenantId == MultitenantConstants.INVALID_TENANT_ID) {
        throw new Exception("Tenant " + tenantDomain + " does not exist");
      }
      PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
      carbonContext.setTenantId(tenantId);
      carbonContext.setTenantDomain(tenantDomain);

      tenantConfigCtx = tenantConfigContexts.get(tenantDomain);
      if (tenantConfigCtx != null) {
        return tenantConfigCtx;
      }

      AxisConfiguration mainAxisConfig = mainConfigCtx.getAxisConfiguration();

      dataHolder.getTenantRegistryLoader().loadTenantRegistry(tenantId);

      try {
        UserRegistry tenantConfigRegistry =
            dataHolder.getRegistryService().getConfigSystemRegistry(tenantId);
        UserRegistry tenantLocalUserRegistry =
            dataHolder.getRegistryService().getLocalRepository(tenantId);
        TenantAxisConfigurator tenantAxisConfigurator =
            new TenantAxisConfigurator(
                mainAxisConfig,
                tenantDomain,
                tenantId,
                tenantConfigRegistry,
                tenantLocalUserRegistry);
        doPreConfigContextCreation(tenantId);
        tenantConfigCtx =
            ConfigurationContextFactory.createConfigurationContext(tenantAxisConfigurator);

        AxisConfiguration tenantAxisConfig = tenantConfigCtx.getAxisConfiguration();

        tenantConfigCtx.setServicePath(CarbonUtils.getAxis2ServicesDir(tenantAxisConfig));
        tenantConfigCtx.setContextRoot("local:/");

        TenantTransportSender transportSender = new TenantTransportSender(mainConfigCtx);
        // Adding transport senders
        HashMap<String, TransportOutDescription> transportSenders =
            mainAxisConfig.getTransportsOut();
        if (transportSenders != null && !transportSenders.isEmpty()) {
          for (String strTransport : transportSenders.keySet()) {
            TransportOutDescription outDescription = new TransportOutDescription(strTransport);
            outDescription.setSender(transportSender);
            tenantAxisConfig.addTransportOut(outDescription);
          }
        }

        // Set the work directory
        tenantConfigCtx.setProperty(
            ServerConstants.WORK_DIR, mainConfigCtx.getProperty(ServerConstants.WORK_DIR));
        PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId);
        new TransportPersistenceManager(tenantAxisConfig)
            .updateEnabledTransports(
                tenantAxisConfig.getTransportsIn().values(),
                tenantAxisConfig.getTransportsOut().values());

        // Notify all observers
        BundleContext bundleContext = dataHolder.getBundleContext();
        if (bundleContext != null) {
          ServiceTracker tracker =
              new ServiceTracker(
                  bundleContext, Axis2ConfigurationContextObserver.class.getName(), null);
          tracker.open();
          Object[] services = tracker.getServices();
          if (services != null) {
            for (Object service : services) {
              ((Axis2ConfigurationContextObserver) service)
                  .createdConfigurationContext(tenantConfigCtx);
            }
          }
          tracker.close();
        }
        tenantConfigCtx.setProperty(MultitenantConstants.LAST_ACCESSED, System.currentTimeMillis());

        // Register Capp deployer for this tenant
        Utils.addCAppDeployer(tenantAxisConfig);

        // deploy the services since all the deployers are initialized by now.
        tenantAxisConfigurator.deployServices();

        // tenant config context must only be made after the tenant is fully loaded, and all its
        // artifacts
        // are deployed.
        // -- THIS SHOULD BE THE LAST OPERATION OF THIS METHOD --
        tenantConfigContexts.put(tenantDomain, tenantConfigCtx);

        log.info(
            "Loaded tenant "
                + tenantDomain
                + " in "
                + (System.currentTimeMillis() - tenantLoadingStartTime)
                + " ms");

        return tenantConfigCtx;
      } catch (Exception e) {
        String msg = "Error occurred while running deployment for tenant ";
        log.error(msg + tenantDomain, e);
        throw new Exception(msg, e);
      }
    }
  }
  /**
   * Initialize the transport sender, and execute reactor in new separate thread
   *
   * @param cfgCtx the Axis2 configuration context
   * @param transportOut the description of the http/s transport from Axis2 configuration
   * @throws AxisFault thrown on an error
   */
  public void init(ConfigurationContext cfgCtx, TransportOutDescription transportOut)
      throws AxisFault {
    this.configurationContext = cfgCtx;

    cfg = NHttpConfiguration.getInstance();
    params = new BasicHttpParams();
    params
        .setIntParameter(
            CoreConnectionPNames.SO_TIMEOUT,
            cfg.getProperty(NhttpConstants.SO_TIMEOUT_SENDER, 60000))
        .setIntParameter(
            CoreConnectionPNames.CONNECTION_TIMEOUT,
            cfg.getProperty(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000))
        .setIntParameter(
            CoreConnectionPNames.SOCKET_BUFFER_SIZE,
            cfg.getProperty(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024))
        .setParameter(CoreProtocolPNames.USER_AGENT, "Synapse-HttpComponents-NIO");
    //                .setParameter(CoreProtocolPNames.HTTP_ELEMENT_CHARSET,
    //
    // cfg.getStringValue(CoreProtocolPNames.HTTP_ELEMENT_CHARSET,HTTP.DEFAULT_PROTOCOL_CHARSET));
    // //TODO:This does not works with HTTPCore 4.3

    name = transportOut.getName().toUpperCase(Locale.US) + " Sender";

    ClientConnFactoryBuilder contextBuilder = initConnFactoryBuilder(transportOut);
    connFactory = contextBuilder.createConnFactory(params);

    connpool = new ConnectionPool();

    proxyConfig = new ProxyConfigBuilder().build(transportOut);
    log.info(proxyConfig.logProxyConfig());

    Parameter param = transportOut.getParameter("warnOnHTTP500");
    if (param != null) {
      String[] warnOnHttp500 = ((String) param.getValue()).split("\\|");
      cfgCtx.setNonReplicableProperty("warnOnHTTP500", warnOnHttp500);
    }

    IOReactorConfig ioReactorConfig = new IOReactorConfig();
    ioReactorConfig.setIoThreadCount(NHttpConfiguration.getInstance().getClientIOWorkers());
    ioReactorConfig.setSoTimeout(cfg.getProperty(NhttpConstants.SO_TIMEOUT_RECEIVER, 60000));
    ioReactorConfig.setConnectTimeout(
        cfg.getProperty(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000));
    ioReactorConfig.setTcpNoDelay(cfg.getProperty(CoreConnectionPNames.TCP_NODELAY, 1) == 1);
    if (cfg.getBooleanValue("http.nio.interest-ops-queueing", false)) {
      ioReactorConfig.setInterestOpQueued(true);
    }

    try {
      String prefix = name + " I/O dispatcher";
      ioReactor =
          new DefaultConnectingIOReactor(
              ioReactorConfig,
              new NativeThreadFactory(new ThreadGroup(prefix + " thread group"), prefix));
      ioReactor.setExceptionHandler(
          new IOReactorExceptionHandler() {
            public boolean handle(IOException ioException) {
              log.warn(
                  "System may be unstable: IOReactor encountered a checked exception : "
                      + ioException.getMessage(),
                  ioException);
              return true;
            }

            public boolean handle(RuntimeException runtimeException) {
              log.warn(
                  "System may be unstable: IOReactor encountered a runtime exception : "
                      + runtimeException.getMessage(),
                  runtimeException);
              return true;
            }
          });
    } catch (IOException e) {
      log.error("Error starting the IOReactor", e);
      throw new AxisFault(e.getMessage(), e);
    }

    metrics = new NhttpMetricsCollector(false, transportOut.getName());
    handler = new ClientHandler(connpool, connFactory, proxyConfig, cfgCtx, params, metrics);
    iodispatch = new ClientIODispatch(handler, connFactory);
    final IOEventDispatch ioEventDispatch = iodispatch;

    // start the Sender in a new seperate thread
    Thread t =
        new Thread(
            new Runnable() {
              public void run() {
                try {
                  ioReactor.execute(ioEventDispatch);
                } catch (InterruptedIOException ex) {
                  log.fatal("Reactor Interrupted");
                } catch (IOException e) {
                  log.fatal("Encountered an I/O error: " + e.getMessage(), e);
                }
                log.info(name + " Shutdown");
              }
            },
            "HttpCoreNIOSender");
    t.start();
    log.info(name + " starting");

    // register with JMX
    mbeanSupport = new TransportMBeanSupport(this, "nio-" + transportOut.getName());
    mbeanSupport.register();

    state = BaseConstants.STARTED;
  }