Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.hibernate.envers.configuration.metadata.reader;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.JoinColumn;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Version;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.envers.AuditJoinTable;
import org.hibernate.envers.AuditMappedBy;
import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.AuditOverrides;
import org.hibernate.envers.Audited;
import org.hibernate.envers.ModificationStore;
import org.hibernate.envers.NotAudited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.hibernate.envers.configuration.GlobalConfiguration;
import org.hibernate.envers.configuration.metadata.MetadataTools;
import org.hibernate.envers.tools.MappingTools;
import org.hibernate.envers.tools.StringTools;
import org.hibernate.envers.tools.Tools;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Value;
import static org.hibernate.envers.tools.Tools.newHashMap;
import static org.hibernate.envers.tools.Tools.newHashSet;
/**
* Reads persistent properties form a
* {@link org.hibernate.envers.configuration.metadata.reader.PersistentPropertiesSource}
* and adds the ones that are audited to a
* {@link org.hibernate.envers.configuration.metadata.reader.AuditedPropertiesHolder},
* filling all the auditing data.
* @author Adam Warski (adam at warski dot org)
* @author Erik-Berndt Scheper
* @author Hern&aacut;n Chanfreau
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @author Michal Skowronek (mskowr at o2 dot pl)
*/
public class AuditedPropertiesReader {
protected final ModificationStore defaultStore;
private final PersistentPropertiesSource persistentPropertiesSource;
private final AuditedPropertiesHolder auditedPropertiesHolder;
private final GlobalConfiguration globalCfg;
private final ReflectionManager reflectionManager;
private final String propertyNamePrefix;
private final Set propertyAccessedPersistentProperties;
private final Set fieldAccessedPersistentProperties;
// Mapping class field to corresponding element.
private final Map propertiesGroupMapping;
private final Set overriddenAuditedProperties;
private final Set overriddenNotAuditedProperties;
private final Set overriddenAuditedClasses;
private final Set overriddenNotAuditedClasses;
public AuditedPropertiesReader(ModificationStore defaultStore,
PersistentPropertiesSource persistentPropertiesSource,
AuditedPropertiesHolder auditedPropertiesHolder,
GlobalConfiguration globalCfg,
ReflectionManager reflectionManager,
String propertyNamePrefix) {
this.defaultStore = defaultStore;
this.persistentPropertiesSource = persistentPropertiesSource;
this.auditedPropertiesHolder = auditedPropertiesHolder;
this.globalCfg = globalCfg;
this.reflectionManager = reflectionManager;
this.propertyNamePrefix = propertyNamePrefix;
propertyAccessedPersistentProperties = newHashSet();
fieldAccessedPersistentProperties = newHashSet();
propertiesGroupMapping = newHashMap();
overriddenAuditedProperties = newHashSet();
overriddenNotAuditedProperties = newHashSet();
overriddenAuditedClasses = newHashSet();
overriddenNotAuditedClasses = newHashSet();
}
public void read() {
// First reading the access types for the persistent properties.
readPersistentPropertiesAccess();
// Retrieve classes and properties that are explicitly marked for auditing process by any superclass
// of currently mapped entity or itself.
XClass clazz = persistentPropertiesSource.getXClass();
readAuditOverrides(clazz);
// Adding all properties from the given class.
addPropertiesFromClass(clazz);
}
/**
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
* using {@link AuditOverride} annotation.
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
*/
private void readAuditOverrides(XClass clazz) {
/* TODO: Code to remove with @Audited.auditParents - start. */
Audited allClassAudited = clazz.getAnnotation(Audited.class);
if (allClassAudited != null && allClassAudited.auditParents().length > 0) {
for (Class c : allClassAudited.auditParents()) {
XClass parentClass = reflectionManager.toXClass(c);
checkSuperclass(clazz, parentClass);
if (!overriddenNotAuditedClasses.contains(parentClass)) {
// If the class has not been marked as not audited by the subclass.
overriddenAuditedClasses.add(parentClass);
}
}
}
/* TODO: Code to remove with @Audited.auditParents - finish. */
List auditOverrides = computeAuditOverrides(clazz);
for (AuditOverride auditOverride : auditOverrides) {
if (auditOverride.forClass() != void.class) {
XClass overrideClass = reflectionManager.toXClass(auditOverride.forClass());
checkSuperclass(clazz, overrideClass);
String propertyName = auditOverride.name();
if (!StringTools.isEmpty(propertyName)) {
// Override @Audited annotation on property level.
XProperty property = getProperty(overrideClass, propertyName);
if (auditOverride.isAudited()) {
if (!overriddenNotAuditedProperties.contains(property)) {
// If the property has not been marked as not audited by the subclass.
overriddenAuditedProperties.add(property);
}
} else {
if (!overriddenAuditedProperties.contains(property)) {
// If the property has not been marked as audited by the subclass.
overriddenNotAuditedProperties.add(property);
}
}
} else {
// Override @Audited annotation on class level.
if (auditOverride.isAudited()) {
if (!overriddenNotAuditedClasses.contains(overrideClass)) {
// If the class has not been marked as not audited by the subclass.
overriddenAuditedClasses.add(overrideClass);
}
} else {
if (!overriddenAuditedClasses.contains(overrideClass)) {
// If the class has not been marked as audited by the subclass.
overriddenNotAuditedClasses.add(overrideClass);
}
}
}
}
}
XClass superclass = clazz.getSuperclass();
if (!clazz.isInterface() && !Object.class.getName().equals(superclass.getName())) {
readAuditOverrides(superclass);
}
}
/**
* @param clazz Source class.
* @return List of @AuditOverride annotations applied at class level.
*/
private List computeAuditOverrides(XClass clazz) {
AuditOverrides auditOverrides = clazz.getAnnotation(AuditOverrides.class);
AuditOverride auditOverride = clazz.getAnnotation(AuditOverride.class);
if (auditOverrides == null && auditOverride != null) {
return Arrays.asList(auditOverride);
} else if (auditOverrides != null && auditOverride == null) {
return Arrays.asList(auditOverrides.value());
} else if (auditOverrides != null && auditOverride != null) {
throw new MappingException("@AuditOverrides annotation should encapsulate all @AuditOverride declarations. " +
"Please revise Envers annotations applied to class " + clazz.getName() + ".");
}
return Collections.EMPTY_LIST;
}
/**
* Checks whether one class is assignable from another. If not {@link MappingException} is thrown.
* @param child Subclass.
* @param parent Superclass.
*/
private void checkSuperclass(XClass child, XClass parent) {
if (!parent.isAssignableFrom(child)) {
throw new MappingException("Class " + parent.getName() + " is not assignable from " + child.getName() + ". " +
"Please revise Envers annotations applied to " + child.getName() + " type.");
}
}
/**
* Checks whether class contains property with a given name. If not {@link MappingException} is thrown.
* @param clazz Class.
* @param propertyName Property name.
* @return Property object.
*/
private XProperty getProperty(XClass clazz, String propertyName) {
XProperty property = Tools.getProperty(clazz, propertyName);
if (property == null) {
throw new MappingException("Property '" + propertyName + "' not found in class " + clazz.getName() + ". " +
"Please revise Envers annotations applied to class " + persistentPropertiesSource.getXClass() + ".");
}
return property;
}
private void readPersistentPropertiesAccess() {
Iterator propertyIter = persistentPropertiesSource.getPropertyIterator();
while (propertyIter.hasNext()) {
Property property = (Property) propertyIter.next();
addPersistentProperty(property);
if ("embedded".equals(property.getPropertyAccessorName()) && property.getName().equals(property.getNodeName())) {
// If property name equals node name and embedded accessor type is used, processing component
// has been defined with tag. See HHH-6636 JIRA issue.
createPropertiesGroupMapping(property);
}
}
}
private void addPersistentProperty(Property property) {
if ("field".equals(property.getPropertyAccessorName())) {
fieldAccessedPersistentProperties.add(property.getName());
} else {
propertyAccessedPersistentProperties.add(property.getName());
}
}
private void createPropertiesGroupMapping(Property property) {
Component component = (Component) property.getValue();
Iterator componentProperties = component.getPropertyIterator();
while (componentProperties.hasNext()) {
Property componentProperty = componentProperties.next();
propertiesGroupMapping.put(componentProperty.getName(), component.getNodeName());
}
}
/**
* @param clazz Class which properties are currently being added.
* @return {@link Audited} annotation of specified class. If processed type hasn't been explicitly marked, method
* checks whether given class exists in {@link AuditedPropertiesReader#overriddenAuditedClasses} collection.
* In case of success, {@link Audited} configuration of currently mapped entity is returned, otherwise
* {@code null}. If processed type exists in {@link AuditedPropertiesReader#overriddenNotAuditedClasses}
* collection, the result is also {@code null}.
*/
private Audited computeAuditConfiguration(XClass clazz) {
Audited allClassAudited = clazz.getAnnotation(Audited.class);
// If processed class is not explicitly marked with @Audited annotation, check whether auditing is
// forced by any of its child entities configuration (@AuditedOverride.forClass).
if (allClassAudited == null && overriddenAuditedClasses.contains(clazz)) {
// Declared audited parent copies @Audited.modStore and @Audited.targetAuditMode configuration from
// currently mapped entity.
allClassAudited = persistentPropertiesSource.getXClass().getAnnotation(Audited.class);
if (allClassAudited == null) {
// If parent class declares @Audited on the field/property level.
allClassAudited = DEFAULT_AUDITED;
}
} else if (allClassAudited != null && overriddenNotAuditedClasses.contains(clazz)) {
return null;
}
return allClassAudited;
}
/**
* Recursively adds all audited properties of entity class and its superclasses.
* @param clazz Currently processed class.
*/
private void addPropertiesFromClass(XClass clazz) {
Audited allClassAudited = computeAuditConfiguration(clazz);
//look in the class
addFromProperties(clazz.getDeclaredProperties("field"), "field", fieldAccessedPersistentProperties, allClassAudited);
addFromProperties(clazz.getDeclaredProperties("property"), "property", propertyAccessedPersistentProperties, allClassAudited);
if(allClassAudited != null || !auditedPropertiesHolder.isEmpty()) {
XClass superclazz = clazz.getSuperclass();
if (!clazz.isInterface() && !"java.lang.Object".equals(superclazz.getName())) {
addPropertiesFromClass(superclazz);
}
}
}
private void addFromProperties(Iterable properties, String accessType, Set 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())))) {
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 tag.
Value propertyValue = persistentPropertiesSource.getProperty(embeddedName).getValue();
this.addFromPropertiesGroup(embeddedName, property, accessType, (Component)propertyValue, allClassAudited);
}
}
}
}
private void addFromPropertiesGroup(String embeddedName, XProperty property, String accessType, Component propertyValue,
Audited allClassAudited) {
ComponentAuditingData componentData = new ComponentAuditingData();
boolean isAudited = fillPropertyData(property, componentData, accessType, allClassAudited);
if (isAudited) {
// EntityPersister.getPropertyNames() returns name of embedded component instead of class field.
componentData.setName(embeddedName);
// Marking component properties as placed directly in class (not inside another component).
componentData.setBeanName(null);
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource((Component) propertyValue);
AuditedPropertiesReader audPropReader = new AuditedPropertiesReader(
ModificationStore.FULL, componentPropertiesSource, componentData, globalCfg, reflectionManager,
propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName)
);
audPropReader.read();
auditedPropertiesHolder.addPropertyAuditingData(embeddedName, componentData);
}
}
private void addFromComponentProperty(XProperty property,
String accessType, Component propertyValue, Audited allClassAudited) {
ComponentAuditingData componentData = new ComponentAuditingData();
boolean isAudited = fillPropertyData(property, componentData, accessType,
allClassAudited);
PersistentPropertiesSource componentPropertiesSource = new ComponentPropertiesSource(
(Component) propertyValue);
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);
}
}
private void addFromNotComponentProperty(XProperty property, String accessType, Audited allClassAudited){
PropertyAuditingData propertyData = new PropertyAuditingData();
boolean isAudited = fillPropertyData(property, propertyData, accessType, allClassAudited);
if (isAudited) {
// Now we know that the property is audited
auditedPropertiesHolder.addPropertyAuditingData(property.getName(), propertyData);
}
}
/**
* 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
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()) {
Version jpaVer = property.getAnnotation(Version.class);
if (jpaVer != null) {
return false;
}
}
}
if(!this.checkAudited(property, propertyData, allClassAudited)){
return false;
}
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)) {
return false; // not audited due to AuditOverride annotation
}
addPropertyMapKey(property, propertyData);
setPropertyAuditMappedBy(property, propertyData);
return true;
}
protected boolean checkAudited(XProperty property,
PropertyAuditingData propertyData, Audited allClassAudited) {
// Checking if this property is explicitly audited or if all properties are.
Audited aud = (property.isAnnotationPresent(Audited.class)) ? (property.getAnnotation(Audited.class)) : allClassAudited;
if (aud == null && overriddenAuditedProperties.contains(property) && !overriddenNotAuditedProperties.contains(property)) {
// Assigning @Audited defaults. If anyone needs to customize those values in the future,
// appropriate fields shall be added to @AuditOverride annotation.
aud = DEFAULT_AUDITED;
}
if (aud != null) {
propertyData.setStore(aud.modStore());
propertyData.setRelationTargetAuditMode(aud.targetAuditMode());
propertyData.setUsingModifiedFlag(checkUsingModifiedFlag(aud));
return true;
} else {
return false;
}
}
protected boolean checkUsingModifiedFlag(Audited aud) {
return globalCfg.hasSettingForUsingModifiedFlag() ?
globalCfg.isGlobalWithModifiedFlag() : aud.withModifiedFlag();
}
private void setPropertyAuditMappedBy(XProperty property, PropertyAuditingData propertyData) {
OneToMany oneToMany = property.getAnnotation(OneToMany.class);
if (oneToMany != null && !"".equals(oneToMany.mappedBy())) {
propertyData.setAuditMappedBy(oneToMany.mappedBy());
}
AuditMappedBy auditMappedBy = property.getAnnotation(AuditMappedBy.class);
if (auditMappedBy != null) {
propertyData.setAuditMappedBy(auditMappedBy.mappedBy());
if (!"".equals(auditMappedBy.positionMappedBy())) {
propertyData.setPositionMappedBy(auditMappedBy.positionMappedBy());
}
}
}
private void addPropertyMapKey(XProperty property, PropertyAuditingData propertyData) {
MapKey mapKey = property.getAnnotation(MapKey.class);
if (mapKey != null) {
propertyData.setMapKey(mapKey.name());
}
}
private void addPropertyJoinTables(XProperty property, PropertyAuditingData propertyData) {
// first set the join table based on the AuditJoinTable annotation
AuditJoinTable joinTable = property.getAnnotation(AuditJoinTable.class);
if (joinTable != null) {
propertyData.setJoinTable(joinTable);
} else {
propertyData.setJoinTable(DEFAULT_AUDIT_JOIN_TABLE);
}
}
/***
* Add the {@link org.hibernate.envers.AuditOverride} annotations.
*
* @param property the property being processed
* @param propertyData the Envers auditing data for this property
*/
private void addPropertyAuditingOverrides(XProperty property, PropertyAuditingData propertyData) {
AuditOverride annotationOverride = property.getAnnotation(AuditOverride.class);
if (annotationOverride != null) {
propertyData.addAuditingOverride(annotationOverride);
}
AuditOverrides annotationOverrides = property.getAnnotation(AuditOverrides.class);
if (annotationOverrides != null) {
propertyData.addAuditingOverrides(annotationOverrides);
}
}
/**
* Process the {@link org.hibernate.envers.AuditOverride} annotations for this property.
*
* @param property
* the property for which the {@link org.hibernate.envers.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) {
List 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 static Audited DEFAULT_AUDITED = new Audited() {
public ModificationStore modStore() { return ModificationStore.FULL; }
public RelationTargetAuditMode targetAuditMode() { return RelationTargetAuditMode.AUDITED; }
public Class[] auditParents() { return new Class[0]; }
public boolean withModifiedFlag() { return false; }
public Class annotationType() { return this.getClass(); }
};
private static AuditJoinTable DEFAULT_AUDIT_JOIN_TABLE = new AuditJoinTable() {
public String name() { return ""; }
public String schema() { return ""; }
public String catalog() { return ""; }
public JoinColumn[] inverseJoinColumns() { return new JoinColumn[0]; }
public Class annotationType() { return this.getClass(); }
};
private class ComponentPropertiesSource implements PersistentPropertiesSource {
private final XClass xclass;
private final Component component;
private ComponentPropertiesSource(Component component) {
try {
this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass());
} catch (ClassNotFoundException e) {
throw new MappingException(e);
}
this.component = component;
}
@SuppressWarnings({"unchecked"})
public Iterator getPropertyIterator() { return component.getPropertyIterator(); }
public Property getProperty(String propertyName) { return component.getProperty(propertyName); }
public XClass getXClass() { return xclass; }
}
}