Search in sources :

Example 1 with AttributeType

use of org.molgenis.data.meta.AttributeType in project molgenis by molgenis.

the class EmxMetaDataParser method parseAttributesSheet.

/**
 * Load all attributes from the source repository and add it to the {@link IntermediateParseResults}.
 *
 * @param attributesRepo      Repository for the attributes
 * @param intermediateResults {@link IntermediateParseResults} with the tags already parsed
 */
private void parseAttributesSheet(Repository<Entity> attributesRepo, IntermediateParseResults intermediateResults) {
    for (Attribute attr : attributesRepo.getEntityType().getAtomicAttributes()) {
        if (!SUPPORTED_ATTRIBUTE_ATTRIBUTES.contains(attr.getName()) && !((isI18n(attr.getName()) && (attr.getName().startsWith(EMX_ATTRIBUTES_LABEL) || attr.getName().startsWith(EMX_ATTRIBUTES_DESCRIPTION))))) {
            // check if casing mismatch
            SUPPORTED_ATTRIBUTE_ATTRIBUTES.forEach(emxAttrMetaAttr -> {
                if (emxAttrMetaAttr.equalsIgnoreCase(attr.getName())) {
                    throw new IllegalArgumentException(format("Unsupported attribute metadata: attributes.%s, did you mean attributes.%s?", attr.getName(), emxAttrMetaAttr));
                }
            });
            throw new IllegalArgumentException("Unsupported attribute metadata: attributes." + attr.getName());
        }
    }
    Map<String, Map<String, EmxAttribute>> attributesMap = newLinkedHashMap();
    // 1st pass: create attribute stubs
    // Header
    int rowIndex = 1;
    for (Entity attributeEntity : attributesRepo) {
        rowIndex++;
        String attributeName = attributeEntity.getString(EMX_ATTRIBUTES_NAME);
        if (attributeName == null)
            throw new IllegalArgumentException(format("attributes.name is missing on line [%d]", rowIndex));
        String entityTypeId = attributeEntity.getString(EMX_ATTRIBUTES_ENTITY);
        if (entityTypeId == null)
            throw new IllegalArgumentException(format("attributes.entity is missing for attribute named: %s on line [%d]", attributeName, rowIndex));
        // create attribute
        Attribute attribute = attrMetaFactory.create().setName(attributeName);
        Map<String, EmxAttribute> entitiesMap = attributesMap.computeIfAbsent(entityTypeId, k -> newLinkedHashMap());
        entitiesMap.put(attributeName, new EmxAttribute(attribute));
    }
    // 2nd pass: set all properties on attribute stubs except for attribute relations
    // Header
    rowIndex = 1;
    for (Entity emxAttrEntity : attributesRepo) {
        rowIndex++;
        String emxEntityName = emxAttrEntity.getString(EMX_ATTRIBUTES_ENTITY);
        Map<String, EmxAttribute> entityMap = attributesMap.get(emxEntityName);
        // If an entity is defined in the attribute sheet only,
        // make sure to create EntityType and set the backend
        EntityType md = intermediateResults.getEntityType(emxEntityName);
        if (md == null) {
            md = intermediateResults.addEntityType(emxEntityName);
            if (dataService != null)
                md.setBackend(dataService.getMeta().getDefaultBackend().getName());
        }
        String emxName = emxAttrEntity.getString(EMX_ATTRIBUTES_NAME);
        EmxAttribute emxAttr = entityMap.get(emxName);
        Attribute attr = emxAttr.getAttr();
        String emxDataType = emxAttrEntity.getString(EMX_ATTRIBUTES_DATA_TYPE);
        String emxRefEntity = emxAttrEntity.getString(EMX_ATTRIBUTES_REF_ENTITY);
        if (emxDataType != null) {
            AttributeType type = toEnum(emxDataType);
            if (type == null) {
                throw new IllegalArgumentException("attributes.dataType error on line " + rowIndex + ": " + emxDataType + " unknown data type");
            }
            attr.setDataType(type);
        } else {
            attr.setDataType(STRING);
        }
        String emxAttrNillable = emxAttrEntity.getString(EMX_ATTRIBUTES_NILLABLE);
        String emxIdAttrValue = emxAttrEntity.getString(EMX_ATTRIBUTES_ID_ATTRIBUTE);
        String emxAttrVisible = emxAttrEntity.getString(EMX_ATTRIBUTES_VISIBLE);
        String emxAggregatable = emxAttrEntity.getString(EMX_ATTRIBUTES_AGGREGATEABLE);
        String emxIsLookupAttr = emxAttrEntity.getString(EMX_ATTRIBUTES_LOOKUP_ATTRIBUTE);
        String emxIsLabelAttr = emxAttrEntity.getString(EMX_ATTRIBUTES_LABEL_ATTRIBUTE);
        String emxReadOnly = emxAttrEntity.getString(EMX_ATTRIBUTES_READ_ONLY);
        String emxUnique = emxAttrEntity.getString(EMX_ATTRIBUTES_UNIQUE);
        String expression = emxAttrEntity.getString(EMX_ATTRIBUTES_EXPRESSION);
        String validationExpression = emxAttrEntity.getString(EMX_ATTRIBUTES_VALIDATION_EXPRESSION);
        String defaultValue = emxAttrEntity.getString(EMX_ATTRIBUTES_DEFAULT_VALUE);
        Object emxAttrTags = emxAttrEntity.get(EMX_ENTITIES_TAGS);
        List<String> tagIdentifiers = toList(emxAttrTags);
        if (tagIdentifiers != null && !tagIdentifiers.isEmpty()) {
            attr.setTags(toTags(intermediateResults, tagIdentifiers));
        }
        if (emxAttrNillable != null) {
            if (emxAttrNillable.equalsIgnoreCase("true") || emxAttrNillable.equalsIgnoreCase("false")) {
                attr.setNillable(parseBoolean(emxAttrNillable, rowIndex, EMX_ATTRIBUTES_NILLABLE));
            } else {
                attr.setNullableExpression(emxAttrNillable);
            }
        }
        if (emxIdAttrValue != null) {
            if (!emxIdAttrValue.equalsIgnoreCase("true") && !emxIdAttrValue.equalsIgnoreCase("false") && !emxIdAttrValue.equalsIgnoreCase(AUTO)) {
                throw new IllegalArgumentException(format("Attributes error on line [%d]. Illegal idAttribute value. Allowed values are 'TRUE', 'FALSE' or 'AUTO'", rowIndex));
            }
            if (emxIdAttrValue.equalsIgnoreCase("true")) {
                if (!isIdAttributeTypeAllowed(attr)) {
                    throw new MolgenisDataException("Identifier is of type [" + attr.getDataType() + "]. Id attributes can only be of type 'STRING', 'INT' or 'LONG'");
                }
            }
            attr.setAuto(emxIdAttrValue.equalsIgnoreCase(AUTO));
            if (!attr.isAuto())
                emxAttr.setIdAttr(parseBoolean(emxIdAttrValue, rowIndex, EMX_ATTRIBUTES_ID_ATTRIBUTE));
            else
                // If it is auto, set idAttr to true
                emxAttr.setIdAttr(true);
        }
        if (attr.isAuto() && !isStringType(attr)) {
            throw new IllegalArgumentException(format("Attributes error on line [%d]. Auto attributes can only be of data type 'string'", rowIndex));
        }
        if (emxAttrVisible != null) {
            if (emxAttrVisible.equalsIgnoreCase("true") || emxAttrVisible.equalsIgnoreCase("false")) {
                attr.setVisible(parseBoolean(emxAttrVisible, rowIndex, EMX_ATTRIBUTES_VISIBLE));
            } else {
                attr.setVisibleExpression(emxAttrVisible);
            }
        }
        if (emxAggregatable != null)
            attr.setAggregatable(parseBoolean(emxAggregatable, rowIndex, EMX_ATTRIBUTES_AGGREGATEABLE));
        if (emxReadOnly != null)
            attr.setReadOnly(parseBoolean(emxReadOnly, rowIndex, EMX_ATTRIBUTES_READ_ONLY));
        if (emxUnique != null)
            attr.setUnique(parseBoolean(emxUnique, rowIndex, EMX_ATTRIBUTES_UNIQUE));
        if (expression != null)
            attr.setExpression(expression);
        if (validationExpression != null)
            attr.setValidationExpression(validationExpression);
        if (defaultValue != null)
            attr.setDefaultValue(defaultValue);
        if (emxIsLookupAttr != null) {
            boolean isLookAttr = parseBoolean(emxIsLookupAttr, rowIndex, EMX_ATTRIBUTES_LOOKUP_ATTRIBUTE);
            if (isLookAttr && isReferenceType(attr)) {
                throw new IllegalArgumentException(format("attributes.lookupAttribute error on line [%d] (%s.%s) lookupAttribute cannot be of type %s", rowIndex, emxEntityName, emxName, attr.getDataType().toString()));
            }
            emxAttr.setLookupAttr(isLookAttr);
        }
        if (emxIsLabelAttr != null) {
            boolean isLabelAttr = parseBoolean(emxIsLabelAttr, rowIndex, EMX_ATTRIBUTES_LABEL_ATTRIBUTE);
            if (isLabelAttr && isReferenceType(attr)) {
                throw new IllegalArgumentException(format("attributes.labelAttribute error on line [%d] (%s.%s): labelAttribute cannot be of type %s", rowIndex, emxEntityName, emxName, attr.getDataType().toString()));
            }
            emxAttr.setLabelAttr(isLabelAttr);
        }
        attr.setLabel(emxAttrEntity.getString(EMX_ATTRIBUTES_LABEL));
        for (String attrName : emxAttrEntity.getAttributeNames()) {
            if (isI18n(attrName)) {
                if (attrName.startsWith(EMX_ATTRIBUTES_LABEL)) {
                    String label = emxAttrEntity.getString(attrName);
                    if (label != null) {
                        String languageCode = getLanguageCode(attrName);
                        attr.setLabel(languageCode, label);
                    }
                } else if (attrName.startsWith(EMX_ATTRIBUTES_DESCRIPTION)) {
                    String description = emxAttrEntity.getString(attrName);
                    if (description != null) {
                        String languageCode = getLanguageCode(attrName);
                        attr.setDescription(languageCode, description);
                    }
                }
            }
        }
        attr.setDescription(emxAttrEntity.getString(EMX_ATTRIBUTES_DESCRIPTION));
        if (attr.getDataType() == ENUM) {
            List<String> enumOptions = DataConverter.toList(emxAttrEntity.get(EMX_ATTRIBUTES_ENUM_OPTIONS));
            if (enumOptions == null || enumOptions.isEmpty()) {
                throw new IllegalArgumentException(format("Missing enum options for attribute [%s] of entity [%s]", attr.getName(), emxEntityName));
            }
            attr.setEnumOptions(enumOptions);
        }
        if (attr.getDataType() != FILE) {
            // Only if an attribute is not of type file we apply the normal reference rules
            if (isReferenceType(attr) && StringUtils.isEmpty(emxRefEntity)) {
                throw new IllegalArgumentException(format("Missing refEntity on line [%d] (%s.%s)", rowIndex, emxEntityName, emxName));
            }
        }
        if (isReferenceType(attr) && attr.isNillable() && attr.isAggregatable()) {
            throw new IllegalArgumentException(format("attributes.isAggregatable error on line [%d] (%s.%s): isAggregatable nillable attribute cannot be of type %s", rowIndex, emxEntityName, emxName, attr.getDataType().toString()));
        }
        String emxRangeMin = emxAttrEntity.getString(EMX_ATTRIBUTES_RANGE_MIN);
        Long rangeMin;
        if (emxRangeMin != null) {
            try {
                rangeMin = Long.valueOf(emxRangeMin);
            } catch (NumberFormatException e) {
                throw new MolgenisDataException(format("Invalid range rangeMin [%s] value for attribute [%s] of entity [%s], should be a long", emxRangeMin, emxName, emxEntityName));
            }
        } else {
            rangeMin = null;
        }
        String emxRangeMax = emxAttrEntity.getString(EMX_ATTRIBUTES_RANGE_MAX);
        Long rangeMax;
        if (emxRangeMax != null) {
            try {
                rangeMax = Long.valueOf(emxRangeMax);
            } catch (NumberFormatException e) {
                throw new MolgenisDataException(format("Invalid range rangeMax [%s] value for attribute [%s] of entity [%s], should be a long", emxRangeMax, emxName, emxEntityName));
            }
        } else {
            rangeMax = null;
        }
        if (rangeMin != null || rangeMax != null) {
            attr.setRange(new Range(rangeMin, rangeMax));
        }
    }
    // 3rd pass: validate and create attribute relationships
    Map<String, Set<String>> rootAttributes = newLinkedHashMap();
    // Header
    rowIndex = 1;
    for (Entity attributeEntity : attributesRepo) {
        rowIndex++;
        String entityTypeId = attributeEntity.getString(EMX_ATTRIBUTES_ENTITY);
        Map<String, EmxAttribute> entityMap = attributesMap.get(entityTypeId);
        String attributeName = attributeEntity.getString(EMX_ATTRIBUTES_NAME);
        Attribute attribute = entityMap.get(attributeName).getAttr();
        // bootstrap attribute parent-children relations for compound attributes
        String partOfAttribute = attributeEntity.getString(EMX_ATTRIBUTES_PART_OF_ATTRIBUTE);
        if (partOfAttribute != null && !partOfAttribute.isEmpty()) {
            EmxAttribute emxCompoundAttribute = entityMap.get(partOfAttribute);
            if (emxCompoundAttribute == null) {
                throw new IllegalArgumentException("partOfAttribute [" + partOfAttribute + "] of attribute [" + attributeName + "] of entity [" + entityTypeId + "] must refer to an existing compound attribute on line " + rowIndex);
            }
            Attribute compoundAttribute = emxCompoundAttribute.getAttr();
            if (compoundAttribute.getDataType() != COMPOUND) {
                throw new IllegalArgumentException("partOfAttribute [" + partOfAttribute + "] of attribute [" + attributeName + "] of entity [" + entityTypeId + "] must refer to a attribute of type [" + COMPOUND + "] on line " + rowIndex);
            }
            attribute.setParent(compoundAttribute);
        }
        Set<String> entityRootAttributes = rootAttributes.computeIfAbsent(entityTypeId, k -> new LinkedHashSet<>());
        entityRootAttributes.add(attributeName);
    }
    // store attributes with entities
    for (Map.Entry<String, Map<String, EmxAttribute>> entry : attributesMap.entrySet()) {
        String entityTypeId = entry.getKey();
        Map<String, EmxAttribute> attributes = entry.getValue();
        List<EmxAttribute> editableEntityType = newArrayList();
        // add root attributes to entity
        Set<String> entityAttributeNames = rootAttributes.get(entityTypeId);
        if (entityAttributeNames != null) {
            for (EmxAttribute attribute : attributes.values()) {
                if (entityAttributeNames.contains(attribute.getAttr().getName())) {
                    editableEntityType.add(attribute);
                }
            }
        }
        intermediateResults.addAttributes(entityTypeId, editableEntityType);
    }
}
Also used : L10nString(org.molgenis.data.i18n.model.L10nString) SystemEntityType(org.molgenis.data.meta.SystemEntityType) AttributeType(org.molgenis.data.meta.AttributeType) ImmutableMap(com.google.common.collect.ImmutableMap) Maps.newHashMap(com.google.common.collect.Maps.newHashMap) Maps.newLinkedHashMap(com.google.common.collect.Maps.newLinkedHashMap)

Example 2 with AttributeType

use of org.molgenis.data.meta.AttributeType in project molgenis by molgenis.

the class DynamicEntity method validateValueType.

/**
 * Validate is value is of the type defined by the attribute data type.
 *
 * @param attrName attribute name
 * @param value    value (must be of the type defined by the attribute data type.)
 */
protected void validateValueType(String attrName, Object value) {
    if (value == null) {
        return;
    }
    Attribute attr = entityType.getAttribute(attrName);
    if (attr == null) {
        throw new UnknownAttributeException(entityType, attrName);
    }
    AttributeType dataType = attr.getDataType();
    switch(dataType) {
        case BOOL:
            if (!(value instanceof Boolean)) {
                throw new MolgenisDataException(format("Value [%s] is of type [%s] instead of [%s] for attribute: [%s]", value.toString(), value.getClass().getSimpleName(), Boolean.class.getSimpleName(), attrName));
            }
            break;
        case CATEGORICAL:
        // expected type is FileMeta. validation is not possible because molgenis-data does not depend on molgenis-file
        case FILE:
        case XREF:
            if (!(value instanceof Entity)) {
                throw new MolgenisDataException(format("Value [%s] is of type [%s] instead of [%s] for attribute: [%s]", value.toString(), value.getClass().getSimpleName(), Entity.class.getSimpleName(), attrName));
            }
            break;
        case CATEGORICAL_MREF:
        case MREF:
        case ONE_TO_MANY:
            if (!(value instanceof Iterable)) {
                throw new MolgenisDataException(format("Value [%s] is of type [%s] instead of [%s] for attribute: [%s]", value.toString(), value.getClass().getSimpleName(), Iterable.class.getSimpleName(), attrName));
            }
            break;
        case COMPOUND:
            throw new IllegalArgumentException(format("Unexpected data type [%s] for attribute: [%s]", dataType.toString(), attrName));
        case DATE:
            if (!(value instanceof LocalDate)) {
                throw new MolgenisDataException(format("Value [%s] is of type [%s] instead of [%s] for attribute: [%s]", value.toString(), value.getClass().getSimpleName(), LocalDate.class.getSimpleName(), attrName));
            }
            break;
        case DATE_TIME:
            if (!(value instanceof Instant)) {
                throw new MolgenisDataException(format("Value [%s] is of type [%s] instead of [%s] for attribute: [%s]", value.toString(), value.getClass().getSimpleName(), Instant.class.getSimpleName(), attrName));
            }
            break;
        case DECIMAL:
            if (!(value instanceof Double)) {
                throw new MolgenisDataException(format("Value [%s] is of type [%s] instead of [%s] for attribute: [%s]", value.toString(), value.getClass().getSimpleName(), Double.class.getSimpleName(), attrName));
            }
            if (((Double) value).isNaN()) {
                throw new MolgenisDataException(format("Value [%s] for type [%s] is not allowed for attribute: [%s]", value.toString(), Double.class.getSimpleName(), attrName));
            }
            break;
        case EMAIL:
        case ENUM:
        case HTML:
        case HYPERLINK:
        case SCRIPT:
        case STRING:
        case TEXT:
            if (!(value instanceof String)) {
                throw new MolgenisDataException(format("Value [%s] is of type [%s] instead of [%s] for attribute: [%s]", value.toString(), value.getClass().getSimpleName(), String.class.getSimpleName(), attrName));
            }
            break;
        case INT:
            if (!(value instanceof Integer)) {
                throw new MolgenisDataException(format("Value [%s] is of type [%s] instead of [%s] for attribute: [%s]", value.toString(), value.getClass().getSimpleName(), Integer.class.getSimpleName(), attrName));
            }
            break;
        case LONG:
            if (!(value instanceof Long)) {
                throw new MolgenisDataException(format("Value [%s] is of type [%s] instead of [%s] for attribute: [%s]", value.toString(), value.getClass().getSimpleName(), Long.class.getSimpleName(), attrName));
            }
            break;
        default:
            throw new UnexpectedEnumException(dataType);
    }
}
Also used : Entity(org.molgenis.data.Entity) Attribute(org.molgenis.data.meta.model.Attribute) Instant(java.time.Instant) LocalDate(java.time.LocalDate) UnexpectedEnumException(org.molgenis.util.UnexpectedEnumException) MolgenisDataException(org.molgenis.data.MolgenisDataException) AttributeType(org.molgenis.data.meta.AttributeType) UnknownAttributeException(org.molgenis.data.UnknownAttributeException)

