/**
   * Construct a DatastoreManager.
   *
   * @param clr The ClassLoaderResolver
   * @param nucContext The NucleusContext
   * @param props Properties to store on this StoreManager
   */
  public DatastoreManager(
      ClassLoaderResolver clr, NucleusContext nucContext, Map<String, Object> props)
      throws NoSuchFieldException, IllegalAccessException {
    super("appengine", clr, nucContext, props);

    // Override some of the default property values for AppEngine
    PersistenceConfiguration conf = nucContext.getPersistenceConfiguration();
    conf.setProperty(
        "datanucleus.attachSameDatastore", Boolean.TRUE.toString()); // Always only one datastore
    // We'd like to respect the user's selection here, but the default value is 1.
    // This is problematic for us in the situation where, for example, an embedded object
    // gets updated more than once in a txn because we end up putting the same entity twice.
    // TODO(maxr) Remove this once we support multiple puts
    conf.setProperty("datanucleus.datastoreTransactionFlushLimit", Integer.MAX_VALUE);
    // Install our key translator
    conf.setProperty("datanucleus.identityKeyTranslatorType", "appengine");

    // Check if datastore api is in CLASSPATH.  Don't let the hard-coded
    // jar name upset you, it's just used for error messages.  The check will
    // succeed so long as the class is available on the classpath
    ClassUtils.assertClassForJarExistsInClasspath(
        clr, "com.google.appengine.api.datastore.DatastoreService", "appengine-api.jar");

    defaultDatastoreServiceConfigPrototypeForReads =
        createDatastoreServiceConfigPrototypeForReads(nucContext.getPersistenceConfiguration());
    defaultDatastoreServiceConfigPrototypeForWrites =
        createDatastoreServiceConfigPrototypeForWrites(nucContext.getPersistenceConfiguration());
    defaultDatastoreTransactionOptionsPrototype =
        createDatastoreTransactionOptionsPrototype(nucContext.getPersistenceConfiguration());

    // Handler for persistence process
    persistenceHandler = new DatastorePersistenceHandler(this);
    flushProcess = new FlushOrdered();

    dba = new DatastoreAdapter();
    initialiseIdentifierFactory(nucContext);

    storageVersion = StorageVersion.fromStoreManager(this);

    String defaultRelationMode = getStringProperty(RELATION_DEFAULT_MODE);
    defaultToOwnedRelations = defaultRelationMode.equalsIgnoreCase("unowned") ? false : true;

    String bigDecimalsEncoding = getStringProperty(BIG_DECIMALS_ENCODEING);
    typeConversionUtils =
        "String".equalsIgnoreCase(bigDecimalsEncoding)
            ? new TypeConversionUtils(true)
            : new TypeConversionUtils(false);

    // Add listener so we can check all metadata for unsupported features and required schema
    metadataValidator = new MetaDataValidator(this, getMetaDataManager(), clr);

    logConfiguration();

    datastoreServiceForReads =
        DatastoreServiceFactoryInternal.getDatastoreService(
            getDefaultDatastoreServiceConfigForReads());
  }
  /** Convenience method to log the configuration of this store manager. */
  protected void logConfiguration() {
    super.logConfiguration();

    if (NucleusLogger.DATASTORE.isDebugEnabled()) {
      NucleusLogger.DATASTORE.debug("StorageVersion : " + storageVersion.toString());
      NucleusLogger.DATASTORE.debug(
          "Default Relation Mode : " + getStringProperty(RELATION_DEFAULT_MODE));
      NucleusLogger.DATASTORE.debug("===========================================================");
    }
  }
 public boolean storageVersionAtLeast(StorageVersion storageVersion) {
   return getStorageVersion().ordinal() >= storageVersion.ordinal();
 }