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

org.molgenis.data.util.EntityUtils Maven / Gradle / Ivy

There is a newer version: 8.4.5
Show newest version
package org.molgenis.data.util;

import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
import static java.util.stream.Collectors.toList;
import static org.molgenis.data.util.MolgenisDateFormat.FAILED_TO_PARSE_ATTRIBUTE_AS_DATETIME_MESSAGE;
import static org.molgenis.data.util.MolgenisDateFormat.FAILED_TO_PARSE_ATTRIBUTE_AS_DATE_MESSAGE;
import static org.molgenis.data.util.MolgenisDateFormat.parseInstant;
import static org.molgenis.data.util.MolgenisDateFormat.parseLocalDate;

import com.google.common.collect.Iterables;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.Objects;
import org.molgenis.data.Entity;
import org.molgenis.data.EntityManager;
import org.molgenis.data.MolgenisDataException;
import org.molgenis.data.meta.AttributeType;
import org.molgenis.data.meta.model.Attribute;
import org.molgenis.data.meta.model.EntityType;
import org.molgenis.data.meta.model.Package;
import org.molgenis.data.meta.model.Tag;
import org.molgenis.util.ListEscapeUtils;
import org.molgenis.util.UnexpectedEnumException;
import org.molgenis.util.i18n.LanguageService;

public class EntityUtils {
  private EntityUtils() {}

  /**
   * Convert a string value to a typed value based on a non-entity-referencing attribute data type.
   *
   * @param valueStr string value
   * @param attr non-entity-referencing attribute
   * @return typed value
   * @throws MolgenisDataException if attribute references another entity
   */
  public static Object getTypedValue(String valueStr, Attribute attr) {
    // Reference types cannot be processed because we lack an entityManager in this route.
    if (EntityTypeUtils.isReferenceType(attr)) {
      throw new MolgenisDataException(
          "getTypedValue(String, AttributeMetadata) can't be used for attributes referencing entities");
    }
    return getTypedValue(valueStr, attr, null);
  }

  /**
   * Convert a string value to a typed value based on the attribute data type.
   *
   * @param valueStr string value
   * @param attr attribute
   * @param entityManager entity manager used to convert referenced entity values
   * @return typed value
   */
  public static Object getTypedValue(String valueStr, Attribute attr, EntityManager entityManager) {
    if (valueStr == null) return null;
    switch (attr.getDataType()) {
      case BOOL:
        return Boolean.valueOf(valueStr);
      case CATEGORICAL:
      case FILE:
      case XREF:
        EntityType xrefEntity = attr.getRefEntity();
        Object xrefIdValue = getTypedValue(valueStr, xrefEntity.getIdAttribute(), entityManager);
        return entityManager.getReference(xrefEntity, xrefIdValue);
      case CATEGORICAL_MREF:
      case MREF:
      case ONE_TO_MANY:
        EntityType mrefEntity = attr.getRefEntity();
        List mrefIdStrValues = ListEscapeUtils.toList(valueStr);
        return mrefIdStrValues.stream()
            .map(
                mrefIdStrValue ->
                    getTypedValue(mrefIdStrValue, mrefEntity.getIdAttribute(), entityManager))
            .map(mrefIdValue -> entityManager.getReference(mrefEntity, mrefIdValue))
            .collect(toList());
      case COMPOUND:
        throw new IllegalArgumentException("Compound attribute has no value");
      case DATE:
        try {
          return parseLocalDate(valueStr);
        } catch (DateTimeParseException e) {
          throw new MolgenisDataException(
              format(FAILED_TO_PARSE_ATTRIBUTE_AS_DATE_MESSAGE, attr.getName(), valueStr), e);
        }
      case DATE_TIME:
        try {
          return parseInstant(valueStr);
        } catch (DateTimeParseException e) {
          throw new MolgenisDataException(
              format(FAILED_TO_PARSE_ATTRIBUTE_AS_DATETIME_MESSAGE, attr.getName(), valueStr), e);
        }
      case DECIMAL:
        return Double.valueOf(valueStr);
      case EMAIL:
      case ENUM:
      case HTML:
      case HYPERLINK:
      case SCRIPT:
      case STRING:
      case TEXT:
        return valueStr;
      case INT:
        return Integer.valueOf(valueStr);
      case LONG:
        return Long.valueOf(valueStr);
      default:
        throw new UnexpectedEnumException(attr.getDataType());
    }
  }

  /** Returns true if entity metadata equals another entity metadata. TODO docs */
  public static boolean equals(EntityType entityType, EntityType otherEntityType) {
    if (entityType == null && otherEntityType != null) return false;
    if (entityType != null && otherEntityType == null) return false;
    if (!(entityType != null && entityType.getId().equals(otherEntityType.getId()))) return false;
    if (!Objects.equals(entityType.getLabel(), otherEntityType.getLabel())) return false;
    if (!LanguageService.getLanguageCodes()
        .allMatch(
            languageCode ->
                Objects.equals(
                    entityType.getLabel(languageCode), otherEntityType.getLabel(languageCode)))) {
      return false;
    }
    if (!Objects.equals(entityType.getDescription(), otherEntityType.getDescription()))
      return false;
    if (!LanguageService.getLanguageCodes()
        .allMatch(
            languageCode ->
                Objects.equals(
                    entityType.getDescription(languageCode),
                    otherEntityType.getDescription(languageCode)))) {
      return false;
    }
    if (entityType.isAbstract() != otherEntityType.isAbstract()) return false;

    // NB This is at such a low level that we do not know the default backend
    // so we don't check if the other one is the default if the backend is null.
    String backend = entityType.getBackend();
    String otherBackend = otherEntityType.getBackend();
    if ((backend == null && otherBackend != null)
        || (backend != null && otherBackend == null)
        || (backend != null && !backend.equals(otherBackend))) {
      return false;
    }

    // compare package identifiers
    Package pack = entityType.getPackage();
    Package otherPackage = otherEntityType.getPackage();
    if (pack == null && otherPackage != null) return false;
    if (pack != null && otherPackage == null) return false;
    if (pack != null && !pack.getIdValue().equals(otherPackage.getIdValue())) {
      return false;
    }

    // compare id attribute identifier (identifier might be null if id attribute hasn't been
    // persisted yet)
    Attribute ownIdAttribute = entityType.getOwnIdAttribute();
    Attribute otherOwnIdAttribute = otherEntityType.getOwnIdAttribute();
    if (ownIdAttribute == null && otherOwnIdAttribute != null) return false;
    if (ownIdAttribute != null && otherOwnIdAttribute == null) return false;
    if (ownIdAttribute != null
        && !Objects.equals(ownIdAttribute.getIdentifier(), otherOwnIdAttribute.getIdentifier()))
      return false;

    // compare label attribute identifier (identifier might be null if id attribute hasn't been
    // persisted yet)
    Attribute ownLabelAttribute = entityType.getOwnLabelAttribute();
    Attribute otherOwnLabelAttribute = otherEntityType.getOwnLabelAttribute();
    if (ownLabelAttribute == null && otherOwnLabelAttribute != null) return false;
    if (ownLabelAttribute != null && otherOwnLabelAttribute == null) return false;
    if (ownLabelAttribute != null
        && !Objects.equals(
            ownLabelAttribute.getIdentifier(), otherOwnLabelAttribute.getIdentifier()))
      return false;

    // compare lookup attribute identifiers
    List lookupAttrs = newArrayList(entityType.getOwnLookupAttributes());
    List otherLookupAttrs = newArrayList(otherEntityType.getOwnLookupAttributes());
    if (lookupAttrs.size() != otherLookupAttrs.size()) return false;
    for (int i = 0; i < lookupAttrs.size(); ++i) {
      // identifier might be null if id attribute hasn't been persisted yet
      if (!Objects.equals(
          lookupAttrs.get(i).getIdentifier(), otherLookupAttrs.get(i).getIdentifier())) {
        return false;
      }
    }

    // compare extends entity identifier
    EntityType extendsEntityType = entityType.getExtends();
    EntityType otherExtendsEntityType = otherEntityType.getExtends();
    if (extendsEntityType == null && otherExtendsEntityType != null) return false;
    if (extendsEntityType != null && otherExtendsEntityType == null) return false;
    if (extendsEntityType != null
        && !extendsEntityType.getId().equals(otherExtendsEntityType.getId())) return false;

    // compare attributes
    if (!equals(entityType.getOwnAllAttributes(), otherEntityType.getOwnAllAttributes()))
      return false;

    // compare tag identifiers
    List tags = newArrayList(entityType.getTags());
    List otherTags = newArrayList(otherEntityType.getTags());
    if (tags.size() != otherTags.size()) return false;
    for (int i = 0; i < tags.size(); ++i) {
      if (!tags.get(i).getId().equals(otherTags.get(i).getId())) return false;
    }

    return entityType.getIndexingDepth() == otherEntityType.getIndexingDepth();
  }