Example 3 with AttributeType

use of org.molgenis.data.meta.AttributeType in project molgenis by molgenis.

the class EntityTypeUtilsTest method isMultipleReferenceTypeProvider.

@DataProvider(name = "isMultipleReferenceTypeProvider")
public static Iterator<Object[]> isMultipleReferenceTypeProvider() {
    List<Object[]> dataList = Lists.newArrayList();
    for (AttributeType attrType : AttributeType.values()) {
        Attribute attr = mock(Attribute.class);
        when(attr.getDataType()).thenReturn(attrType);
        when(attr.toString()).thenReturn("attr_" + attrType.toString());
        boolean isMultipleRefAttr = attrType == CATEGORICAL_MREF || attrType == MREF || attrType == ONE_TO_MANY;
        dataList.add(new Object[] { attr, isMultipleRefAttr });
    }
    return dataList.iterator();
}
Also used : Attribute(org.molgenis.data.meta.model.Attribute) AttributeType(org.molgenis.data.meta.AttributeType) DataProvider(org.testng.annotations.DataProvider)

Example 4 with AttributeType

use of org.molgenis.data.meta.AttributeType in project molgenis by molgenis.

the class DocumentContentBuilderTest method createDocumentReferenceProvider.

@DataProvider(name = "createDocumentReference")
public static Iterator<Object[]> createDocumentReferenceProvider() {
    List<Object[]> dataItems = new ArrayList<>();
    String refAttr = "refAttr";
    Entity refEntity = createEntity(refAttr, AttributeType.STRING);
    when(refEntity.getString(refAttr)).thenReturn("str");
    for (AttributeType attributeType : EnumSet.of(CATEGORICAL, FILE, XREF)) {
        dataItems.add(new Object[] { attributeType, null, "{\"attr\":null}" });
        dataItems.add(new Object[] { attributeType, refEntity, "{\"attr\":{\"refAttr\":\"str\"}}" });
    }
    return dataItems.iterator();
}
Also used : Entity(org.molgenis.data.Entity) AttributeType(org.molgenis.data.meta.AttributeType) ArrayList(java.util.ArrayList) DataProvider(org.testng.annotations.DataProvider)

