private DatastoreServiceConfig createDatastoreServiceConfigPrototype( PersistenceConfiguration persistenceConfiguration, String... timeoutProps) { DatastoreServiceConfig datastoreServiceConfig = DatastoreServiceConfig.Builder.withDefaults(); for (String timeoutProp : timeoutProps) { int defaultDeadline = persistenceConfiguration.getIntProperty(timeoutProp); if (defaultDeadline > 0) { datastoreServiceConfig.deadline(defaultDeadline / 1000d); } } String defaultReadConsistencyStr = persistenceConfiguration.getStringProperty(DATASTORE_READ_CONSISTENCY_PROPERTY); if (defaultReadConsistencyStr != null) { try { datastoreServiceConfig.readPolicy( new ReadPolicy(Consistency.valueOf(defaultReadConsistencyStr))); } catch (IllegalArgumentException iae) { throw new NucleusFatalUserException( "Illegal value for " + DATASTORE_READ_CONSISTENCY_PROPERTY + ". Valid values are " + Arrays.toString(Consistency.values())); } } return datastoreServiceConfig; }
/** * 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()); }
/** * Method to apply any restrictions to the created ResultSet. * * @param ps The PreparedStatement * @param query The query * @param applyTimeout Whether to apply the query timeout (if any) direct to the PreparedStatement * @throws SQLException Thrown when an error occurs applying the constraints */ public static void prepareStatementForExecution( PreparedStatement ps, Query query, boolean applyTimeout) throws SQLException { NucleusContext nucleusCtx = query.getExecutionContext().getNucleusContext(); RDBMSStoreManager storeMgr = (RDBMSStoreManager) query.getStoreManager(); PersistenceConfiguration conf = nucleusCtx.getPersistenceConfiguration(); if (applyTimeout) { Integer timeout = query.getDatastoreReadTimeoutMillis(); if (timeout != null && timeout > 0) { ps.setQueryTimeout(timeout / 1000); } } // Apply any fetch size int fetchSize = 0; if (query.getFetchPlan().getFetchSize() > 0) { // FetchPlan has a size set so use that fetchSize = query.getFetchPlan().getFetchSize(); } if (storeMgr.getDatastoreAdapter().supportsQueryFetchSize(fetchSize)) { ps.setFetchSize(fetchSize); } // Apply any fetch direction String fetchDir = conf.getStringProperty(RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_FETCH_DIRECTION); Object fetchDirExt = query.getExtension(RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_FETCH_DIRECTION); if (fetchDirExt != null) { fetchDir = (String) fetchDirExt; if (!fetchDir.equals("forward") && !fetchDir.equals("reverse") && !fetchDir.equals("unknown")) { throw new NucleusUserException(LOCALISER.msg("052512")); } } if (fetchDir.equals("reverse")) { ps.setFetchDirection(ResultSet.FETCH_REVERSE); } else if (fetchDir.equals("unknown")) { ps.setFetchDirection(ResultSet.FETCH_UNKNOWN); } // Add a limit on the number of rows to include the maximum we may need long toExclNo = query.getRangeToExcl(); if (toExclNo != 0 && toExclNo != Long.MAX_VALUE) { if (toExclNo > Integer.MAX_VALUE) { // setMaxRows takes an int as input so limit to the correct range ps.setMaxRows(Integer.MAX_VALUE); } else { ps.setMaxRows((int) toExclNo); } } }
@SuppressWarnings("deprecation") private TransactionOptions createDatastoreTransactionOptionsPrototype( PersistenceConfiguration persistenceConfig) { // return TransactionOptions.Builder.withXG( return TransactionOptions.Builder.allowMultipleEntityGroups( persistenceConfig.getBooleanProperty(DATASTORE_ENABLE_XG_TXNS_PROPERTY)); }