cdc.mf.html.adaptors.MfElementAdaptor Maven / Gradle / Ivy
The newest version!
package cdc.mf.html.adaptors;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.stringtemplate.v4.Interpreter;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.misc.ObjectModelAdaptor;
import org.stringtemplate.v4.misc.STNoSuchPropertyException;
import cdc.args.Strictness;
import cdc.graphs.EdgeDirection;
import cdc.graphs.impl.BasicGraphEdge;
import cdc.graphs.impl.BasicSuperLightGraph;
import cdc.mf.Config;
import cdc.mf.html.MfHtmlGenerationArgs;
import cdc.mf.html.MfHtmlGenerationHint;
import cdc.mf.html.MfParams;
import cdc.mf.model.MfAbstractItem;
import cdc.mf.model.MfAggregation;
import cdc.mf.model.MfAnnotation;
import cdc.mf.model.MfAssociation;
import cdc.mf.model.MfCardinalityItem;
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.MfDecoratedElement;
import cdc.mf.model.MfDependency;
import cdc.mf.model.MfDerivedItem;
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.MfInheritance;
import cdc.mf.model.MfInterface;
import cdc.mf.model.MfLink;
import cdc.mf.model.MfMember;
import cdc.mf.model.MfMemberOwner;
import cdc.mf.model.MfModel;
import cdc.mf.model.MfModifierItem;
import cdc.mf.model.MfNameItem;
import cdc.mf.model.MfOperation;
import cdc.mf.model.MfOrderedItem;
import cdc.mf.model.MfPackage;
import cdc.mf.model.MfPackageOwner;
import cdc.mf.model.MfPackagedItem;
import cdc.mf.model.MfParameter;
import cdc.mf.model.MfProperty;
import cdc.mf.model.MfQNameItem;
import cdc.mf.model.MfReadOnlyItem;
import cdc.mf.model.MfSpecialization;
import cdc.mf.model.MfSpecializationOwner;
import cdc.mf.model.MfStereotypesItem;
import cdc.mf.model.MfTag;
import cdc.mf.model.MfTagOwner;
import cdc.mf.model.MfTip;
import cdc.mf.model.MfType;
import cdc.mf.model.MfTypeOwner;
import cdc.mf.model.MfTypeRefItem;
import cdc.mf.model.MfUtils;
import cdc.mf.model.MfVisibilityItem;
import cdc.mf.model.deps.MfDependencyGraph;
import cdc.util.strings.StringUtils;
public class MfElementAdaptor extends ObjectModelAdaptor {
private final MfHtmlGenerationArgs args;
private final MfDependencyGraph deps;
private BasicSuperLightGraph packagesDeps = null;
private static final Pattern HTML = Pattern.compile("^html\\((.*)\\)$");
private static final String HAS_CMAPX = "has-cmapx";
private static final String CMAPX = "cmapx";
private static final Map> IS_INSTANCE = new HashMap<>();
private static void add(Class extends MfElement> cls) {
final String name = cls.getSimpleName();
// Do this even if first char is always M (at the moment)
final String camel = Character.toLowerCase(name.charAt(0)) + name.substring(1);
IS_INSTANCE.put(camel, cls);
}
static {
add(MfAbstractItem.class);
add(MfAggregation.class);
add(MfAnnotation.class);
add(MfAssociation.class);
add(MfCardinalityItem.class);
add(MfClass.class);
add(MfComposition.class);
add(MfConnector.class);
add(MfConnectorOwner.class);
add(MfConstraint.class);
add(MfConstraintOwner.class);
add(MfDependency.class);
add(MfDerivedItem.class);
add(MfDocumentation.class);
add(MfElement.class);
add(MfEnumeration.class);
add(MfEnumerationValue.class);
add(MfImplementation.class);
add(MfImplementationOwner.class);
add(MfInheritance.class);
add(MfInterface.class);
add(MfLink.class);
add(MfMember.class);
add(MfMemberOwner.class);
add(MfModel.class);
add(MfModifierItem.class);
add(MfNameItem.class);
add(MfOperation.class);
add(MfOrderedItem.class);
add(MfPackage.class);
add(MfPackagedItem.class);
add(MfPackageOwner.class);
add(MfParameter.class);
add(MfPackageOwner.class);
add(MfProperty.class);
add(MfQNameItem.class);
add(MfReadOnlyItem.class);
add(MfSpecialization.class);
add(MfSpecializationOwner.class);
add(MfTag.class);
add(MfTagOwner.class);
add(MfTip.class);
add(MfType.class);
add(MfTypeOwner.class);
add(MfTypeRefItem.class);
add(MfVisibilityItem.class);
}
private static Boolean isInstance(MfElement element,
String propertyName) {
final Class> cls = IS_INSTANCE.get(propertyName);
return cls == null
? null
: cls.isInstance(element);
}
public MfElementAdaptor(MfHtmlGenerationArgs args) {
this.args = args;
this.deps = new MfDependencyGraph(args.getModel());
}
private void buildPackagesDeps() {
if (packagesDeps == null) {
packagesDeps = deps.getPackagesDependencies(args.getModelOverviewIgnoredPackages());
}
}
private T fail(T value,
MfElement element,
String propertyName) {
if (args.getHints().contains(MfHtmlGenerationHint.FAIL)) {
throw new IllegalArgumentException("Failed to retrieve " + propertyName + " on " + element);
} else {
return value;
}
}
@Override
public synchronized Object getProperty(Interpreter interp,
ST self,
MfElement element,
Object property,
String propertyName) throws STNoSuchPropertyException {
switch (propertyName) {
case "issues":
// The issues associated to element
return args.getIssues(element);
case "hasDeepIssues":
return args.hasDeepIssues(element);
case "worstIssueSeverity":
return args.getWorstIssueSeverity(element);
case "worstDeepIssueSeverity":
return args.getWorstDeepIssueSeverity(element);
case "metas":
return MfParams.getMetas(element);
case "configVersion":
// Version of the code
return Config.VERSION;
case "abstract":
// Is the element abstract?
if (element instanceof final MfClass c) {
return c.isAbstract();
} else {
return element instanceof MfInterface;
}
case "simplifiedName":
if (element instanceof final MfNameItem x) {
return args.simplifyName(x.getName());
} else {
return fail(null, element, propertyName);
}
case "allImplements":
return getAllImplements(element);
case "allImplemented":
return getAllImplemented(element);
case "decoratedExtends":
return getDecoratedExtends(element);
case "decoratedExtended":
return getDecoratedExtended(element);
case "decoratedImplements":
return getDecoratedImplements(element);
case "decoratedImplemented":
return getDecoratedImplemented(element);
case "decoratedConnectors":
return getDecoratedConnectors(element);
case "decoratedReversedConnectors":
return getDecoratedReversedConnectors(element);
case "decoratedMembers":
return getDecoratedMembers(element);
case "decoratedProperties":
return getDecoratedProperties(element);
case "decoratedOperations":
return getDecoratedOperations(element);
case "directExtends":
return getDirectExtends(element);
case "directExtended":
return getDirectExtended(element);
case "directImplements":
return getDirectImplements(element, false);
case "directImplemented":
return getDirectImplemented(element);
case "wrappedDirectExtends":
return wrap(getDirectExtends(element), '-');
case "wrappedDirectExtended":
return wrap(getDirectExtended(element), '-');
case "wrappedDirectImplements":
return wrap(getDirectImplements(element, false), '.');
case "wrappedDirectImplemented":
return wrap(getDirectImplemented(element), '.');
case "wrappedDirectInternalImplements":
return wrap(getDirectImplements(element, true), '.');
case "wrappedConnectors":
if (element instanceof final MfConnectorOwner co1) {
return wrap(co1.getConnectors(), '-');
} else {
return fail(null, element, propertyName);
}
case "wrappedConnectors0":
if (element instanceof final MfConnectorOwner co2) {
return wrap(co2.getConnectors(), '-', 0);
} else {
return fail(null, element, propertyName);
}
case "wrappedReversedConnectors":
if (element instanceof final MfType t2) {
return wrap(t2.getReversedConnectors(), '-');
} else {
return fail(null, element, propertyName);
}
case "ownedClasses":
// List of classes owned by the element
if (element instanceof MfPackage) {
return sort(element.getChildren(MfClass.class), MfNameItem.NAME_COMPARATOR);
} else {
return fail(null, element, propertyName);
}
case "ownedInterfaces":
// List of interfaces owned by the element
if (element instanceof MfPackage) {
return sort(element.getChildren(MfInterface.class), MfNameItem.NAME_COMPARATOR);
} else {
return fail(null, element, propertyName);
}
case "ownedEnumerations":
// List of enumerations owned by the element
if (element instanceof MfPackage) {
return sort(element.getChildren(MfEnumeration.class), MfNameItem.NAME_COMPARATOR);
} else {
return fail(null, element, propertyName);
}
case "allPackages":
// List of all packages of the model
if (element instanceof MfModel) {
return sort(element.collect(MfPackage.class), MfQNameItem.QNAME_COMPARATOR);
} else {
return fail(null, element, propertyName);
}
case "htmlId":
return MfParams.getHtmlId(element);
case "displayName":
// The display name
return MfParams.getDisplayName(element);
case "itemRef":
return MfParams.toItemRef(element, args);
case "itemUrl":
return MfParams.toItemUrl(element, args);
case "upPath":
return MfParams.getUpPath(element, args);
case "imgUpPath":
return MfParams.toString(MfParams.Dirs.getImgUpPath(element, args));
case "packageItemsRef":
if (element instanceof final MfPackage p4) {
return MfParams.toUrl(MfParams.Files.getHtmlPackageItemsFile(p4, args));
} else {
return fail(null, element, propertyName);
}
case "packageOverviewRef":
if (element instanceof final MfPackage p3) {
return MfParams.toUrl(MfParams.Files.getHtmlPackageOverviewFile(p3, args));
} else {
return fail(null, element, propertyName);
}
case "kind":
// The element kind
return MfParams.getKind(element);
case "pumlKind":
// The element kind
return MfParams.getPumlKind(element);
case "pumlId":
// The element safe id for PlantUML
return MfParams.getPumlId(element);
case "modelOverviewAllPackages":
// Return all packages of Model Overview graph
buildPackagesDeps();
return sort(packagesDeps.getNodes(), MfQNameItem.QNAME_COMPARATOR);
case "modelOverviewPackages":
// Return children packages of a PackageOwner belonging to the Model Overview graph
if (element instanceof MfModel || element instanceof MfPackage) {
buildPackagesDeps();
return ((MfPackageOwner) element).getPackages()
.stream()
.filter(packagesDeps::containsNode)
.toList();
} else {
return fail(null, element, propertyName);
}
case "modelOverviewDependencies":
// Return all dependencies of a package in Model Overview graph
if (element instanceof final MfPackage p1) {
buildPackagesDeps();
return packagesDeps.getEdgesStream(p1, EdgeDirection.OUTGOING)
.map(BasicGraphEdge::getTarget)
.sorted(MfQNameItem.QNAME_COMPARATOR)
.toList();
} else {
return fail(null, element, propertyName);
}
case "externalTypes":
if (element instanceof final MfPackage p2) {
return MfParams.getExternalTypes(p2, args);
} else {
return fail(null, element, propertyName);
}
case "relatedTypes":
if (element instanceof final MfType t) {
return MfParams.getRelatedTypes(t, args);
} else {
return fail(null, element, propertyName);
}
case "displayedConstrainedElementRefs":
if (element instanceof final MfConstraint constraint) {
return MfParams.getDisplayedConstrainedElementRefs(constraint);
} else {
return fail(null, element, propertyName);
}
case "tags":
if (element instanceof final MfTagOwner to) {
if (args.getHints().contains(MfHtmlGenerationHint.SORT_TAGS)) {
return to.getTags()
.stream()
.sorted(MfTag.NAME_VALUE_COMPARATOR)
.toList();
} else {
return ((MfTagOwner) element).getTags();
}
} else {
return fail(null, element, propertyName);
}
case "usages":
return MfUtils.getUsages(element, args.getHints().contains(MfHtmlGenerationHint.SHOW_NON_NAVIGABLE_TIPS));
case "layoutLinks":
return MfParams.getLayoutLinks(element);
case "stereotypes":
if (element instanceof final MfStereotypesItem s) {
return s.getStereotypes();
} else {
return null;
}
default:
break;
}
final Boolean isInstance = isInstance(element, propertyName);
if (isInstance != null) {
return isInstance;
}
if (propertyName.endsWith(HAS_CMAPX)) {
final String prefix = propertyName.substring(0, propertyName.length() - HAS_CMAPX.length());
return MfParams.hasCmapx(args.getBaseDir(), prefix, element);
} else if (propertyName.endsWith(CMAPX)) {
final String prefix = propertyName.substring(0, propertyName.length() - CMAPX.length());
return MfParams.loadCmapx(args.getBaseDir(), prefix, element);
}
final Matcher m = HTML.matcher(propertyName);
if (m.matches()) {
final String upPath = m.group(1);
// The html content of an MfDocumentation
if (element instanceof final MfDocumentation d) {
return MfParams.toHtml(d.getText(), upPath, args);
} else {
return "";
}
}
return super.getProperty(interp, self, element, property, propertyName);
}
private static List> getDecoratedMembers(MfElement element) {
if (element instanceof final MfMemberOwner owner) {
return sort(owner.getDecoratedMembers(),
MfDecoratedElement.ID_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List> getDecoratedProperties(MfElement element) {
if (element instanceof final MfMemberOwner owner) {
return sort(owner.getDecoratedProperties(),
MfDecoratedElement.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List> getDecoratedOperations(MfElement element) {
if (element instanceof final MfMemberOwner owner) {
return sort(owner.getDecoratedOperations(),
MfDecoratedElement.ID_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List> getDecoratedConnectors(MfElement element) {
if (element instanceof final MfConnectorOwner owner) {
return sort(owner.getDecoratedConnectors(),
MfDecoratedElement.ID_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List> getDecoratedReversedConnectors(MfElement element) {
if (element instanceof final MfType type) {
return sort(type.getDecoratedReversedConnectors(),
MfDecoratedElement.ID_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List> getDecoratedExtends(MfElement element) {
if (element instanceof final MfClass e) {
return sort(e.getDecoratedAncestors(MfClass.class),
MfDecoratedElement.QNAME_COMPARATOR);
} else if (element instanceof final MfInterface e) {
return sort(e.getDecoratedAncestors(MfInterface.class),
MfDecoratedElement.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List> getDecoratedExtended(MfElement element) {
if (element instanceof final MfClass e) {
return sort(e.getDecoratedDescendants(MfClass.class),
MfDecoratedElement.QNAME_COMPARATOR);
} else if (element instanceof final MfInterface e) {
return sort(e.getDecoratedDescendants(MfInterface.class),
MfDecoratedElement.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List> getDecoratedImplements(MfElement element) {
if (element instanceof MfClass || element instanceof MfEnumeration) {
return sort(((MfType) element).getDecoratedAncestors(MfInterface.class),
MfDecoratedElement.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List> getDecoratedImplemented(MfElement element) {
if (element instanceof final MfInterface e) {
final Set> set = new HashSet<>();
set.addAll(e.getDecoratedDescendants(MfClass.class));
set.addAll(e.getDecoratedDescendants(MfEnumeration.class));
return sort(set,
MfDecoratedElement.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List extends MfType> getDirectExtends(MfElement element) {
// List of directly extended types
if (element instanceof final MfClass e) {
return sort(e.getDirectAncestors(MfClass.class),
MfQNameItem.QNAME_COMPARATOR);
} else if (element instanceof final MfInterface e) {
return sort(e.getDirectAncestors(MfInterface.class),
MfQNameItem.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List extends MfType> getDirectExtended(MfElement element) {
// Types that directly extend the element
if (element instanceof final MfClass e) {
return sort(e.getDirectDescendants(MfClass.class),
MfQNameItem.QNAME_COMPARATOR);
} else if (element instanceof final MfInterface e) {
return sort(e.getDirectDescendants(MfInterface.class),
MfQNameItem.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List getDirectImplements(MfElement element,
boolean internal) {
// Interfaces that the element directly implements
if (element instanceof MfClass || element instanceof MfEnumeration) {
if (internal) {
return sort(((MfType) element).getDirectAncestors(MfInterface.class)
.stream()
.filter(x -> x.getRootType()
.getOwningPackage() == ((MfType) element).getRootType()
.getOwningPackage())
.toList(),
MfQNameItem.QNAME_COMPARATOR);
} else {
return sort(((MfType) element).getDirectAncestors(MfInterface.class),
MfQNameItem.QNAME_COMPARATOR);
}
} else {
return Collections.emptyList();
}
}
private static List getAllImplements(MfElement element) {
// List of all implemented interfaces
if (element instanceof MfClass || element instanceof MfEnumeration) {
return sort(((MfType) element).getAllAncestors(Strictness.STRICT, MfInterface.class),
MfQNameItem.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List extends MfType> getDirectImplemented(MfElement element) {
// Types that directly implement the interface
if (element instanceof final MfInterface e) {
return sort(e.getAllImplementors(),
MfQNameItem.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List extends MfType> getAllImplemented(MfElement element) {
// List of types that implement this interface
if (element instanceof final MfInterface e) {
return sort(e.getAllImplementors(),
MfQNameItem.QNAME_COMPARATOR);
} else {
return Collections.emptyList();
}
}
private static List sort(Collection extends X> collection,
Comparator super X> comparator) {
return collection.stream()
.sorted(comparator)
.collect(Collectors.toList());
}
static class LengthWrapper {
public final X data;
public final int length;
public final String filler;
public LengthWrapper(X data,
int length,
char fill) {
this.data = data;
this.length = length;
this.filler = StringUtils.toString(fill, length);
}
}
private List> wrap(List list,
char fill) {
return wrap(list, fill, Integer.MAX_VALUE);
}
private List> wrap(List list,
char fill,
int max) {
if (list == null) {
return null;
} else {
final List> out = new ArrayList<>();
final int length = list.size();
final int m = Math.max(1, Math.min(length / 2, args.getLayoutDepth()));
for (int index = 0; index < list.size(); index++) {
// final int mod = index % (2 * m);
final int mod = index % m;
out.add(new LengthWrapper<>(list.get(index),
// Math.min(max, Math.min(mod, 2 * m - 1 - mod)),
Math.min(max, mod),
fill));
}
return out;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy