blob: 414e297bfab97c7845c25495628ebed3a770cbf9 [file] [log] [blame]
// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gwtorm.nosql;
import com.google.gwtorm.client.KeyUtil;
import com.google.gwtorm.schema.RelationModel;
import com.google.gwtorm.schema.SchemaModel;
import com.google.gwtorm.schema.java.JavaSchemaModel;
import com.google.gwtorm.server.GeneratedClassLoader;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.Schema;
import com.google.gwtorm.server.SchemaConstructorGen;
import com.google.gwtorm.server.SchemaFactory;
import com.google.gwtorm.server.SchemaGen;
import com.google.gwtorm.server.StandardKeyEncoder;
/**
* Base class for NoSQL typed databases.
*
* <p>Applications should use the database class to create instances of their Schema extension
* interface, and thus open and connect to the data store.
*
* <p>Creating a new database instance is expensive, due to the type analysis and code generation
* performed to implement the Schema and Access interfaces. Applications should create and cache
* their database instance for the life of the application.
*
* <p>Database instances are thread-safe, but returned Schema instances are not.
*
* <p>This class must be further extended by the NoSQL implementation to configure the connectivity
* with the data store and supply the correct subclass of {@link NoSqlSchema} that knows how to
* interact with the data store.
*
* @param <T> type of the application's Schema.
* @param <S> type of the implementation's base for Schema implementations.
* @param <A> type of the implementation's base for Access implementations.
*/
@SuppressWarnings("rawtypes")
public abstract class NoSqlDatabase<T extends Schema, S extends NoSqlSchema, A extends NoSqlAccess>
implements SchemaFactory<T> {
static {
KeyUtil.setEncoderImpl(new StandardKeyEncoder());
}
private final SchemaModel schemaModel;
private final SchemaFactory<T> implFactory;
/**
* Initialize a new database and generate the implementation.
*
* @param schemaBaseType class that the generated Schema implementation should extend in order to
* provide data store connectivity.
* @param accessBaseType class that the generated Access implementations should extend in order to
* provide single-relation access for each schema instance.
* @param appSchema the application schema interface that must be implemented and constructed on
* demand.
* @throws OrmException the schema cannot be created because of an annotation error in the
* interface definitions.
*/
protected NoSqlDatabase(
final Class<S> schemaBaseType, final Class<A> accessBaseType, final Class<T> appSchema)
throws OrmException {
schemaModel = new JavaSchemaModel(appSchema);
final GeneratedClassLoader loader = newLoader(appSchema);
final Class<T> impl = generate(schemaBaseType, accessBaseType, loader);
implFactory = new SchemaConstructorGen<>(loader, impl, this).create();
}
@Override
public T open() throws OrmException {
return implFactory.open();
}
/** @return the derived model of the application's schema. */
public SchemaModel getSchemaModel() {
return schemaModel;
}
@SuppressWarnings("unchecked")
private Class<T> generate(
final Class<S> schemaBaseType,
final Class<A> accessBaseType,
final GeneratedClassLoader loader)
throws OrmException {
return new SchemaGen(
loader,
schemaModel,
getClass(),
schemaBaseType,
new SchemaGen.AccessGenerator() {
@Override
public Class<?> create(GeneratedClassLoader loader, RelationModel rm)
throws OrmException {
return new AccessGen(loader, rm, schemaBaseType, accessBaseType).create();
}
})
.create();
}
private static <T> GeneratedClassLoader newLoader(final Class<T> schema) {
return new GeneratedClassLoader(schema.getClassLoader());
}
}