private void addFromProperties(
     Iterable<XProperty> properties,
     String accessType,
     Set<String> persistentProperties,
     Audited allClassAudited) {
   for (XProperty property : properties) {
     // If this is not a persistent property, with the same access type as currently checked,
     // it's not audited as well.
     // If the property was already defined by the subclass, is ignored by superclasses
     if (persistentProperties.contains(property.getName())
         && !auditedPropertiesHolder.contains(property.getName())) {
       final Value propertyValue =
           persistentPropertiesSource.getProperty(property.getName()).getValue();
       if (propertyValue instanceof Component) {
         this.addFromComponentProperty(
             property, accessType, (Component) propertyValue, allClassAudited);
       } else {
         this.addFromNotComponentProperty(property, accessType, allClassAudited);
       }
     } else if (propertiesGroupMapping.containsKey(property.getName())) {
       // Retrieve embedded component name based on class field.
       final String embeddedName = propertiesGroupMapping.get(property.getName());
       if (!auditedPropertiesHolder.contains(embeddedName)) {
         // Manage properties mapped within <properties> tag.
         final Value propertyValue =
             persistentPropertiesSource.getProperty(embeddedName).getValue();
         this.addFromPropertiesGroup(
             embeddedName, property, accessType, (Component) propertyValue, allClassAudited);
       }
     }
   }
 }
  /**
   * Checks if a property is audited and if yes, fills all of its data.
   *
   * @param property Property to check.
   * @param propertyData Property data, on which to set this property's modification store.
   * @param accessType Access type for the property.
   * @return False if this property is not audited.
   */
  private boolean fillPropertyData(
      XProperty property,
      PropertyAuditingData propertyData,
      String accessType,
      Audited allClassAudited) {

    // check if a property is declared as not audited to exclude it
    // useful if a class is audited but some properties should be excluded
    final NotAudited unVer = property.getAnnotation(NotAudited.class);
    if ((unVer != null && !overriddenAuditedProperties.contains(property))
        || overriddenNotAuditedProperties.contains(property)) {
      return false;
    } else {
      // if the optimistic locking field has to be unversioned and the current property
      // is the optimistic locking field, don't audit it
      if (globalCfg.isDoNotAuditOptimisticLockingField()) {
        final Version jpaVer = property.getAnnotation(Version.class);
        if (jpaVer != null) {
          return false;
        }
      }
    }

    if (!this.checkAudited(property, propertyData, allClassAudited)) {
      return false;
    }

    final String propertyName = propertyNamePrefix + property.getName();
    propertyData.setName(propertyName);
    propertyData.setModifiedFlagName(
        MetadataTools.getModifiedFlagPropertyName(propertyName, globalCfg.getModifiedFlagSuffix()));
    propertyData.setBeanName(property.getName());
    propertyData.setAccessType(accessType);

    addPropertyJoinTables(property, propertyData);
    addPropertyAuditingOverrides(property, propertyData);
    if (!processPropertyAuditingOverrides(property, propertyData)) {
      // not audited due to AuditOverride annotation
      return false;
    }
    addPropertyMapKey(property, propertyData);
    setPropertyAuditMappedBy(property, propertyData);
    setPropertyRelationMappedBy(property, propertyData);

    return true;
  }
  private void addFromNotComponentProperty(
      XProperty property, String accessType, Audited allClassAudited) {
    final PropertyAuditingData propertyData = new PropertyAuditingData();
    final boolean isAudited = fillPropertyData(property, propertyData, accessType, allClassAudited);

    if (isAudited) {
      // Now we know that the property is audited
      auditedPropertiesHolder.addPropertyAuditingData(property.getName(), propertyData);
    }
  }
  private void addFromComponentProperty(
      XProperty property, String accessType, Component propertyValue, Audited allClassAudited) {
    final ComponentAuditingData componentData = new ComponentAuditingData();
    final boolean isAudited =
        fillPropertyData(property, componentData, accessType, allClassAudited);

    if (propertyValue.isDynamic()) {
      if (isAudited) {
        throw new MappingException(
            "Audited dynamic-component properties are not supported. Consider applying @NotAudited annotation to "
                + propertyValue.getOwner().getEntityName()
                + "#"
                + property
                + ".");
      }
      return;
    }

    final PersistentPropertiesSource componentPropertiesSource =
        new ComponentPropertiesSource(reflectionManager, propertyValue);

    final ComponentAuditedPropertiesReader audPropReader =
        new ComponentAuditedPropertiesReader(
            ModificationStore.FULL,
            componentPropertiesSource,
            componentData,
            globalCfg,
            reflectionManager,
            propertyNamePrefix + MappingTools.createComponentPrefix(property.getName()));
    audPropReader.read();

    if (isAudited) {
      // Now we know that the property is audited
      auditedPropertiesHolder.addPropertyAuditingData(property.getName(), componentData);
    }
  }
 /**
  * Process the {@link AuditOverride} annotations for this property.
  *
  * @param property the property for which the {@link AuditOverride} annotations are being
  *     processed
  * @param propertyData the Envers auditing data for this property
  * @return {@code false} if isAudited() of the override annotation was set to
  */
 private boolean processPropertyAuditingOverrides(
     XProperty property, PropertyAuditingData propertyData) {
   // if this property is part of a component, process all override annotations
   if (this.auditedPropertiesHolder instanceof ComponentAuditingData) {
     final List<AuditOverride> overrides =
         ((ComponentAuditingData) this.auditedPropertiesHolder).getAuditingOverrides();
     for (AuditOverride override : overrides) {
       if (property.getName().equals(override.name())) {
         // the override applies to this property
         if (!override.isAudited()) {
           return false;
         } else {
           if (override.auditJoinTable() != null) {
             propertyData.setJoinTable(override.auditJoinTable());
           }
         }
       }
     }
   }
   return true;
 }
  private void searchForRevisionInfoCfgInProperties(
      XClass clazz,
      ReflectionManager reflectionManager,
      MutableBoolean revisionNumberFound,
      MutableBoolean revisionTimestampFound,
      MutableBoolean modifiedEntityNamesFound,
      String accessType) {
    for (XProperty property : clazz.getDeclaredProperties(accessType)) {
      RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class);
      RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class);
      ModifiedEntityNames modifiedEntityNames = property.getAnnotation(ModifiedEntityNames.class);

      if (revisionNumber != null) {
        if (revisionNumberFound.isSet()) {
          throw new MappingException("Only one property may be annotated with @RevisionNumber!");
        }

        XClass revisionNumberClass = property.getType();
        if (reflectionManager.equals(revisionNumberClass, Integer.class)
            || reflectionManager.equals(revisionNumberClass, Integer.TYPE)) {
          revisionInfoIdData =
              new PropertyData(property.getName(), property.getName(), accessType, null);
          revisionNumberFound.set();
        } else if (reflectionManager.equals(revisionNumberClass, Long.class)
            || reflectionManager.equals(revisionNumberClass, Long.TYPE)) {
          revisionInfoIdData =
              new PropertyData(property.getName(), property.getName(), accessType, null);
          revisionNumberFound.set();

          // The default is integer
          revisionPropType = "long";
        } else {
          throw new MappingException(
              "The field annotated with @RevisionNumber must be of type "
                  + "int, Integer, long or Long");
        }

        // Getting the @Column definition of the revision number property, to later use that info to
        // generate the same mapping for the relation from an audit table's revision number to the
        // revision entity revision number.
        Column revisionPropColumn = property.getAnnotation(Column.class);
        if (revisionPropColumn != null) {
          revisionPropSqlType = revisionPropColumn.columnDefinition();
        }
      }

      if (revisionTimestamp != null) {
        if (revisionTimestampFound.isSet()) {
          throw new MappingException("Only one property may be annotated with @RevisionTimestamp!");
        }

        XClass revisionTimestampClass = property.getType();
        if (reflectionManager.equals(revisionTimestampClass, Long.class)
            || reflectionManager.equals(revisionTimestampClass, Long.TYPE)
            || reflectionManager.equals(revisionTimestampClass, Date.class)
            || reflectionManager.equals(revisionTimestampClass, java.sql.Date.class)) {
          revisionInfoTimestampData =
              new PropertyData(property.getName(), property.getName(), accessType, null);
          revisionTimestampFound.set();
        } else {
          throw new MappingException(
              "The field annotated with @RevisionTimestamp must be of type "
                  + "long, Long, java.util.Date or java.sql.Date");
        }
      }

      if (modifiedEntityNames != null) {
        if (modifiedEntityNamesFound.isSet()) {
          throw new MappingException(
              "Only one property may be annotated with @ModifiedEntityNames!");
        }
        XClass modifiedEntityNamesClass = property.getType();
        if (reflectionManager.equals(modifiedEntityNamesClass, Set.class)
            && reflectionManager.equals(property.getElementClass(), String.class)) {
          modifiedEntityNamesData =
              new PropertyData(property.getName(), property.getName(), accessType, null);
          modifiedEntityNamesFound.set();
        } else {
          throw new MappingException(
              "The field annotated with @ModifiedEntityNames must be of Set<String> type.");
        }
      }
    }
  }