/**
* 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.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import org.whole.lang.commons.reflect.CommonsEntityDescriptorEnum;
import org.whole.lang.comparators.IEntityComparator;
import org.whole.lang.factories.GenericEntityFactory;
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.model.NullEntity;
import org.whole.lang.operations.CloneOperation;
import org.whole.lang.operations.RemoveOperation;
import org.whole.lang.reflect.EntityDescriptor;
import org.whole.lang.reflect.EntityDescriptorEnum;
import org.whole.lang.reflect.FeatureDescriptor;
import org.whole.lang.reflect.ILanguageKit;
import org.whole.lang.reflect.ReflectionFactory;
/**
* @author Riccardo Solmi
*/
public class EntityUtils {
public static final boolean isSimple(EntityDescriptor<?> ed) {
return ed.getEntityKind().isSimple();
}
public static final boolean isComposite(EntityDescriptor<?> ed) {
return ed.getEntityKind().isComposite();
}
public static final boolean isData(EntityDescriptor<?> ed) {
return ed.getEntityKind().isData();
}
public static final boolean isResolver(EntityDescriptor<?> ed) {
return CommonsEntityDescriptorEnum.Resolver.equals(ed);//WAS ed.getEntityKind().isResolver();
}
public static final boolean isVariable(EntityDescriptor<?> ed) {
return CommonsEntityDescriptorEnum.Variable.equals(ed) || isInlineVariable(ed);//WAS ed.getEntityKind().isVariable();
}
public static final boolean isInlineVariable(EntityDescriptor<?> ed) {
return CommonsEntityDescriptorEnum.InlineVariable.equals(ed);
}
public static final boolean isFragment(EntityDescriptor<?> ed) {
return isSameStageFragment(ed) || isStageDownFragment(ed) || isStageUpFragment(ed) ||
CommonsEntityDescriptorEnum.RootFragment.equals(ed);//WAS ed.getEntityKind().isFragment();
}
public static final boolean isSameStageFragment(EntityDescriptor<?> ed) {
return CommonsEntityDescriptorEnum.SameStageFragment.equals(ed);//WAS ed.getEntityKind().isSameStageFragment();
}
public static final boolean isStageDownFragment(EntityDescriptor<?> ed) {
return CommonsEntityDescriptorEnum.StageDownFragment.equals(ed);//WAS ed.getEntityKind().isStageDownFragment();
}
public static final boolean isStageUpFragment(EntityDescriptor<?> ed) {
return CommonsEntityDescriptorEnum.StageUpFragment.equals(ed);//WAS ed.getEntityKind().isStageUpFragment();
}
//FIXME before cleaning EntityKinds
// public static final boolean isImpl(EntityDescriptor<?> ed) {
// EntityKinds kind = ed.getEntityKind();
// return (kind.isSimple() || kind.isComposite() || kind.isData()) && !ed.isAbstract();
// }
public static final boolean isIncompleteClone(IEntity entity) {
for (int i=0; i<entity.wSize(); i++)
if (entity.wGet(i).wGetParent() != entity)
return true;
return false;
}
public static final boolean isNull(IEntity entity) {
return NullEntity.instance.equals(entity);
}
public static final boolean isSimple(IEntity entity) {
return entity.wGetEntityKind().isSimple();
}
public static final boolean isComposite(IEntity entity) {
return entity.wGetEntityKind().isComposite();
}
public static final boolean isData(IEntity entity) {
return entity.wGetEntityKind().isData();
}
public static final boolean isResolver(IEntity entity) {
return Matcher.matchImpl(CommonsEntityDescriptorEnum.Resolver, entity);
}
public static final boolean isVariable(IEntity entity) {
return Matcher.matchAnyImpl(entity,
CommonsEntityDescriptorEnum.Variable, CommonsEntityDescriptorEnum.InlineVariable);
}
public static final boolean isInlineVariable(IEntity entity) {
return Matcher.matchImpl(CommonsEntityDescriptorEnum.InlineVariable, entity);
}
public static final boolean isFragment(IEntity entity) {
return Matcher.matchAnyImpl(entity,
CommonsEntityDescriptorEnum.SameStageFragment,
CommonsEntityDescriptorEnum.StageDownFragment,
CommonsEntityDescriptorEnum.StageUpFragment,
CommonsEntityDescriptorEnum.RootFragment);
}
public static final boolean isSameStageFragment(IEntity entity) {
return Matcher.matchImpl(CommonsEntityDescriptorEnum.SameStageFragment, entity);
}
public static final boolean isStageDownFragment(IEntity entity) {
return Matcher.matchImpl(CommonsEntityDescriptorEnum.StageDownFragment, entity);
}
public static final boolean isStageUpFragment(IEntity entity) {
return Matcher.matchImpl(CommonsEntityDescriptorEnum.StageUpFragment, entity);
}
//TODO test and inline
public static final boolean isNotResolver(IEntity entity) {
return !isResolver(entity);
}
//FIXME before cleaning EntityKinds
// public static final boolean isImpl(IEntity entity) {
// EntityKinds kind = entity.wGetEntityKind();
// return kind.isSimple() || kind.isComposite() || kind.isData();
// }
public static final boolean isImpl(IEntity... entities) {
for (IEntity entity : entities)
if (!isNotResolver(entity))
return false;
return true;
}
public static final boolean isDefault(IEntity entity, FeatureDescriptor fd, IEntity value) {
return GenericEntityFactory.instance.matchFeature(entity.wGetEntityDescriptor(), fd, value);
}
public static final boolean isDefault(IEntity entity, int index, IEntity value) {
return GenericEntityFactory.instance.matchFeature(entity.wGetEntityDescriptor(), index, value);
}
public static final void setDefault(IEntity entity, FeatureDescriptor fd) {
entity.wSet(fd, GenericEntityFactory.instance.cloneFeature(entity.wGetEntityDescriptor(), fd));
}
public static final void setDefault(IEntity entity, int index) {
entity.wSet(index, GenericEntityFactory.instance.cloneFeature(entity.wGetEntityDescriptor(), index));
}
public static final boolean isOptional(IEntity entity) {
IEntity parent = entity.wGetParent();
return isNull(parent) ? false : parent.wGetFeatureDescriptor(entity).isOptional();
}
public static final ILanguageKit getEnvironmentLanguageKit() {
return ReflectionFactory.getLanguageKit("http://lang.whole.org/Environment", false, null);//EnvironmentLanguageKit.URI
}
public static final boolean isTuple(IEntity entity) {
EntityDescriptorEnum edEnum = getEnvironmentLanguageKit().getEntityDescriptorEnum();
return Matcher.matchImpl(edEnum.valueOf("ContainmentTuple"), entity) ||
Matcher.matchImpl(edEnum.valueOf("Tuple"), entity);
}
@SuppressWarnings("unchecked")
public static final <E extends IEntity> E safeGet(E entity) {
return isNotResolver(entity) ? entity :
(E) GenericEntityFactory.instance.create(entity.wGetEntityDescriptor());
}
public static final <E extends IEntity> E safeGet(E entity, E defaultEntity) {
return isNotResolver(entity) ? entity : defaultEntity;
}
@SuppressWarnings("unchecked")
public static final <E extends IEntity> E safeGet(E entity, Object defaultValue) {
return isNotResolver(entity) ? entity :
(E) GenericEntityFactory.instance.create(
entity.wGetEntityDescriptor(), defaultValue);
}
public static final boolean safeBooleanValue(IEntity entity, boolean defaultValue) {
return DataTypeUtils.getDataKind(entity).isBoolean() ? entity.wBooleanValue() : defaultValue;
}
public static final byte safeByteValue(IEntity entity, byte defaultValue) {
return DataTypeUtils.getDataKind(entity).isByte() ? entity.wByteValue() : defaultValue;
}
public static final char safeCharValue(IEntity entity, char defaultValue) {
return DataTypeUtils.getDataKind(entity).isChar() ? entity.wCharValue() : defaultValue;
}
public static final double safeDoubleValue(IEntity entity, double defaultValue) {
return DataTypeUtils.getDataKind(entity).isDouble() ? entity.wDoubleValue() : defaultValue;
}
public static final float safeFloatValue(IEntity entity, float defaultValue) {
return DataTypeUtils.getDataKind(entity).isFloat() ? entity.wFloatValue() : defaultValue;
}
public static final int safeIntValue(IEntity entity, int defaultValue) {
return DataTypeUtils.getDataKind(entity).isInt() ? entity.wIntValue() : defaultValue;
}
public static final long safeLongValue(IEntity entity, long defaultValue) {
return DataTypeUtils.getDataKind(entity).isLong() ? entity.wLongValue() : defaultValue;
}
public static final short safeShortValue(IEntity entity, short defaultValue) {
return DataTypeUtils.getDataKind(entity).isShort() ? entity.wShortValue() : defaultValue;
}
public static final String safeStringValue(IEntity entity, String defaultValue) {
return DataTypeUtils.getDataKind(entity).isString() ? entity.wStringValue() : defaultValue;
}
public static final Date safeDateValue(IEntity entity, Date defaultValue) {
return DataTypeUtils.getDataKind(entity).isDate() ? entity.wDateValue() : defaultValue;
}
public static final EnumValue safeEnumValueValue(IEntity entity, EnumValue defaultValue) {
return DataTypeUtils.getDataKind(entity).isEnumValue() ? entity.wEnumValue() : defaultValue;
}
@SuppressWarnings("unchecked")
public static final <T, E extends T> T safeGetValue(IEntity entity, E defaultValue, Class<T> dataType) {
return !DataTypeUtils.getDataKind(entity).isNotAData() && dataType.isAssignableFrom(entity.wGetValue().getClass()) ?
(T) entity.wGetValue() : defaultValue;
}
@SuppressWarnings("unchecked")
public static final <T, E extends T> T safeGetValue(IEntity entity, E defaultValue) {
return EntityUtils.<T, E>safeGetValue(entity, defaultValue, (Class<T>) defaultValue.getClass());
}
public static final EntityDescriptor<?> getFormalEntityDescriptor(IEntity entity) {
return entity.wGetParent().wGetEntityDescriptor(entity); //TODO ? replace with getFormalType
}
public static final EntityDescriptor<?> getParentFormalType(IEntity entity) {
return entity.wGetParent().wGetEntityDescriptor(entity);
}
public static final EntityDescriptor<?> getAdjacentsFormalType(IEntity entity) {
EntityDescriptor<?> adjacentsFormalType = CommonsEntityDescriptorEnum.Any;
for (IEntity inverseAdjacent : entity.wInverseAdjacents()) {
EntityDescriptor<?> ed = inverseAdjacent.wGetEntityDescriptor(entity);
if (!ed.isExtendedLanguageSupertypeOf(adjacentsFormalType))
adjacentsFormalType = ed;
}
return adjacentsFormalType;
}
public static final EntityDescriptor<?> getFormalType(IEntity entity) {
EntityDescriptor<?> parentFormalType = getParentFormalType(entity);
EntityDescriptor<?> adjacentsFormalType = getAdjacentsFormalType(entity);
return parentFormalType.isExtendedLanguageSupertypeOf(adjacentsFormalType) ?
adjacentsFormalType : parentFormalType;
}
public static final boolean hasParent(IEntity entity) {
return !isNull(entity.wGetParent());
}
public static final boolean hasInverseAdjacents(IEntity entity) {
return entity.wInverseAdjacentSize() > 0;
}
public static final boolean isReachable(IEntity entity) {
return hasParent(entity) || hasInverseAdjacents(entity);
}
public static final IEntity safeGetRootEntity(IEntity entity) {
while (hasParent(entity))
entity = entity.wGetParent();
return entity;
}
public static final void addCloneIfReparenting(IEntity entity, int index, IEntity value) {
entity.wAdd(index, cloneIfReparenting(value, entity.wGetFeatureDescriptor(index).isReference()));
}
public static final void setCloneIfReparenting(IEntity entity, int index, IEntity value) {
entity.wSet(index, cloneIfReparenting(value, entity.wGetFeatureDescriptor(index).isReference()));
}
public static final void setCloneIfReparenting(IEntity entity, FeatureDescriptor fd, IEntity value) {
FeatureDescriptor efd = fd.isEntityFeatureDescriptor() ? fd : entity.wGetEntityDescriptor().getEntityFeatureDescriptor(fd);
entity.wSet(fd, cloneIfReparenting(value, efd.isReference()));
}
public static final <E extends IEntity> E cloneIfReparenting(E entity, boolean assignToReference) {
return !assignToReference && hasParent(entity) ? clone(entity) : entity;
}
public static final <E extends IEntity> E cloneIfParented(E entity) {
return hasParent(entity) ? clone(entity) : entity;
}
public static final <E extends IEntity> E clone(E entity) {
return new CloneOperation().clone(entity);
}
public static final <E extends IEntity> Collection<E> cloneAll(Collection<E> entities) {
return new CloneOperation().cloneAll(entities);
}
public static final <E extends IEntity> E remove(E entity) {
return new RemoveOperation().remove(entity);
}
public static final <E extends IEntity> Collection<E> removeAll(Collection<E> entities) {
return new RemoveOperation().removeAll(entities);
}
public static boolean isReplaceable(IEntity oldEntity, IEntity newEntity) {
return isReplaceable(oldEntity, newEntity.wGetEntityDescriptor());
}
public static boolean isReplaceableAsIs(IEntity oldEntity, IEntity newEntity) {
return isReplaceableAsIs(oldEntity, newEntity.wGetEntityDescriptor());
}
public static boolean isReplaceable(IEntity oldEntity, EntityDescriptor<?> ed) {
return getFormalEntityDescriptor(oldEntity).isExtendedLanguageSupertypeOf(ed);
}
public static boolean isReplaceableAsIs(IEntity oldEntity, EntityDescriptor<?> ed) {
return getFormalEntityDescriptor(oldEntity).isLanguageSupertypeOf(ed);
}
public static boolean isAddable(IEntity compositeEntity, IEntity newEntity) {
return isAddable(compositeEntity, newEntity.wGetEntityDescriptor());
}
public static boolean isAddableAsIs(IEntity compositeEntity, IEntity newEntity) {
return isAddableAsIs(compositeEntity, newEntity.wGetEntityDescriptor());
}
public static boolean isAddable(IEntity entity, EntityDescriptor<?> ed) {
return isComposite(entity) && entity.wGetEntityDescriptor(0).isExtendedLanguageSupertypeOf(ed);
}
public static boolean isAddableAsIs(IEntity entity, EntityDescriptor<?> ed) {
return isComposite(entity) && entity.wGetEntityDescriptor(0).isLanguageSupertypeOf(ed);
}
public static final IEntity convertCloneIfParented(IEntity value, EntityDescriptor<?> toType) {
return convertCloneIfReparenting(value, toType, false);
}
public static final IEntity convertCloneIfReparenting(IEntity value, FeatureDescriptor toEFd) {
return toEFd.isEntityFeatureDescriptor() ?
convertCloneIfReparenting(value, toEFd.getEntityDescriptor(), toEFd.isReference()) :
cloneIfReparenting(value, false);
}
public static final IEntity convertCloneIfReparenting(IEntity value, EntityDescriptor<?> toEd, boolean isToReference) {
//FIXME (workaround) force conversion semantics for data types
if (toEd.getEntityKind().isData() && value.wGetEntityKind().isData())
try {
return DataTypeUtils.convertCloneIfReparenting(value, toEd, isToReference);
} catch (IllegalArgumentException e) {
}
if (toEd.isPlatformSupertypeOf(value.wGetEntityDescriptor()))
return cloneIfReparenting(value, isToReference);
else if (value.wGetEntityKind().isData())
try {
return DataTypeUtils.convertCloneIfReparenting(value, toEd, isToReference);
} catch (IllegalArgumentException e) {
//TODO test in synch with wGetAdaptee behavior on WholeEditPartFactory
return cloneIfReparenting(value, isToReference).wGetAdapter(toEd);
}
else
return cloneIfReparenting(value, isToReference).wGetAdapter(toEd);
}
public static final IEntity merge(IEntity merger, IEntity mergee, IEntityComparator<IEntity> comparator, boolean orderAware) {
IEntity initialMerger = merger;
IEntity initialMergee = mergee;
merger = merger.wGetAdaptee(false);
mergee = mergee.wGetAdaptee(false);
EntityDescriptor<?> mergerED = merger.wGetEntityDescriptor();
if (!mergerED.equals(mergee.wGetEntityDescriptor())) {
IEntity parent = initialMerger.wGetParent();
if (!EntityUtils.isNull(parent)) {
int index = parent.wIndexOf(initialMerger);
if (parent.wGetEntityDescriptor(index).isLanguageSupertypeOf(mergee.wGetEntityDescriptor()))
setCloneIfReparenting(parent, index, mergee);
return parent.wGet(index);
} else
return initialMergee;
}
switch (mergerED.getEntityKind()) {
case SIMPLE:
for (FeatureDescriptor fd : mergerED.getEntityFeatureDescriptors()) {
IEntity mergerFeature = merger.wGet(fd).wGetAdaptee(false);
IEntity mergeeFeature = mergee.wGet(fd).wGetAdaptee(false);
if (mergerFeature.wGetEntityDescriptor().equals(mergeeFeature.wGetEntityDescriptor()))
merge(mergerFeature, mergeeFeature, comparator, orderAware);
else
merger.wSet(fd, cloneIfParented(mergeeFeature));
}
break;
case COMPOSITE:
if (mergerED.getCompositeKind().isOrdered() && orderAware) {
int i=0, j=0;
while (i<merger.wSize() && j<mergee.wSize()) {
IEntity mergerChild = merger.wGet(i).wGetAdaptee(false);
while (j<mergee.wSize()) {
IEntity mergeeChild = mergee.wGet(j++).wGetAdaptee(false);
if (comparator.equals(mergerChild, mergeeChild))
merger.wSet(i, cloneIfParented(merge(mergerChild, mergeeChild, comparator, orderAware)));
else {
merger.wAdd(++i, cloneIfParented(mergeeChild));
break;
}
}
i++;
}
while (j<mergee.wSize())
merger.wAdd(cloneIfParented(mergee.wGet(j++).wGetAdaptee(false)));
} else {
IEntityIterator<IEntity> mergeeIterator = IteratorFactory.childIterator();
mergeeIterator.reset(mergee);
while (mergeeIterator.hasNext()) {
IEntity mergeeChild = mergeeIterator.next();
if (comparator.contains(merger, mergeeChild)) {
IEntity mergerChild = comparator.get(merger, mergeeChild);
merger.wSet(mergeeChild, merge(mergerChild, mergeeChild, comparator, orderAware));
} else {
merger.wAdd(cloneIfParented(mergeeChild));
}
}
}
break;
default:
case DATA:
// do not merge data entities
break;
}
return initialMerger;
}
public static boolean isAncestorOrSelf(IEntity ancestorEntity, IEntity entity) {
if (ancestorEntity == entity)
return true;
IEntity ancestor = entity.wGetParent();
while (!isNull(ancestor) && ancestorEntity != ancestor)
ancestor = ancestor.wGetParent();
return !isNull(ancestor);
}
public static IEntity getCompoundRoot(IEntity entity) {
IEntity fragment = entity.wGetModel().getFragment();
IEntity root = fragment != null ? fragment.wGetRoot() : entity;
IEntity ancestor = entity.wGetParent();
while (!(isNull(ancestor) || CommonsEntityDescriptorEnum.RootFragment.equals(ancestor.wGetEntityDescriptor()))) {
root = ancestor;
ancestor = ancestor.wGetParent();
}
return root;
}
public static IEntity getLanguageFragmentRoot(IEntity entity) {
String languageURI = entity.wGetLanguageKit().getURI();
IEntity root = entity;
IEntity ancestor = entity.wGetParent();
while (!isNull(ancestor) && ancestor.wGetLanguageKit().getURI().equals(languageURI)) {
root = ancestor;
ancestor = ancestor.wGetParent();
}
return root;
}
public static IEntity getFragmentRoot(IEntity entity) {
IEntity fragment = entity.wGetModel().getFragment();
if (fragment != null)
return fragment.wGetRoot();
IEntity root = entity;
IEntity ancestor = entity.wGetParent();
while (!(isNull(ancestor) || isFragment(ancestor))) {
root = ancestor;
ancestor = ancestor.wGetParent();
}
return root;
}
public static String getLocation(IEntity entity) {
StringBuffer path = new StringBuffer();
if (entity != null) {
IEntity parent = null;
IEntityIterator<IEntity> i = IteratorFactory.ancestorOrSelfReverseIterator();
i.reset(entity);
if (CommonsEntityDescriptorEnum.RootFragment.equals(i.lookahead().wGetEntityDescriptor()))
i.next();
for (IEntity child : i) {
if (parent != null) {
path.append('/');
if (EntityUtils.isSimple(parent))
path.append(parent.wGetFeatureDescriptor(child).getName());
else
path.append(parent.wIndexOf(child));
}
parent = child;
}
}
String result = path.toString();
return result.equals("") ? "/" : result;
}
public static IEntity getEntity(IEntity rootEntity, String location) {
IEntity result = rootEntity;
if (location.charAt(0) != '/')
return null;
try {
String substring = location.substring(1);
if (substring.length() == 0)
return rootEntity;
String[] steps = substring.split("/");
for (String step : steps) {
try {
int child = Integer.parseInt(step);
result = result.wGet(child);
} catch (NumberFormatException e) {
result = result.wGet(result.wGetLanguageKit().getFeatureDescriptorEnum().valueOf(step));
}
}
} catch (Exception e) {
result = null;
}
return result;
}
public static IEntity mapEntity(IEntity entity, IEntity toModel) {
return getEntity(toModel, getLocation(entity));
}
public static List<IEntity> mapEntities(List<IEntity> entities, IEntity toModel) {
return entities.stream()
.map((entity) -> mapEntity(entity, toModel))
.filter((entity) -> entity != null)
.collect(Collectors.toCollection(ArrayList::new));
}
}