/*
* Copyright 2009-2016 Tilmann Zaeschke. All rights reserved.
*
* This file is part of ZooDB.
*
* ZooDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZooDB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZooDB. If not, see <http://www.gnu.org/licenses/>.
*
* See the README and COPYING files for further information.
*/
package org.zoodb.internal.client;
import org.zoodb.internal.Node;
import org.zoodb.internal.ZooClassDef;
import org.zoodb.internal.ZooClassProxy;
import org.zoodb.internal.ZooFieldDef;
import org.zoodb.internal.client.session.ClientSessionCache;
/**
* Super class for schema and index operations.
*
* This is important for example for creating indices, which we should do only during commit,
* instead of as soon as the index creation method is called by the user. Therefore we need special
* messages that can be sent to the storage engine.
* To get this working even if the schema itself is not committed yet, schema creation and deletion
* has to become an operation as well.
* These messages also need to be ordered, which is another reason why they cannot be treated
* as normal objects.
*
* However schemata are objects, so they get also treated by the normal commit procedure, so we
* have to take care that we don't interfere with normal commit when we execute these schema
* operations.
*
* Finally, we need to perform all operations before objects are committed to ensure that the
* required schemata are already present in the database.
*
* TODO If we implement this for adding/removing schema as well, we should treat them even more
* like normal objects in the commit-procedure, no special treatment should be necessary anymore.
*
* @author Tilmann Zaeschke
*
*/
public abstract class SchemaOperation {
protected final Node node;
private SchemaOperation(Node node) {
this.node = node;
}
abstract void initial();
abstract void commit();
abstract void rollback();
/**
* Operation to create an index.
*/
public static class IndexCreate extends SchemaOperation {
private final ZooFieldDef field;
private final boolean isUnique;
public IndexCreate(ZooFieldDef field, boolean isUnique) {
super(field.getDeclaringType().jdoZooGetNode());
this.field = field;
this.isUnique = isUnique;
initial();
}
@Override
void initial() {
field.setIndexed(true);
field.setUnique(isUnique);
ZooClassDef def = field.getDeclaringType();
def.getProvidedContext().getIndexer().refreshWithSchema(def);
}
@Override
void commit() {
node.defineIndex(field.getDeclaringType(), field, isUnique);
}
@Override
void rollback() {
field.setIndexed(false);
ZooClassDef def = field.getDeclaringType();
def.getProvidedContext().getIndexer().refreshWithSchema(def);
}
}
/**
* Operation to remove an index.
*/
public static class IndexRemove extends SchemaOperation {
private final ZooFieldDef field;
private final boolean isUnique;
public IndexRemove(ZooFieldDef field) {
super(field.getDeclaringType().jdoZooGetNode());
this.field = field;
this.isUnique = field.isIndexUnique();
initial();
}
@Override
void initial() {
field.setIndexed(false);
ZooClassDef def = field.getDeclaringType();
def.getProvidedContext().getIndexer().refreshWithSchema(def);
}
@Override
void commit() {
node.removeIndex(field.getDeclaringType(), field);
}
@Override
void rollback() {
field.setIndexed(true);
field.setUnique(isUnique);
ZooClassDef def = field.getDeclaringType();
def.getProvidedContext().getIndexer().refreshWithSchema(def);
}
}
public static class DropInstances extends SchemaOperation {
private final ZooClassProxy def;
public DropInstances(ZooClassProxy def) {
super(def.getSchemaDef().jdoZooGetNode());
this.def = def;
initial();
}
@Override
void initial() {
// Nothing to do
}
@Override
void commit() {
node.dropInstances(def);
}
@Override
void rollback() {
// Nothing to do
}
}
public static class SchemaDefine extends SchemaOperation {
private final ZooClassDef def;
public SchemaDefine(ZooClassDef def) {
super(def.jdoZooGetNode());
this.def = def;
initial();
}
@Override
void initial() {
//Nothing to do?
}
@Override
void commit() {
node.defineSchema(def);
}
@Override
void rollback() {
def.getVersionProxy().socRemoveDef();
def.getVersionProxy().invalidate();
}
}
public static class SchemaRename extends SchemaOperation {
private final ZooClassDef def;
private final String newName;
private final String oldName;
private final ClientSessionCache cache;
public SchemaRename(ClientSessionCache cache, ZooClassDef def, String newName) {
super(def.jdoZooGetNode());
this.def = def;
this.newName = newName;
this.oldName = def.getClassName();
this.cache = cache;
initial();
}
@Override
void initial() {
Class<?> oldCls = def.getJavaClass();
def.rename(newName);
cache.updateSchema(def, oldCls, def.getJavaClass());
}
@Override
void commit() {
def.getProvidedContext().getNode().renameSchema(def, newName);
}
@Override
void rollback() {
Class<?> oldCls = def.getJavaClass();
def.rename(oldName);
cache.updateSchema(def, oldCls, def.getJavaClass());
}
}
public static class SchemaDelete extends SchemaOperation {
private final ZooClassProxy def;
public SchemaDelete(ZooClassProxy def) {
super(def.getSchemaDef().jdoZooGetNode());
this.def = def;
initial();
}
@Override
void initial() {
def.socRemoveDef();
}
@Override
void commit() {
node.undefineSchema(def);
}
@Override
void rollback() {
def.socRemoveDefRollback();
}
}
public static class SchemaFieldDefine extends SchemaOperation {
private final ZooClassDef cls;
private final ZooFieldDef field;
public SchemaFieldDefine(ZooClassDef cls, ZooFieldDef field) {
super(cls.jdoZooGetNode());
this.cls = cls;
this.field = field;
initial();
}
@Override
void initial() {
//TODO roll back to previous version instance???
cls.addField(field);
}
@Override
void commit() {
//nothing to do?
}
@Override
void rollback() {
cls.removeField(field);
field.getProxy().invalidate();
}
public ZooFieldDef getField() {
return field;
}
}
public static class SchemaFieldRename extends SchemaOperation {
private final ZooFieldDef field;
private final String newName;
private final String oldName;
public SchemaFieldRename(ZooFieldDef field, String newName) {
super(field.getDeclaringType().jdoZooGetNode());
this.field = field;
this.newName = newName;
this.oldName = field.getName();
initial();
}
@Override
void initial() {
field.updateName(newName);
}
@Override
void commit() {
//nothing to do?
}
@Override
void rollback() {
field.updateName(oldName);
}
}
public static class SchemaFieldDelete extends SchemaOperation {
private final ZooClassDef cls;
private final ZooFieldDef field;
public SchemaFieldDelete(ZooClassDef cls, ZooFieldDef field) {
super(cls.jdoZooGetNode());
this.cls = cls;
this.field = field;
initial();
}
@Override
void initial() {
cls.removeField(field);
}
@Override
void commit() {
// nothing to do?
}
@Override
void rollback() {
//TODO roll back to old version???
cls.addField(field);
}
public ZooFieldDef getField() {
return field;
}
}
/**
* This operation creates a new version in the schema version tree.
*/
public static class SchemaNewVersion extends SchemaOperation {
private final ZooClassDef defOld;
private final ZooClassDef defNew;
private final ClientSessionCache cache;
public SchemaNewVersion(ZooClassDef defOld, ZooClassDef defNew, ClientSessionCache cache) {
super(defOld.getProvidedContext().getNode());
this.defOld = defOld;
this.defNew = defNew;
this.cache = cache;
initial();
}
@Override
void initial() {
// nothing to do?
}
@Override
void commit() {
node.newSchemaVersion(defNew);
}
@Override
void rollback() {
defOld.newVersionRollback(defNew, cache);
}
}
}