public void run() {
        validateState();
        performModelTransforms();

        List<I> integrations = findIntegrations();
        preprocessModelWithIntegrations(integrations);

        ServiceShape serviceShape = model.expectShape(service, ServiceShape.class);

        SymbolProvider provider = createSymbolProvider(integrations, serviceShape);

        C context = createContext(serviceShape, provider, integrations);

        // After the context is created, it holds the model that should be used for rest of codegen. So `model` should
        // not really be used directly after this point in the flow. Setting the `model` to `context.model()` to avoid
        // issues even if `model` gets used unknowingly.
        model = context.model();

        registerInterceptors(context, integrations);

        LOGGER.fine("All setup done. Beginning code generation");

        LOGGER.finest(() -> "Performing custom codegen for "
                + directedCodegen.getClass().getName() + " before shape codegen");
        CustomizeDirective<C, S> customizeDirective = new CustomizeDirective<>(context, serviceShape);
        directedCodegen.customizeBeforeShapeGeneration(customizeDirective);

        LOGGER.finest(() -> "Generating shapes for service " + serviceShape.getId());
        generateShapesInService(context, serviceShape);

        LOGGER.finest(() -> "Generating service " + serviceShape.getId());
        directedCodegen.generateService(new GenerateServiceDirective<>(context, serviceShape));

        LOGGER.finest(() -> "Performing custom codegen for "
                + directedCodegen.getClass().getName() + " before integrations");
        directedCodegen.customizeBeforeIntegrations(customizeDirective);

        applyIntegrationCustomizations(context, integrations);

        LOGGER.finest(() -> "Performing custom codegen for "
                + directedCodegen.getClass().getName() + " after integrations");
        directedCodegen.customizeAfterIntegrations(customizeDirective);

        LOGGER.finest(() -> "Directed codegen finished for " + directedCodegen.getClass().getName());

        if (!context.writerDelegator().getWriters().isEmpty()) {
            LOGGER.info(() -> "Flushing remaining writers of " + directedCodegen.getClass().getName());
            context.writerDelegator().flushWriters();
        }
    }
Finalizes the Runner and performs directed code generation.

@throws IllegalStateException if a required value has not been provided.
smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/directed/CodegenDirector.java