protected Cache getGatewayKeyCache() {
   String apimGWCacheExpiry =
       ServiceReferenceHolder.getInstance()
           .getAPIManagerConfiguration()
           .getFirstProperty(APIConstants.TOKEN_CACHE_EXPIRY);
   if (!gatewayKeyCacheInit) {
     gatewayKeyCacheInit = true;
     if (apimGWCacheExpiry != null) {
       return APIUtil.getCache(
           APIConstants.API_MANAGER_CACHE_MANAGER,
           APIConstants.GATEWAY_KEY_CACHE_NAME,
           Long.parseLong(apimGWCacheExpiry),
           Long.parseLong(apimGWCacheExpiry));
     } else {
       long defaultCacheTimeout =
           Long.valueOf(
                   ServerConfiguration.getInstance()
                       .getFirstProperty(APIConstants.DEFAULT_CACHE_TIMEOUT))
               * 60;
       return APIUtil.getCache(
           APIConstants.API_MANAGER_CACHE_MANAGER,
           APIConstants.GATEWAY_KEY_CACHE_NAME,
           defaultCacheTimeout,
           defaultCacheTimeout);
     }
   }
   return Caching.getCacheManager(APIConstants.API_MANAGER_CACHE_MANAGER)
       .getCache(APIConstants.GATEWAY_KEY_CACHE_NAME);
 }
  protected Cache getResourceCache() {

    if (!resourceCacheInit) {
      resourceCacheInit = true;
      long defaultCacheTimeout =
          Long.valueOf(
                  ServerConfiguration.getInstance()
                      .getFirstProperty(APIConstants.DEFAULT_CACHE_TIMEOUT))
              * 60;
      return APIUtil.getCache(
          APIConstants.API_MANAGER_CACHE_MANAGER,
          APIConstants.RESOURCE_CACHE_NAME,
          defaultCacheTimeout,
          defaultCacheTimeout);
    }
    return Caching.getCacheManager(APIConstants.API_MANAGER_CACHE_MANAGER)
        .getCache(APIConstants.RESOURCE_CACHE_NAME);
  }
  /**
   * Invalidates registry cache of the resource in the given path in given server
   *
   * @param path registry path of the resource
   * @param tenantDomain
   * @param serverURL
   * @param cookie
   * @throws AxisFault
   * @throws RemoteException
   * @throws APIManagementException
   */
  public void clearCache(String path, String tenantDomain, String serverURL, String cookie)
      throws AxisFault, RemoteException, APIManagementException {
    RegistryCacheInvalidationServiceStub registryCacheServiceStub;

    ConfigurationContext ctx =
        ConfigurationContextFactory.createConfigurationContextFromFileSystem(null, null);
    registryCacheServiceStub =
        new RegistryCacheInvalidationServiceStub(
            ctx, serverURL + "RegistryCacheInvalidationService");
    ServiceClient client = registryCacheServiceStub._getServiceClient();
    Options options = client.getOptions();
    options.setTimeOutInMilliSeconds(TIMEOUT_IN_MILLIS);
    options.setProperty(HTTPConstants.SO_TIMEOUT, TIMEOUT_IN_MILLIS);
    options.setProperty(HTTPConstants.CONNECTION_TIMEOUT, TIMEOUT_IN_MILLIS);
    options.setManageSession(true);
    options.setProperty(HTTPConstants.COOKIE_STRING, cookie);

    try {
      registryCacheServiceStub.invalidateCache(path, tenantDomain);
    } catch (RegistryCacheInvalidationServiceAPIManagementExceptionException e) {
      APIUtil.handleException(e.getMessage(), e);
    }
  }
 public void invalidateCache(String tenantDomain) {
   APIUtil.clearTiersCache(tenantDomain);
 }
  public VerbInfoDTO findMatchingVerb(MessageContext synCtx)
      throws ResourceNotFoundException, APISecurityException {

    VerbInfoDTO verb = null;

    // This function is used by more than one handler. If on one execution of this function, it has
    // found and placed
    // the matching verb in the cache, the same can be re-used from all handlers since all handlers
    // share the same
    // MessageContext. The API_RESOURCE_CACHE_KEY property will be set in the MessageContext to
    // indicate that the
    // verb has been put into the cache.
    String resourceCacheKey = (String) synCtx.getProperty(APIConstants.API_RESOURCE_CACHE_KEY);
    if (resourceCacheKey != null) {
      verb = (VerbInfoDTO) getResourceCache().get(resourceCacheKey);
      // Cache hit
      if (verb != null) {
        if (log.isDebugEnabled()) {
          log.debug("Found resource in Cache for key: ".concat(resourceCacheKey));
        }
        return verb;
      }
      if (log.isDebugEnabled()) {
        log.debug("Resource not found in cache for key: ".concat(resourceCacheKey));
      }
    }
    String resourceString = (String) synCtx.getProperty(APIConstants.API_ELECTED_RESOURCE);
    String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT);
    String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION);
    String fullRequestPath = (String) synCtx.getProperty(RESTConstants.REST_FULL_REQUEST_PATH);
    String apiName = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API);

    String requestPath = Utils.getRequestPath(synCtx, fullRequestPath, apiContext, apiVersion);
    if ("".equals(requestPath)) {
      requestPath = "/";
    }

    if (log.isDebugEnabled()) {
      log.debug("Setting REST_SUB_REQUEST_PATH in msg context: ".concat(requestPath));
    }
    synCtx.setProperty(RESTConstants.REST_SUB_REQUEST_PATH, requestPath);

    String httpMethod =
        (String)
            ((Axis2MessageContext) synCtx)
                .getAxis2MessageContext()
                .getProperty(Constants.Configuration.HTTP_METHOD);
    if (resourceString == null) {
      API selectedApi = synCtx.getConfiguration().getAPI(apiName);
      Resource selectedResource = null;

      if (selectedApi != null) {
        Resource[] selectedAPIResources = selectedApi.getResources();

        Set<Resource> acceptableResources = new HashSet<Resource>();

        for (Resource resource : selectedAPIResources) {
          // If the requesting method is OPTIONS or if the Resource contains the requesting method
          if (RESTConstants.METHOD_OPTIONS.equals(httpMethod)
              || (resource.getMethods() != null
                  && Arrays.asList(resource.getMethods()).contains(httpMethod))) {
            acceptableResources.add(resource);
          }
        }

        if (acceptableResources.size() > 0) {
          for (RESTDispatcher dispatcher : RESTUtils.getDispatchers()) {
            Resource resource = dispatcher.findResource(synCtx, acceptableResources);
            if (resource != null && Arrays.asList(resource.getMethods()).contains(httpMethod)) {
              selectedResource = resource;
              break;
            }
          }
        }
      }

      if (selectedResource == null) {
        // No matching resource found.
        String msg = "Could not find matching resource for " + requestPath;
        log.error(msg);
        throw new ResourceNotFoundException(msg);
      }

      resourceString = selectedResource.getDispatcherHelper().getString();
      resourceCacheKey =
          APIUtil.getResourceInfoDTOCacheKey(apiContext, apiVersion, resourceString, httpMethod);

      if (log.isDebugEnabled()) {
        log.debug("Selected Resource: ".concat(resourceString));
      }
      // Set the elected resource
      synCtx.setProperty(APIConstants.API_ELECTED_RESOURCE, resourceString);
    }
    verb = (VerbInfoDTO) getResourceCache().get(resourceCacheKey);

    // Cache hit
    if (verb != null) {
      if (log.isDebugEnabled()) {
        log.debug("Got Resource from cache for key: ".concat(resourceCacheKey));
      }
      // Set cache key in the message context so that it can be used by the subsequent handlers.
      synCtx.setProperty(APIConstants.API_RESOURCE_CACHE_KEY, resourceCacheKey);
      return verb;
    }

    if (log.isDebugEnabled()) {
      log.debug("Cache miss for Resource for key: ".concat(resourceCacheKey));
    }

    String apiCacheKey = APIUtil.getAPIInfoDTOCacheKey(apiContext, apiVersion);
    APIInfoDTO apiInfoDTO = null;
    apiInfoDTO = (APIInfoDTO) getResourceCache().get(apiCacheKey);

    // Cache miss
    if (apiInfoDTO == null) {
      if (log.isDebugEnabled()) {
        log.debug("Could not find API object in cache for key: ".concat(apiCacheKey));
      }
      apiInfoDTO = doGetAPIInfo(apiContext, apiVersion);
      getResourceCache().put(apiCacheKey, apiInfoDTO);
    }
    if (apiInfoDTO.getResources() != null) {
      for (ResourceInfoDTO resourceInfoDTO : apiInfoDTO.getResources()) {
        if ((resourceString.trim()).equalsIgnoreCase(resourceInfoDTO.getUrlPattern().trim())) {
          for (VerbInfoDTO verbDTO : resourceInfoDTO.getHttpVerbs()) {
            if (verbDTO.getHttpVerb().equals(httpMethod)) {
              if (log.isDebugEnabled()) {
                log.debug("Putting resource object in cache with key: ".concat(resourceCacheKey));
              }
              verbDTO.setRequestKey(resourceCacheKey);
              // Store verb in cache
              getResourceCache().put(resourceCacheKey, verbDTO);
              // Set cache key in the message context so that it can be used by the subsequent
              // handlers.
              synCtx.setProperty(APIConstants.API_RESOURCE_CACHE_KEY, resourceCacheKey);
              return verbDTO;
            }
          }
        }
      }
    }
    return null;
  }
  /**
   * Get the API key validated against the specified API
   *
   * @param context API context
   * @param apiKey API key to be validated
   * @param apiVersion API version number
   * @return An APIKeyValidationInfoDTO object
   * @throws APISecurityException If an error occurs while accessing backend services
   */
  public APIKeyValidationInfoDTO getKeyValidationInfo(
      String context,
      String apiKey,
      String apiVersion,
      String authenticationScheme,
      String clientDomain,
      String matchingResource,
      String httpVerb,
      boolean defaultVersionInvoked)
      throws APISecurityException {

    String prefixedVersion = apiVersion;
    // Check if client has invoked the default version API.
    if (defaultVersionInvoked) {
      // Prefix the version so that it looks like _default_1.0 (_default_<version>)).
      // This is so that the Key Validator knows that this request is coming through a default api
      // version
      prefixedVersion = APIConstants.DEFAULT_VERSION_PREFIX.concat(prefixedVersion);
    }

    String cacheKey =
        APIUtil.getAccessTokenCacheKey(
            apiKey, context, prefixedVersion, matchingResource, httpVerb, authenticationScheme);
    // If Gateway key caching is enabled.
    if (gatewayKeyCacheEnabled) {
      // Get the access token from the first level cache.
      String cachedToken = (String) getGatewayTokenCache().get(apiKey);

      // If the access token exists in the first level cache.
      if (cachedToken != null) {
        APIKeyValidationInfoDTO info = (APIKeyValidationInfoDTO) getGatewayKeyCache().get(cacheKey);

        if (info != null) {
          if (APIUtil.isAccessTokenExpired(info)) {
            log.info("Invalid OAuth Token : Access Token " + apiKey + " expired.");
            info.setAuthorized(false);
            // in cache, if token is expired  remove cache entry.
            getGatewayKeyCache().remove(cacheKey);

            // Remove from the first level token cache as well.
            getGatewayTokenCache().remove(apiKey);
          }
          return info;
        }
      }
    }

    // synchronized (apiKey.intern()) {
    // We synchronize on the API key here to allow concurrent processing
    // of different API keys - However when a burst of requests with the
    // same key is encountered, only one will be allowed to execute the logic,
    // and the rest will pick the value from the cache.
    //   info = (APIKeyValidationInfoDTO) infoCache.get(cacheKey);
    // if (info != null) {
    //   return info;
    // }
    APIKeyValidationInfoDTO info =
        doGetKeyValidationInfo(
            context,
            prefixedVersion,
            apiKey,
            authenticationScheme,
            clientDomain,
            matchingResource,
            httpVerb);
    if (info != null) {
      if (gatewayKeyCacheEnabled) {
        // Get the tenant domain of the API that is being invoked.
        String tenantDomain =
            PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();

        // Add to first level Token Cache.
        getGatewayTokenCache().put(apiKey, tenantDomain);
        // Add to Key Cache.
        getGatewayKeyCache().put(cacheKey, info);

        // If this is NOT a super-tenant API that is being invoked
        if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
          // Add the tenant domain as a reference to the super tenant cache so we know from which
          // tenant cache
          // to remove the entry when the need occurs to clear this particular cache entry.
          try {
            PrivilegedCarbonContext.startTenantFlow();
            PrivilegedCarbonContext.getThreadLocalCarbonContext()
                .setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME, true);

            getGatewayTokenCache().put(apiKey, tenantDomain);
          } finally {
            PrivilegedCarbonContext.endTenantFlow();
          }
        }
      }

      return info;
    } else {
      String warnMsg = "API key validation service returns null object";
      log.warn(warnMsg);
      throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR, warnMsg);
    }
  }
  public void invoke(Request request, Response response, CompositeValve compositeValve) {

    if (authenticator == null) {
      authenticator = new APITokenAuthenticator();
    }

    String context = request.getContextPath();
    if (context == null || context.equals("")) {
      // Invoke next valve in pipe.
      getNext().invoke(request, response, compositeValve);
      return;
    }

    // todo remove version from context - special case for apps
    //        context = stripVersionfromContext(context);

    boolean contextExist;
    Boolean contextValueInCache = null;
    if (APIUtil.getAPIContextCache().get(context) != null) {
      contextValueInCache =
          Boolean.parseBoolean(APIUtil.getAPIContextCache().get(context).toString());
    }

    if (contextValueInCache != null) {
      contextExist = contextValueInCache;
    } else {
      contextExist = ApiMgtDAO.isContextExist(context);
      APIUtil.getAPIContextCache().put(context, contextExist);
    }

    if (!contextExist) {
      getNext().invoke(request, response, compositeValve);
      return;
    }

    handleWSDLGetRequest(request, response, compositeValve, context);

    String dispatcherPath = null;
    boolean forwardingRequired = false;

    long requestTime = System.currentTimeMillis();
    APIManagerInterceptorOps interceptorOps = new APIManagerInterceptorOps();
    UsageStatConfiguration statConfiguration = new UsageStatConfiguration();
    if (contextExist) {
      // Use embedded API Management
      if (log.isDebugEnabled()) {
        log.debug("API Manager Interceptor Valve Got invoked!!");
      }

      String bearerToken = request.getHeader(APIConstants.OperationParameter.AUTH_PARAM_NAME);
      String accessToken = null;

      /* Authenticate*/
      try {
        if (bearerToken != null) {
          accessToken = APIManagetInterceptorUtils.getBearerToken(bearerToken);
        } else {
          // There can be some API published with None Auth Type
          /*
           * throw new
           * APIFaultException(APIConstants.KeyValidationStatus
           * .API_AUTH_INVALID_CREDENTIALS,
           * "Invalid format for Authorization header. Expected 'Bearer <token>'"
           * );
           */
        }

        String apiVersion = APIManagetInterceptorUtils.getAPIVersion(request);
        dispatcherPath = apiVersion;
        // todo get proper version
        // handling version for web-application API mgmt

        if (!APIManagerInterceptorConstant.DEFAULT_API_VERSION.equals(apiVersion)
            || "".equals(apiVersion)) {
          apiVersion = APIManagerInterceptorConstant.DEFAULT_API_VERSION;
        } else {
          forwardingRequired = true;
        }

        String domain = request.getHeader(APITokenValidator.getAPIManagerClientDomainHeader());
        String authLevel =
            authenticator.getResourceAuthenticationScheme(
                context, apiVersion, request.getRequestURI(), request.getMethod());
        if (authLevel.equals(APIConstants.NO_MATCHING_AUTH_SCHEME)) {
          APIManagetInterceptorUtils.handleNoMatchAuthSchemeCallForRestService(
              response, request.getMethod(), request.getRequestURI(), apiVersion, context);
          return;
        } else {
          interceptorOps.doAuthenticate(
              context,
              APIConstants.DEFAULT_VERSION_PREFIX + apiVersion,
              accessToken,
              authLevel,
              domain);
        }
      } catch (APIManagementException e) {
        // ignore
      } catch (APIFaultException e) {
          /* If !isAuthorized APIFaultException is thrown*/
        APIManagetInterceptorUtils.handleAPIFaultForRestService(
            e,
            APIManagerErrorConstants.API_SECURITY_NS,
            APIManagerErrorConstants.API_SECURITY_NS_PREFIX,
            response);
        return;
      }
      /* Throttle*/
      try {
        interceptorOps.doThrottle(request, accessToken);
      } catch (APIFaultException e) {
        APIManagetInterceptorUtils.handleAPIFaultForRestService(
            e,
            APIManagerErrorConstants.API_THROTTLE_NS,
            APIManagerErrorConstants.API_THROTTLE_NS_PREFIX,
            response);
        return;
      }
      /* Publish Statistic if enabled*/
      if (statConfiguration.isStatsPublishingEnabled()) {
        try {
          interceptorOps.publishStatistics(request, requestTime, false);
        } catch (APIManagementException e) {
          log.error("Error occurred when publishing stats", e);
        }
      }
    }

    if (forwardingRequired) {
      try {
        request
            .getRequestDispatcher(
                request.getContextPath() + "/services/customers/customerservice/customers/123")
            .forward(request, response);
        //                response.sendRedirect(request.getContextPath() +
        // "/services/customers/customerservice/customers/123");
        //                return;
      } catch (ServletException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    // Invoke next valve in pipe.
    getNext().invoke(request, response, compositeValve);

    // Handle Responses
    if (contextExist && statConfiguration.isStatsPublishingEnabled()) {
      try {
        interceptorOps.publishStatistics(request, requestTime, true);
      } catch (APIManagementException e) {
        log.error("Error occurred when publishing stats", e);
      }
    }
  }
  /**
   * This method updates the stat publishing status in gateway domain
   *
   * @param receiverUrl event receiver url
   * @param user username for the event receiver
   * @param password password for the event receiver
   * @param statUpdateStatus status of the stat publishing state
   * @throws APIManagementException if an error occurs while adding BAMServerProfile
   * @throws ClusteringFault if it fails to send cluster message to Gateway domain and update stats
   *     publishing status
   * @throws Exception if an error occurs while updating EventingConfiguration
   */
  public void updateStatPublishGateway(
      String receiverUrl, String user, String password, Boolean statUpdateStatus)
      throws APIManagementException, ClusteringFault, Exception {

    if (log.isDebugEnabled()) {
      log.debug("Updating stats publishing status in Gateway.");
    }

    // updating stat publishing at the receiver node, self update
    APIManagerAnalyticsConfiguration analyticsConfiguration =
        APIManagerAnalyticsConfiguration.getInstance();
    analyticsConfiguration.setAnalyticsEnabled(statUpdateStatus);

    if (log.isDebugEnabled()) {
      log.debug("Updated stats publishing status in Gateway to : " + statUpdateStatus);
    }

    ServiceDataPublisherAdmin serviceDataPublisherAdmin =
        APIManagerComponent.getDataPublisherAdminService();
    EventingConfigData eventingConfigData = null;
    if (serviceDataPublisherAdmin != null) {
      eventingConfigData = serviceDataPublisherAdmin.getEventingConfigData();
    }

    if (eventingConfigData != null) {
      // config values must be updated if the stats publishing is true
      if (statUpdateStatus) {
        if (log.isDebugEnabled()) {
          log.debug("Updating values related to stats publishing status.");
        }
        // values related to stats publishing status are only updated if all of them are non-empty
        if (!(receiverUrl.isEmpty()) && !(user.isEmpty()) && !(password.isEmpty())) {
          analyticsConfiguration.setBamServerUrlGroups(receiverUrl);
          analyticsConfiguration.setBamServerUser(user);
          analyticsConfiguration.setBamServerPassword(password);

          eventingConfigData.setUrl(receiverUrl);
          eventingConfigData.setUserName(user);
          eventingConfigData.setPassword(password);
          if (log.isDebugEnabled()) {
            log.debug(
                "BAMServerURL : "
                    + receiverUrl
                    + " , BAMServerUserName : "******" , "
                    + "BAMServerPassword : "******"Sending cluster message to Gateway domain to update stats publishing status.");
      }
      clusteringAgent.sendMessage(
          new StatUpdateClusterMessage(statUpdateStatus, receiverUrl, user, password), true);
    }
  }