@Override
  public Continuation apply(final ContainerRequest request) {
    final RoutingContext routingCtx = injector.inject(RoutingContext.class);

    Object subResource = getResource(routingCtx);
    if (subResource == null) {
      throw new WebApplicationException(Response.Status.NOT_FOUND);
    }
    if (subResource.getClass().isAssignableFrom(Class.class)) {
      final Class<?> clazz = (Class<?>) subResource;
      SingletonResourceBinder singletonResourceFactory =
          injector.inject(SingletonResourceBinder.class);
      singletonResourceFactory.bindResourceClassAsSingleton(clazz);
      subResource = injector.inject(clazz);
    }

    // TODO: what to do with the issues?
    final Resource subResourceModel =
        Resource.builder(subResource, new LinkedList<ResourceModelIssue>()).build();
    runtimeModelBuilder.process(subResourceModel, true);

    // TODO: implement generated sub-resource methodAcceptorPair caching
    routingCtx.pushMatchedResource(subResource);
    Router subResourceAcceptor = runtimeModelBuilder.buildModel(true);
    return Continuation.of(request, subResourceAcceptor);
  }
  /** Assumes the configuration field is initialized with a valid ResourceConfig. */
  private void initialize() {
    LOGGER.info(LocalizationMessages.INIT_MSG(Version.getBuildId()));

    // Lock original ResourceConfig.
    if (application instanceof ResourceConfig) {
      ((ResourceConfig) application).lock();
    }

    // add WADL support
    runtimeConfig.register(WadlModelProcessorFeature.class);

    // Configure binders and features.
    runtimeConfig.configureMetaProviders(locator);

    // Introspecting classes & instances
    final ResourceBag.Builder resourceBagBuilder = new ResourceBag.Builder();
    for (Class<?> c : runtimeConfig.getClasses()) {
      try {
        Resource resource = Resource.from(c);
        if (resource != null) {
          resourceBagBuilder.registerResource(c, resource);
        }
      } catch (IllegalArgumentException ex) {
        LOGGER.warning(ex.getMessage());
      }
    }

    for (Object o : runtimeConfig.getSingletons()) {
      try {
        Resource resource = Resource.from(o.getClass());
        if (resource != null) {
          resourceBagBuilder.registerResource(o, resource);
        }
      } catch (IllegalArgumentException ex) {
        LOGGER.warning(ex.getMessage());
      }
    }

    // Adding programmatic resource models
    for (Resource programmaticResource : runtimeConfig.getResources()) {
      resourceBagBuilder.registerProgrammaticResource(programmaticResource);
    }

    final ResourceBag resourceBag = resourceBagBuilder.build();

    runtimeConfig.lock();

    // Registering Injection Bindings
    final Set<ComponentProvider> componentProviders = new HashSet<ComponentProvider>();

    for (ComponentProvider provider : ServiceFinder.find(ComponentProvider.class)) {
      provider.initialize(locator);
      componentProviders.add(provider);
    }

    final ComponentBag componentBag = runtimeConfig.getComponentBag();
    bindProvidersAndResources(
        componentProviders, componentBag, resourceBag.classes, resourceBag.instances);
    for (ComponentProvider componentProvider : componentProviders) {
      componentProvider.done();
    }

    // scan for NameBinding annotations attached to the application class
    Collection<Class<? extends Annotation>> applicationNameBindings =
        ReflectionHelper.getAnnotationTypes(application.getClass(), NameBinding.class);

    // find all filters, interceptors and dynamic features
    final Iterable<RankedProvider<ContainerResponseFilter>> responseFilters =
        Providers.getAllRankedProviders(locator, ContainerResponseFilter.class);
    final MultivaluedMap<Class<? extends Annotation>, RankedProvider<ContainerResponseFilter>>
        nameBoundResponseFilters =
            filterNameBound(responseFilters, null, componentBag, applicationNameBindings);

    final Iterable<RankedProvider<ContainerRequestFilter>> requestFilters =
        Providers.getAllRankedProviders(locator, ContainerRequestFilter.class);
    final List<RankedProvider<ContainerRequestFilter>> preMatchFilters = Lists.newArrayList();
    final MultivaluedMap<Class<? extends Annotation>, RankedProvider<ContainerRequestFilter>>
        nameBoundRequestFilters =
            filterNameBound(requestFilters, preMatchFilters, componentBag, applicationNameBindings);

    final Iterable<RankedProvider<ReaderInterceptor>> readerInterceptors =
        Providers.getAllRankedProviders(locator, ReaderInterceptor.class);
    final MultivaluedMap<Class<? extends Annotation>, RankedProvider<ReaderInterceptor>>
        nameBoundReaderInterceptors =
            filterNameBound(readerInterceptors, null, componentBag, applicationNameBindings);

    final Iterable<RankedProvider<WriterInterceptor>> writerInterceptors =
        Providers.getAllRankedProviders(locator, WriterInterceptor.class);
    final MultivaluedMap<Class<? extends Annotation>, RankedProvider<WriterInterceptor>>
        nameBoundWriterInterceptors =
            filterNameBound(writerInterceptors, null, componentBag, applicationNameBindings);
    final Iterable<DynamicFeature> dynamicFeatures =
        Providers.getAllProviders(locator, DynamicFeature.class);

    ResourceModel resourceModel =
        new ResourceModel.Builder(resourceBag.getRootResources(), false).build();

    resourceModel = processResourceModel(resourceModel);
    // validate the models
    validate(resourceModel);

    bindEnhancingResourceClasses(resourceModel, resourceBag, componentProviders);

    final RuntimeModelBuilder runtimeModelBuilder = locator.getService(RuntimeModelBuilder.class);
    runtimeModelBuilder.setGlobalInterceptors(readerInterceptors, writerInterceptors);
    runtimeModelBuilder.setBoundProviders(
        nameBoundRequestFilters,
        nameBoundResponseFilters,
        nameBoundReaderInterceptors,
        nameBoundWriterInterceptors,
        dynamicFeatures);

    // assembly request processing chain
    /**
     * Root hierarchical request matching acceptor. Invoked in a single linear stage as part of the
     * main linear accepting chain.
     */
    final Router resourceRoutingRoot =
        runtimeModelBuilder.buildModel(resourceModel.getRuntimeResourceModel(), false);

    final ContainerFilteringStage preMatchRequestFilteringStage =
        locator
            .createAndInitialize(ContainerFilteringStage.Builder.class)
            .build(preMatchFilters, responseFilters);
    final RoutingStage routingStage =
        locator.createAndInitialize(RoutingStage.Builder.class).build(resourceRoutingRoot);
    final ContainerFilteringStage resourceFilteringStage =
        locator
            .createAndInitialize(ContainerFilteringStage.Builder.class)
            .build(requestFilters, null);
    final RoutedInflectorExtractorStage routedInflectorExtractorStage =
        locator.createAndInitialize(RoutedInflectorExtractorStage.class);
    /**
     * Root linear request acceptor. This is the main entry point for the whole request processing.
     */
    final Stage<ContainerRequest> rootStage =
        Stages.chain(locator.createAndInitialize(ReferencesInitializer.class))
            .to(locator.createAndInitialize(ContainerMessageBodyWorkersInitializer.class))
            .to(preMatchRequestFilteringStage)
            .to(routingStage)
            .to(resourceFilteringStage)
            .build(routedInflectorExtractorStage);

    // Inject instances.
    for (Object instance : componentBag.getInstances(ComponentBag.EXCLUDE_META_PROVIDERS)) {
      locator.inject(instance);
    }
    for (Object instance : resourceBag.instances) {
      locator.inject(instance);
    }

    // initiate resource model into JerseyResourceContext
    JerseyResourceContext jerseyResourceContext = locator.getService(JerseyResourceContext.class);
    jerseyResourceContext.setResourceModel(resourceModel);

    this.runtime = locator.createAndInitialize(ServerRuntime.Builder.class).build(rootStage);

    // inject self
    locator.inject(this);
  }