  /** Returns true if an Iterable equals another Iterable. */
  public static boolean equals(Iterable attrsIt, Iterable otherAttrsIt) {
    List attrs = newArrayList(attrsIt);
    List otherAttrs = newArrayList(otherAttrsIt);

    if (attrs.size() != otherAttrs.size()) return false;
    for (int i = 0; i < attrs.size(); ++i) {
      if (!equals(attrs.get(i), otherAttrs.get(i))) return false;
    }
    return true;
  }

  /** Returns true if an Iterable equals another Iterable. */
  public static boolean equalsEntities(
      Iterable entityIterable, Iterable otherEntityIterable) {
    List attrs = newArrayList(entityIterable);
    List otherAttrs = newArrayList(otherEntityIterable);

    if (attrs.size() != otherAttrs.size()) return false;
    for (int i = 0; i < attrs.size(); ++i) {
      if (!equals(attrs.get(i), otherAttrs.get(i))) return false;
    }
    return true;
  }

  /** Returns true if a Tag equals another Tag. */
  public static boolean equals(Tag tag, Tag otherTag) {
    if (!Objects.equals(tag.getId(), otherTag.getId())) return false;
    if (!Objects.equals(tag.getObjectIri(), otherTag.getObjectIri())) return false;
    if (!Objects.equals(tag.getLabel(), otherTag.getLabel())) return false;
    if (!Objects.equals(tag.getRelationIri(), otherTag.getRelationIri())) return false;
    if (!Objects.equals(tag.getRelationLabel(), otherTag.getRelationLabel())) return false;
    return Objects.equals(tag.getCodeSystem(), otherTag.getCodeSystem());
  }

  /** Returns true if an attribute equals another attribute. */
  public static boolean equals(Attribute attr, Attribute otherAttr) {
    return equals(attr, otherAttr, true);
  }

