cdc.mf.transform.MfChildTransformer Maven / Gradle / Ivy
package cdc.mf.transform;
import java.util.function.BiFunction;
import java.util.function.Function;
import cdc.mf.model.MfAbstractChildElement;
import cdc.mf.model.MfAggregation;
import cdc.mf.model.MfAssociation;
import cdc.mf.model.MfClass;
import cdc.mf.model.MfComposition;
import cdc.mf.model.MfConnector;
import cdc.mf.model.MfConnectorOwner;
import cdc.mf.model.MfConstraint;
import cdc.mf.model.MfConstraintOwner;
import cdc.mf.model.MfDocumentation;
import cdc.mf.model.MfElement;
import cdc.mf.model.MfEnumeration;
import cdc.mf.model.MfEnumerationValue;
import cdc.mf.model.MfImplementation;
import cdc.mf.model.MfImplementationOwner;
import cdc.mf.model.MfInterface;
import cdc.mf.model.MfMemberOwner;
import cdc.mf.model.MfOperation;
import cdc.mf.model.MfPackage;
import cdc.mf.model.MfPackageOwner;
import cdc.mf.model.MfParameter;
import cdc.mf.model.MfParameterOwner;
import cdc.mf.model.MfProperty;
import cdc.mf.model.MfSpecialization;
import cdc.mf.model.MfSpecializationOwner;
import cdc.mf.model.MfTag;
import cdc.mf.model.MfTagOwner;
import cdc.mf.model.MfTip;
import cdc.mf.model.MfTypeOwner;
/**
* Interface used to locally transform a {@link MfAbstractChildElement child element}.
*
* For a deep transformation, use {@link MfTransformer}.
*
* Note: at most one element is returned, but one can create several target children for one source child.
*
* @author Damien Carbonne
*
* @param The child element type.
* @param The parent element type.
*/
public interface MfChildTransformer, P extends MfElement> {
/**
* @return The child element class.
*/
public Class getChildClass();
/**
* Converts a source child element to a target one, possibly none.
*
* @param srcChild The source child.
* @param tgtParent The target parent.
* @return A target child, transformation of {@code srcChild}.
*/
public E transform(E srcChild,
P tgtParent);
public default E transformRaw(MfElement srcChild,
MfElement tgtParent) {
@SuppressWarnings("unchecked")
final P tmp = (P) tgtParent;
return transform(getChildClass().cast(srcChild), tmp);
}
/**
* @param The element type.
* @param The element parent type.
* @param cls The element class.
* @return An instance of {@link MfChildTransformer} that duplicates the source element.
*/
public static , P extends MfElement> MfChildTransformer cloner(Class cls) {
return new MfChildTransformer<>() {
@Override
public Class getChildClass() {
return cls;
}
@Override
public E transform(E srcChild,
P tgtParent) {
return cls.cast(srcChild.duplicate(tgtParent));
}
};
}
/**
* @param The element type.
* @param The element parent type.
* @param cls The element class.
* @return An instance of {@link MfChildTransformer} that ignores a source element.
*/
public static , P extends MfElement> MfChildTransformer ignorer(Class cls) {
return new MfChildTransformer<>() {
@Override
public Class getChildClass() {
return cls;
}
@Override
public E transform(E srcChild,
P tgtParent) {
return null;
}
};
}
/**
* Creates an instance of {@link MfChildTransformer} from an {@link MfElementFixer}.
*
* @param The builder type.
* @param The element type.
* @param The element parent type.
* @param cls The element class.
* @param fixer The element fixer.
* @return A new instance of {@link MfChildTransformer} built from {@code fixer}.
* @throws IllegalArgumentException When {@code cls} is not recognized.
*/
public static ,
E extends MfAbstractChildElement
,
P extends MfElement>
MfChildTransformer of(Class cls,
MfElementFixer fixer) {
final MfChildTransformer, ?> x;
if (cls.equals(MfAggregation.class)) {
x = builder1(MfAggregation.class, MfConnectorOwner::aggregation, fixer);
} else if (cls.equals(MfAssociation.class)) {
x = builder1(MfAssociation.class, MfConnectorOwner::association, fixer);
} else if (cls.equals(MfClass.class)) {
x = builder1(MfClass.class, MfTypeOwner::cls, fixer);
} else if (cls.equals(MfComposition.class)) {
x = builder1(MfComposition.class, MfConnectorOwner::composition, fixer);
} else if (cls.equals(MfConstraint.class)) {
x = builder1(MfConstraint.class, MfConstraintOwner::constraint, fixer);
} else if (cls.equals(MfDocumentation.class)) {
x = builder1(MfDocumentation.class, MfElement::documentation, fixer);
} else if (cls.equals(MfEnumeration.class)) {
x = builder1(MfEnumeration.class, MfTypeOwner::enumeration, fixer);
} else if (cls.equals(MfEnumerationValue.class)) {
x = builder1(MfEnumerationValue.class, MfEnumeration::value, fixer);
} else if (cls.equals(MfImplementation.class)) {
x = builder1(MfImplementation.class, y -> ((MfImplementationOwner) y).implementation(), fixer);
} else if (cls.equals(MfInterface.class)) {
x = builder1(MfInterface.class, MfTypeOwner::xface, fixer);
} else if (cls.equals(MfOperation.class)) {
x = builder1(MfOperation.class, MfMemberOwner::operation, fixer);
} else if (cls.equals(MfPackage.class)) {
x = builder1(MfPackage.class, MfPackageOwner::pack, fixer);
} else if (cls.equals(MfParameter.class)) {
x = builder1(MfParameter.class, MfParameterOwner::parameter, fixer);
} else if (cls.equals(MfProperty.class)) {
x = builder1(MfProperty.class, MfMemberOwner::property, fixer);
} else if (cls.equals(MfSpecialization.class)) {
x = builder1(MfSpecialization.class, y -> ((MfSpecializationOwner) y).specialization(), fixer);
} else if (cls.equals(MfTag.class)) {
x = builder1(MfTag.class, MfTagOwner::tag, fixer);
} else if (cls.equals(MfTip.class)) {
final BiFunction> createBuilder =
(tgtParent,
srcChild) -> tgtParent.tip(srcChild.getSide());
x = builder2(MfTip.class, createBuilder, fixer);
} else {
throw new IllegalArgumentException("Unexpected class: " + cls);
}
@SuppressWarnings("unchecked")
final MfChildTransformer tmp = (MfChildTransformer) x;
return tmp;
}
private static ,
E extends MfAbstractChildElement,
P extends MfElement>
MfChildTransformer builder1(Class cls,
Function createBuilder,
MfElementFixer, ?> fixer) {
return new MfChildTransformer() {
@Override
public Class getChildClass() {
return cls;
}
@SuppressWarnings("unchecked")
@Override
public E transform(E srcChild,
P tgtParent) {
final B tgtBuilder = createBuilder.apply(tgtParent);
srcChild.setRaw(tgtBuilder);
((MfElementFixer) fixer).fix(srcChild, tgtBuilder);
return tgtBuilder.build();
}
};
}
private static ,
E extends MfAbstractChildElement,
P extends MfElement>
MfChildTransformer builder2(Class cls,
BiFunction createBuilder,
MfElementFixer, ?> fixer) {
return new MfChildTransformer() {
@Override
public Class getChildClass() {
return cls;
}
@SuppressWarnings("unchecked")
@Override
public E transform(E srcChild,
P tgtParent) {
final B tgtBuilder = createBuilder.apply(tgtParent, srcChild);
srcChild.setRaw(tgtBuilder);
((MfElementFixer) fixer).fix(srcChild, tgtBuilder);
return tgtBuilder.build();
}
};
}
}