All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cdc.mf.model.MfElementRef Maven / Gradle / Ivy

The newest version!
package cdc.mf.model;

import java.util.ArrayList;
import java.util.List;

import cdc.util.lang.Checks;
import cdc.util.paths.Path;
import cdc.util.refs.ResolutionException;

/**
 * Element reference.
 * 

* It has several forms: *

    *
  • Eager when the referenced element exists in memory at time of creation of the reference. *
  • Lazy when the referenced element does not yet exist time of creation of the reference. *
  • Invalid when there is not enough information to reference the element. *
* * @author Damien Carbonne * * @param The referenced element type. */ public interface MfElementRef { public static final MfElementRef NO_TYPE = of(MfType.class); public static final MfElementRef NO_INTERFACE = of(MfInterface.class); public static final String REF_CLASS = "refClass"; /** * @return The Class of the referenced element. */ public Class getRefClass(); /** * @return The identifier of the referenced element. * May be {@code null} if this is not known when the reference is built. * In that case, {@link #getRefQName()} should return a valid value. */ public String getRefId(); /** * Returns the resolved identifier of the referenced element. *

* If this reference was not created with an identifier, then it is resolved * and the identifier of the referenced element is returned. * * @return The resolved identifier of the referenced element. */ public default String resolveRefId() { if (getRefId() != null) { return getRefId(); } else if (isValid()) { final X ref = get(); return ref.getId(); } else { return null; } } /** * @return The qualified name of the referenced element. * May be {@code null} if this is not known when the reference is built. * In that case, {@link #getRefId()} should return a valid value. */ public Path getRefQName(); /** * Returns the resolved qualified name of the referenced element. *

* If this reference was not created with a qualified name, then it is resolved * and the qualified name of the referenced element is returned.
* This can work if the referenced element implements {@link MfQNameItem}. * * @return The resolved qualified name of the referenced element. */ public default Path resolveRefQName() { if (getRefQName() != null) { return getRefQName(); } else if (isValid()) { final X ref = get(); if (ref instanceof final MfQNameItem x) { return x.getQName(); } else { return null; } } else { return null; } } /** * @return {@code true} if this reference has neither id nor qualified name. */ public default boolean isEmpty() { return getRefId() == null && getRefQName() == null; } /** * @return {@code true} when the reference is valid: calling get() should return a result. */ public boolean isValid(); /** * @return The referenced element. */ public X get(); public default X getElement() { return get(); } /** * Creates an eager element reference. * * @param The element type. * @param ref The element. * @return An eager element reference instance from {@code ref}. * @throws IllegalArgumentException When {@code ref} is {@code null}. */ public static MfElementRef of(X ref) { return new Eager<>(ref); } /** * Creates an element reference. *

    *
  1. Tries to create an eager instance from {@code model} and {@code refId}. *
  2. Tries to create an eager instance from {@code model} and {@code refQName}. *
  3. Tries to create a lazy instance from {@code model}, {@code refClass}, {@code refId} and {@code refQName}, * if one of {@code refId} or {@code refQName} is not {@code null} *
  4. Creates a nothing instance from {@code refClass}, if {@code refId} and {@code refQName} are both {@code null}. *
* * @param The element type. * @param model The model. * @param refClass The element class. * @param refId The referenced element identifier. May be {@code null}. * @param refQName The referenced element QName. May be {@code null}. * @return An element reference instance. * @throws IllegalArgumentException When {@code model} or {@code refClass} is {@code null}. */ public static MfElementRef of(MfModel model, Class refClass, String refId, Path refQName) { // Checks.isNotNull(model, "model"); Checks.isNotNull(refClass, REF_CLASS); if (refId != null && model.hasItemWithId(refId)) { final X ref = model.getItemWithId(refId, refClass).orElseThrow(); return new Eager<>(ref); } else if (refQName != null && model.hasItemWithQName(refQName)) { final X ref = model.getItemWithQName(refQName, refClass); return new Eager<>(ref); } else if (refId == null && refQName == null) { return new None<>(refClass); } else { return new Lazy<>(model, refClass, refId, refQName); } } /** * Creates a nothing element reference. * * @param The element type. * @param refClass The element class. * @return A nothing element reference. * @throws IllegalArgumentException When {@code refClass} is {@code null}. */ public static MfElementRef of(Class refClass) { return of(null, refClass, null, null); } public static MfElementRef of(MfModel model, Class refClass) { return of(model, refClass, null, null); } public static MfElementRef of(MfModel model, Class refClass, String refId) { return of(model, refClass, refId, null); } public static MfElementRef of(MfModel model, Class refClass, Path refQName) { return of(model, refClass, null, refQName); } public static MfElementRef toLazy(MfElementRef srcRef, MfModel tgtModel) { return new Lazy<>(tgtModel, srcRef.getRefClass(), srcRef.getRefId(), srcRef.getRefQName()); } public static List> toLazy(List> srcRefs, MfModel tgtModel) { final List> list = new ArrayList<>(); for (final MfElementRef srcRef : srcRefs) { list.add(toLazy(srcRef, tgtModel)); } return list; } } /** * Eager implementation of {@link MfElementRef}. * * @param The referenced element type. */ class Eager implements MfElementRef { private final X ref; public Eager(X ref) { this.ref = Checks.isNotNull(ref, "ref"); Checks.assertTrue(isValid(), "Invalid ref"); } @Override public Class getRefClass() { @SuppressWarnings("unchecked") final Class tmp = (Class) ref.getClass(); return tmp; } @Override public String getRefId() { return ref.getId(); } @Override public Path getRefQName() { if (ref instanceof final MfQNameItem x) { return x.getQName(); } else { return null; } } @Override public boolean isValid() { return getRefId() != null || getRefQName() != null; } @Override public X get() { return ref; } } /** * Lazy implementation of {@link MfElementRef}. * * @param The referenced element type. */ class Lazy implements MfElementRef { private final MfModel model; private final Class refClass; private final String refId; private final Path refQName; private X ref; public Lazy(MfModel model, Class refClass, String refId, Path refQName) { this.model = Checks.isNotNull(model, "model"); this.refClass = Checks.isNotNull(refClass, REF_CLASS); this.refId = refId; this.refQName = refQName; } private void resolve() { if (ref == null) { if (refId != null) { ref = model.getItemWithId(refId, refClass).orElseThrow(); } else if (refQName != null) { ref = model.getItemWithQName(refQName, refClass); } // We can not do anything } } @Override public Class getRefClass() { return refClass; } @Override public String getRefId() { return refId; } @Override public Path getRefQName() { return refQName; } @Override public boolean isValid() { try { resolve(); } catch (final RuntimeException e) { // ignore } return ref != null; } @Override public X get() { resolve(); if (ref == null) { throw new ResolutionException("Can not resolve " + this); } return ref; } @Override public String toString() { return "[" + getRefClass().getCanonicalName() + " " + getRefId() + " " + getRefQName() + "]"; } } /** * Implementation of {@link MfElementRef} that references nothing. * * @param The referenced element type. */ class None implements MfElementRef { private final Class refClass; public None(Class refClass) { this.refClass = Checks.isNotNull(refClass, REF_CLASS); } @Override public Class getRefClass() { return refClass; } @Override public String getRefId() { return null; } @Override public Path getRefQName() { return null; } @Override public boolean isValid() { return false; } @Override public X get() { throw new ResolutionException("Can not resolve " + this); } @Override public String toString() { return "[" + getRefClass().getCanonicalName() + "]"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy