/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.bindings;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.whole.lang.iterators.IEntityIterator;
import org.whole.lang.model.EnumValue;
import org.whole.lang.model.IEntity;
import org.whole.lang.operations.ICloneContext;
/**
* @author Riccardo Solmi
*/
public class EarlyTransactionScope extends AbstractDelegatingScope implements ITransactionScope {
private static final IEntity UNDEF_VALUE = BindingManagerFactory.instance.createValue((Object) null);
protected Map<String, IEntity> map;
public static enum CachedResult { NONE, VALUE, ITERATOR };
protected CachedResult cachedResult = CachedResult.NONE;
protected IEntity result = null;
protected IEntityIterator<?> resultIterator = null;
protected EarlyTransactionScope() {
this(new HashMap<String, IEntity>());
}
protected EarlyTransactionScope(Map<String, IEntity> map) {
super(NullScope.instance);
this.map = map;
}
@Override
public IBindingScope clone(ICloneContext cc) {
EarlyTransactionScope scope = (EarlyTransactionScope) super.clone(cc);
scope.map = new HashMap<String, IEntity>(map);
return scope;
}
public Kind getKind() {
return Kind.OUTER_SCOPE_ADAPTER;
}
public IBindingScope wTargetScope() {
return this;
}
public final IBindingScope wEnclosingScope() {
return wDelegateScope();
}
public final ITransactionScope wWithEnclosingScope(IBindingScope enclosingScope) {
wSetDelegateScope(enclosingScope);
return this;
}
public boolean isChanged() {
return !map.isEmpty() || cachedResult != CachedResult.NONE;
}
public void commit() {
map.clear();
cachedResult = CachedResult.NONE;
result = null;
resultIterator = null;
}
public void rollback() {
for (Entry<String, IEntity> entry : map.entrySet()) {
final String name = entry.getKey();
final IEntity value = entry.getValue();
if (value == UNDEF_VALUE)
super.wUnset(name);
else if (super.wIsSet(name))
super.wSet(name, value);
else
super.wDef(name, value);
}
if (cachedResult == CachedResult.VALUE)
super.setResult(result);
else if (cachedResult == CachedResult.ITERATOR)
super.setResultIterator(resultIterator);
map.clear();
cachedResult = CachedResult.NONE;
result = null;
resultIterator = null;
}
private void updateMap(String name) {
if (!map.containsKey(name)) {
//TODO
// IBindingScope scope = wFindScope(name);
// IEntity value = scope.wGet(name);
IEntity value = super.wGet(name);
map.put(name, value != null ? value : UNDEF_VALUE);
}
}
@Override
public void wAddAll(IBindingScope scope) {
if (scope == NullScope.instance)
return;
Set<String> names = scope.wEnclosingScope() == this ?
scope.wLocalNames() :
scope.wNames();
for (String name : names)
updateMap(name);
super.wAddAll(scope);
}
public void wClear() {
for (String name : super.wLocalNames())
updateMap(name);
super.wClear();
}
public void wUnset(String name) {
updateMap(name);
super.wUnset(name);
}
public void wSet(String name, IEntity value) {
updateMap(name);
super.wSet(name, value);
}
public void wDef(String name, IEntity value) {
updateMap(name);
super.wDef(name, value);
}
public void wSetValue(String name, boolean value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, byte value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, char value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, Date value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, double value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, EnumValue value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, float value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, int value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, long value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, Object value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, short value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wSetValue(String name, String value) {
updateMap(name);
super.wSetValue(name, value);
}
public void wDefValue(String name, boolean value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, byte value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, char value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, Date value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, double value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, EnumValue value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, float value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, int value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, long value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, Object value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, short value) {
updateMap(name);
super.wDefValue(name, value);
}
public void wDefValue(String name, String value) {
updateMap(name);
super.wDefValue(name, value);
}
@Override
public void wSetResultScope(IBindingScope scope) {
super.wSetResultScope(scope != this ? scope : scope.wEnclosingScope());
}
public void setResultIterator(IEntityIterator<?> resultIterator) {
cacheResult();
super.setResultIterator(resultIterator);
}
public void setResult(IEntity value) {
cacheResult();
super.setResult(value);
}
protected void cacheResult() {
if (cachedResult == CachedResult.NONE) {
if (super.hasResultIterator()) {
cachedResult = CachedResult.ITERATOR;
this.result = null;
this.resultIterator = super.getResultIterator();
} else {
cachedResult = CachedResult.VALUE;
this.result = super.getResult();
this.resultIterator = null;
}
}
}
public String toString() {
SortedSet<String> treeSet = new TreeSet<String>(map.keySet());
StringBuilder sb = new StringBuilder();
sb.append("--- begin resettable scope ---\n");
sb.append("--- changed names: ");
sb.append(treeSet);
sb.append('\n');
sb.append(super.toString());
sb.append("--- end resettable scope -----\n");
return sb.toString();
}
}