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.
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.configuration;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import javax.persistence.Column;
import org.dom4j.Document;
import org.dom4j.Element;
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.cfg.Configuration;
import org.hibernate.envers.Audited;
import org.hibernate.envers.DefaultRevisionEntity;
import org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity;
import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.RevisionEntity;
import org.hibernate.envers.RevisionListener;
import org.hibernate.envers.RevisionNumber;
import org.hibernate.envers.RevisionTimestamp;
import org.hibernate.envers.configuration.metadata.AuditTableData;
import org.hibernate.envers.configuration.metadata.MetadataTools;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.revisioninfo.DefaultRevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.DefaultTrackingModifiedEntitiesRevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.ModifiedEntityNamesReader;
import org.hibernate.envers.revisioninfo.RevisionInfoGenerator;
import org.hibernate.envers.revisioninfo.RevisionInfoNumberReader;
import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator;
import org.hibernate.envers.tools.MutableBoolean;
import org.hibernate.internal.util.xml.XMLHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.type.LongType;
import org.hibernate.type.Type;
/**
* @author Adam Warski (adam at warski dot org)
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class RevisionInfoConfiguration {
private String revisionInfoEntityName;
private PropertyData revisionInfoIdData;
private PropertyData revisionInfoTimestampData;
private PropertyData modifiedEntityNamesData;
private Type revisionInfoTimestampType;
private GlobalConfiguration globalCfg;
private String revisionPropType;
private String revisionPropSqlType;
public RevisionInfoConfiguration(GlobalConfiguration globalCfg) {
this.globalCfg = globalCfg;
revisionInfoEntityName = "org.hibernate.envers.DefaultRevisionEntity";
revisionInfoIdData = new PropertyData("id", "id", "field", null);
revisionInfoTimestampData = new PropertyData("timestamp", "timestamp", "field", null);
modifiedEntityNamesData = new PropertyData("modifiedEntityNames", "modifiedEntityNames", "field", null);
revisionInfoTimestampType = new LongType();
revisionPropType = "integer";
}
private Document generateDefaultRevisionInfoXmlMapping() {
Document document = XMLHelper.getDocumentFactory().createDocument();
Element class_mapping = MetadataTools.createEntity(document, new AuditTableData(null, null, globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName()), null);
class_mapping.addAttribute("name", revisionInfoEntityName);
class_mapping.addAttribute("table", "REVINFO");
Element idProperty = MetadataTools.addNativelyGeneratedId(class_mapping, revisionInfoIdData.getName(),
revisionPropType);
MetadataTools.addColumn(idProperty, "REV", null, null, null, null, null, null, false);
Element timestampProperty = MetadataTools.addProperty(class_mapping, revisionInfoTimestampData.getName(),
revisionInfoTimestampType.getName(), true, false);
MetadataTools.addColumn(timestampProperty, "REVTSTMP", null, null, null, null, null, null, false);
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) {
generateEntityNamesTrackingTableMapping(class_mapping, "modifiedEntityNames",
globalCfg.getDefaultSchemaName(), globalCfg.getDefaultCatalogName(),
"REVCHANGES", "REV", "ENTITYNAME", "string");
}
return document;
}
/**
* Generates mapping that represents a set of primitive types.
*
* <set name="propertyName" table="joinTableName" schema="joinTableSchema" catalog="joinTableCatalog"
* cascade="persist, delete" lazy="false" fetch="join">
* <key column="joinTablePrimaryKeyColumnName" />
* <element type="joinTableValueColumnType">
* <column name="joinTableValueColumnName" />
* </element>
* </set>
*
*/
private void generateEntityNamesTrackingTableMapping(Element class_mapping, String propertyName,
String joinTableSchema, String joinTableCatalog, String joinTableName,
String joinTablePrimaryKeyColumnName, String joinTableValueColumnName,
String joinTableValueColumnType) {
Element set = class_mapping.addElement("set");
set.addAttribute("name", propertyName);
set.addAttribute("table", joinTableName);
set.addAttribute("schema", joinTableSchema);
set.addAttribute("catalog", joinTableCatalog);
set.addAttribute("cascade", "persist, delete");
set.addAttribute("fetch", "join");
set.addAttribute("lazy", "false");
Element key = set.addElement("key");
key.addAttribute("column", joinTablePrimaryKeyColumnName);
Element element = set.addElement("element");
element.addAttribute("type", joinTableValueColumnType);
Element column = element.addElement("column");
column.addAttribute("name", joinTableValueColumnName);
}
private Element generateRevisionInfoRelationMapping() {
Document document = XMLHelper.getDocumentFactory().createDocument();
Element rev_rel_mapping = document.addElement("key-many-to-one");
rev_rel_mapping.addAttribute("type", revisionPropType);
rev_rel_mapping.addAttribute("class", revisionInfoEntityName);
if (revisionPropSqlType != null) {
// Putting a fake name to make Hibernate happy. It will be replaced later anyway.
MetadataTools.addColumn(rev_rel_mapping, "*" , null, null, null, revisionPropSqlType, null, null, false);
}
return rev_rel_mapping;
}
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 type.");
}
}
}
}
private void searchForRevisionInfoCfg(XClass clazz, ReflectionManager reflectionManager,
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
MutableBoolean modifiedEntityNamesFound) {
XClass superclazz = clazz.getSuperclass();
if (!"java.lang.Object".equals(superclazz.getName())) {
searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound);
}
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
modifiedEntityNamesFound, "field");
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
modifiedEntityNamesFound, "property");
}
public RevisionInfoConfigurationResult configure(Configuration cfg, ReflectionManager reflectionManager) {
Iterator classes = (Iterator) cfg.getClassMappings();
boolean revisionEntityFound = false;
RevisionInfoGenerator revisionInfoGenerator = null;
Class revisionInfoClass = null;
while (classes.hasNext()) {
PersistentClass pc = classes.next();
XClass clazz;
try {
clazz = reflectionManager.classForName(pc.getClassName(), this.getClass());
} catch (ClassNotFoundException e) {
throw new MappingException(e);
}
RevisionEntity revisionEntity = clazz.getAnnotation(RevisionEntity.class);
if (revisionEntity != null) {
if (revisionEntityFound) {
throw new MappingException("Only one entity may be annotated with @RevisionEntity!");
}
// Checking if custom revision entity isn't audited
if (clazz.getAnnotation(Audited.class) != null) {
throw new MappingException("An entity annotated with @RevisionEntity cannot be audited!");
}
revisionEntityFound = true;
MutableBoolean revisionNumberFound = new MutableBoolean();
MutableBoolean revisionTimestampFound = new MutableBoolean();
MutableBoolean modifiedEntityNamesFound = new MutableBoolean();
searchForRevisionInfoCfg(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound);
if (!revisionNumberFound.isSet()) {
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionNumber!");
}
if (!revisionTimestampFound.isSet()) {
throw new MappingException("An entity annotated with @RevisionEntity must have a field annotated " +
"with @RevisionTimestamp!");
}
revisionInfoEntityName = pc.getEntityName();
revisionInfoClass = pc.getMappedClass();
Class revisionListenerClass = getRevisionListenerClass(revisionEntity.value());
revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType();
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled() ||
DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom(revisionInfoClass) ||
modifiedEntityNamesFound.isSet()) {
// If tracking modified entities parameter is enabled, custom revision info entity is a subtype
// of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames annotation is used.
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName,
revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(),
modifiedEntityNamesData);
globalCfg.setTrackEntitiesChangedInRevisionEnabled(true);
} else {
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate());
}
}
}
// In case of a custom revision info generator, the mapping will be null.
Document revisionInfoXmlMapping = null;
Class revisionListenerClass = getRevisionListenerClass(RevisionListener.class);
if (revisionInfoGenerator == null) {
if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) {
revisionInfoClass = DefaultTrackingModifiedEntitiesRevisionEntity.class;
revisionInfoEntityName = DefaultTrackingModifiedEntitiesRevisionEntity.class.getName();
revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData);
} else {
revisionInfoClass = DefaultRevisionEntity.class;
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate());
}
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
}
return new RevisionInfoConfigurationResult(
revisionInfoGenerator, revisionInfoXmlMapping,
new RevisionInfoQueryCreator(revisionInfoEntityName, revisionInfoIdData.getName(),
revisionInfoTimestampData.getName(), isTimestampAsDate()),
generateRevisionInfoRelationMapping(),
new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData),
globalCfg.isTrackEntitiesChangedInRevisionEnabled() ? new ModifiedEntityNamesReader(revisionInfoClass, modifiedEntityNamesData)
: null,
revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData);
}
private boolean isTimestampAsDate() {
String typename = revisionInfoTimestampType.getName();
return "date".equals(typename) || "time".equals(typename) || "timestamp".equals(typename);
}
/**
* @param defaultListener Revision listener that shall be applied if {@code org.hibernate.envers.revision_listener}
* parameter has not been set.
* @return Revision listener.
*/
private Class getRevisionListenerClass(Class defaultListener) {
if (globalCfg.getRevisionListenerClass() != null) {
return globalCfg.getRevisionListenerClass();
}
return defaultListener;
}
}
class RevisionInfoConfigurationResult {
private final RevisionInfoGenerator revisionInfoGenerator;
private final Document revisionInfoXmlMapping;
private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final Element revisionInfoRelationMapping;
private final RevisionInfoNumberReader revisionInfoNumberReader;
private final ModifiedEntityNamesReader modifiedEntityNamesReader;
private final String revisionInfoEntityName;
private final Class revisionInfoClass;
private final PropertyData revisionInfoTimestampData;
RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator,
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
Element revisionInfoRelationMapping, RevisionInfoNumberReader revisionInfoNumberReader,
ModifiedEntityNamesReader modifiedEntityNamesReader, String revisionInfoEntityName,
Class revisionInfoClass, PropertyData revisionInfoTimestampData) {
this.revisionInfoGenerator = revisionInfoGenerator;
this.revisionInfoXmlMapping = revisionInfoXmlMapping;
this.revisionInfoQueryCreator = revisionInfoQueryCreator;
this.revisionInfoRelationMapping = revisionInfoRelationMapping;
this.revisionInfoNumberReader = revisionInfoNumberReader;
this.modifiedEntityNamesReader = modifiedEntityNamesReader;
this.revisionInfoEntityName = revisionInfoEntityName;
this.revisionInfoClass = revisionInfoClass;
this.revisionInfoTimestampData = revisionInfoTimestampData;
}
public RevisionInfoGenerator getRevisionInfoGenerator() {
return revisionInfoGenerator;
}
public Document getRevisionInfoXmlMapping() {
return revisionInfoXmlMapping;
}
public RevisionInfoQueryCreator getRevisionInfoQueryCreator() {
return revisionInfoQueryCreator;
}
public Element getRevisionInfoRelationMapping() {
return revisionInfoRelationMapping;
}
public RevisionInfoNumberReader getRevisionInfoNumberReader() {
return revisionInfoNumberReader;
}
public String getRevisionInfoEntityName() {
return revisionInfoEntityName;
}
public Class getRevisionInfoClass() {
return revisionInfoClass;
}
public PropertyData getRevisionInfoTimestampData() {
return revisionInfoTimestampData;
}
public ModifiedEntityNamesReader getModifiedEntityNamesReader() {
return modifiedEntityNamesReader;
}
}