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

org.apache.cayenne.project.validation.ObjAttributeValidator Maven / Gradle / Ivy

There is a newer version: 5.0-M1
Show newest version
/*****************************************************************
 *   Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 ****************************************************************/
package org.apache.cayenne.project.validation;

import java.util.Map;

import org.apache.cayenne.exp.ExpressionException;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.Embeddable;
import org.apache.cayenne.map.EmbeddableAttribute;
import org.apache.cayenne.map.EmbeddedAttribute;
import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.util.Util;
import org.apache.cayenne.validation.ValidationResult;

class ObjAttributeValidator extends ConfigurationNodeValidator {

    void validate(ObjAttribute attribute, ValidationResult validationResult) {

        validateName(attribute, validationResult);

        // all attributes must have type
        if (Util.isEmptyString(attribute.getType())) {
            addFailure(validationResult, attribute,
                    "ObjAttribute '%s' has no Java type",
                    attribute.getName());
        }

        if (attribute instanceof EmbeddedAttribute) {
            validateEmbeddable((EmbeddedAttribute)attribute, validationResult);
        } else {
            validateDbAttribute(attribute, validationResult);
        }

        checkForDuplicates(attribute, validationResult);
        checkSuperEntityAttributes(attribute, validationResult);
    }

    private void validateName(ObjAttribute attribute, ValidationResult validationResult) {
        // Must have name
        if (Util.isEmptyString(attribute.getName())) {
            addFailure(validationResult, attribute, "Unnamed ObjAttribute");
            return;
        }

        NameValidationHelper helper = NameValidationHelper.getInstance();
        String invalidChars = helper.invalidCharsInObjPathComponent(attribute.getName());

        if (invalidChars != null) {
            addFailure(validationResult, attribute,
                    "ObjAttribute name '%s' contains invalid characters: %s",
                    attribute.getName(),
                    invalidChars);
        } else if (helper.invalidDataObjectProperty(attribute.getName())) {
            addFailure(validationResult, attribute,
                    "ObjAttribute name '%s' is invalid",
                    attribute.getName());
        }
    }

    private void checkSuperEntityAttributes(ObjAttribute attribute, ValidationResult validationResult) {
        // Check there is an attribute in entity and super entity at the same time

        boolean selfAttribute = false;
        if (attribute.getEntity().getDeclaredAttribute(attribute.getName()) != null) {
            selfAttribute = true;
        }

        ObjEntity superEntity = attribute.getEntity().getSuperEntity();
        if (selfAttribute && superEntity != null && superEntity.getAttribute(attribute.getName()) != null) {
            addFailure(validationResult, attribute, "'%s' and super '%s' can't have attribute '%s' together ",
                    attribute.getEntity().getName(), superEntity.getName(), attribute.getName());
        }
    }

    private void validateDbAttribute(ObjAttribute attribute, ValidationResult validationResult) {
        if (attribute.getEntity().isAbstract()) {
            // nothing to validate
            // abstract entity does not have to define a dbAttribute
            return;
        }

        DbAttribute dbAttribute;
        try {
            dbAttribute = attribute.getDbAttribute();
        } catch (ExpressionException e) {
            // see CAY-2153
            // getDbAttribute() can fail if db path for this attribute is invalid
            // so we catch it here and show nice validation failure instead of crash
            addFailure(validationResult, attribute,
                    "ObjAttribute '%s' has invalid DB path: %s",
                    attribute.getName(),
                    e.getExpressionString());
            return;
        }

        if (dbAttribute == null) {
            addFailure(validationResult, attribute,
                    "ObjAttribute '%s' has no DbAttribute mapping",
                    attribute.getName());
            return;
        }

        if (dbAttribute.isPrimaryKey() && dbAttribute.isGenerated()) {
            // can't support generated meaningful attributes for now;
            // besides they don't make sense.
            // TODO: andrus 03/10/2010 - is that really so? I think those are supported...
            addFailure(validationResult, attribute,
                    "ObjAttribute '%s' is mapped to a generated PK: %s",
                    attribute.getName(),
                    attribute.getDbAttributeName());
        }
    }

    private void validateEmbeddable(EmbeddedAttribute attribute, ValidationResult validationResult) {
        Embeddable embeddable = attribute.getEmbeddable();

        if (embeddable == null) {
            String msg = attribute.getType() == null ?
                    "EmbeddedAttribute '%s' has no Embeddable" :
                    "EmbeddedAttribute '%s' has incorrect Embeddable";

            addFailure(validationResult, attribute, msg, attribute.getName());
            return;
        }

        Map attrOverrides = attribute.getAttributeOverrides();

        for (EmbeddableAttribute embeddableAttribute : embeddable.getAttributes()) {
            String dbAttributeName;
            if (!attrOverrides.isEmpty()
                    && attrOverrides.containsKey(embeddableAttribute.getName())) {
                dbAttributeName = attrOverrides.get(embeddableAttribute.getName());
            } else {
                dbAttributeName = embeddableAttribute.getDbAttributeName();
            }

            if (Util.isEmptyString(dbAttributeName)) {
                addFailure(validationResult, attribute,
                        "EmbeddedAttribute '%s' has no DbAttribute mapping",
                        attribute.getName());
            } else if (attribute.getEntity()
                    .getDbEntity()
                    .getAttribute(dbAttributeName) == null) {
                addFailure(validationResult, attribute,
                        "EmbeddedAttribute '%s' has incorrect DbAttribute mapping",
                        attribute.getName());
            }
        }
    }

    /**
     * Per CAY-1813, make sure two (or more) ObjAttributes do not map to the
     * same database path.
     */
    private void checkForDuplicates(ObjAttribute     attribute,
                                    ValidationResult validationResult) {
        if ( attribute               != null &&
             attribute.getName()     != null &&
            !attribute.isInherited()) {

            ObjEntity entity = attribute.getEntity();

            for (ObjAttribute comparisonAttribute : entity.getAttributes()) {
                if (attribute != comparisonAttribute) {
                    String dbAttributePath = attribute.getDbAttributePath();

                    if (dbAttributePath != null) {
                        if (dbAttributePath.equals(comparisonAttribute.getDbAttributePath())) {
                            addFailure(validationResult, attribute,
                                 "ObjEntity '%s' contains a duplicate DbAttribute mapping ('%s' -> '%s')",
                                 entity.getName(),
                                 attribute.getName(),
                                 dbAttributePath);
                            return; // Duplicate found, stop.
                        }
                    }
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy