@Deprecated
  public TenantAxisConfigurator(
      AxisConfiguration mainAxisConfig, String tenantDomain, int tenantId, UserRegistry registry)
      throws AxisFault {
    this.tenantDomain = tenantDomain;
    this.tenantId = tenantId;
    this.mainAxisConfig = mainAxisConfig;
    this.registry = registry;
    this.bundleContext = CarbonCoreDataHolder.getInstance().getBundleContext();
    this.moduleBundles =
        ((CarbonAxisConfigurator) mainAxisConfig.getConfigurator())
            .getConfigItemHolder()
            .getModuleBundles();
    this.deployerBundles =
        ((CarbonAxisConfigurator) mainAxisConfig.getConfigurator())
            .getConfigItemHolder()
            .getDeployerBundles();
    File tenantDir = new File(CarbonUtils.getCarbonTenantsDirPath() + File.separator + tenantId);
    if (!tenantDir.exists() && !tenantDir.mkdirs()) {
      log.warn("Could not create directory " + tenantDir.getAbsolutePath());
    }
    this.repoLocation = tenantDir.getAbsolutePath();

    // Use registry based deployer if necessary
    if (CarbonUtils.useRegistryBasedRepository()) {
      String registryPath = "/repository/deployment";
      new RegistryBasedRepository(registry, registryPath, repoLocation)
          .updateFileSystemFromRegistry();
      RegistryBasedRepositoryUpdater.scheduleAtFixedRate(
          registry, registryPath, repoLocation, 0, 10);
    }
  }
 private static void setHostName(AxisConfiguration axisConfig) throws DeploymentException {
   try {
     String hostName =
         CarbonCoreDataHolder.getInstance()
             .getServerConfigurationService()
             .getFirstProperty("HostName");
     if (hostName != null) {
       Parameter param = ParameterUtil.createParameter(HOST_ADDRESS, hostName);
       axisConfig.addParameter(param);
     }
   } catch (AxisFault axisFault) {
     throw new DeploymentException(axisFault.getMessage(), axisFault);
   }
 }
 private static void doPreConfigContextCreation(int tenantId) {
   BundleContext bundleContext = CarbonCoreDataHolder.getInstance().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).creatingConfigurationContext(tenantId);
       }
     }
     tracker.close();
   }
 }
  public static ConfigurationContext getTenantConfigurationContext(
      String tenantDomain, ConfigurationContext mainConfigCtx) {
    ConfigurationContext tenantConfigCtx;

    Boolean isTenantActive;
    try {
      isTenantActive =
          CarbonCoreDataHolder.getInstance()
              .getRealmService()
              .getTenantManager()
              .isTenantActive(getTenantId(tenantDomain));
    } catch (Exception e) {
      throw new RuntimeException("Error while getting tenant activation status.", e);
    }

    if (!isTenantActive) {
      throw new RuntimeException("Trying to access inactive tenant domain : " + tenantDomain);
    }

    if (tenantReadWriteLocks.get(tenantDomain) == null) {
      synchronized (tenantDomain.intern()) {
        if (tenantReadWriteLocks.get(tenantDomain) == null) {
          tenantReadWriteLocks.put(tenantDomain, new ReentrantReadWriteLock());
        }
      }
    }
    Lock tenantReadLock = tenantReadWriteLocks.get(tenantDomain).readLock();
    try {
      tenantReadLock.lock();
      Map<String, ConfigurationContext> tenantConfigContexts =
          getTenantConfigurationContexts(mainConfigCtx);
      tenantConfigCtx = tenantConfigContexts.get(tenantDomain);
      if (tenantConfigCtx == null) {
        try {
          tenantConfigCtx = createTenantConfigurationContext(mainConfigCtx, tenantDomain);
        } catch (Exception e) {
          throw new RuntimeException(
              "Cannot create tenant ConfigurationContext for tenant " + tenantDomain, e);
        }
      }
      tenantConfigCtx.setProperty(MultitenantConstants.LAST_ACCESSED, System.currentTimeMillis());
    } finally {
      tenantReadLock.unlock();
    }
    return tenantConfigCtx;
  }
 @Override
 protected void startSearch(RepositoryListener listener) {
   schedulerTask =
       new CarbonDeploymentSchedulerTask(
           listener, axisConfig,
           tenantId, tenantDomain);
   scheduler = Executors.newScheduledThreadPool(1);
   String deploymentInterval =
       CarbonCoreDataHolder.getInstance()
           .getServerConfigurationService()
           .getFirstProperty("Axis2Config.DeploymentUpdateInterval");
   int deploymentIntervalInt = 15;
   if (deploymentInterval != null) {
     deploymentIntervalInt = Integer.parseInt(deploymentInterval);
   }
   scheduler.scheduleWithFixedDelay(schedulerTask, 0, deploymentIntervalInt, TimeUnit.SECONDS);
 }
 /**
  * Terminate the provided Tenant ConfigurationContext
  *
  * @param tenantCfgCtx The tenant ConfigurationContext which needs to be terminated
  */
 public static void terminateTenantConfigContext(ConfigurationContext tenantCfgCtx) {
   ConfigurationContext mainServerConfigContext =
       CarbonCoreDataHolder.getInstance().getMainServerConfigContext();
   Map<String, ConfigurationContext> tenantConfigContexts =
       getTenantConfigurationContexts(mainServerConfigContext);
   String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
   log.info("Starting to clean tenant : " + tenantDomain);
   tenantCfgCtx.getAxisConfiguration().getConfigurator().cleanup();
   try {
     doPreConfigContextTermination(tenantCfgCtx);
     tenantCfgCtx.terminate();
     doPostConfigContextTermination(tenantCfgCtx);
     tenantConfigContexts.remove(tenantDomain);
     log.info("Cleaned up tenant " + tenantDomain);
   } catch (AxisFault e) {
     log.error("Cannot cleanup ConfigurationContext of tenant " + tenantDomain, e);
   }
 }
 /**
  * Get the list of all active tenants in the system
  *
  * @param mainConfigCtx The main super-tenant ConfigurationContext
  * @return The list of active tenants
  * @throws Exception If an error occurs while retrieving tenants
  */
 public static List<Tenant> getActiveTenants(ConfigurationContext mainConfigCtx) throws Exception {
   Map<String, ConfigurationContext> tenantConfigContexts =
       getTenantConfigurationContexts(mainConfigCtx);
   List<Tenant> tenants = new ArrayList<Tenant>();
   try {
     TenantManager tenantManager = dataHolder.getRealmService().getTenantManager();
     for (ConfigurationContext tenantCfgCtx : tenantConfigContexts.values()) {
       Tenant tenant =
           (Tenant) tenantManager.getTenant(MultitenantUtils.getTenantId(tenantCfgCtx));
       tenants.add(tenant);
     }
   } catch (Exception e) {
     String msg = "Error occurred while getting active tenant list";
     log.error(msg, e);
     throw new Exception(msg, e);
   }
   return tenants;
 }
  /**
   * Traverse the list of tenants and cleanup tenants which have been idling for longer than <code>
   * tenantIdleTimeMillis</code>
   *
   * @param tenantIdleTimeMillis The maximum tenant idle time in milliseconds
   */
  public static void cleanupTenants(long tenantIdleTimeMillis) {
    ConfigurationContext mainServerConfigContext =
        CarbonCoreDataHolder.getInstance().getMainServerConfigContext();
    if (mainServerConfigContext == null) {
      return;
    }
    Map<String, ConfigurationContext> tenantConfigContexts =
        getTenantConfigurationContexts(mainServerConfigContext);
    for (Map.Entry<String, ConfigurationContext> entry : tenantConfigContexts.entrySet()) {
      String tenantDomain = entry.getKey();
      synchronized (tenantDomain.intern()) {
        ConfigurationContext tenantCfgCtx = entry.getValue();
        Long lastAccessed = (Long) tenantCfgCtx.getProperty(MultitenantConstants.LAST_ACCESSED);
        if (System.currentTimeMillis() - lastAccessed >= tenantIdleTimeMillis) {
          // Get the write lock.
          Lock tenantWriteLock = tenantReadWriteLocks.get(tenantDomain).writeLock();
          tenantWriteLock.lock();
          try {
            lastAccessed = (Long) tenantCfgCtx.getProperty(MultitenantConstants.LAST_ACCESSED);
            if (System.currentTimeMillis() - lastAccessed >= tenantIdleTimeMillis) {
              try {
                PrivilegedCarbonContext.startTenantFlow();
                // Creating CarbonContext object for these threads.
                PrivilegedCarbonContext carbonContext =
                    PrivilegedCarbonContext.getThreadLocalCarbonContext();
                carbonContext.setTenantDomain(tenantDomain, true);

                // Terminating idle tenant configuration contexts.
                terminateTenantConfigContext(tenantCfgCtx);
                tenantConfigContexts.remove(tenantDomain);
              } finally {
                PrivilegedCarbonContext.endTenantFlow();
              }
            }
          } finally {
            tenantWriteLock.unlock();
          }
        }
      }
    }
  }
/** Utility methods for Tenant Operations at Axis2-level. */
@SuppressWarnings("unused")
public final class TenantAxisUtils {

  private static final Log log = LogFactory.getLog(TenantAxisUtils.class);
  private static final String TENANT_CONFIGURATION_CONTEXTS = "tenant.config.contexts";
  private static final String TENANT_CONFIGURATION_CONTEXTS_CREATED =
      "tenant.config.contexts.created";
  private static CarbonCoreDataHolder dataHolder = CarbonCoreDataHolder.getInstance();
  private static Map<String, ReentrantReadWriteLock> tenantReadWriteLocks =
      new ConcurrentHashMap<String, ReentrantReadWriteLock>();

  private TenantAxisUtils() {}

  /**
   * Get tenant ID from config context
   *
   * @param configCtx The config context
   * @return The tenant ID
   * @deprecated use {@link MultitenantUtils#getTenantId(ConfigurationContext)}
   */
  public static int getTenantId(ConfigurationContext configCtx) {
    return MultitenantUtils.getTenantId(configCtx);
  }

  public static AxisConfiguration getTenantAxisConfiguration(
      String tenant, ConfigurationContext mainConfigCtx) {
    ConfigurationContext tenantConfigCtx = getTenantConfigurationContext(tenant, mainConfigCtx);
    if (tenantConfigCtx != null) {
      return tenantConfigCtx.getAxisConfiguration();
    }
    return null;
  }

