/*
* Copyright 2011 Future Systems
*
* 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 org.krakenapps.dom.api;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.krakenapps.confdb.Config;
import org.krakenapps.confdb.ConfigDatabase;
import org.krakenapps.confdb.ConfigTransaction;
public class Transaction {
private static final boolean CHECK_CONFLICT = false;
private static Map<ConfigTransaction, Transaction> xacts = new HashMap<ConfigTransaction, Transaction>();
private String domain;
private ConfigDatabase db;
private ConfigTransaction xact;
private List<Log> logs = new ArrayList<Log>();
private Map<Class<?>, DefaultEntityEventProvider<?>> eventProviders = new HashMap<Class<?>, DefaultEntityEventProvider<?>>();
public static Transaction getInstance(ConfigTransaction xact) {
return xacts.get(xact);
}
public Transaction(String domain, ConfigDatabase db) {
this.domain = domain;
this.db = db;
this.xact = db.beginTransaction();
xacts.put(this.xact, this);
}
public ConfigDatabase getConfigDatabase() {
return xact.getDatabase();
}
public ConfigTransaction getConfigTransaction() {
return xact;
}
public void add(Object doc) {
add(doc, null);
}
public void add(Object doc, Object state) {
db.add(xact, doc);
logs.add(new Log(Log.Operation.Add, doc, state));
}
public void update(Config c, Object doc) {
update(c, doc, CHECK_CONFLICT, null);
}
public void update(Config c, Object doc, boolean checkConflict) {
update(c, doc, checkConflict, null);
}
public void update(Config c, Object doc, Object state) {
update(c, doc, CHECK_CONFLICT, state);
}
public void update(Config c, Object doc, boolean checkConflict, Object state) {
db.update(xact, c, doc, checkConflict);
logs.add(new Log(Log.Operation.Update, doc, state));
}
public void remove(Config c, Object doc) {
remove(c, doc, CHECK_CONFLICT, null);
}
public void remove(Config c, Object doc, boolean checkConflict) {
remove(c, doc, checkConflict, null);
}
public void remove(Config c, Object doc, Object removingState, Object removedState) {
remove(c, doc, CHECK_CONFLICT, removingState, removedState);
}
@SuppressWarnings("unchecked")
public void remove(Config c, Object doc, boolean checkConflict, Object removingState, Object removedState) {
DefaultEntityEventProvider<Object> provider = (DefaultEntityEventProvider<Object>) eventProviders.get(doc.getClass());
if (provider != null)
provider.fireEntityRemoving(domain, doc, xact, removingState);
db.remove(xact, c, checkConflict);
logs.add(new Log(Log.Operation.Remove, doc, removedState));
}
public void removePreChecked(Config c, Object doc, boolean checkConflict, Object removedState) {
db.remove(xact, c, checkConflict);
logs.add(new Log(Log.Operation.Remove, doc, removedState));
}
@SuppressWarnings("unchecked")
public void commit(String committer, String log) {
xact.commit(committer, log);
Map<Class<?>, List<EntityState>> addedMap = new HashMap<Class<?>, List<EntityState>>();
Map<Class<?>, List<EntityState>> updatedMap = new HashMap<Class<?>, List<EntityState>>();
Map<Class<?>, List<EntityState>> removedMap = new HashMap<Class<?>, List<EntityState>>();
for (Log l : logs) {
Class<?> clazz = l.obj.getClass();
DefaultEntityEventProvider<Object> provider = (DefaultEntityEventProvider<Object>) eventProviders.get(clazz);
if (provider == null)
continue;
if (l.op == Log.Operation.Add) {
List<EntityState> logs = addedMap.get(clazz);
if (logs == null) {
logs = new LinkedList<EntityState>();
addedMap.put(clazz, logs);
}
logs.add(new EntityState(l.obj, l.state));
} else if (l.op == Log.Operation.Update) {
List<EntityState> logs = updatedMap.get(clazz);
if (logs == null) {
logs = new LinkedList<EntityState>();
updatedMap.put(clazz, logs);
}
logs.add(new EntityState(l.obj, l.state));
} else if (l.op == Log.Operation.Remove) {
List<EntityState> logs = removedMap.get(clazz);
if (logs == null) {
logs = new LinkedList<EntityState>();
removedMap.put(clazz, logs);
}
logs.add(new EntityState(l.obj, l.state));
}
}
for (Class<?> key : addedMap.keySet()) {
DefaultEntityEventProvider<Object> provider = (DefaultEntityEventProvider<Object>) eventProviders.get(key);
provider.fireEntitiesAdded(domain, addedMap.get(key));
}
for (Class<?> key : updatedMap.keySet()) {
DefaultEntityEventProvider<Object> provider = (DefaultEntityEventProvider<Object>) eventProviders.get(key);
provider.fireEntitiesUpdated(domain, updatedMap.get(key));
}
for (Class<?> key : removedMap.keySet()) {
DefaultEntityEventProvider<Object> provider = (DefaultEntityEventProvider<Object>) eventProviders.get(key);
provider.fireEntitiesRemoved(domain, removedMap.get(key));
}
xacts.remove(this.xact);
}
public <T> void checkRemovability(Class<T> cls, Collection<EntityState> entities) {
@SuppressWarnings("unchecked")
DefaultEntityEventProvider<Object> provider = (DefaultEntityEventProvider<Object>) eventProviders.get(cls);
if (provider != null)
provider.fireEntitiesRemoving(domain, entities, xact);
}
public <T> void checkAddability(Class<T> cls, EntityState entity) {
@SuppressWarnings("unchecked")
DefaultEntityEventProvider<Object> provider = (DefaultEntityEventProvider<Object>) eventProviders.get(cls);
if (provider != null)
provider.fireEntityAdding(domain, entity.entity);
}
public <T> void checkAddability(Class<T> cls, Collection<EntityState> entities) {
@SuppressWarnings("unchecked")
DefaultEntityEventProvider<Object> provider = (DefaultEntityEventProvider<Object>) eventProviders.get(cls);
if (provider != null)
provider.fireEntitiesAdding(domain, entities);
}
public void rollback() {
xact.rollback();
xacts.remove(this.xact);
}
public <T> void addEventProvider(Class<T> cls, DefaultEntityEventProvider<T> provider) {
eventProviders.put(cls, provider);
}
public DefaultEntityEventProvider<?> getEventProvider(Class<?> cls) {
return eventProviders.get(cls);
}
public void removeEventProvider(Class<?> cls) {
eventProviders.remove(cls);
}
public String getDomain() {
return domain;
}
private static class Log {
private static enum Operation {
Add, Update, Remove
}
private Operation op;
private Object obj;
private Object state;
private Log(Operation op, Object obj, Object state) {
if (op == null || obj == null)
throw new NullPointerException();
this.op = op;
this.obj = obj;
this.state = state;
}
}
}