private static void processKeyExpression(
      Class<?> clz, String keyExpr, CachableValueAccessor accessorCache) throws ServiceException {

    if (keyExpr == null || keyExpr.isEmpty())
      throw new ServiceException(
          ErrorDataFactory.createErrorData(
              ErrorConstants.SVC_CACHE_POLICY_INVALID_KEY,
              ErrorConstants.ERRORDOMAIN,
              new Object[] {keyExpr}));

    StringTokenizer st = new StringTokenizer(keyExpr, ".");
    StringBuffer currentPath = new StringBuffer();
    Class<?> curClz = clz;
    CachableValueAccessor curLevelAccessor = accessorCache;

    while (st.hasMoreElements()) {
      String xmlElement = (String) st.nextElement();
      CachableValueAccessor childLevelAccessor = null;
      Method m = null;
      if (currentPath.length() != 0) currentPath.append(".").append(xmlElement);
      else currentPath.append(xmlElement);

      if (curLevelAccessor.m_elementAccessors.get(xmlElement) != null) {
        // found. No need to create method
        childLevelAccessor = curLevelAccessor.m_elementAccessors.get(xmlElement);
        m = childLevelAccessor.m_accessor;
      } else {
        // find the matching java method
        m = ReflectionUtils.findMatchingJavaMethod(curClz, xmlElement);
        if (m == null) {
          // System.out.println("Method not found: class=" + curClz.getName() + ", xmlElement=" +
          // xmlElement);
          throw new ServiceException(
              ErrorDataFactory.createErrorData(
                  ErrorConstants.SVC_CACHE_POLICY_INVALID_KEY,
                  ErrorConstants.ERRORDOMAIN,
                  new Object[] {keyExpr}));
        }
        childLevelAccessor = new CachableValueAccessor(xmlElement, m, currentPath.toString());
        // insert to the current level of the accessorCache
        curLevelAccessor.m_elementAccessors.put(xmlElement, childLevelAccessor);
      }
      // advance the iteration to use the childLevelAccessor
      curLevelAccessor = childLevelAccessor;
      curClz = m.getReturnType();
    }

    if (!KeyExpressionValidator.validateReturnType(curClz))
      throw new ServiceException(
          ErrorDataFactory.createErrorData(
              ErrorConstants.SVC_CACHE_POLICY_INVALID_KEY,
              ErrorConstants.ERRORDOMAIN,
              new Object[] {keyExpr}));
  }
  private ErrorDataProvider getErrorDataProviderClass(
      MessageProcessorConfigHolder config, ClassLoader cl) throws ServiceException {
    ErrorDataProvider result = null;
    String className = config.getErrorDataProviderClass();
    if (className == null) {
      // if error data provider not configured, for now set it to null

    } else {
      result = ReflectionUtils.createInstance(className, ErrorDataProvider.class, cl);
    }

    return result;
  }
  private ErrorMapper createErrorMapper(
      MessageProcessorConfigHolder config, ServerServiceId svcId, ClassLoader cl)
      throws ServiceException {
    ErrorMapper result;
    String className = config.getErrorMappingClass();
    if (className == null) {
      // if error mapper not configured, use the system default one
      result = new DefaultErrorMapperImpl();
    } else {
      result = ReflectionUtils.createInstance(className, ErrorMapper.class, cl);
    }

    ErrorMapperInitContextImpl initCtx = new ErrorMapperInitContextImpl(svcId);
    result.init(initCtx);
    initCtx.kill();

    return result;
  }
  private VersionCheckHandler createVersionCheckHandler(
      ServerServiceId serverSvcId, ServiceConfigHolder config, ClassLoader cl)
      throws ServiceException {
    String currentVersion = config.getMetaData().getVersion();
    if (currentVersion == null || currentVersion.length() == 0) {
      throw new ServiceCreationException(
          ErrorDataFactory.createErrorData(
              ErrorConstants.SVC_FACTORY_MISSING_SERVICE_VERSION,
              ErrorConstants.ERRORDOMAIN,
              new Object[] {serverSvcId.getAdminName()}));
    }

    Collection<String> supportedVersions = config.getSupportedVersions();
    if (supportedVersions != null) {
      supportedVersions = new ArrayList<String>(supportedVersions);
    } else {
      supportedVersions = new ArrayList<String>();
    }
    if (!supportedVersions.contains(currentVersion)) {
      supportedVersions.add(currentVersion);
    }
    supportedVersions = Collections.unmodifiableCollection(supportedVersions);

    String versionCheckClassName = config.getVersionCheckHandlerClassName();
    if (versionCheckClassName == null) {
      versionCheckClassName = SimpleVersionCheckHandler.class.getName();
    }

    VersionCheckHandler versionCheckHandler =
        ReflectionUtils.createInstance(versionCheckClassName, VersionCheckHandler.class, cl);

    VersionCheckHandlerInitContextImpl initCtx =
        new VersionCheckHandlerInitContextImpl(serverSvcId, currentVersion, supportedVersions);
    versionCheckHandler.init(initCtx);
    initCtx.kill();

    return versionCheckHandler;
  }
  @Override
  protected ServerServiceDesc createServiceDesc(ServiceId id) throws ServiceException {
    ServerServiceId serverSvcId = (ServerServiceId) id;
    String adminName = id.getAdminName();
    ServiceConfigHolder config = ServiceConfigManager.getInstance().getConfig(adminName);
    QName serviceQName = config.getServiceQName();

    ClassLoader cl = Thread.currentThread().getContextClassLoader();

    MessageProcessorConfigHolder processorConfig = config.getMessageProcessorConfig();
    TypeMappingConfigHolder typeMappingsCfg = config.getTypeMappings();

    Pipeline requestPipeline = createPipeline(id, PipelineMode.REQUEST, processorConfig, cl);
    Pipeline responsePipeline = createPipeline(id, PipelineMode.RESPONSE, processorConfig, cl);

    Class serviceInterfaceClass = loadServiceInterfaceClass(config, true, cl);

    ServiceTypeMappings typeMappings =
        createTypeMappings(id, typeMappingsCfg, serviceInterfaceClass, cl);

    Collection<String> unsupportedOperations = config.getUnsupportedOperation();
    Map<String, ServiceOperationDesc> operations =
        createOperations(
            id,
            typeMappingsCfg,
            unsupportedOperations,
            typeMappings,
            serviceQName,
            cl,
            config.getOperationProperties());
    RequestPatternMatcher<ServiceOperationDesc> operationMatcher =
        createOperationsMatcher(operations.values());

    Map<String, ProtocolProcessorDesc> protocols =
        createProtocolProcessors(serverSvcId, processorConfig.getProtocolProcessors(), cl);
    RequestPatternMatcher<ProtocolProcessorDesc> protocolMatcher =
        createProtocolProcessorsMatcher(processorConfig.getProtocolProcessors(), protocols);

    Collection<String> supportedDataBindings = config.getSupportedDataBindings();
    Set<Class> rootClasses = getRootClassesFromOperations(operations.values());
    for (String className : typeMappingsCfg.getJavaTypes()) {
      Class clazz = ReflectionUtils.loadClass(className, null, true, cl);
      if (clazz == null) {
        if (LOGGER.isLogEnabled(LogLevel.WARN)) {
          LOGGER.log(LogLevel.WARN, "Unable to load type mapping class: " + className);
        }
      } else {
        rootClasses.add(clazz);
      }
    }
    Map<String, DataBindingDesc> bindings =
        createDataBindings(
            serverSvcId, processorConfig, supportedDataBindings, rootClasses, true, cl, true);

    DataBindingDesc defaultRequestBinding =
        getDefaultRequestDataBinding(config, supportedDataBindings, bindings, adminName);
    DataBindingDesc defaultResponseBinding =
        getDefaultResponseDataBinding(config, supportedDataBindings, bindings, adminName);

    RequestPatternMatcher<DataBindingDesc> bindingMatcherForRequest =
        new RequestPatternMatcher<DataBindingDesc>(true);
    RequestPatternMatcher<DataBindingDesc> bindingMatcherForResponse =
        new RequestPatternMatcher<DataBindingDesc>(true);
    createDataBindingsMatchers(
        bindings.values(), bindingMatcherForRequest, bindingMatcherForResponse);

    ErrorMapper errorMapper = createErrorMapper(processorConfig, serverSvcId, cl);
    ErrorDataProvider errorDataProviderClass = getErrorDataProviderClass(processorConfig, cl);
    List<LoggingHandler> loggingHandlers = createLoggingHandlers(id, processorConfig, cl);

    String serviceDispatcherClassName = getDispatcherClassName(config);

    String serviceImplClassName = config.getServiceImplClassName();
    String implFactory = config.getServiceImplFactoryClassName();

    BaseServiceRequestDispatcher<?> serviceDispatcher = null;
    try {
      serviceDispatcher =
          ReflectionUtils.createInstance(
              serviceDispatcherClassName, BaseServiceRequestDispatcher.class, cl);
    } catch (ServiceException se) {
      String mode = "Service Impl";
      if (implFactory != null) {
        mode += " factory";
      }
      throw new ServiceCreationException(
          ErrorDataFactory.createErrorData(
              ErrorConstants.SVC_FACTORY_MISSING_DISPATCHER_IMPL,
              ErrorConstants.ERRORDOMAIN,
              new Object[] {serviceDispatcherClassName}),
          se.getCause());
    }

    VersionCheckHandler versionCheckHandler = createVersionCheckHandler(serverSvcId, config, cl);

    serviceDispatcher.init(
        serverSvcId,
        serviceInterfaceClass,
        serviceImplClassName,
        cl,
        operations.values(),
        versionCheckHandler,
        implFactory,
        config.isImplCached());

    Dispatcher requestDispatcher = new SimpleInvokerDispatcher(serviceDispatcher);
    Dispatcher responseDispatcher = new SimpleServerResponseDispatcher(true);

    Collection<GlobalIdEntry> registryEntries =
        GlobalRegistryConfigManager.getInstance().getAllEntries();
    Map<String, GlobalIdDesc> globalIdMap = createGlobalIdMap(registryEntries, config);

    Charset serviceCharset = null; // default is to use request charset
    String serviceCharsetName = config.getDefaultEncoding();
    if (serviceCharsetName != null) {
      try {
        serviceCharset = Charset.forName(serviceCharsetName);
      } catch (Exception e) {
        throw new ServiceException(
            ErrorDataFactory.createErrorData(
                ErrorConstants.SVC_FACTORY_UNSUPPORTED_CHARSET,
                ErrorConstants.ERRORDOMAIN,
                new Object[] {serviceCharsetName, adminName}),
            e);
      }
    }

    UrlMappingsDesc urlMappings = loadUrlMappings(adminName, config);
    OperationMappings operationMappings = config.getOperationMappings();
    if (operationMappings == null) {
      operationMappings = new OperationMappings();
    }
    HeaderMappingsDesc requestHeaderMappings =
        loadHeaderMappings(adminName, config.getRequestHeaderMappingOptions(), true);
    HeaderMappingsDesc responseHeaderMappings =
        loadHeaderMappings(adminName, config.getResponseHeaderMappingOptions(), false);

    SecurityPolicyConfigHolder securityPolicy = config.getSecurityPolicy();
    Map<String, Map<String, String>> authentOperationsMap =
        new HashMap<String, Map<String, String>>();
    loadSecurityPolicy(adminName, securityPolicy, operations, authentOperationsMap);

    CachePolicyDesc cachePolicyDesc = null;
    if (config.getCachePolicy() != null) {
      cachePolicyDesc =
          CachePolicyDesc.create(config.getCachePolicy(), createOpRequestTypeDesc(operations));
    }

    List<String> serviceLayers =
        ServiceConfigManager.getInstance().getGlobalConfig().getServiceLayerNames();

    String httpErrorMapperClassName = config.getHttpErrorMapper();
    HttpErrorMapper httpErrorMapper = null;
    if (httpErrorMapperClassName != null) {
      httpErrorMapper =
          ReflectionUtils.createInstance(httpErrorMapperClassName, HttpErrorMapper.class, cl);
    }

    ServerServiceDesc result =
        new ServerServiceDesc(
            serverSvcId,
            serviceQName,
            config,
            requestPipeline,
            responsePipeline,
            requestDispatcher,
            responseDispatcher,
            operations,
            protocols,
            bindings,
            typeMappings,
            cl,
            loggingHandlers,
            serviceInterfaceClass,
            operationMatcher,
            protocolMatcher,
            bindingMatcherForRequest,
            bindingMatcherForResponse,
            serviceImplClassName,
            errorMapper,
            errorDataProviderClass,
            globalIdMap,
            versionCheckHandler,
            serviceCharset,
            urlMappings,
            operationMappings,
            requestHeaderMappings,
            responseHeaderMappings,
            authentOperationsMap,
            defaultRequestBinding,
            defaultResponseBinding,
            serviceLayers,
            cachePolicyDesc,
            config.getRequestParamsDescriptor(),
            implFactory,
            httpErrorMapper);

    return result;
  }