  public static ConfigurationContext getTenantConfigurationContextFromUrl(
      String url, ConfigurationContext mainConfigCtx) {
    String tenantDomain = MultitenantUtils.getTenantDomainFromUrl(url);
    return getTenantConfigurationContext(tenantDomain, mainConfigCtx);
  }

  public static ConfigurationContext getTenantConfigurationContext(
      String tenantDomain, ConfigurationContext mainConfigCtx) {
    ConfigurationContext tenantConfigCtx;

    Boolean isTenantActive;
    try {
      isTenantActive =
          CarbonCoreDataHolder.getInstance()
              .getRealmService()
              .getTenantManager()
              .isTenantActive(getTenantId(tenantDomain));
    } catch (Exception e) {
      throw new RuntimeException("Error while getting tenant activation status.", e);
    }

    if (!isTenantActive) {
      throw new RuntimeException("Trying to access inactive tenant domain : " + tenantDomain);
    }

    if (tenantReadWriteLocks.get(tenantDomain) == null) {
      synchronized (tenantDomain.intern()) {
        if (tenantReadWriteLocks.get(tenantDomain) == null) {
          tenantReadWriteLocks.put(tenantDomain, new ReentrantReadWriteLock());
        }
      }
    }
    Lock tenantReadLock = tenantReadWriteLocks.get(tenantDomain).readLock();
    try {
      tenantReadLock.lock();
      Map<String, ConfigurationContext> tenantConfigContexts =
          getTenantConfigurationContexts(mainConfigCtx);
      tenantConfigCtx = tenantConfigContexts.get(tenantDomain);
      if (tenantConfigCtx == null) {
        try {
          tenantConfigCtx = createTenantConfigurationContext(mainConfigCtx, tenantDomain);
        } catch (Exception e) {
          throw new RuntimeException(
              "Cannot create tenant ConfigurationContext for tenant " + tenantDomain, e);
        }
      }
      tenantConfigCtx.setProperty(MultitenantConstants.LAST_ACCESSED, System.currentTimeMillis());
    } finally {
      tenantReadLock.unlock();
    }
    return tenantConfigCtx;
  }

