content: /*****************************************************************
   *   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.modeler.editor.cgen;
  
  import java.util.Collection;
  
  import org.apache.cayenne.configuration.BaseConfigurationNodeVisitor;
  import org.apache.cayenne.configuration.ConfigurationNode;
  import org.apache.cayenne.map.DataMap;
  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.map.ObjRelationship;
  import org.apache.cayenne.modeler.util.CodeValidationUtil;
  import org.apache.cayenne.validation.BeanValidationFailure;
  import org.apache.cayenne.validation.SimpleValidationFailure;
  import org.apache.cayenne.validation.ValidationFailure;
  import org.apache.cayenne.validation.ValidationResult;
  
  /**
   * Validator that checks classes and embeddables for code-generation specific problems.
   *
   * @since 4.2
   */
  class CgenValidator {
  
      ValidationResult getValidationResult(Collection<? extends ConfigurationNode> classes) {
          ValidationResult validationResult = new ValidationResult();
          for (ConfigurationNode configurationNode : classes) {
              configurationNode.acceptVisitor(new BaseConfigurationNodeVisitor<Void>() {
                  @Override
                  public Void visitObjEntity(ObjEntity entity) {
                      validateEntity(validationResult, entity);
                      return null;
                  }
  
                  @Override
                  public Void visitEmbeddable(Embeddable embeddable) {
                      validateEmbeddable(validationResult, embeddable);
                      return null;
                  }
  
                  @Override
                  public Void visitDataMap(DataMap dataMap) {
                      return null;
                  }
              });
          }
          return validationResult;
      }
  
      private ValidationFailure validateEmbeddableAttribute(EmbeddableAttribute attribute) {
          return validateAttribute(attribute.getEmbeddable().getClassName(), attribute.getName(), attribute.getType());
      }
  
      private ValidationFailure validateAttribute(String objectName, String attributeName, String attributeType) {
          ValidationFailure emptyName = BeanValidationFailure.validateNotEmpty(objectName, "attribute.name",
                  attributeName);
          if (emptyName != null) {
              return emptyName;
          }
  
          ValidationFailure badName = CodeValidationUtil.validateJavaIdentifier(objectName, "attribute.name",
                  attributeName);
          if (badName != null) {
              return badName;
          }
  
          ValidationFailure emptyType = BeanValidationFailure.validateNotEmpty(objectName, "attribute.type",
                  attributeType);
          if (emptyType != null) {
              return emptyType;
          }
  
          return BeanValidationFailure.validateJavaClassName(objectName, "attribute.type", attributeType);
      }
  
      private ValidationFailure validateEmbeddable(Embeddable embeddable) {
  
          String name = embeddable.getClassName();
  
          ValidationFailure emptyClass = BeanValidationFailure.validateNotEmpty(name, "className",
                  embeddable.getClassName());
          if (emptyClass != null) {
              return emptyClass;
          }
  
          return BeanValidationFailure.validateJavaClassName(name, "className", embeddable.getClassName());
      }
  
      private void validateEntity(ValidationResult validationBuffer, ObjEntity entity) {
  
          ValidationFailure entityFailure = validateEntity(entity);
          if (entityFailure != null) {
              validationBuffer.addFailure(entityFailure);
              return;
          }
  
          for (ObjAttribute attribute : entity.getAttributes()) {
              if (attribute instanceof EmbeddedAttribute) {
                  EmbeddedAttribute embeddedAttribute = (EmbeddedAttribute) attribute;
                  for (ObjAttribute subAttribute : embeddedAttribute.getAttributes()) {
                      ValidationFailure failure = validateEmbeddedAttribute(subAttribute);
                      if (failure != null) {
                          validationBuffer.addFailure(failure);
                          return;
                      }
                  }
              } else {
  
                  ValidationFailure failure = validateAttribute(attribute);
                  if (failure != null) {
                      validationBuffer.addFailure(failure);
                      return;
                  }
              }
          }
  
          for (ObjRelationship rel : entity.getRelationships()) {
              ValidationFailure failure = validateRelationship(rel);
              if (failure != null) {
                  validationBuffer.addFailure(failure);
                  return;
              }
          }
      }
  
      private ValidationFailure validateEntity(ObjEntity entity) {
  
          String name = entity.getName();
  
          if (entity.isGeneric()) {
              return new SimpleValidationFailure(name, "Generic class");
          }
  
          ValidationFailure emptyClass = BeanValidationFailure.validateNotEmpty(name, "className", entity.getClassName());
          if (emptyClass != null) {
              return emptyClass;
          }
  
          ValidationFailure badClass = BeanValidationFailure.validateJavaClassName(name, "className",
                  entity.getClassName());
          if (badClass != null) {
              return badClass;
          }
  
          if (entity.getSuperClassName() != null) {
              return BeanValidationFailure.validateJavaClassName(name, "superClassName", entity.getSuperClassName());
          }
  
          return null;
      }
  
      private ValidationFailure validateAttribute(ObjAttribute attribute) {
          return validateAttribute(attribute.getEntity().getName(), attribute.getName(), attribute.getType());
      }
  
      private ValidationFailure validateEmbeddedAttribute(ObjAttribute attribute) {
  
          String name = attribute.getEntity().getName();
  
          // validate embeddedAttribute and attribute names
          // embeddedAttribute returned attibute as
          // [name_embeddedAttribute].[name_attribute]
          String[] attributes = attribute.getName().split("\\.");
          String nameEmbeddedAttribute = attributes[0];
          int beginIndex = attributes[0].length();
          String attr = attribute.getName().substring(beginIndex + 1);
  
          ValidationFailure emptyEmbeddedName = BeanValidationFailure.validateNotEmpty(name, "attribute.name",
                  nameEmbeddedAttribute);
          if (emptyEmbeddedName != null) {
              return emptyEmbeddedName;
          }
  
          ValidationFailure badEmbeddedName = CodeValidationUtil.validateJavaIdentifier(name, "attribute.name",
                  nameEmbeddedAttribute);
          if (badEmbeddedName != null) {
              return badEmbeddedName;
          }
  
          return validateAttribute(name, attr, attribute.getType());
      }
  
      private ValidationFailure validateRelationship(ObjRelationship relationship) {
  
          String name = relationship.getSourceEntity().getName();
  
          ValidationFailure emptyName = BeanValidationFailure.validateNotEmpty(name, "relationship.name",
                  relationship.getName());
          if (emptyName != null) {
              return emptyName;
          }
  
          ValidationFailure badName = CodeValidationUtil.validateJavaIdentifier(name, "relationship.name",
                  relationship.getName());
          if (badName != null) {
              return badName;
          }
  
          if (!relationship.isToMany()) {
  
              ObjEntity targetEntity = relationship.getTargetEntity();
              if (targetEntity == null) {
  
                  return new BeanValidationFailure(name, "relationship.targetEntity", "No target entity");
              } else if (!targetEntity.isGeneric()) {
                  ValidationFailure emptyClass = BeanValidationFailure.validateNotEmpty(name,
                          "relationship.targetEntity.className", targetEntity.getClassName());
                  if (emptyClass != null) {
                      return emptyClass;
                  }
  
                  return BeanValidationFailure.validateJavaClassName(name, "relationship.targetEntity.className",
                          targetEntity.getClassName());
              }
          }
  
          return null;
      }
  
      private void validateEmbeddable(ValidationResult validationBuffer, Embeddable embeddable) {
          ValidationFailure embeddableFailure = validateEmbeddable(embeddable);
          if (embeddableFailure != null) {
              validationBuffer.addFailure(embeddableFailure);
              return;
          }
  
          for (EmbeddableAttribute attribute : embeddable.getAttributes()) {
              ValidationFailure failure = validateEmbeddableAttribute(attribute);
              if (failure != null) {
                  validationBuffer.addFailure(failure);
                  return;
              }
          }
      }
  
  }
  