code: package it.unibz.inf.ontop.injection.impl;
  
  import com.google.inject.Module;
  import it.unibz.inf.ontop.exception.InvalidOntopConfigurationException;
  import it.unibz.inf.ontop.injection.OntopReformulationSQLConfiguration;
  import it.unibz.inf.ontop.injection.OntopReformulationSQLSettings;
  import it.unibz.inf.ontop.injection.impl.OntopSQLCoreConfigurationImpl.DefaultOntopSQLCoreBuilderFragment;
  import it.unibz.inf.ontop.injection.impl.OntopSQLCoreConfigurationImpl.OntopSQLCoreOptions;
  
  import javax.annotation.Nonnull;
  import java.util.Properties;
  import java.util.stream.Stream;
  import java.io.File;
  
  public class OntopReformulationSQLConfigurationImpl extends OntopReformulationConfigurationImpl
          implements OntopReformulationSQLConfiguration {
  
      private final OntopReformulationSQLSettings settings;
      private final OntopSQLCoreConfigurationImpl sqlConfiguration;
  
      OntopReformulationSQLConfigurationImpl(OntopReformulationSQLSettings settings,
                                             OntopReformulationSQLOptions options,
                                             SpecificationLoader specificationLoader) {
          super(settings, options.reformulationOptions, specificationLoader);
          this.settings = settings;
          this.sqlConfiguration = new OntopSQLCoreConfigurationImpl(settings, options.sqlOptions);
      }
  
      /**
       * Assumes the OBDA specification to be already assigned
       */
      OntopReformulationSQLConfigurationImpl(OntopReformulationSQLSettings settings,
                                             OntopReformulationSQLOptions options) {
          super(settings, options.reformulationOptions);
          this.settings = settings;
          this.sqlConfiguration = new OntopSQLCoreConfigurationImpl(settings, options.sqlOptions);
      }
  
      @Override
      public OntopReformulationSQLSettings getSettings() {
          return settings;
      }
  
      @Override
      protected Stream<Module> buildGuiceModules() {
          return Stream.concat(
                  Stream.concat(
                          super.buildGuiceModules(),
                          sqlConfiguration.buildGuiceModules()),
                  Stream.of(new OntopReformulationSQLModule(this),
                          new OntopReformulationPostModule(getSettings())));
      }
  
      static class OntopReformulationSQLOptions {
  
          final OntopReformulationOptions reformulationOptions;
          final OntopSQLCoreOptions sqlOptions;
  
          private OntopReformulationSQLOptions(OntopReformulationOptions reformulationOptions, OntopSQLCoreOptions sqlOptions) {
              this.reformulationOptions = reformulationOptions;
              this.sqlOptions = sqlOptions;
          }
      }
  
      static class DefaultOntopReformulationSQLBuilderFragment<B extends OntopReformulationSQLConfiguration.Builder<B>>
          implements OntopReformulationSQLBuilderFragment<B> {
  
          private final B builder;
  
          DefaultOntopReformulationSQLBuilderFragment(B builder) {
              this.builder = builder;
          }
  
          OntopReformulationSQLOptions generateSQLReformulationOptions(OntopReformulationOptions qaOptions,
                                                                       OntopSQLCoreOptions sqlOptions) {
              return new OntopReformulationSQLOptions(qaOptions, sqlOptions);
          }
  
          Properties generateProperties() {
              return new Properties();
          }
      }
  
      static abstract class OntopReformulationSQLBuilderMixin<B extends OntopReformulationSQLConfiguration.Builder<B>>
              extends OntopReformulationBuilderMixin<B>
              implements OntopReformulationSQLConfiguration.Builder<B> {
  
          private final DefaultOntopReformulationSQLBuilderFragment<B> localBuilderFragment;
          private final DefaultOntopSQLCoreBuilderFragment<B> sqlBuilderFragment;
          private final DefaultOntopModelBuilderFragment<B> modelBuilderFragment;
  
          OntopReformulationSQLBuilderMixin() {
              B builder = (B) this;
              localBuilderFragment = new DefaultOntopReformulationSQLBuilderFragment<>(builder);
              sqlBuilderFragment = new DefaultOntopSQLCoreBuilderFragment<>(builder);
              modelBuilderFragment = new DefaultOntopModelBuilderFragment<>(builder);
          }
  
          @Override
          protected Properties generateProperties() {
              Properties properties = super.generateProperties();
              properties.putAll(modelBuilderFragment.generateProperties());
              properties.putAll(sqlBuilderFragment.generateProperties());
              properties.putAll(localBuilderFragment.generateProperties());
              return properties;
          }
  
          OntopReformulationSQLOptions generateSQLReformulationOptions() {
              OntopReformulationOptions reformulationOptions = generateReformulationOptions();
              OntopSQLCoreOptions sqlOptions = sqlBuilderFragment.generateSQLCoreOptions(
                      reformulationOptions.queryOptions.obdaOptions.modelOptions);
  
              return new OntopReformulationSQLOptions(reformulationOptions, sqlOptions);
          }
  
          @Override
          public B jdbcUrl(String jdbcUrl) {
              return sqlBuilderFragment.jdbcUrl(jdbcUrl);
          }
  
          @Override
          public B jdbcDriver(String jdbcDriver) {
              return sqlBuilderFragment.jdbcDriver(jdbcDriver);
          }
  
          @Override
          public B properties(@Nonnull Properties properties) {
              return modelBuilderFragment.properties(properties);
          }
  
          @Override
          public B propertyFile(String propertyFilePath) {
              return modelBuilderFragment.propertyFile(propertyFilePath);
          }
  
          @Override
          public B propertyFile(File propertyFile) {
              return modelBuilderFragment.propertyFile(propertyFile);
          }
  
          @Override
          public B enableTestMode() {
              return modelBuilderFragment.enableTestMode();
          }
      }
  
      /**
       * Requires the OBDA specification to be already assigned
       */
      public static class BuilderImpl<B extends OntopReformulationSQLConfiguration.Builder<B>>
          extends OntopReformulationSQLBuilderMixin<B> {
  
          @Override
          public OntopReformulationSQLConfiguration build() {
              if (!isOBDASpecificationAssigned())
                  throw new InvalidOntopConfigurationException("An OBDA specification must be assigned " +
                          "to directly instantiate such a OntopReformulationSQLConfiguration");
  
              OntopReformulationSQLSettings settings = new OntopReformulationSQLSettingsImpl(generateProperties());
              OntopReformulationSQLOptions options = generateSQLReformulationOptions();
              return new OntopReformulationSQLConfigurationImpl(settings, options);
          }
      }
  
  }
  