  public static long getLastAccessed(String tenantDomain, ConfigurationContext mainConfigCtx) {
    Map<String, ConfigurationContext> tenantConfigContexts =
        getTenantConfigurationContexts(mainConfigCtx);
    ConfigurationContext tenantConfigCtx = tenantConfigContexts.get(tenantDomain);
    if (tenantConfigCtx != null) {
      Long lastAccessed = (Long) tenantConfigCtx.getProperty(MultitenantConstants.LAST_ACCESSED);
      return lastAccessed == null ? -1 : lastAccessed;
    }
    return -1;
  }

  public static void setTenantAccessed(String tenantDomain, ConfigurationContext mainConfigCtx) {
    getTenantConfigurationContext(tenantDomain, mainConfigCtx);
  }

  /**
   * @param url will have pattern <some-string>/t/<tenant>/<service>?<some-params>
   * @param mainConfigContext The main ConfigurationContext from the server
   * @return The tenant's AxisService
   * @throws org.apache.axis2.AxisFault If an error occurs while retrieving the AxisService
   */
  public static AxisService getAxisService(String url, ConfigurationContext mainConfigContext)
      throws AxisFault {
    String[] strings = url.split("/");
    boolean foundTenantDelimiter = false;
    String tenant = null;
    String service = null;
    for (String str : strings) {
      if (!foundTenantDelimiter && str.equals("t")) {
        foundTenantDelimiter = true;
        continue;
      }
      if (foundTenantDelimiter & tenant == null) {
        tenant = str;
        continue;
      }
      if (tenant != null) {
        if (service == null) {
          service = str;
        } else {
          service += "/" + str;
        }
      }
    }
    if (service != null) {
      service = service.split("\\?")[0];
      AxisConfiguration tenantAxisConfig = getTenantAxisConfiguration(tenant, mainConfigContext);
      if (tenantAxisConfig != null) {
        return tenantAxisConfig.getServiceForActivation(service);
      }
    }
    return null;
  }

  /**
   * Get all the tenant ConfigurationContexts
   *
   * @param mainConfigCtx Super-tenant Axis2 ConfigurationContext
   * @return the tenant ConfigurationContexts as a Map of "tenant domain -> ConfigurationContext"
   */
  @SuppressWarnings("unchecked")
  public static Map<String, ConfigurationContext> getTenantConfigurationContexts(
      ConfigurationContext mainConfigCtx) {
    Map<String, ConfigurationContext> tenantConfigContexts =
        (Map<String, ConfigurationContext>)
            mainConfigCtx.getProperty(TENANT_CONFIGURATION_CONTEXTS);
    if (tenantConfigContexts == null) {
      tenantConfigContexts = new ConcurrentHashMap<String, ConfigurationContext>();
      mainConfigCtx.setProperty(TENANT_CONFIGURATION_CONTEXTS, tenantConfigContexts);
    }
    return tenantConfigContexts;
  }

  /**
   * Set the transports for the tenants
   *
   * @param mainConfigCtx The main config context
   * @throws AxisFault If an error occurs while initializing tenant transports
   */
  @SuppressWarnings("unchecked")
  public static void initializeTenantTransports(ConfigurationContext mainConfigCtx)
      throws AxisFault {
    AxisConfiguration mainAxisConfig = mainConfigCtx.getAxisConfiguration();
    Map<String, ConfigurationContext> tenantConfigContexts =
        getTenantConfigurationContexts(mainConfigCtx);
    if (tenantConfigContexts != null) {
      for (Map.Entry<String, ConfigurationContext> entry : tenantConfigContexts.entrySet()) {
        String tenantDomain = entry.getKey();
        ConfigurationContext tenantConfigCtx = entry.getValue();
        AxisConfiguration tenantAxisConfig = tenantConfigCtx.getAxisConfiguration();
        // Add the transports that are made available in the main axis2.xml file
        setTenantTransports(mainAxisConfig, tenantDomain, tenantAxisConfig);
      }
    }
  }

  public static void setTenantTransports(
      AxisConfiguration mainAxisConfig, String tenantDomain, AxisConfiguration tenantAxisConfig)
      throws AxisFault {
    for (String transport : mainAxisConfig.getTransportsIn().keySet()) {
      TenantTransportInDescription tenantTransportIn = new TenantTransportInDescription(transport);
      tenantTransportIn.setMainTransportInDescription(
          mainAxisConfig.getTransportsIn().get(transport));
      TransportListener mainTransportListener =
          mainAxisConfig.getTransportIn(transport).getReceiver();
      tenantTransportIn.setReceiver(
          new DummyTransportListener(mainTransportListener, tenantDomain));
      tenantAxisConfig.addTransportIn(tenantTransportIn);
    }
  }

  /**
   * 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);
      }
    }
  }

  /**
   * Get the list of all active tenants in the system
   *
   * @param mainConfigCtx The main super-tenant ConfigurationContext
   * @return The list of active tenants
   * @throws Exception If an error occurs while retrieving tenants
   */
  public static List<Tenant> getActiveTenants(ConfigurationContext mainConfigCtx) throws Exception {
    Map<String, ConfigurationContext> tenantConfigContexts =
        getTenantConfigurationContexts(mainConfigCtx);
    List<Tenant> tenants = new ArrayList<Tenant>();
    try {
      TenantManager tenantManager = dataHolder.getRealmService().getTenantManager();
      for (ConfigurationContext tenantCfgCtx : tenantConfigContexts.values()) {
        Tenant tenant =
            (Tenant) tenantManager.getTenant(MultitenantUtils.getTenantId(tenantCfgCtx));
        tenants.add(tenant);
      }
    } catch (Exception e) {
      String msg = "Error occurred while getting active tenant list";
      log.error(msg, e);
      throw new Exception(msg, e);
    }
    return tenants;
  }

  /**
   * Get the tenantID given the domain
   *
   * @param tenantDomain The tenant domain
   * @return The tenant ID
   * @throws Exception If an error occurs while retrieving tenant ID
   */
  private static int getTenantId(String tenantDomain) throws Exception {
    return dataHolder.getRealmService().getTenantManager().getTenantId(tenantDomain);
  }

  /**
   * Traverse the list of tenants and cleanup tenants which have been idling for longer than <code>
   * tenantIdleTimeMillis</code>
   *
   * @param tenantIdleTimeMillis The maximum tenant idle time in milliseconds
   */
  public static void cleanupTenants(long tenantIdleTimeMillis) {
    ConfigurationContext mainServerConfigContext =
        CarbonCoreDataHolder.getInstance().getMainServerConfigContext();
    if (mainServerConfigContext == null) {
      return;
    }
    Map<String, ConfigurationContext> tenantConfigContexts =
        getTenantConfigurationContexts(mainServerConfigContext);
    for (Map.Entry<String, ConfigurationContext> entry : tenantConfigContexts.entrySet()) {
      String tenantDomain = entry.getKey();
      synchronized (tenantDomain.intern()) {
        ConfigurationContext tenantCfgCtx = entry.getValue();
        Long lastAccessed = (Long) tenantCfgCtx.getProperty(MultitenantConstants.LAST_ACCESSED);
        if (System.currentTimeMillis() - lastAccessed >= tenantIdleTimeMillis) {
          // Get the write lock.
          Lock tenantWriteLock = tenantReadWriteLocks.get(tenantDomain).writeLock();
          tenantWriteLock.lock();
          try {
            lastAccessed = (Long) tenantCfgCtx.getProperty(MultitenantConstants.LAST_ACCESSED);
            if (System.currentTimeMillis() - lastAccessed >= tenantIdleTimeMillis) {
              try {
                PrivilegedCarbonContext.startTenantFlow();
                // Creating CarbonContext object for these threads.
                PrivilegedCarbonContext carbonContext =
                    PrivilegedCarbonContext.getThreadLocalCarbonContext();
                carbonContext.setTenantDomain(tenantDomain, true);

                // Terminating idle tenant configuration contexts.
                terminateTenantConfigContext(tenantCfgCtx);
                tenantConfigContexts.remove(tenantDomain);
              } finally {
                PrivilegedCarbonContext.endTenantFlow();
              }
            }
          } finally {
            tenantWriteLock.unlock();
          }
        }
      }
    }
  }

  /**
   * Calculate the tenant domain from the complete URL
   *
   * @param url - incoming URL
   * @return - Tenant domain
   */
  public static String getTenantDomain(String url) {
    String[] strings = url.split("/");
    boolean foundTenantDelimiter = false;
    String tenant = null;
    for (String str : strings) {
      if (!foundTenantDelimiter && str.equals("t")) {
        foundTenantDelimiter = true;
        continue;
      }
      if (foundTenantDelimiter) {
        tenant = str;
        break;
      }
    }
    return tenant;
  }

  /**
   * Terminate the provided Tenant ConfigurationContext
   *
   * @param tenantCfgCtx The tenant ConfigurationContext which needs to be terminated
   */
  public static void terminateTenantConfigContext(ConfigurationContext tenantCfgCtx) {
    ConfigurationContext mainServerConfigContext =
        CarbonCoreDataHolder.getInstance().getMainServerConfigContext();
    Map<String, ConfigurationContext> tenantConfigContexts =
        getTenantConfigurationContexts(mainServerConfigContext);
    String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
    log.info("Starting to clean tenant : " + tenantDomain);
    tenantCfgCtx.getAxisConfiguration().getConfigurator().cleanup();
    try {
      doPreConfigContextTermination(tenantCfgCtx);
      tenantCfgCtx.terminate();
      doPostConfigContextTermination(tenantCfgCtx);
      tenantConfigContexts.remove(tenantDomain);
      log.info("Cleaned up tenant " + tenantDomain);
    } catch (AxisFault e) {
      log.error("Cannot cleanup ConfigurationContext of tenant " + tenantDomain, e);
    }
  }

  private static void doPreConfigContextCreation(int tenantId) {
    BundleContext bundleContext = CarbonCoreDataHolder.getInstance().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).creatingConfigurationContext(tenantId);
        }
      }
      tracker.close();
    }
  }

  private static void doPreConfigContextTermination(ConfigurationContext tenantCfgCtx) {
    BundleContext bundleContext = CarbonCoreDataHolder.getInstance().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)
              .terminatingConfigurationContext(tenantCfgCtx);
        }
      }
      tracker.close();
    }
  }

  private static void doPostConfigContextTermination(ConfigurationContext tenantCfgCtx) {
    BundleContext bundleContext = CarbonCoreDataHolder.getInstance().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)
              .terminatedConfigurationContext(tenantCfgCtx);
        }
      }
      tracker.close();
    }
  }
}
 /**
  * Get the tenantID given the domain
  *
  * @param tenantDomain The tenant domain
  * @return The tenant ID
  * @throws Exception If an error occurs while retrieving tenant ID
  */
 private static int getTenantId(String tenantDomain) throws Exception {
   return dataHolder.getRealmService().getTenantManager().getTenantId(tenantDomain);
 }
  /**
   * 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);
      }
    }
  }
  public AxisConfiguration populateAxisConfiguration(InputStream in) throws DeploymentException {
    axisConfig = TenantAxisConfiguration.createInstance();
    PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getCurrentContext(axisConfig);
    carbonContext.setTenantId(tenantId);
    carbonContext.setTenantDomain(tenantDomain);

    boolean isUrlRepo = CarbonUtils.isURL(repoLocation);
    if (repoLocation != null && repoLocation.trim().length() != 0) {
      try {
        if (isUrlRepo) {
          URL axis2Repository = new URL(repoLocation);
          axisConfig.setRepository(axis2Repository);
        } else {
          axisConfig.setRepository(new URL("file://" + repoLocation));
        }
      } catch (MalformedURLException e) {
        throw new DeploymentException("Invalid URL " + repoLocation, e);
      }
    }

    // Notify all observers
    if (bundleContext != null) {
      ServiceTracker tracker =
          new ServiceTracker(
              bundleContext, PreAxisConfigurationPopulationObserver.class.getName(), null);
      tracker.open();
      Object[] services = tracker.getServices();
      if (services != null) {
        for (Object service : services) {
          ((PreAxisConfigurationPopulationObserver) service).createdAxisConfiguration(axisConfig);
        }
      }
      tracker.close();
    }
    try {
      // Add the relevant AxisObservers to the tenantAxisConfig
      if (bundleContext != null) {
        ServiceTracker tracker =
            new ServiceTracker(bundleContext, AxisObserver.class.getName(), null);
        tracker.open();
        ServiceReference[] serviceRefs = tracker.getServiceReferences();
        if (serviceRefs != null) {
          for (ServiceReference serviceRef : serviceRefs) {
            if (serviceRef.getProperty(MultitenantConstants.TENANT_ID) != null
                && tenantId == (Integer) serviceRef.getProperty(MultitenantConstants.TENANT_ID)) {
              axisConfig.addObservers((AxisObserver) bundleContext.getService(serviceRef));
            }
          }
        }
        tracker.close();
      }

      // Set services dir
      File servicesDir =
          new File(repoLocation + File.separator + CarbonUtils.getAxis2ServicesDir(axisConfig));
      if (!servicesDir.exists() && !servicesDir.mkdirs()) {
        throw new DeploymentException(
            "Could not create services directory " + servicesDir.getAbsolutePath());
      }

      // Set modules dir
      String modulesDirName = "axis2modules";
      File modulesDir = new File(repoLocation + File.separator + modulesDirName);
      if (!modulesDir.exists() && !modulesDir.mkdirs()) {
        throw new DeploymentException(
            "Could not create modules directory " + modulesDir.getAbsolutePath());
      }
      axisConfig.addParameter(new Parameter(DeploymentConstants.MODULE_DRI_PATH, modulesDirName));
    } catch (AxisFault e) {
      String msg =
          "Cannot add DeploymentConstants.SERVICE_DIR_PATH or "
              + "DeploymentConstants.MODULE_DIR_PATH parameters";
      log.error(msg, e);
      throw new DeploymentException(msg, e);
    }

    carbonContext.setRegistry(RegistryType.SYSTEM_CONFIGURATION, registry);
    try {
      // TODO: The governance system registry should be passed into the tenant axis
      // configurator like the config system registry - Senaka.
      carbonContext.setRegistry(
          RegistryType.SYSTEM_GOVERNANCE,
          CarbonCoreDataHolder.getInstance()
              .getRegistryService()
              .getGovernanceSystemRegistry(tenantId));
      carbonContext.setRegistry(
          RegistryType.LOCAL_REPOSITORY,
          CarbonCoreDataHolder.getInstance().getRegistryService().getLocalRepository(tenantId));
    } catch (Exception ignored) {
      // We are not worried about the exception in here.
    }

    // The following two lines of code are kept for backward compatibility. Remove this once we
    // are certain that this is not required. -- Senaka.
    // Please also note that we no longer need to set the user realm to the configuration
    // explicitly.
    setRegistry();
    setUserRealm();

    // Add the DeploymentInterceptor for the tenant AxisConfigurations
    DeploymentInterceptor interceptor = new DeploymentInterceptor();
    interceptor.setRegistry(registry);
    interceptor.init(axisConfig);
    axisConfig.addObservers(interceptor);

    setHostName(axisConfig);

    // TCCL will be based on OSGi
    AxisConfigBuilder builder = new AxisConfigBuilder(in, axisConfig, this);
    builder.populateConfig();
    try {
      if (in != null) {
        in.close();
      }
    } catch (IOException e) {
      String msg = "error in closing input stream";
      log.error(msg, e);
    }
    axisConfig.setConfigurator(this);
    Parameter disableArtifactLoading = axisConfig.getParameter("DisableArtifactLoading");
    if (disableArtifactLoading == null || "false".equals(disableArtifactLoading.getValue())) {
      moduleDeployer = new ModuleDeployer(axisConfig);
      new Axis2ModuleRegistry(axisConfig).register(moduleBundles);
      // Add Ghost deployer registry only if ghost is on
      if (GhostDeployerUtils.isGhostOn()) {
        new GhostDeployerRegistry(axisConfig).register(deployerBundles);
      } else {
        new Axis2DeployerRegistry(axisConfig).register(deployerBundles);
      }
    }
    return axisConfig;
  }