Example 5 with AttributeType

use of org.molgenis.data.meta.AttributeType in project molgenis by molgenis.

the class DocumentContentBuilderTest method createDocumentMultiReferenceProvider.

@DataProvider(name = "createDocumentMultiReference")
public static Iterator<Object[]> createDocumentMultiReferenceProvider() {
    List<Object[]> dataItems = new ArrayList<>();
    String refAttr = "refAttr";
    Entity refEntity = createEntity(refAttr, AttributeType.STRING);
    when(refEntity.getString(refAttr)).thenReturn("str");
    for (AttributeType attributeType : EnumSet.of(CATEGORICAL_MREF, MREF, ONE_TO_MANY)) {
        dataItems.add(new Object[] { attributeType, emptyList(), "{\"attr\":null}" });
        dataItems.add(new Object[] { attributeType, singletonList(refEntity), "{\"attr\":[{\"refAttr\":\"str\"}]}" });
    }
    return dataItems.iterator();
}
Also used : Entity(org.molgenis.data.Entity) AttributeType(org.molgenis.data.meta.AttributeType) ArrayList(java.util.ArrayList) DataProvider(org.testng.annotations.DataProvider)

Aggregations

AttributeType (org.molgenis.data.meta.AttributeType)46 Attribute (org.molgenis.data.meta.model.Attribute)24 UnexpectedEnumException (org.molgenis.util.UnexpectedEnumException)24 LocalDate (java.time.LocalDate)11 Instant (java.time.Instant)10 Entity (org.molgenis.data.Entity)10 EntityType (org.molgenis.data.meta.model.EntityType)7 DataProvider (org.testng.annotations.DataProvider)7 ArrayList (java.util.ArrayList)5 MolgenisDataException (org.molgenis.data.MolgenisDataException)3 Maps.newHashMap (com.google.common.collect.Maps.newHashMap)2 String.format (java.lang.String.format)2 Collectors.toList (java.util.stream.Collectors.toList)2 Test (org.testng.annotations.Test)2 ImmutableMap (com.google.common.collect.ImmutableMap)1 Maps.newLinkedHashMap (com.google.common.collect.Maps.newLinkedHashMap)1 UTC (java.time.ZoneOffset.UTC)1 ChronoUnit (java.time.temporal.ChronoUnit)1 Collection (java.util.Collection)1 Iterator (java.util.Iterator)1