PageRenderTime 53ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/sandbox/simondud/Envers.NET/Envers.NET/Envers/Configuration/RevisionInfoConfiguration.cs

https://bitbucket.org/dabide/nhcontrib
C# | 241 lines | 184 code | 41 blank | 16 comment | 31 complexity | 2e391bd95d6f048b00badc0cce166883 MD5 | raw file
Possible License(s): BSD-3-Clause, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0, Apache-2.0, LGPL-3.0, LGPL-2.1
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using NHibernate;
  6. using NHibernate.Envers.Entities;
  7. using NHibernate.Envers.Configuration.Metadata;
  8. using System.Xml;
  9. using System.Reflection;
  10. using NHibernate.Mapping;
  11. using NHibernate.Envers.RevisionInfo;
  12. using NHibernate.Type;
  13. using NHibernate.SqlTypes;
  14. using NHibernate.Envers.Compatibility;
  15. namespace NHibernate.Envers.Configuration
  16. {
  17. /**
  18. * @author Simon Duduica, port of Envers omonyme class by Adam Warski (adam at warski dot org)
  19. */
  20. public class RevisionInfoConfiguration {
  21. private String revisionInfoEntityName;
  22. private PropertyData revisionInfoIdData;
  23. private PropertyData revisionInfoTimestampData;
  24. private IType revisionInfoTimestampType;
  25. private String revisionPropType;
  26. private String revisionPropSqlType;
  27. public RevisionInfoConfiguration() {
  28. revisionInfoEntityName = "NHibernate.Envers.DefaultRevisionEntity, Envers.NET";
  29. revisionInfoIdData = new PropertyData("id", "id", "field", ModificationStore._NULL);
  30. revisionInfoTimestampData = new PropertyData("RevisionDate", "RevisionDate", "field", ModificationStore._NULL);
  31. revisionInfoTimestampType = new DateTimeType(); //ORIG: LongType();
  32. revisionPropType = "integer";
  33. }
  34. private XmlDocument generateDefaultRevisionInfoXmlMapping() {
  35. XmlDocument document = new XmlDocument();//ORIG: DocumentHelper.createDocument();
  36. XmlElement class_mapping = MetadataTools.CreateEntity(document, new AuditTableData(null, null, null, null), null);
  37. class_mapping.SetAttribute("name", revisionInfoEntityName);
  38. class_mapping.SetAttribute("table", "REVINFO");
  39. XmlElement idProperty = MetadataTools.AddNativelyGeneratedId(document,class_mapping, revisionInfoIdData.Name,
  40. revisionPropType);
  41. //ORIG: MetadataTools.addColumn(idProperty, "REV", -1, 0, 0, null);
  42. XmlElement col = idProperty.OwnerDocument.CreateElement("column");
  43. col.SetAttribute("name", "REV");
  44. //idProperty should have a "generator" node otherwise sth. is wrong.
  45. idProperty.InsertBefore(col, idProperty.GetElementsByTagName("generator")[0]);
  46. XmlElement timestampProperty = MetadataTools.AddProperty(class_mapping, revisionInfoTimestampData.Name,
  47. revisionInfoTimestampType.Name, true, false);
  48. MetadataTools.AddColumn(timestampProperty, "REVTSTMP", -1, 0, 0, SqlTypeFactory.DateTime.ToString());
  49. return document;
  50. }
  51. private XmlElement generateRevisionInfoRelationMapping() {
  52. XmlDocument document = new XmlDocument();
  53. XmlElement rev_rel_mapping = document.CreateElement("key-many-to-one");
  54. //rk: removed type attribute from key-many-to-one
  55. //rev_rel_mapping.SetAttribute("type", revisionPropType);
  56. rev_rel_mapping.SetAttribute("class", revisionInfoEntityName);
  57. if (revisionPropSqlType != null) {
  58. // Putting a fake name to make Hibernate happy. It will be replaced later anyway.
  59. MetadataTools.AddColumn(rev_rel_mapping, "*" , -1, 0, 0, revisionPropSqlType);
  60. }
  61. return rev_rel_mapping;
  62. }
  63. private void searchForRevisionInfoCfgInProperties(System.Type t, ref bool revisionNumberFound,
  64. ref bool revisionTimestampFound, String accessType) {
  65. foreach (PropertyInfo property in t.GetProperties()) {
  66. //RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class);
  67. RevisionNumberAttribute revisionNumber = (RevisionNumberAttribute)Attribute.GetCustomAttribute(property, typeof(RevisionNumberAttribute));
  68. RevisionTimestampAttribute revisionTimestamp = (RevisionTimestampAttribute)Attribute.GetCustomAttribute(property, typeof(RevisionTimestampAttribute));
  69. if (revisionNumber != null) {
  70. if (revisionNumberFound) {
  71. throw new MappingException("Only one property may have the attribute [RevisionNumber]!");
  72. }
  73. System.Type revNrType = property.PropertyType;
  74. if (revNrType.Equals( typeof(int)) || revNrType.Equals( typeof(Int16)) || revNrType.Equals( typeof(Int32)) || revNrType.Equals( typeof(Int64))) {
  75. revisionInfoIdData = new PropertyData(property.Name, property.Name, accessType, ModificationStore._NULL);
  76. revisionNumberFound = true;
  77. } else if (revNrType.Equals(typeof(long))) {
  78. revisionInfoIdData = new PropertyData(property.Name, property.Name, accessType, ModificationStore._NULL);
  79. revisionNumberFound = true;
  80. // The default is integer
  81. revisionPropType = "long";
  82. } else {
  83. throw new MappingException("The field decorated with [RevisionNumberAttribute] must be of type " +
  84. "int, Int16, Int32, Int64 or long");
  85. }
  86. // Getting the @Column definition of the revision number property, to later use that info to
  87. // generate the same mapping for the relation from an audit table's revision number to the
  88. // revision entity revision number.
  89. ColumnAttribute revisionPropColumn = (ColumnAttribute)Attribute.GetCustomAttribute(property,typeof(ColumnAttribute));
  90. if (revisionPropColumn != null) {
  91. revisionPropSqlType = revisionPropColumn.columnDefinition;
  92. }
  93. }
  94. if (revisionTimestamp != null) {
  95. if (revisionTimestampFound) {
  96. throw new MappingException("Only one property may be decorated with [RevisionTimestampAttribute]!");
  97. }
  98. System.Type revisionTimestampType = property.GetType();
  99. if (typeof(DateTime).Equals(revisionTimestampType)) {
  100. revisionInfoTimestampData = new PropertyData(property.Name, property.Name, accessType, ModificationStore._NULL);
  101. revisionTimestampFound = true;
  102. } else {
  103. throw new MappingException("The field decorated with @RevisionTimestamp must be of type DateTime");
  104. }
  105. }
  106. }
  107. }
  108. private void searchForRevisionInfoCfg(System.Type t, ref bool revisionNumberFound, ref bool revisionTimestampFound) {
  109. System.Type superT = t.BaseType;
  110. if (!typeof(System.Object).Equals(t)) {
  111. searchForRevisionInfoCfg(superT, ref revisionNumberFound, ref revisionTimestampFound);
  112. }
  113. searchForRevisionInfoCfgInProperties(t, ref revisionNumberFound, ref revisionTimestampFound,
  114. "field");
  115. searchForRevisionInfoCfgInProperties(t, ref revisionNumberFound, ref revisionTimestampFound,
  116. "property");
  117. }
  118. //@SuppressWarnings({"unchecked"})
  119. public RevisionInfoConfigurationResult configure(NHibernate.Cfg.Configuration cfg) {
  120. ICollection<PersistentClass> classes = cfg.ClassMappings;
  121. bool revisionEntityFound = false;
  122. IRevisionInfoGenerator revisionInfoGenerator = null;
  123. System.Type revisionInfoClass = null;
  124. foreach (PersistentClass pc in classes) {
  125. System.Type clazz;
  126. try {
  127. clazz = System.Type.GetType(pc.ClassName, true);
  128. } catch (System.Exception e) {
  129. throw new MappingException(e);
  130. }
  131. RevisionEntityAttribute revisionEntity = (RevisionEntityAttribute)Attribute.GetCustomAttribute( clazz, typeof(RevisionEntityAttribute));
  132. if (revisionEntity != null) {
  133. if (revisionEntityFound) {
  134. throw new MappingException("Only one entity may be decorated with [RevisionEntity]!");
  135. }
  136. // Checking if custom revision entity isn't audited
  137. if (Attribute.GetCustomAttribute( clazz, typeof(AuditedAttribute)) != null) {
  138. throw new MappingException("An entity decorated with [RevisionEntity] cannot be audited!");
  139. }
  140. revisionEntityFound = true;
  141. bool revisionNumberFound = false;
  142. bool revisionTimestampFound = false;
  143. searchForRevisionInfoCfg(clazz, ref revisionNumberFound, ref revisionTimestampFound);
  144. if (!revisionNumberFound) {
  145. throw new MappingException("An entity decorated with [RevisionEntity] must have a field decorated " +
  146. "with [RevisionNumber]!");
  147. }
  148. if (!revisionTimestampFound) {
  149. throw new MappingException("An entity decorated with [RevisionEntity] must have a field decorated " +
  150. "with [RevisionTimestamp]!");
  151. }
  152. revisionInfoEntityName = pc.EntityName;
  153. revisionInfoClass = pc.MappedClass;
  154. revisionInfoTimestampType = pc.GetProperty(revisionInfoTimestampData.Name).Type;
  155. revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
  156. /*revisionEntity.value, */revisionInfoTimestampData/*, isTimestampAsDate()*/);
  157. }
  158. }
  159. // In case of a custom revision info generator, the mapping will be null.
  160. XmlDocument revisionInfoXmlMapping = null;
  161. if (revisionInfoGenerator == null) {
  162. revisionInfoClass = typeof(DefaultRevisionEntity);
  163. revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
  164. revisionInfoTimestampData);
  165. revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
  166. }
  167. return new RevisionInfoConfigurationResult(
  168. revisionInfoGenerator, revisionInfoXmlMapping,
  169. new RevisionInfoQueryCreator(revisionInfoEntityName, revisionInfoIdData.Name,
  170. revisionInfoTimestampData.Name),
  171. generateRevisionInfoRelationMapping(),
  172. new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData), revisionInfoEntityName);
  173. }
  174. private bool isTimestampAsDate() {
  175. String typename = revisionInfoTimestampType.Name;
  176. return "date".Equals(typename) || "time".Equals(typename) || "RevisionDate".Equals(typename);
  177. }
  178. }
  179. public class RevisionInfoConfigurationResult {
  180. public IRevisionInfoGenerator RevisionInfoGenerator { get; private set; }
  181. public XmlDocument RevisionInfoXmlMapping { get; private set; }
  182. public RevisionInfoQueryCreator RevisionInfoQueryCreator { get; private set; }
  183. public XmlElement RevisionInfoRelationMapping { get; private set; }
  184. public RevisionInfoNumberReader RevisionInfoNumberReader { get; private set; }
  185. public String RevisionInfoEntityName { get; private set; }
  186. public RevisionInfoConfigurationResult(IRevisionInfoGenerator revisionInfoGenerator,
  187. XmlDocument revisionInfoXmlMapping,
  188. RevisionInfoQueryCreator revisionInfoQueryCreator,
  189. XmlElement revisionInfoRelationMapping,
  190. RevisionInfoNumberReader revisionInfoNumberReader,
  191. String revisionInfoEntityName) {
  192. this.RevisionInfoGenerator = revisionInfoGenerator;
  193. this.RevisionInfoXmlMapping = revisionInfoXmlMapping;
  194. this.RevisionInfoQueryCreator = revisionInfoQueryCreator;
  195. this.RevisionInfoRelationMapping = revisionInfoRelationMapping;
  196. this.RevisionInfoNumberReader = revisionInfoNumberReader;
  197. this.RevisionInfoEntityName = revisionInfoEntityName;
  198. }
  199. }
  200. }