blob: 927df3235a34a46433b0f9de82dd88016e3d85f4 [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());
}
}