/**
* 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.lang.reflect.Constructor;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.whole.lang.commons.factories.CommonsEntityFactory;
import org.whole.lang.exceptions.WholeIllegalArgumentException;
import org.whole.lang.factories.GenericEntityFactory;
import org.whole.lang.factories.IEntityFactory;
import org.whole.lang.iterators.IEntityIterator;
import org.whole.lang.iterators.IteratorFactory;
import org.whole.lang.matchers.Matcher;
import org.whole.lang.model.EnumValue;
import org.whole.lang.model.IEntity;
import org.whole.lang.operations.IOperation;
import org.whole.lang.reflect.DataKinds;
import org.whole.lang.reflect.EntityDescriptor;
import org.whole.lang.reflect.EntityDescriptorEnum;
import org.whole.lang.reflect.FeatureDescriptorEnum;
import org.whole.lang.reflect.ReflectionFactory;
import org.whole.lang.util.BehaviorUtils;
import org.whole.lang.util.DataTypeUtils;
import org.whole.lang.util.EntityUtils;
import org.whole.lang.util.WholeMessages;
import org.whole.lang.visitors.MissingVariableException;
/**
* @author Riccardo Solmi
*/
public class BindingManagerFactory {
public static BindingManagerFactory instance = new BindingManagerFactory();
private BindingManagerFactory() {
}
private EntityDescriptorEnum edEnum;
private EntityDescriptorEnum getEdEnum() {
if (edEnum == null)
edEnum = EntityUtils.getEnvironmentLanguageKit().getEntityDescriptorEnum();
return edEnum;
}
private FeatureDescriptorEnum fdEnum;
private FeatureDescriptorEnum getFdEnum() {
if (fdEnum == null)
fdEnum = EntityUtils.getEnvironmentLanguageKit().getFeatureDescriptorEnum();
return fdEnum;
}
private EntityDescriptor<?> voidEd;
private EntityDescriptor<?> getVoidEd() {
if (voidEd == null)
voidEd = getEdEnum().valueOf("Void");
return voidEd;
}
public IEnvironmentManager createEnvironmentManager() {
return new EnvironmentManager();
}
public IBindingManager createArguments() {
IBindingManager args = createEnvironmentManager().createEnvironment("env");
args.wEnterScope();
return args;
}
public IBindingManager createBindingManager() {
IBindingManager args = createEnvironmentManager().createEnvironment("bm");
return args;
}
public IBindingManager createBindingManager(IBindingScope scope, IEnvironmentManager em) {
return new BindingManager(em, scope);
}
public IBindingScope createSimpleScope() {
return new SimpleScope();
}
public INestableScope createNestedScope(IBindingScope scope, boolean dynamic) {
return dynamic ? new NestedDynamicScope(scope) : new NestedStaticScope(scope);
}
//Same behavior of createNestedScope(createSimpleScope(), true)
public INestableScope createNestedDynamicSimpleScope() {
return new NestedDynamicSimpleScope();
}
public AbstractFilterScope createIncludeFilterScope(Set<String> names) {
return new IncludeFilterScope(names);
}
public AbstractFilterScope createIncludeReadOnlyFilterScope(Set<String> names) {
return new IncludeReadOnlyFilterScope(names);
}
public AbstractFilterScope createExcludeFilterScope(Set<String> names) {
return new ExcludeFilterScope(names);
}
public AbstractFilterScope createExcludeFilterSimpleScope() {
return createExcludeFilterScope(new HashSet<String>()).wWithEnclosingScope(createSimpleScope());
}
public ITransactionScope createTransactionScope() {
return new EarlyTransactionScope();
}
public IBindingScope createVoidScope() {
return VoidScope.instance;
}
public IBindingScope createEntityScope(IEntity entity) {
return new EntityScope(entity);
}
@SuppressWarnings("unchecked")
public IBindingScope createJavaBeanScope(Object bean) {
//workaround for Android compatibility
//was return new JavaBeanScope(bean);
try {
Class<IBindingScope> clazz = (Class<IBindingScope>) Class.forName("org.whole.lang.bindings.JavaBeanScope", true, ReflectionFactory.getPlatformClassLoader());
Constructor<IBindingScope> constructor = clazz.getConstructor(Object.class);
return constructor.newInstance(bean);
} catch (Exception e) {
throw new IllegalStateException("cannot istantiate a JavaBeanScope", e);
}
}
public RuntimeException createNoBindingException(String name) {
return new MissingVariableException("Binding is undefined: ", null, name);
}
public IEntity createValue(boolean value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("BooleanData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(byte value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("ByteData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(char value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("CharData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(double value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("DoubleData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(float value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("FloatData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(int value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("IntData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(long value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("LongData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(short value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("ShortData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(String value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("StringData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(Date value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("DateData"));
entity.wSetValue(value);
return entity;
}
public IEntity createValue(EnumValue value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("ObjectData")); //TODO ?
entity.wSetValue((Object) value);
return entity;
}
public IEntity createValue(Object value) {
IEntity entity = GenericEntityFactory.instance.create(
getEdEnum().valueOf("ObjectData"));
entity.wSetValue(value);
return entity;
}
public IEntity createSpecificValue(Object value) {
return createSpecificValue(value, DataTypeUtils.toUnboxedDataKind(value));
}
public IEntity createSpecificValue(Object value, DataKinds dataKind) {
switch (dataKind) {
case NOT_A_DATA:
throw new WholeIllegalArgumentException(WholeMessages.no_data);
case BOOLEAN:
return createValue(((Boolean) value).booleanValue());
case BYTE:
return createValue(((Byte) value).byteValue());
case CHAR:
return createValue(((Character) value).charValue());
case DOUBLE:
return createValue(((Double) value).doubleValue());
case FLOAT:
return createValue(((Float) value).floatValue());
case INT:
return createValue(((Integer) value).intValue());
case LONG:
return createValue(((Long) value).longValue());
case SHORT:
return createValue(((Short) value).shortValue());
case DATE:
return createValue((Date) value);
case ENUM_VALUE:
return createValue((EnumValue) value);
case STRING:
return createValue((String) value);
case OBJECT:
default:
return createValue(value);
}
}
public IEntity createSpecificValue(IEntity dataEntity) {
switch (DataTypeUtils.getDataKind(dataEntity)) {
case NOT_A_DATA:
throw new WholeIllegalArgumentException(WholeMessages.no_data);
case BOOLEAN:
return createValue(dataEntity.wBooleanValue());
case BYTE:
return createValue(dataEntity.wByteValue());
case CHAR:
return createValue(dataEntity.wCharValue());
case DOUBLE:
return createValue(dataEntity.wDoubleValue());
case FLOAT:
return createValue(dataEntity.wFloatValue());
case INT:
return createValue(dataEntity.wIntValue());
case LONG:
return createValue(dataEntity.wLongValue());
case SHORT:
return createValue(dataEntity.wShortValue());
case DATE:
return createValue(dataEntity.wDateValue());
case ENUM_VALUE:
return createValue(dataEntity.wEnumValue());
case STRING:
return createValue(dataEntity.wStringValue());
case OBJECT:
default:
return createValue(dataEntity.wGetValue());
}
}
public IEntity createTuple(boolean withContainment) {
IEntityFactory ef = GenericEntityFactory.instance;
return ef.create(getEdEnum().valueOf(withContainment ? "ContainmentTuple" : "Tuple"));
}
public IEntity createTuple() {
return createTuple(false);
}
public IEntity createTuple(boolean withContainment, IEntity... values) {
IEntityFactory ef = GenericEntityFactory.instance;
return ef.create(getEdEnum().valueOf(withContainment ? "ContainmentTuple" : "Tuple"), values);
}
public IEntity createTuple(IEntity... values) {
return createTuple(false, values);
}
public IEntity createVoid() {
return GenericEntityFactory.instance.create(
getVoidEd());
}
public boolean isVoid(IEntity entity) {
return Matcher.match(getVoidEd(), entity);
}
public <E extends IEntity> IEntityIterator<E> resultIteratorOf(E result) {
return result != null ?
IteratorFactory.constantIterator(result, false) :
IteratorFactory.emptyIterator();
}
public IEntity resultOf(IEntityIterator<?> resultIterator) {
IBindingManager riBindings = resultIterator.getBindings();
riBindings.setResultIterator(resultIterator);
return BehaviorUtils.evaluateResult(riBindings);
}
public IEntity createContextViewModel(IBindingManager bm, IBindingScope scope) {
IEntityFactory ef = GenericEntityFactory.instance;
return ef.create(getEdEnum().valueOf("ContextViewModel"),
ef.create(getEdEnum().valueOf("Environments")),
ef.create(getEdEnum().valueOf("Bindings")));
}
public IEntity createSampleViewModel(IEntity behavior, IEntity result) {
IEntityFactory ef = GenericEntityFactory.instance;
return ef.create(getEdEnum().valueOf("SampleViewModel"), behavior, result);
}
public IEntity createVariablesViewModel(IOperation operation, Set<String> includeNames) {
return createVariablesViewModel(operation.getOperationEnvironment(), includeNames);
}
public IEntity createVariablesViewModel(IBindingManager bm, Set<String> includeNames) {
IEntityFactory ef = GenericEntityFactory.instance;
IEntity environments = ef.create(getEdEnum().valueOf("Environments"));
environments.wAdd(createEnvironment(bm, "env", includeNames, createFlatBindingsModel(bm)));
return ef.create(getEdEnum().valueOf("VariablesViewModel"),
ef.create(getEdEnum().valueOf("EnvironmentManager"), (Object) bm.wGetEnvironmentManager()),
environments);
}
public IEntity createEnvironment(IBindingManager bm, String name, Set<String> includeNames, IEntity bindingsModel) {
IEntityFactory ef = GenericEntityFactory.instance;
return ef.create(getEdEnum().valueOf("Environment"),
ef.create(getEdEnum().valueOf("Name"), name),
createNames(includeNames),
ef.create(getEdEnum().valueOf("BindingManager"), (Object) bm),
bindingsModel);
}
public IEntity createNames(Set<String> includeNames) {
IEntityFactory ef = GenericEntityFactory.instance;
IEntity names = ef.create(getEdEnum().valueOf("Names"));
for (String name : includeNames)
names.wAdd(ef.create(getEdEnum().valueOf("Name"), name));
return names;
}
public IEntity createFlatScopedBindingsModel(IBindingManager bm) {
IEntityFactory ef = GenericEntityFactory.instance;
IEntity scopedBindings = ef.create(getEdEnum().valueOf("ScopedBindings"));
IBindingScope scope = bm;
Map<String, IEntity> bindingsMap = new TreeMap<String, IEntity>();
do {
for (String name : scope.wLocalNames()) {
IEntity value = scope.wGet(name);
if (value == null)
continue;
if (!bindingsMap.containsKey(name))
bindingsMap.put(name, value);
}
IEntity sourceEntity = scope.getSourceEntity();
if (sourceEntity != null || scope.wEnclosingScope() == NullScope.instance) {
int i=0;
for (Map.Entry<String, IEntity> entry : bindingsMap.entrySet())
scopedBindings.wAdd(i++, createBinding(entry.getKey(), entry.getValue()));
bindingsMap.clear();
scopedBindings.wAdd(0, ef.create(getEdEnum().valueOf("Scope"),
ef.create(getEdEnum().valueOf("BindingScope"), (Object) scope),
ef.create(getEdEnum().valueOf("Value"), (Object) scope.getSourceEntity())));
}
} while ((scope = scope.wEnclosingScope()) != NullScope.instance);
return scopedBindings;
}
public IEntity createFlatBindingsModel(IBindingManager bm) {
IEntityFactory ef = GenericEntityFactory.instance;
IEntity bindings = ef.create(getEdEnum().valueOf("Bindings"));
Set<String> names = bm.wNames();
for (String name : new TreeSet<String>(names))
bindings.wAdd(createBinding(name, bm.wGet(name)));
return bindings;
}
public IEntity createFlatBindingsModel(IOperation operation, Set<String> includeNames) {
return createFlatBindingsModel(operation.getOperationEnvironment(), includeNames);
}
public IEntity createFlatBindingsModel(IBindingManager bm, Set<String> includeNames) {
IEntityFactory ef = GenericEntityFactory.instance;
IEntity bindings = ef.create(getEdEnum().valueOf("Bindings"));
Set<String> names = bm.wNames();
for (String name : new TreeSet<String>(includeNames))
bindings.wAdd(createBinding(name, names.contains(name) ?
bm.wGet(name) : CommonsEntityFactory.instance.createResolver()));
return bindings;
}
public IEntity createBinding(String name, IEntity value) {
IEntityFactory ef = GenericEntityFactory.instance;
return ef.create(getEdEnum().valueOf("Binding"),
ef.create(getEdEnum().valueOf("Name"), name),
ef.create(getEdEnum().valueOf("Value"), (Object) value));
}
}