  /**
   * Returns true if an attribute equals another attribute. Skips the identifier if checkIdentifier
   * is set to false
   *
   * 

Other attribute identifiers can be null when importing and this attribute has not been * persisted to the db yet * * @param checkIdentifier skips checking attribute identifier, parent attribute identifier and * attribute entity identifier */ public static boolean equals(Attribute attr, Attribute otherAttr, boolean checkIdentifier) { if (attr == null || otherAttr == null) { return (attr == null && otherAttr == null); } if (checkIdentifier && !Objects.equals(attr.getIdentifier(), otherAttr.getIdentifier())) { return false; } if (!Objects.equals(attr.getName(), otherAttr.getName())) { return false; } EntityType entity = attr.getEntity(); EntityType otherEntity = otherAttr.getEntity(); if (checkIdentifier) { if (entity == null && otherEntity != null) { return false; } if (entity != null && otherEntity == null) { return false; } if (entity != null && !entity.getId().equals(otherEntity.getId())) { return false; } } if (!Objects.equals(attr.getSequenceNumber(), otherAttr.getSequenceNumber())) { return false; } if (!Objects.equals(attr.getLabel(), otherAttr.getLabel())) { return false; } if (!LanguageService.getLanguageCodes() .allMatch( languageCode -> Objects.equals(attr.getLabel(languageCode), otherAttr.getLabel(languageCode)))) { return false; } if (!Objects.equals(attr.getDescription(), otherAttr.getDescription())) { return false; } if (!LanguageService.getLanguageCodes() .allMatch( languageCode -> Objects.equals( attr.getDescription(languageCode), otherAttr.getDescription(languageCode)))) { return false; } if (!Objects.equals(attr.getDataType(), otherAttr.getDataType())) { return false; } if (!Objects.equals(attr.isIdAttribute(), otherAttr.isIdAttribute())) { return false; } if (!Objects.equals(attr.isLabelAttribute(), otherAttr.isLabelAttribute())) { return false; } if (!Objects.equals(attr.getLookupAttributeIndex(), otherAttr.getLookupAttributeIndex())) { return false; } // recursively compare attribute parent if (!EntityUtils.equals(attr.getParent(), otherAttr.getParent(), checkIdentifier)) { return false; } // compare entity identifier if (attr.hasRefEntity() && !otherAttr.hasRefEntity()) { return false; } if (!attr.hasRefEntity() && otherAttr.hasRefEntity()) { return false; } if (attr.hasRefEntity() && !attr.getRefEntity().getId().equals(otherAttr.getRefEntity().getId())) { return false; } if (!Objects.equals(attr.getCascadeDelete(), otherAttr.getCascadeDelete())) { return false; } if (!EntityUtils.equals(attr.getMappedBy(), otherAttr.getMappedBy(), checkIdentifier)) { return false; } if (!Objects.equals(attr.getOrderBy(), otherAttr.getOrderBy())) { return false; } if (!Objects.equals(attr.getExpression(), otherAttr.getExpression())) { return false; } if (!Objects.equals(attr.isNillable(), otherAttr.isNillable())) { return false; } if (!Objects.equals(attr.isAuto(), otherAttr.isAuto())) { return false; } if (!Objects.equals(attr.isVisible(), otherAttr.isVisible())) { return false; } if (!Objects.equals(attr.isAggregatable(), otherAttr.isAggregatable())) { return false; } if (!Objects.equals(attr.getEnumOptions(), otherAttr.getEnumOptions())) { return false; } if (!Objects.equals(attr.getRangeMin(), otherAttr.getRangeMin())) { return false; } if (!Objects.equals(attr.getRangeMax(), otherAttr.getRangeMax())) { return false; } if (!Objects.equals(attr.isReadOnly(), otherAttr.isReadOnly())) { return false; } if (!Objects.equals(attr.isUnique(), otherAttr.isUnique())) { return false; } if (!Objects.equals(attr.getNullableExpression(), otherAttr.getNullableExpression())) { return false; } if (!Objects.equals(attr.getVisibleExpression(), otherAttr.getVisibleExpression())) { return false; } if (!Objects.equals(attr.getValidationExpression(), otherAttr.getValidationExpression())) { return false; } if (!Objects.equals(attr.getDefaultValue(), otherAttr.getDefaultValue())) { return false; } // compare tag identifiers List tags = newArrayList(attr.getTags()); List otherTags = newArrayList(otherAttr.getTags()); if (tags.size() != otherTags.size()) { return false; } for (int i = 0; i < tags.size(); ++i) { if (!Objects.equals(tags.get(i).getId(), otherTags.get(i).getId())) { return false; } } return true; } /** * Returns true if entity equals another entity. For referenced entities compares the referenced * entity ids. * * @return true if entity equals another entity */ public static boolean equals(Entity entity, Entity otherEntity) { if (entity == null && otherEntity != null) return false; if (entity != null && otherEntity == null) return false; if (entity == null) return true; if (!entity.getEntityType().getId().equals(otherEntity.getEntityType().getId())) return false; for (Attribute attr : entity.getEntityType().getAtomicAttributes()) { String attrName = attr.getName(); switch (attr.getDataType()) { case BOOL: if (!Objects.equals(entity.getBoolean(attrName), otherEntity.getBoolean(attrName))) return false; break; case CATEGORICAL: case FILE: case XREF: Entity xrefValue = entity.getEntity(attrName); Entity otherXrefValue = otherEntity.getEntity(attrName); if (xrefValue == null && otherXrefValue != null) return false; if (xrefValue != null && otherXrefValue == null) return false; if (xrefValue != null && otherXrefValue != null && !xrefValue.getIdValue().equals(otherXrefValue.getIdValue())) return false; break; case CATEGORICAL_MREF: case ONE_TO_MANY: case MREF: List entities = newArrayList(entity.getEntities(attrName)); List otherEntities = newArrayList(otherEntity.getEntities(attrName)); if (entities.size() != otherEntities.size()) return false; for (int i = 0; i < entities.size(); ++i) { Entity mrefValue = entities.get(i); Entity otherMrefValue = otherEntities.get(i); if (mrefValue == null && otherMrefValue != null) return false; if (mrefValue != null && otherMrefValue == null) return false; if (mrefValue != null && otherMrefValue != null && !mrefValue.getIdValue().equals(otherMrefValue.getIdValue())) return false; } break; case COMPOUND: throw new RuntimeException(format("Invalid data type [%s]", attr.getDataType())); case DATE: if (!Objects.equals(entity.getLocalDate(attrName), otherEntity.getLocalDate(attrName))) return false; break; case DATE_TIME: if (!Objects.equals(entity.getInstant(attrName), otherEntity.getInstant(attrName))) return false; break; case DECIMAL: if (!Objects.equals(entity.getDouble(attrName), otherEntity.getDouble(attrName))) return false; break; case EMAIL: case ENUM: case HTML: case HYPERLINK: case SCRIPT: case STRING: case TEXT: if (!Objects.equals(entity.getString(attrName), otherEntity.getString(attrName))) return false; break; case INT: if (!Objects.equals(entity.getInt(attrName), otherEntity.getInt(attrName))) return false; break; case LONG: if (!Objects.equals(entity.getLong(attrName), otherEntity.getLong(attrName))) return false; break; default: throw new UnexpectedEnumException(attr.getDataType()); } } return true; } public static int hashCode(Entity entity) { int h = 0; for (Attribute attr : entity.getEntityType().getAtomicAttributes()) { int hValue = 0; String attrName = attr.getName(); switch (attr.getDataType()) { case BOOL: hValue = Objects.hashCode(entity.getBoolean(attrName)); break; case CATEGORICAL: case FILE: case XREF: Entity xrefValue = entity.getEntity(attrName); Object xrefIdValue = xrefValue != null ? xrefValue.getIdValue() : null; hValue = Objects.hashCode(xrefIdValue); break; case CATEGORICAL_MREF: case ONE_TO_MANY: case MREF: for (Entity mrefValue : entity.getEntities(attrName)) { Object mrefIdValue = mrefValue != null ? mrefValue.getIdValue() : null; hValue += Objects.hashCode(mrefIdValue); } break; case COMPOUND: throw new RuntimeException(format("Invalid data type [%s]", attr.getDataType())); case DATE: hValue = Objects.hashCode(entity.getLocalDate(attrName)); break; case DATE_TIME: hValue = Objects.hashCode(entity.getInstant(attrName)); break; case DECIMAL: hValue = Objects.hashCode(entity.getDouble(attrName)); break; case EMAIL: case ENUM: case HTML: case HYPERLINK: case SCRIPT: case STRING: case TEXT: hValue = Objects.hashCode(entity.getString(attrName)); break; case INT: hValue = Objects.hashCode(entity.getInt(attrName)); break; case LONG: hValue = Objects.hashCode(entity.getLong(attrName)); break; default: throw new UnexpectedEnumException(attr.getDataType()); } h += Objects.hashCode(attrName) ^ hValue; } int result = entity.getEntityType().getId().hashCode(); return 31 * result + h; } /** * Returns whether an entity attribute value is null or empty for attributes referencing * multiple entities. */ public static boolean isNullValue(Entity entity, Attribute attribute) { boolean isNullValue; String attributeName = attribute.getName(); AttributeType attributeType = attribute.getDataType(); switch (attributeType) { case BOOL: isNullValue = entity.getBoolean(attributeName) == null; break; case CATEGORICAL: case FILE: case XREF: isNullValue = entity.getEntity(attributeName) == null; break; case CATEGORICAL_MREF: case MREF: case ONE_TO_MANY: Iterable refEntities = entity.getEntities(attributeName); isNullValue = Iterables.isEmpty(refEntities); break; case COMPOUND: throw new RuntimeException(format("Invalid data type [%s]", attribute.getDataType())); case DATE: isNullValue = entity.getLocalDate(attributeName) == null; break; case DATE_TIME: isNullValue = entity.getInstant(attributeName) == null; break; case DECIMAL: isNullValue = entity.getDouble(attributeName) == null; break; case EMAIL: case ENUM: case HTML: case HYPERLINK: case SCRIPT: case STRING: case TEXT: isNullValue = entity.getString(attributeName) == null; break; case INT: isNullValue = entity.getInt(attributeName) == null; break; case LONG: isNullValue = entity.getLong(attributeName) == null; break; default: throw new UnexpectedEnumException(attributeType); } return isNullValue; } /** Returns whether two entities have the same identifier and same entity type identifier. */ public static boolean isSame(Entity thisEntity, Entity thatEntity) { return thisEntity == thatEntity || thisEntity.getIdValue().equals(thatEntity.getIdValue()) && thisEntity.getEntityType().getId().equals(thatEntity.getEntityType().getId()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy