HHH-3351 : import envers as core module

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15406 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2008-10-27 18:56:31 +00:00
parent e163f8264d
commit 78e5d9fd89
390 changed files with 35614 additions and 1 deletions

235
envers/pom.xml Normal file
View File

@ -0,0 +1,235 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-parent</artifactId>
<version>3.4.0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
<packaging>jar</packaging>
<name>Hibernate Envers</name>
<description>Support for entity historizing</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemProperties>
</systemProperties>
<suiteXmlFiles>
<suiteXmlFile>resources/test/testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
<!-- javadocs : we want these run in the 'package' lifecycle phase-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>javadoc</goal>
</goals>
<configuration>
<aggregate>${jbossenvers.reports.aggregate}</aggregate>
<links>
<link>http://java.sun.com/j2se/1.5.0/docs/api/</link>
<link>http://java.sun.com/javaee/5/docs/api/</link>
</links>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<exclusions>
<!-- todo : only needed until we migrate annotations/em back to core -->
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
</exclusion>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm-attrs</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<exclusions>
<!-- todo : only needed until we migrate annotations/em back to core -->
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
</exclusion>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm-attrs</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<exclusions>
<!-- todo : only needed until we migrate annotations/em back to core -->
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
</exclusion>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm-attrs</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-tools</artifactId>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>5.8</version>
<scope>test</scope>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<!-- todo : change to work like hibernate-core after we import annotations and em back into core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.3.0.ga</version>
</dependency>
<!-- todo : change to work like hibernate-core after we import annotations and em back into core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.3.0.ga</version>
</dependency>
<!-- todo : change to work like hibernate-core after we import annotations and em back into core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.3.1.ga</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-tools</artifactId>
<version>3.2.0.ga</version>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.6.5</version>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<!-- for now, at least, lets aggregate them -->
<jbossenvers.reports.aggregate>true</jbossenvers.reports.aggregate>
</properties>
</project>

View File

@ -0,0 +1,113 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.demo;
import org.jboss.envers.Versioned;
import javax.persistence.*;
import java.util.Set;
/**
* @author Adam Warski (adam at warski dot org)
*/
@Entity
public class Address {
@Id
@GeneratedValue
private int id;
@Versioned
private String streetName;
@Versioned
private Integer houseNumber;
@Versioned
private Integer flatNumber;
@Versioned
@OneToMany(mappedBy = "address")
private Set<Person> persons;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
public Integer getHouseNumber() {
return houseNumber;
}
public void setHouseNumber(Integer houseNumber) {
this.houseNumber = houseNumber;
}
public Integer getFlatNumber() {
return flatNumber;
}
public void setFlatNumber(Integer flatNumber) {
this.flatNumber = flatNumber;
}
public Set<Person> getPersons() {
return persons;
}
public void setPersons(Set<Person> persons) {
this.persons = persons;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Address)) return false;
Address address = (Address) o;
if (id != address.id) return false;
if (flatNumber != null ? !flatNumber.equals(address.flatNumber) : address.flatNumber != null) return false;
if (houseNumber != null ? !houseNumber.equals(address.houseNumber) : address.houseNumber != null) return false;
if (streetName != null ? !streetName.equals(address.streetName) : address.streetName != null) return false;
return true;
}
public int hashCode() {
int result;
result = id;
result = 31 * result + (streetName != null ? streetName.hashCode() : 0);
result = 31 * result + (houseNumber != null ? houseNumber.hashCode() : 0);
result = 31 * result + (flatNumber != null ? flatNumber.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,99 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.demo;
import org.jboss.envers.Versioned;
import javax.persistence.*;
/**
* @author Adam Warski (adam at warski dot org)
*/
@Entity
public class Person {
@Id
@GeneratedValue
private int id;
@Versioned
private String name;
@Versioned
private String surname;
@Versioned
@ManyToOne
private Address address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
if (id != person.id) return false;
if (name != null ? !name.equals(person.name) : person.name != null) return false;
if (surname != null ? !surname.equals(person.surname) : person.surname != null) return false;
return true;
}
public int hashCode() {
int result;
result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (surname != null ? surname.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,467 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.demo;
import org.jboss.envers.VersionsReader;
import org.jboss.envers.VersionsReaderFactory;
import org.jboss.envers.DefaultRevisionEntity;
import org.jboss.envers.query.VersionsRestrictions;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.*;
import java.io.PrintStream;
import java.io.File;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class TestConsole {
private EntityManager entityManager;
public TestConsole(EntityManager entityManager) {
this.entityManager = entityManager;
}
private String convertString(String s, String def) {
if ("NULL".equals(s)) { return null; }
if ("".equals(s)) { return def; }
return s;
}
private int convertStringToInteger(String s, int def) {
if ("".equals(s)) { return def; }
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
System.err.println("Invalid number, returning 0.");
return 0;
}
}
private void printPerson(StringBuilder sb, Person p) {
sb.append("id = ").append(p.getId()).append(", name = ").append(p.getName())
.append(", surname = ").append(p.getSurname());
Address a = p.getAddress();
if (a != null) {
sb.append(", address = <").append(a.getId()).append("> ").append(a.getStreetName()).append(" ")
.append(a.getHouseNumber()).append("/").append(a.getFlatNumber());
}
}
@SuppressWarnings({"unchecked"})
private void printPersons(StringBuilder sb) {
List<Person> persons = entityManager.createQuery(
"select p from Person p order by p.id").getResultList();
sb.append("Persons:\n");
for (Person p : persons) {
printPerson(sb, p);
sb.append("\n");
}
}
private void printPersonHistory(StringBuilder sb, int personId) {
VersionsReader reader = VersionsReaderFactory.get(entityManager);
List personHistory = reader.createQuery()
.forRevisionsOfEntity(Person.class, false, true)
.add(VersionsRestrictions.idEq(personId))
.getResultList();
if (personHistory.size() == 0) {
sb.append("A person with id ").append(personId).append(" does not exist.\n");
} else {
for (Object historyObj : personHistory) {
Object[] history = (Object[]) historyObj;
DefaultRevisionEntity revision = (DefaultRevisionEntity) history[1];
sb.append("revision = ").append(revision.getId()).append(", ");
printPerson(sb, (Person) history[0]);
sb.append(" (").append(revision.getRevisionDate()).append(")\n");
}
}
}
private void printPersonAtRevision(StringBuilder sb, int personId, int revision) {
VersionsReader reader = VersionsReaderFactory.get(entityManager);
Person p = reader.find(Person.class, personId, revision);
if (p == null) {
sb.append("This person does not exist at that revision.");
} else {
printPerson(sb, p);
}
}
private void readAndSetAddress(Scanner scanner, Person p) {
Address old = p.getAddress();
String input = scanner.nextLine();
if ("NULL".equals(input)) {
p.setAddress(null);
if (old != null) {
old.getPersons().remove(p);
}
} else if ("".equals(input)) {
} else {
try {
Integer id = Integer.valueOf(input);
Address a = entityManager.find(Address.class, id);
if (a == null) {
System.err.println("Unknown address id, setting to NULL.");
p.setAddress(null);
if (old != null) {
old.getPersons().remove(p);
}
} else {
p.setAddress(a);
a.getPersons().add(p);
if (old != null) {
old.getPersons().remove(p);
}
}
} catch (NumberFormatException e) {
System.err.println("Invalid address id, setting to NULL.");
p.setAddress(null);
if (old != null) {
old.getPersons().remove(p);
}
}
}
}
private Person readNewPerson(PrintStream out, Scanner scanner) {
Person p = new Person();
out.print("Person name (NULL for null): ");
p.setName(convertString(scanner.nextLine(), ""));
out.print("Person surname (NULL for null): ");
p.setSurname(convertString(scanner.nextLine(), ""));
out.print("Person address id (NULL for null): ");
readAndSetAddress(scanner, p);
return p;
}
private void readModifyPerson(PrintStream out, Scanner scanner, int personId) {
Person current = entityManager.find(Person.class, personId);
if (current == null) {
out.println("Person with id " + personId + " does not exist.");
return;
}
out.print("Person name (NULL for null, enter for no change, current - " + current.getName() + "): ");
current.setName(convertString(scanner.nextLine(), current.getName()));
out.print("Person surname (NULL for null, enter for no change, current - " + current.getSurname() + "): ");
current.setSurname(convertString(scanner.nextLine(), current.getSurname()));
out.print("Person address id (NULL for null, enter for no change, current - " +
(current.getAddress() == null ? "NULL" : current.getAddress().getId()) + "): ");
readAndSetAddress(scanner, current);
}
private void printAddress(StringBuilder sb, Address a) {
sb.append("id = ").append(a.getId()).append(", streetName = ").append(a.getStreetName())
.append(", houseNumber = ").append(a.getHouseNumber())
.append(", flatNumber = ").append(a.getFlatNumber())
.append(", persons = (");
Iterator<Person> iter = a.getPersons().iterator();
while (iter.hasNext()) {
Person p = iter.next();
sb.append("<").append(p.getId()).append("> ").append(p.getName()).append(" ").append(p.getSurname());
if (iter.hasNext()) {
sb.append(", ");
}
}
sb.append(")");
}
@SuppressWarnings({"unchecked"})
private void printAddresses(StringBuilder sb) {
List<Address> addresses = entityManager.createQuery(
"select a from Address a order by a.id").getResultList();
sb.append("Addresses:\n");
for (Address a : addresses) {
printAddress(sb, a);
sb.append("\n");
}
}
private void printAddressHistory(StringBuilder sb, int addressId) {
VersionsReader reader = VersionsReaderFactory.get(entityManager);
List addressHistory = reader.createQuery()
.forRevisionsOfEntity(Address.class, false, true)
.add(VersionsRestrictions.idEq(addressId))
.getResultList();
if (addressHistory.size() == 0) {
sb.append("A address with id ").append(addressId).append(" does not exist.\n");
} else {
for (Object historyObj : addressHistory) {
Object[] history = (Object[]) historyObj;
DefaultRevisionEntity revision = (DefaultRevisionEntity) history[1];
sb.append("revision = ").append(revision.getId()).append(", ");
printAddress(sb, (Address) history[0]);
sb.append(" (").append(revision.getRevisionDate()).append(")\n");
}
}
}
private void printAddressAtRevision(StringBuilder sb, int addressId, int revision) {
VersionsReader reader = VersionsReaderFactory.get(entityManager);
Address a = reader.find(Address.class, addressId, revision);
if (a == null) {
sb.append("This address does not exist at that revision.");
} else {
printAddress(sb, a);
}
}
private Address readNewAddress(PrintStream out, Scanner scanner) {
Address a = new Address();
out.print("Street name (NULL for null): ");
a.setStreetName(convertString(scanner.nextLine(), ""));
out.print("House number: ");
a.setHouseNumber(convertStringToInteger(scanner.nextLine(), 0));
out.print("Flat number: ");
a.setFlatNumber(convertStringToInteger(scanner.nextLine(), 0));
a.setPersons(new HashSet<Person>());
return a;
}
private void readModifyAddress(PrintStream out, Scanner scanner, int addressId) {
Address current = entityManager.find(Address.class, addressId);
if (current == null) {
out.println("Address with id " + addressId + " does not exist.");
return;
}
out.print("Street name (NULL for null, enter for no change, current - " + current.getStreetName() + "): ");
current.setStreetName(convertString(scanner.nextLine(), current.getStreetName()));
out.print("House number (enter for no change, current - " + current.getHouseNumber() + "): ");
current.setHouseNumber(convertStringToInteger(scanner.nextLine(), current.getHouseNumber()));
out.print("Flat number (enter for no change, current - " + current.getFlatNumber() + "): ");
current.setFlatNumber(convertStringToInteger(scanner.nextLine(), current.getFlatNumber()));
}
private void start() {
Scanner scanner = new Scanner(System.in);
PrintStream out = System.out;
while (true) {
out.println("-----------------------------------------------");
out.println("1 - list persons 5 - list addresses");
out.println("2 - list person history 6 - list addresses history");
out.println("3 - new person 7 - new address");
out.println("4 - modify person 8 - modify address");
out.println("9 - get person at revision 10 - get address at revision");
out.println(" 0 - end");
try {
int choice = scanner.nextInt();
scanner.nextLine();
entityManager.getTransaction().begin();
StringBuilder sb;
int personId;
int addressId;
int revision;
switch (choice) {
case 1:
sb = new StringBuilder();
printPersons(sb);
out.println(sb.toString());
break;
case 2:
out.print("Person id: ");
personId = scanner.nextInt(); scanner.nextLine();
sb = new StringBuilder();
printPersonHistory(sb, personId);
out.println(sb.toString());
break;
case 3:
Person p = readNewPerson(out, scanner);
entityManager.persist(p);
break;
case 4:
out.print("Person id: ");
personId = scanner.nextInt(); scanner.nextLine();
readModifyPerson(out, scanner, personId);
break;
case 5:
sb = new StringBuilder();
printAddresses(sb);
out.println(sb.toString());
break;
case 6:
out.print("Address id: ");
addressId = scanner.nextInt(); scanner.nextLine();
sb = new StringBuilder();
printAddressHistory(sb, addressId);
out.println(sb.toString());
break;
case 7:
Address a = readNewAddress(out, scanner);
entityManager.persist(a);
break;
case 8:
out.print("Address id: ");
addressId = scanner.nextInt(); scanner.nextLine();
readModifyAddress(out, scanner, addressId);
break;
case 9:
out.print("Person id: ");
personId = scanner.nextInt(); scanner.nextLine();
out.print("Revision number: ");
revision = scanner.nextInt(); scanner.nextLine();
if (revision <= 0) {
System.out.println("Revision must be greater then 0!");
continue;
}
sb = new StringBuilder();
printPersonAtRevision(sb, personId, revision);
out.println(sb.toString());
break;
case 10:
out.print("Address id: ");
addressId = scanner.nextInt(); scanner.nextLine();
out.print("Revision number: ");
revision = scanner.nextInt(); scanner.nextLine();
if (revision <= 0) {
System.out.println("Revision must be greater then 0!");
continue;
}
sb = new StringBuilder();
printAddressAtRevision(sb, addressId, revision);
out.println(sb.toString());
break;
case 0:
return;
}
} catch (InputMismatchException e) {
// continuing
} finally {
entityManager.getTransaction().commit();
}
}
}
private boolean hasData() {
return (((Long) entityManager.createQuery("select count(a) from Address a").getSingleResult()) +
((Long) entityManager.createQuery("select count(p) from Person p").getSingleResult())) > 0;
}
private void populateTestData() {
entityManager.getTransaction().begin();
if (!hasData()) {
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
Address a1 = new Address();
Address a2 = new Address();
p1.setName("James");
p1.setSurname("Bond");
p1.setAddress(a1);
p2.setName("John");
p2.setSurname("McClane");
p2.setAddress(a2);
p3.setName("Holly");
p3.setSurname("Gennaro");
p3.setAddress(a2);
a1.setStreetName("MI6");
a1.setHouseNumber(18);
a1.setFlatNumber(25);
a1.setPersons(new HashSet<Person>());
a1.getPersons().add(p1);
a2.setStreetName("Nakatomi Plaza");
a2.setHouseNumber(10);
a2.setFlatNumber(34);
a2.setPersons(new HashSet<Person>());
a2.getPersons().add(p2);
a2.getPersons().add(p3);
entityManager.persist(a1);
entityManager.persist(a2);
entityManager.persist(p1);
entityManager.persist(p2);
entityManager.persist(p3);
System.out.println("The DB was populated with example data.");
}
entityManager.getTransaction().commit();
}
public static void main(String[] args) {
String userDbFile = System.getProperty("java.io.tmpdir") + File.separator + "_versions_demo.db";
Map<String, String> configurationOverrides = new HashMap<String, String>();
EntityManagerFactory emf = Persistence.createEntityManagerFactory("ConsolePU", configurationOverrides);
EntityManager entityManager = emf.createEntityManager();
TestConsole console = new TestConsole(entityManager);
System.out.println("");
System.out.println("Welcome to EntityVersions demo!");
System.out.println("HSQLDB database file location: " + userDbFile);
console.populateTestData();
console.start();
entityManager.close();
emf.close();
}
}

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="ConsolePU">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.jboss.envers.demo.Address</class>
<class>org.jboss.envers.demo.Person</class>
<exclude-unlisted-classes />
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.connection.url" value="jdbc:hsqldb:file:${java.io.tmpdir}/_versions_demo.db"/>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<!--<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.connection.url" value="jdbc:mysql:///hibernate_tests?useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value=""/>-->
<property name="hibernate.hbm2ddl.auto" value="update"/>
<!--<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>-->
<property name="hibernate.ejb.event.post-insert" value="org.jboss.envers.event.VersionsEventListener" />
<property name="hibernate.ejb.event.post-update" value="org.jboss.envers.event.VersionsEventListener" />
<property name="hibernate.ejb.event.post-delete" value="org.jboss.envers.event.VersionsEventListener" />
</properties>
</persistence-unit>
</persistence>

View File

@ -0,0 +1,59 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.hibernate.tool.ant;
import org.jboss.envers.ant.JPAConfigurationTaskWithEnvers;
import org.jboss.envers.ant.ConfigurationTaskWithEnvers;
import org.jboss.envers.ant.AnnotationConfigurationTaskWithEnvers;
import org.apache.tools.ant.BuildException;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class EnversHibernateToolTask extends HibernateToolTask {
private void checkConfiguration() {
if (configurationTask!=null) {
throw new BuildException("Only a single configuration is allowed.");
}
}
public JPAConfigurationTask createJpaConfiguration() {
checkConfiguration();
JPAConfigurationTask task = new JPAConfigurationTaskWithEnvers();
configurationTask = task;
return task;
}
public ConfigurationTask createConfiguration() {
checkConfiguration();
ConfigurationTaskWithEnvers task = new ConfigurationTaskWithEnvers();
configurationTask = task;
return task;
}
public AnnotationConfigurationTask createAnnotationConfiguration() {
checkConfiguration();
AnnotationConfigurationTaskWithEnvers task = new AnnotationConfigurationTaskWithEnvers();
configurationTask = task;
return task;
}
}

View File

@ -0,0 +1,87 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import javax.persistence.MappedSuperclass;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Transient;
import java.util.Date;
import java.text.DateFormat;
/**
* @author Adam Warski (adam at warski dot org)
*/
@MappedSuperclass
public class DefaultRevisionEntity {
@Id
@GeneratedValue
@RevisionNumber
private int id;
@RevisionTimestamp
private long timestamp;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Transient
public Date getRevisionDate() {
return new Date(timestamp);
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultRevisionEntity)) return false;
DefaultRevisionEntity that = (DefaultRevisionEntity) o;
if (id != that.id) return false;
if (timestamp != that.timestamp) return false;
return true;
}
public int hashCode() {
int result;
result = id;
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
return result;
}
public String toString() {
return "DefaultRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
}
}

View File

@ -0,0 +1,29 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
/**
* @author Adam Warski (adam at warski dot org)
*/
public enum ModificationStore {
FULL
}

View File

@ -0,0 +1,41 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Marks an entity to be created whenever a new revision is generated. The revisions entity must have
* an integer-valued unique property (preferrably the primary id) annotated with {@link RevisionNumber}
* and a long-valued property annotated with {@link RevisionTimestamp}. The {@link DefaultRevisionEntity}
* already has those two fields, so you may extend it, but you may also write your own revision entity
* from scratch.
* @author Adam Warski (adam at warski dot org)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RevisionEntity {
Class<? extends RevisionListener> value() default RevisionListener.class;
}

View File

@ -0,0 +1,36 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
/**
* An implementation of this class, having a no-arg constructor, should be passed as an argument to the
* {@link RevisionEntity} annotation.
* @author Adam Warski (adam at warski dot org)
*/
public interface RevisionListener {
/**
* Called when a new revision is created.
* @param revisionEntity An instance of the entity annotated with {@link RevisionEntity}, which will be persisted
* after this method returns. All properties on this entity that are to be persisted should be set by this method.
*/
void newRevision(Object revisionEntity);
}

View File

@ -0,0 +1,40 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Marks a property which will hold the number of the revision in a revision entity, see
* {@link RevisionListener}. Values of this property should form a strictly-increasing sequence
* of numbers. The value of this property won't be set by Envers. In most cases, this should be
* an auto-generated database-assigned primary id.
* @author Adam Warski (adam at warski dot org)
* @author Sanne Grinovero
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface RevisionNumber {
}

View File

@ -0,0 +1,38 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
/**
* Marks a property which will hold the timestamp of the revision in a revision entity, see
* {@link RevisionListener}. The value of this property will be automatically set by Envers.
* @author Adam Warski (adam at warski dot org)
* @author Sanne Grinovero
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface RevisionTimestamp {
}

View File

@ -0,0 +1,65 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
/**
* Type of the revision.
* @author Adam Warski (adam at warski dot org)
*/
public enum RevisionType {
/**
* Indicates that the entity was added (persisted) at that revision.
*/
ADD((byte) 0),
/**
* Indicates that the entity was modified (one or more of its fields) at that revision.
*/
MOD((byte) 1),
/**
* Indicates that the entity was deleted (removed) at that revision.
*/
DEL((byte) 2);
private Byte representation;
RevisionType(byte representation) {
this.representation = representation;
}
public Byte getRepresentation() {
return representation;
}
public static RevisionType fromRepresentation(Object representation) {
if (representation == null || !(representation instanceof Byte)) {
return null;
}
switch ((Byte) representation) {
case 0: return ADD;
case 1: return MOD;
case 2: return DEL;
}
throw new IllegalArgumentException("Unknown representation: " + representation);
}
}

View File

@ -0,0 +1,38 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Adam Warski (adam at warski dot org)
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SecondaryVersionsTable {
String secondaryTableName();
String secondaryVersionsTableName();
}

View File

@ -0,0 +1,36 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author Adam Warski (adam at warski dot org)
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SecondaryVersionsTables {
SecondaryVersionsTable[] value();
}

View File

@ -0,0 +1,37 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* When applied to a field, indicates that this field should not be versioned.
* @author Sebastian Komander
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Unversioned {
}

View File

@ -0,0 +1,38 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* When applied to a class, indicates that all of its properties should be versioned.
* When applied to a field, indicates that this field should be versioned.
* @author Adam Warski (adam at warski dot org)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface Versioned {
ModificationStore modStore() default ModificationStore.FULL;
}

View File

@ -0,0 +1,57 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import javax.persistence.JoinColumn;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Adam Warski (adam at warski dot org)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface VersionsJoinTable {
/**
* @return Name of the join table. Defaults to a concatenation of the names of the primary table of the entity
* owning the association and of the primary table of the entity referenced by the association.
*/
String name() default "";
/**
* @return The schema of the join table. Defaults to the schema of the entity owning the association.
*/
String schema() default "";
/**
* @return The catalog of the join table. Defaults to the catalog of the entity owning the association.
*/
String catalog() default "";
/**
* @return The foreign key columns of the join table which reference the primary table of the entity that does not
* own the association (i.e. the inverse side of the association).
*/
JoinColumn[] inverseJoinColumns() default {};
}

View File

@ -0,0 +1,108 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import org.jboss.envers.exception.NotVersionedException;
import org.jboss.envers.exception.RevisionDoesNotExistException;
import org.jboss.envers.query.VersionsQueryCreator;
import java.util.List;
import java.util.Date;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface VersionsReader {
/**
* Find an entity by primary key at the given revision.
* @param cls Class of the entity.
* @param primaryKey Primary key of the entity.
* @param revision Revision in which to get the entity.
* @return The found entity instance at the given revision (its properties may be partially filled
* if not all properties are versioned) or null, if an entity with that id didn't exist at that
* revision.
* @throws IllegalArgumentException If cls or primaryKey is null or revision is less or equal to 0.
* @throws NotVersionedException When entities of the given class are not versioned.
* @throws IllegalStateException If the associated entity manager is closed.
*/
<T> T find(Class<T> cls, Object primaryKey, Number revision) throws
IllegalArgumentException, NotVersionedException, IllegalStateException;
/**
* Get a list of revision numbers, at which an entity was modified.
* @param cls Class of the entity.
* @param primaryKey Primary key of the entity.
* @return A list of revision numbers, at which the entity was modified, sorted in ascending order (so older
* revisions come first).
* @throws NotVersionedException When entities of the given class are not versioned.
* @throws IllegalArgumentException If cls or primaryKey is null.
* @throws IllegalStateException If the associated entity manager is closed.
*/
List<Number> getRevisions(Class<?> cls, Object primaryKey)
throws IllegalArgumentException, NotVersionedException, IllegalStateException;
/**
* Get the date, at which a revision was created.
* @param revision Number of the revision for which to get the date.
* @return Date of commiting the given revision.
* @throws IllegalArgumentException If revision is less or equal to 0.
* @throws RevisionDoesNotExistException If the revision does not exist.
* @throws IllegalStateException If the associated entity manager is closed.
*/
Date getRevisionDate(Number revision) throws IllegalArgumentException, RevisionDoesNotExistException,
IllegalStateException;
/**
* Gets the revision number, that corresponds to the given date. More precisely, returns
* the number of the highest revision, which was created on or before the given date. So:
* <code>getRevisionDate(getRevisionNumberForDate(date)) <= date</code> and
* <code>getRevisionDate(getRevisionNumberForDate(date)+1) > date</code>.
* @param date Date for which to get the revision.
* @return Revision number corresponding to the given date.
* @throws IllegalStateException If the associated entity manager is closed.
* @throws RevisionDoesNotExistException If the given date is before the first revision.
* @throws IllegalArgumentException If <code>date</code> is <code>null</code>.
*/
Number getRevisionNumberForDate(Date date) throws IllegalStateException, RevisionDoesNotExistException,
IllegalArgumentException;
/**
* A helper method; should be used only if a custom revision entity is used. See also {@link RevisionEntity}.
* @param revisionEntityClass Class of the revision entity. Should be annotated with {@link RevisionEntity}.
* @param revision Number of the revision for which to get the data.
* @return Entity containing data for the given revision.
* @throws IllegalArgumentException If revision is less or equal to 0 or if the class of the revision entity
* is invalid.
* @throws RevisionDoesNotExistException If the revision does not exist.
* @throws IllegalStateException If the associated entity manager is closed.
*/
<T> T findRevision(Class<T> revisionEntityClass, Number revision) throws IllegalArgumentException,
RevisionDoesNotExistException, IllegalStateException;
/**
*
* @return A query creator, associated with this VersionsReader instance, with which queries can be
* created and later executed. Shouldn't be used after the associated Session or EntityManager
* is closed.
*/
VersionsQueryCreator createQuery();
}

View File

@ -0,0 +1,90 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import org.hibernate.Session;
import org.hibernate.event.EventListeners;
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.engine.SessionImplementor;
import org.jboss.envers.exception.VersionsException;
import org.jboss.envers.event.VersionsEventListener;
import static org.jboss.envers.tools.ArraysTools.arrayIncludesInstanceOf;
import org.jboss.envers.reader.VersionsReaderImpl;
import javax.persistence.EntityManager;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class VersionsReaderFactory {
private VersionsReaderFactory() { }
/**
* Create a versions reader associated with an open session.
* <b>WARNING:</b> Using Envers with Hibernate (not with Hibernate Entity Manager/JPA) is experimental,
* if possible, use {@link org.jboss.envers.VersionsReaderFactory#get(javax.persistence.EntityManager)}.
* @param session An open session.
* @return A versions reader associated with the given sesison. It shouldn't be used
* after the session is closed.
* @throws VersionsException When the given required listeners aren't installed.
*/
public static VersionsReader get(Session session) throws VersionsException {
SessionImplementor sessionImpl = (SessionImplementor) session;
EventListeners listeners = sessionImpl.getListeners();
for (PostInsertEventListener listener : listeners.getPostInsertEventListeners()) {
if (listener instanceof VersionsEventListener) {
if (arrayIncludesInstanceOf(listeners.getPostUpdateEventListeners(), VersionsEventListener.class) &&
arrayIncludesInstanceOf(listeners.getPostDeleteEventListeners(), VersionsEventListener.class)) {
return new VersionsReaderImpl(((VersionsEventListener) listener).getVerCfg(), session,
sessionImpl);
}
}
}
throw new VersionsException("You need install the org.jboss.envers.event.VersionsEventListener " +
"class as post insert, update and delete event listener.");
}
/**
* Create a versions reader associated with an open entity manager.
* @param entityManager An open entity manager.
* @return A versions reader associated with the given entity manager. It shouldn't be used
* after the entity manager is closed.
* @throws VersionsException When the given entity manager is not based on Hibernate, or if the required
* listeners aren't installed.
*/
public static VersionsReader get(EntityManager entityManager) throws VersionsException {
if (entityManager.getDelegate() instanceof Session) {
return get((Session) entityManager.getDelegate());
}
if (entityManager.getDelegate() instanceof EntityManager) {
if (entityManager.getDelegate() instanceof Session) {
return get((Session) entityManager.getDelegate());
}
}
throw new VersionsException("Hibernate EntityManager not present!");
}
}

View File

@ -0,0 +1,46 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author Adam Warski (adam at warski dot org)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface VersionsTable {
String value();
/**
* @return The schema of the table. Defaults to the schema of the annotated entity.
*/
String schema() default "";
/**
* @return The catalog of the table. Defaults to the catalog of the annotated entity.
*/
String catalog() default "";
}

View File

@ -0,0 +1,37 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.ant;
import org.hibernate.tool.ant.AnnotationConfigurationTask;
import org.hibernate.cfg.Configuration;
import org.jboss.envers.configuration.VersionsConfiguration;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class AnnotationConfigurationTaskWithEnvers extends AnnotationConfigurationTask {
protected void doConfiguration(Configuration configuration) {
VersionsConfiguration.getFor(configuration);
super.doConfiguration(configuration);
}
}

View File

@ -0,0 +1,37 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.ant;
import org.hibernate.tool.ant.ConfigurationTask;
import org.hibernate.cfg.Configuration;
import org.jboss.envers.configuration.VersionsConfiguration;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class ConfigurationTaskWithEnvers extends ConfigurationTask {
protected void doConfiguration(Configuration configuration) {
VersionsConfiguration.getFor(configuration);
super.doConfiguration(configuration);
}
}

View File

@ -0,0 +1,37 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.ant;
import org.hibernate.tool.ant.JPAConfigurationTask;
import org.hibernate.cfg.Configuration;
import org.jboss.envers.configuration.VersionsConfiguration;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class JPAConfigurationTaskWithEnvers extends JPAConfigurationTask {
protected void doConfiguration(Configuration configuration) {
VersionsConfiguration.getFor(configuration);
super.doConfiguration(configuration);
}
}

View File

@ -0,0 +1,143 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration;
import org.jboss.envers.entities.EntitiesConfigurations;
import org.jboss.envers.configuration.metadata.VersionsMetadataGenerator;
import org.jboss.envers.configuration.metadata.PersistentClassVersioningData;
import org.jboss.envers.configuration.metadata.AnnotationsMetadataReader;
import org.jboss.envers.configuration.metadata.EntityXmlMappingData;
import org.jboss.envers.tools.graph.GraphTopologicalSort;
import org.jboss.envers.tools.reflection.YReflectionManager;
import org.jboss.envers.tools.StringTools;
import org.dom4j.io.DOMWriter;
import org.dom4j.io.XMLWriter;
import org.dom4j.io.OutputFormat;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.io.ByteArrayOutputStream;
import java.io.Writer;
import java.io.PrintWriter;
import java.io.IOException;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class EntitiesConfigurator {
public EntitiesConfigurations configure(Configuration cfg, YReflectionManager reflectionManager,
GlobalConfiguration globalCfg, VersionsEntitiesConfiguration verEntCfg,
Document revisionInfoXmlMapping, Element revisionInfoRelationMapping) {
VersionsMetadataGenerator versionsMetaGen = new VersionsMetadataGenerator(cfg, globalCfg, verEntCfg,
revisionInfoRelationMapping);
DOMWriter writer = new DOMWriter();
// Sorting the persistent class topologically - superclass always before subclass
Iterator<PersistentClass> classes = GraphTopologicalSort.sort(new PersistentClassGraphDefiner(cfg)).iterator();
Map<PersistentClass, PersistentClassVersioningData> pcDatas =
new HashMap<PersistentClass, PersistentClassVersioningData>();
Map<PersistentClass, EntityXmlMappingData> xmlMappings = new HashMap<PersistentClass, EntityXmlMappingData>();
// First pass
while (classes.hasNext()) {
PersistentClass pc = classes.next();
// Collecting information from annotations on the persistent class pc
AnnotationsMetadataReader annotationsMetadataReader =
new AnnotationsMetadataReader(globalCfg, reflectionManager, pc);
PersistentClassVersioningData versioningData = annotationsMetadataReader.getVersioningData();
if (versioningData.isVersioned()) {
pcDatas.put(pc, versioningData);
if (!StringTools.isEmpty(versioningData.versionsTable.value())) {
verEntCfg.addCustomVersionsTableName(pc.getEntityName(), versioningData.versionsTable.value());
}
EntityXmlMappingData xmlMappingData = new EntityXmlMappingData();
versionsMetaGen.generateFirstPass(pc, versioningData, xmlMappingData);
xmlMappings.put(pc, xmlMappingData);
}
}
// Second pass
for (Map.Entry<PersistentClass, PersistentClassVersioningData> pcDatasEntry : pcDatas.entrySet()) {
EntityXmlMappingData xmlMappingData = xmlMappings.get(pcDatasEntry.getKey());
versionsMetaGen.generateSecondPass(pcDatasEntry.getKey(), pcDatasEntry.getValue(), xmlMappingData);
try {
cfg.addDocument(writer.write(xmlMappingData.getMainXmlMapping()));
// TODO
//writeDocument(xmlMappingData.getMainXmlMapping());
for (Document additionalMapping : xmlMappingData.getAdditionalXmlMappings()) {
cfg.addDocument(writer.write(additionalMapping));
// TODO
//writeDocument(additionalMapping);
}
} catch (DocumentException e) {
throw new MappingException(e);
}
}
// Only if there are any versioned classes
if (pcDatas.size() > 0) {
try {
if (revisionInfoXmlMapping != null) {
// TODO
//writeDocument(revisionInfoXmlMapping);
cfg.addDocument(writer.write(revisionInfoXmlMapping));
}
} catch (DocumentException e) {
throw new MappingException(e);
}
}
return new EntitiesConfigurations(versionsMetaGen.getEntitiesConfigurations());
}
// todo
private void writeDocument(Document e) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Writer w = new PrintWriter(baos);
try {
XMLWriter xw = new XMLWriter(w, new OutputFormat(" ", true));
xw.write(e);
w.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
System.out.println("-----------");
System.out.println(baos.toString());
System.out.println("-----------");
}
}

View File

@ -0,0 +1,82 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration;
import java.util.Properties;
/**
* @author Adam Warski (adam at warski dot org)
* @author Nicolas Doroskevich
*/
public class GlobalConfiguration {
// Should a revision be generated when a not-owned relation field changes
private final boolean generateRevisionsForCollections;
// Should a warning, instead of an error and an exception, be logged, when an unsupported type is versioned
private final boolean warnOnUnsupportedTypes;
// Should the optimistic locking property of an entity be considered unversioned
private final boolean unversionedOptimisticLockingField;
/*
Which operator to use in correlated subqueries (when we want a property to be equal to the result of
a correlated subquery, for example: e.p <operator> (select max(e2.p) where e2.p2 = e.p2 ...).
Normally, this should be "=". However, HSQLDB has an issue related to that, so as a workaround,
"in" is used. See {@link org.jboss.envers.test.various.HsqlTest}.
*/
private final String correlatedSubqueryOperator;
public GlobalConfiguration(Properties properties) {
String generateRevisionsForCollectionsStr = properties.getProperty("org.jboss.envers.revisionOnCollectionChange",
"true");
generateRevisionsForCollections = Boolean.parseBoolean(generateRevisionsForCollectionsStr);
String warnOnUnsupportedTypesStr = properties.getProperty("org.jboss.envers.warnOnUnsupportedTypes",
"false");
warnOnUnsupportedTypes = Boolean.parseBoolean(warnOnUnsupportedTypesStr);
String ignoreOptimisticLockingPropertyStr = properties.getProperty("org.jboss.envers.unversionedOptimisticLockingField",
"false");
unversionedOptimisticLockingField = Boolean.parseBoolean(ignoreOptimisticLockingPropertyStr);
correlatedSubqueryOperator = "org.hibernate.dialect.HSQLDialect".equals(
properties.getProperty("hibernate.dialect")) ? "in" : "=";
}
public boolean isGenerateRevisionsForCollections() {
return generateRevisionsForCollections;
}
public boolean isWarnOnUnsupportedTypes() {
return warnOnUnsupportedTypes;
}
public boolean isUnversionedOptimisticLockingField() {
return unversionedOptimisticLockingField;
}
public String getCorrelatedSubqueryOperator() {
return correlatedSubqueryOperator;
}
}

View File

@ -0,0 +1,75 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.cfg.Configuration;
import org.jboss.envers.tools.graph.GraphDefiner;
import org.jboss.envers.tools.Tools;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
/**
* Defines a graph, where the vertexes are all persistent classes, and there is an edge from
* p.c. A to p.c. B iff A is a superclass of B.
* @author Adam Warski (adam at warski dot org)
*/
public class PersistentClassGraphDefiner implements GraphDefiner<PersistentClass, String> {
private Configuration cfg;
public PersistentClassGraphDefiner(Configuration cfg) {
this.cfg = cfg;
}
public String getRepresentation(PersistentClass pc) {
return pc.getEntityName();
}
public PersistentClass getValue(String entityName) {
return cfg.getClassMapping(entityName);
}
@SuppressWarnings({"unchecked"})
private void addNeighbours(List<PersistentClass> neighbours, Iterator<PersistentClass> subclassIterator) {
while (subclassIterator.hasNext()) {
PersistentClass subclass = subclassIterator.next();
neighbours.add(subclass);
addNeighbours(neighbours, (Iterator<PersistentClass>) subclass.getSubclassIterator());
}
}
@SuppressWarnings({"unchecked"})
public List<PersistentClass> getNeighbours(PersistentClass pc) {
List<PersistentClass> neighbours = new ArrayList<PersistentClass>();
addNeighbours(neighbours, (Iterator<PersistentClass>) pc.getSubclassIterator());
return neighbours;
}
@SuppressWarnings({"unchecked"})
public List<PersistentClass> getValues() {
return Tools.iteratorToList((Iterator<PersistentClass>) cfg.getClassMappings());
}
}

View File

@ -0,0 +1,265 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration;
import org.jboss.envers.tools.reflection.YClass;
import org.jboss.envers.tools.reflection.YReflectionManager;
import org.jboss.envers.tools.reflection.YProperty;
import org.jboss.envers.tools.MutableBoolean;
import org.jboss.envers.*;
import org.jboss.envers.configuration.metadata.MetadataTools;
import org.jboss.envers.revisioninfo.*;
import org.hibernate.MappingException;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.cfg.Configuration;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.util.Iterator;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class RevisionInfoConfiguration {
private String revisionInfoEntityName;
private String revisionInfoIdName;
private String revisionInfoTimestampName;
private String revisionInfoTimestampType;
private String revisionPropType;
public RevisionInfoConfiguration() {
revisionInfoEntityName = "org.jboss.envers.DefaultRevisionEntity";
revisionInfoIdName = "id";
revisionInfoTimestampName = "timestamp";
revisionInfoTimestampType = "long";
revisionPropType = "integer";
}
private Document generateDefaultRevisionInfoXmlMapping() {
Document document = DocumentHelper.createDocument();
Element class_mapping = MetadataTools.createEntity(document, null, null, null, null, null);
class_mapping.addAttribute("name", revisionInfoEntityName);
class_mapping.addAttribute("table", "_revisions_info");
Element idProperty = MetadataTools.addNativelyGeneratedId(class_mapping, revisionInfoIdName,
revisionPropType);
MetadataTools.addColumn(idProperty, "revision_id", null);
Element timestampProperty = MetadataTools.addProperty(class_mapping, revisionInfoTimestampName,
revisionInfoTimestampType, true, false);
MetadataTools.addColumn(timestampProperty, "revision_timestamp", null);
return document;
}
private Element generateRevisionInfoRelationMapping() {
Document document = DocumentHelper.createDocument();
Element rev_rel_mapping =document.addElement("key-many-to-one");
rev_rel_mapping.addAttribute("type", revisionPropType);
rev_rel_mapping.addAttribute("class", revisionInfoEntityName);
return rev_rel_mapping;
}
private void searchForRevisionInfoCfgInProperties(YClass clazz, YReflectionManager reflectionManager,
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound,
String accessType) {
for (YProperty property : clazz.getDeclaredProperties(accessType)) {
RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class);
RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class);
if (revisionNumber != null) {
if (revisionNumberFound.isSet()) {
throw new MappingException("Only one property may be annotated with @RevisionNumber!");
}
YClass revisionNumberClass = property.getType();
if (reflectionManager.equals(revisionNumberClass, Integer.class) ||
reflectionManager.equals(revisionNumberClass, Integer.TYPE)) {
revisionInfoIdName = property.getName();
revisionNumberFound.set();
} else if (reflectionManager.equals(revisionNumberClass, Long.class) ||
reflectionManager.equals(revisionNumberClass, Long.TYPE)) {
revisionInfoIdName = property.getName();
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");
}
}
if (revisionTimestamp != null) {
if (revisionTimestampFound.isSet()) {
throw new MappingException("Only one property may be annotated with @RevisionTimestamp!");
}
YClass revisionTimestampClass = property.getType();
if (reflectionManager.equals(revisionTimestampClass, Long.class) ||
reflectionManager.equals(revisionTimestampClass, Long.TYPE)) {
revisionInfoTimestampName = property.getName();
revisionTimestampFound.set();
} else {
throw new MappingException("The field annotated with @RevisionTimestamp must be of type " +
"long or Long");
}
}
}
}
private void searchForRevisionInfoCfg(YClass clazz, YReflectionManager reflectionManager,
MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound) {
YClass superclazz = clazz.getSuperclass();
if (!"java.lang.Object".equals(superclazz.getName())) {
searchForRevisionInfoCfg(superclazz, reflectionManager, revisionNumberFound, revisionTimestampFound);
}
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
"field");
searchForRevisionInfoCfgInProperties(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound,
"property");
}
@SuppressWarnings({"unchecked"})
public RevisionInfoConfigurationResult configure(Configuration cfg, YReflectionManager reflectionManager) {
Iterator<PersistentClass> classes = (Iterator<PersistentClass>) cfg.getClassMappings();
boolean revisionEntityFound = false;
RevisionInfoGenerator revisionInfoGenerator = null;
Class<?> revisionInfoClass = null;
while (classes.hasNext()) {
PersistentClass pc = classes.next();
YClass 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 versioned
if (clazz.getAnnotation(Versioned.class) != null) {
throw new MappingException("An entity annotated with @RevisionEntity cannot be versioned!");
}
revisionEntityFound = true;
MutableBoolean revisionNumberFound = new MutableBoolean();
MutableBoolean revisionTimestampFound = new MutableBoolean();
searchForRevisionInfoCfg(clazz, reflectionManager, revisionNumberFound, revisionTimestampFound);
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();
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
revisionEntity.value(), revisionInfoTimestampName);
}
}
// In case of a custom revision info generator, the mapping will be null.
Document revisionInfoXmlMapping = null;
if (revisionInfoGenerator == null) {
revisionInfoClass = DefaultRevisionEntity.class;
revisionInfoGenerator = new DefaultRevisionInfoGenerator(revisionInfoEntityName, revisionInfoClass,
RevisionListener.class, revisionInfoTimestampName);
revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping();
}
return new RevisionInfoConfigurationResult(
revisionInfoGenerator, revisionInfoXmlMapping,
new RevisionInfoQueryCreator(revisionInfoEntityName, revisionInfoIdName, revisionInfoTimestampName),
generateRevisionInfoRelationMapping(),
new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdName), revisionInfoEntityName);
}
}
class RevisionInfoConfigurationResult {
private final RevisionInfoGenerator revisionInfoGenerator;
private final Document revisionInfoXmlMapping;
private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final Element revisionInfoRelationMapping;
private final RevisionInfoNumberReader revisionInfoNumberReader;
private final String revisionInfoEntityName;
RevisionInfoConfigurationResult(RevisionInfoGenerator revisionInfoGenerator,
Document revisionInfoXmlMapping, RevisionInfoQueryCreator revisionInfoQueryCreator,
Element revisionInfoRelationMapping,
RevisionInfoNumberReader revisionInfoNumberReader, String revisionInfoEntityName) {
this.revisionInfoGenerator = revisionInfoGenerator;
this.revisionInfoXmlMapping = revisionInfoXmlMapping;
this.revisionInfoQueryCreator = revisionInfoQueryCreator;
this.revisionInfoRelationMapping = revisionInfoRelationMapping;
this.revisionInfoNumberReader = revisionInfoNumberReader;
this.revisionInfoEntityName = revisionInfoEntityName;
}
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;
}
}

View File

@ -0,0 +1,101 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration;
import org.hibernate.cfg.Configuration;
import org.jboss.envers.entities.EntitiesConfigurations;
import org.jboss.envers.synchronization.VersionsSyncManager;
import org.jboss.envers.tools.reflection.YReflectionManager;
import org.jboss.envers.revisioninfo.RevisionInfoQueryCreator;
import org.jboss.envers.revisioninfo.RevisionInfoNumberReader;
import java.util.*;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class VersionsConfiguration {
private final GlobalConfiguration globalCfg;
private final VersionsEntitiesConfiguration verEntCfg;
private final VersionsSyncManager versionsSyncManager;
private final EntitiesConfigurations entCfg;
private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final RevisionInfoNumberReader revisionInfoNumberReader;
public VersionsEntitiesConfiguration getVerEntCfg() {
return verEntCfg;
}
public VersionsSyncManager getSyncManager() {
return versionsSyncManager;
}
public GlobalConfiguration getGlobalCfg() {
return globalCfg;
}
public EntitiesConfigurations getEntCfg() {
return entCfg;
}
public RevisionInfoQueryCreator getRevisionInfoQueryCreator() {
return revisionInfoQueryCreator;
}
public RevisionInfoNumberReader getRevisionInfoNumberReader() {
return revisionInfoNumberReader;
}
@SuppressWarnings({"unchecked"})
public VersionsConfiguration(Configuration cfg) {
Properties properties = cfg.getProperties();
YReflectionManager reflectionManager = YReflectionManager.get(cfg);
RevisionInfoConfiguration revInfoCfg = new RevisionInfoConfiguration();
RevisionInfoConfigurationResult revInfoCfgResult = revInfoCfg.configure(cfg, reflectionManager);
verEntCfg = new VersionsEntitiesConfiguration(properties, revInfoCfgResult.getRevisionInfoEntityName());
globalCfg = new GlobalConfiguration(properties);
versionsSyncManager = new VersionsSyncManager(revInfoCfgResult.getRevisionInfoGenerator());
revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
entCfg = new EntitiesConfigurator().configure(cfg, reflectionManager, globalCfg, verEntCfg,
revInfoCfgResult.getRevisionInfoXmlMapping(), revInfoCfgResult.getRevisionInfoRelationMapping());
}
//
private static Map<Configuration, VersionsConfiguration> cfgs
= new WeakHashMap<Configuration, VersionsConfiguration>();
public synchronized static VersionsConfiguration getFor(Configuration cfg) {
VersionsConfiguration verCfg = cfgs.get(cfg);
if (verCfg == null) {
verCfg = new VersionsConfiguration(cfg);
cfgs.put(cfg, verCfg);
cfg.buildMappings();
}
return verCfg;
}
}

View File

@ -0,0 +1,108 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration;
import java.util.*;
/**
* Configuration of versions entities - names of fields, entities and tables created to store versioning information.
* @author Adam Warski (adam at warski dot org)
*/
public class VersionsEntitiesConfiguration {
private final String versionsTablePrefix;
private final String versionsTableSuffix;
private final String originalIdPropName;
private final String revisionPropName;
private final String revisionPropPath;
private final String revisionTypePropName;
private final String revisionTypePropType;
private final String revisionInfoEntityName;
private final Map<String, String> customVersionsTablesNames;
public VersionsEntitiesConfiguration(Properties properties, String revisionInfoEntityName) {
this.revisionInfoEntityName = revisionInfoEntityName;
versionsTablePrefix = properties.getProperty("org.jboss.envers.versionsTablePrefix", "");
versionsTableSuffix = properties.getProperty("org.jboss.envers.versionsTableSuffix", "_versions");
originalIdPropName = "originalId";
revisionPropName = properties.getProperty("org.jboss.envers.revisionFieldName", "_revision");
revisionTypePropName = properties.getProperty("org.jboss.envers.revisionTypeFieldName", "_revision_type");
revisionTypePropType = "byte";
customVersionsTablesNames = new HashMap<String, String>();
revisionPropPath = originalIdPropName + "." + revisionPropName + ".id";
}
public String getOriginalIdPropName() {
return originalIdPropName;
}
public String getRevisionPropName() {
return revisionPropName;
}
public String getRevisionPropPath() {
return revisionPropPath;
}
public String getRevisionTypePropName() {
return revisionTypePropName;
}
public String getRevisionTypePropType() {
return revisionTypePropType;
}
public String getRevisionInfoEntityName() {
return revisionInfoEntityName;
}
//
public void addCustomVersionsTableName(String entityName, String tableName) {
customVersionsTablesNames.put(entityName, tableName);
}
//
public String getVersionsEntityName(String entityName) {
return versionsTablePrefix + entityName + versionsTableSuffix;
}
public String getVersionsTableName(String entityName, String tableName) {
String customHistoryTableName = customVersionsTablesNames.get(entityName);
if (customHistoryTableName == null) {
return versionsTablePrefix + tableName + versionsTableSuffix;
}
return customHistoryTableName;
}
}

View File

@ -0,0 +1,181 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import javax.persistence.Version;
import javax.persistence.MapKey;
import org.jboss.envers.configuration.GlobalConfiguration;
import org.jboss.envers.tools.reflection.YClass;
import org.jboss.envers.tools.reflection.YProperty;
import org.jboss.envers.tools.reflection.YReflectionManager;
import org.jboss.envers.*;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.MappingException;
import java.lang.annotation.Annotation;
/**
* A helper class to read versioning meta-data from annotations on a persistent class.
* @author Adam Warski (adam at warski dot org)
* @author Sebastian Komander
*/
public final class AnnotationsMetadataReader {
private final GlobalConfiguration globalCfg;
private final YReflectionManager reflectionManager;
private final PersistentClass pc;
/**
* This object is filled with information read from annotations and returned by the <code>getVersioningData</code>
* method.
*/
private final PersistentClassVersioningData versioningData;
public AnnotationsMetadataReader(GlobalConfiguration globalCfg, YReflectionManager reflectionManager,
PersistentClass pc) {
this.globalCfg = globalCfg;
this.reflectionManager = reflectionManager;
this.pc = pc;
versioningData = new PersistentClassVersioningData();
}
private void addPropertyVersioned(YProperty property) {
Versioned ver = property.getAnnotation(Versioned.class);
if (ver != null) {
versioningData.propertyStoreInfo.propertyStores.put(property.getName(), ver.modStore());
}
}
private void addPropertyMapKey(YProperty property) {
MapKey mapKey = property.getAnnotation(MapKey.class);
if (mapKey != null) {
versioningData.mapKeys.put(property.getName(), mapKey.name());
}
}
private void addPropertyUnversioned(YProperty property) {
// check if a property is declared as unversioned to exclude it
// useful if a class is versioned but some properties should be excluded
Unversioned unVer = property.getAnnotation(Unversioned.class);
if (unVer != null) {
versioningData.unversionedProperties.add(property.getName());
} else {
// if the optimistic locking field has to be unversioned and the current property
// is the optimistic locking field, add it to the unversioned properties list
if (globalCfg.isUnversionedOptimisticLockingField()) {
Version jpaVer = property.getAnnotation(Version.class);
if (jpaVer != null) {
versioningData.unversionedProperties.add(property.getName());
}
}
}
}
private void addPropertyJoinTables(YProperty property) {
VersionsJoinTable joinTable = property.getAnnotation(VersionsJoinTable.class);
if (joinTable != null) {
versioningData.versionsJoinTables.put(property.getName(), joinTable);
}
}
private void addFromProperties(Iterable<YProperty> properties) {
for (YProperty property : properties) {
addPropertyVersioned(property);
addPropertyUnversioned(property);
addPropertyJoinTables(property);
addPropertyMapKey(property);
}
}
private void addPropertiesFromClass(YClass clazz) {
YClass superclazz = clazz.getSuperclass();
if (!"java.lang.Object".equals(superclazz.getName())) {
addPropertiesFromClass(superclazz);
}
addFromProperties(clazz.getDeclaredProperties("field"));
addFromProperties(clazz.getDeclaredProperties("property"));
}
private void addDefaultVersioned(YClass clazz) {
Versioned defaultVersioned = clazz.getAnnotation(Versioned.class);
if (defaultVersioned != null) {
versioningData.propertyStoreInfo.defaultStore = defaultVersioned.modStore();
}
}
private void addVersionsTable(YClass clazz) {
VersionsTable versionsTable = clazz.getAnnotation(VersionsTable.class);
if (versionsTable != null) {
versioningData.versionsTable = versionsTable;
} else {
versioningData.versionsTable = getDefaultVersionsTable();
}
}
private void addVersionsSecondaryTables(YClass clazz) {
// Getting information on secondary tables
SecondaryVersionsTable secondaryVersionsTable1 = clazz.getAnnotation(SecondaryVersionsTable.class);
if (secondaryVersionsTable1 != null) {
versioningData.secondaryTableDictionary.put(secondaryVersionsTable1.secondaryTableName(),
secondaryVersionsTable1.secondaryVersionsTableName());
}
SecondaryVersionsTables secondaryVersionsTables = clazz.getAnnotation(SecondaryVersionsTables.class);
if (secondaryVersionsTables != null) {
for (SecondaryVersionsTable secondaryVersionsTable2 : secondaryVersionsTables.value()) {
versioningData.secondaryTableDictionary.put(secondaryVersionsTable2.secondaryTableName(),
secondaryVersionsTable2.secondaryVersionsTableName());
}
}
}
public PersistentClassVersioningData getVersioningData() {
if (pc.getClassName() == null) {
return versioningData;
}
try {
YClass clazz = reflectionManager.classForName(pc.getClassName(), this.getClass());
addDefaultVersioned(clazz);
addPropertiesFromClass(clazz);
addVersionsTable(clazz);
addVersionsSecondaryTables(clazz);
} catch (ClassNotFoundException e) {
throw new MappingException(e);
}
return versioningData;
}
private VersionsTable getDefaultVersionsTable() {
return new VersionsTable() {
public String value() { return ""; }
public String schema() { return ""; }
public String catalog() { return ""; }
public Class<? extends Annotation> annotationType() { return this.getClass(); }
};
}
}

View File

@ -0,0 +1,164 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.dom4j.Element;
import org.hibernate.mapping.*;
import org.hibernate.type.*;
import org.hibernate.util.StringHelper;
import org.jboss.envers.entities.mapper.SimpleMapperBuilder;
import org.jboss.envers.entities.mapper.CompositeMapperBuilder;
import org.jboss.envers.ModificationStore;
import java.util.Iterator;
import java.util.Properties;
/**
* Generates metadata for basic properties: immutable types (including enums) and components
* @author Adam Warski (adam at warski dot org)
*/
public final class BasicMetadataGenerator {
boolean addBasic(Element parent, String name, Value value, CompositeMapperBuilder mapper,
ModificationStore store, String entityName, boolean insertable, boolean key) {
Type type = value.getType();
if (type instanceof ComponentType) {
addComponent(parent, name, value, mapper, entityName, key);
return true;
} else {
return addBasicNoComponent(parent, name, value, mapper, store, insertable, key);
}
}
boolean addBasicNoComponent(Element parent, String name, Value value, SimpleMapperBuilder mapper,
ModificationStore store, boolean insertable, boolean key) {
Type type = value.getType();
if (type instanceof ImmutableType || type instanceof MutableType) {
addSimpleValue(parent, name, value, mapper, store, insertable, key);
} else if (type instanceof CustomType || type instanceof CompositeCustomType) {
addCustomValue(parent, name, value, mapper, store, insertable, key);
} else if ("org.hibernate.type.PrimitiveByteArrayBlobType".equals(type.getClass().getName())) {
addSimpleValue(parent, name, value, mapper, store, insertable, key);
} else {
return false;
}
return true;
}
@SuppressWarnings({"unchecked"})
private void addSimpleValue(Element parent, String name, Value value, SimpleMapperBuilder mapper,
ModificationStore store, boolean insertable, boolean key) {
if (parent != null) {
Element prop_mapping = MetadataTools.addProperty(parent, name,
value.getType().getName(), insertable, key);
MetadataTools.addColumns(prop_mapping, (Iterator<Column>) value.getColumnIterator());
}
// A null mapper means that we only want to add xml mappings
if (mapper != null) {
mapper.add(name, store);
}
}
@SuppressWarnings({"unchecked"})
private void addCustomValue(Element parent, String name, Value value, SimpleMapperBuilder mapper,
ModificationStore store, boolean insertable, boolean key) {
if (parent != null) {
Element prop_mapping = MetadataTools.addProperty(parent, name,
null, insertable, key);
//CustomType propertyType = (CustomType) value.getType();
Element type_mapping = prop_mapping.addElement("type");
type_mapping.addAttribute("name", value.getType().getName());
if (value instanceof SimpleValue) {
Properties typeParameters = ((SimpleValue) value).getTypeParameters();
if (typeParameters != null) {
for (java.util.Map.Entry paramKeyValue : typeParameters.entrySet()) {
Element type_param = type_mapping.addElement("param");
type_param.addAttribute("name", (String) paramKeyValue.getKey());
type_param.setText((String) paramKeyValue.getValue());
}
}
}
MetadataTools.addColumns(prop_mapping, (Iterator<Column>) value.getColumnIterator());
}
if (mapper != null) {
mapper.add(name, store);
}
}
private void addComponentClassName(Element any_mapping, Component comp) {
if (StringHelper.isNotEmpty(comp.getComponentClassName())) {
any_mapping.addAttribute("class", comp.getComponentClassName());
}
}
@SuppressWarnings({"unchecked"})
private void addComponent(Element parent, String name, Value value, CompositeMapperBuilder mapper,
String entityName, boolean key) {
Element component_mapping = null;
Component prop_component = (Component) value;
if (parent != null) {
/*
TODO: investigate relations inside components
if (!firstPass) {
// The required element already exists.
Iterator<Element> iter = parent.elementIterator("component");
while (iter.hasNext()) {
Element child = iter.next();
if (child.attribute("name").getText().equals(name)) {
component_mapping = child;
break;
}
}
if (component_mapping == null) {
throw new VersionsException("Element for component not found during second pass!");
}
} else {
*/
component_mapping = parent.addElement("component");
component_mapping.addAttribute("name", name);
addComponentClassName(component_mapping, prop_component);
}
CompositeMapperBuilder componentMapper = mapper.addComposite(name);
Iterator<Property> properties = (Iterator<Property>) prop_component.getPropertyIterator();
while (properties.hasNext()) {
Property property = properties.next();
addBasic(component_mapping, property.getName(), property.getValue(), componentMapper,
ModificationStore.FULL, entityName, property.isInsertable(), key);
}
}
}

View File

@ -0,0 +1,490 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.hibernate.mapping.*;
import org.hibernate.mapping.Collection;
import org.hibernate.MappingException;
import org.hibernate.type.*;
import org.jboss.envers.entities.mapper.CompositeMapperBuilder;
import org.jboss.envers.entities.mapper.relation.*;
import org.jboss.envers.entities.mapper.relation.lazy.proxy.*;
import org.jboss.envers.entities.mapper.relation.query.RelationQueryGenerator;
import org.jboss.envers.entities.mapper.relation.query.OneVersionsEntityQueryGenerator;
import org.jboss.envers.entities.mapper.relation.component.*;
import org.jboss.envers.entities.EntityConfiguration;
import org.jboss.envers.entities.IdMappingData;
import org.jboss.envers.tools.Tools;
import org.jboss.envers.tools.StringTools;
import org.jboss.envers.ModificationStore;
import org.jboss.envers.VersionsJoinTable;
import org.dom4j.Element;
import javax.persistence.JoinColumn;
import java.util.*;
import java.util.Set;
import java.util.List;
import java.util.Map;
import java.lang.annotation.Annotation;
/**
* Generates metadata for a collection-valued property.
* @author Adam Warski (adam at warski dot org)
*/
public final class CollectionMetadataGenerator {
private final VersionsMetadataGenerator mainGenerator;
private final String propertyName;
private final Collection propertyValue;
private final CompositeMapperBuilder currentMapper;
private final String referencingEntityName;
private final EntityXmlMappingData xmlMappingData;
private final VersionsJoinTable joinTable;
private final String mapKey;
private final EntityConfiguration referencingEntityConfiguration;
/**
* Null if this collection isn't a relation to another entity.
*/
private final String referencedEntityName;
/**
* @param mainGenerator Main generator, giving access to configuration and the basic mapper.
* @param propertyName Name of the property that references the collection in the referencing entity.
* @param propertyValue Value of the collection, as mapped by Hibernate.
* @param currentMapper Mapper, to which the appropriate {@link org.jboss.envers.entities.mapper.PropertyMapper}
* will be added.
* @param referencingEntityName Name of the entity that owns this collection.
* @param xmlMappingData In case this collection requires a middle table, additional mapping documents will
* be created using this object.
* @param joinTable User data for the middle (join) table. <code>null</code> if the user didn't specify it.
* @param mapKey The value of the name() property of the MapKey annotation on this property. Null, if this
* property isn't annotated with this annotation.
*/
public CollectionMetadataGenerator(VersionsMetadataGenerator mainGenerator, String propertyName,
Collection propertyValue, CompositeMapperBuilder currentMapper,
String referencingEntityName, EntityXmlMappingData xmlMappingData,
VersionsJoinTable joinTable, String mapKey) {
this.mainGenerator = mainGenerator;
this.propertyName = propertyName;
this.propertyValue = propertyValue;
this.currentMapper = currentMapper;
this.referencingEntityName = referencingEntityName;
this.xmlMappingData = xmlMappingData;
this.joinTable = joinTable == null ? getDefaultVersionsJoinTable() : joinTable;
this.mapKey = mapKey;
referencingEntityConfiguration = mainGenerator.getEntitiesConfigurations().get(referencingEntityName);
if (referencingEntityConfiguration == null) {
throw new MappingException("Unable to read versioning configuration for " + referencingEntityName + "!");
}
referencedEntityName = getReferencedEntityName(propertyValue.getElement());
}
private String getReferencedEntityName(Value value) {
if (value instanceof ToOne) {
return ((ToOne) value).getReferencedEntityName();
} else if (value instanceof OneToMany) {
return ((OneToMany) value).getReferencedEntityName();
} else {
return null;
}
}
void addCollection() {
Type type = propertyValue.getType();
if ((type instanceof BagType || type instanceof SetType || type instanceof MapType) &&
(propertyValue.getElement() instanceof OneToMany) && (propertyValue.isInverse())) {
// A one-to-many relation mapped using @ManyToOne and @OneToMany(mappedBy="...")
addOneToManyAttached();
} else {
// All other kinds of relations require a middle (join) table.
addWithMiddleTable();
}
}
@SuppressWarnings({"unchecked"})
private void addOneToManyAttached() {
String mappedBy = getMappedBy(propertyValue);
EntityConfiguration referencedEntityConfiguration = mainGenerator.getEntitiesConfigurations()
.get(referencedEntityName);
IdMappingData referencedIdMapping = referencedEntityConfiguration.getIdMappingData();
IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
// Generating the id mappers data for the referencing side of the relation.
MiddleIdData referencingIdData = new MiddleIdData(mainGenerator.getVerEntCfg(), referencingIdMapping,
mappedBy + "_", referencingEntityName);
// And for the referenced side. The prefixed mapper won't be used (as this collection isn't persisted
// in a join table, so the prefix value is arbitrary).
MiddleIdData referencedIdData = new MiddleIdData(mainGenerator.getVerEntCfg(), referencedIdMapping,
null, referencedEntityName);
// Generating the element mapping.
MiddleComponentData elementComponentData = new MiddleComponentData(
new MiddleRelatedComponentMapper(referencedIdData), 0);
// Generating the index mapping, if an index exists. It can only exists in case a javax.persistence.MapKey
// annotation is present on the entity. So the middleEntityXml will be not be used. The queryGeneratorBuilder
// will only be checked for nullnes.
MiddleComponentData indexComponentData = addIndex(null, null);
// Generating the query generator - it should read directly from the related entity.
RelationQueryGenerator queryGenerator = new OneVersionsEntityQueryGenerator(mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(), referencingIdData, referencedEntityName,
referencedIdMapping.getIdMapper());
// Creating common mapper data.
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
mainGenerator.getVerEntCfg(), referencedEntityName, propertyName,
referencingIdData, queryGenerator);
// Checking the type of the collection and adding an appropriate mapper.
addMapper(commonCollectionMapperData, elementComponentData, indexComponentData);
// Storing information about this relation.
referencingEntityConfiguration.addToManyNotOwningRelation(propertyName, mappedBy,
referencedEntityName, referencingIdData.getPrefixedMapper());
}
/**
* Adds mapping of the id of a related entity to the given xml mapping, prefixing the id with the given prefix.
* @param xmlMapping Mapping, to which to add the xml.
* @param prefix Prefix for the names of properties which will be prepended to properties that form the id.
* @param columnNameIterator Iterator over the column names that will be used for properties that form the id.
* @param relatedIdMapping Id mapping data of the related entity.
*/
@SuppressWarnings({"unchecked"})
private void addRelatedToXmlMapping(Element xmlMapping, String prefix,
MetadataTools.ColumnNameIterator columnNameIterator,
IdMappingData relatedIdMapping) {
Element properties = (Element) relatedIdMapping.getXmlRelationMapping().clone();
MetadataTools.prefixNamesInPropertyElement(properties, prefix, columnNameIterator, true);
for (Element idProperty : (java.util.List<Element>) properties.elements()) {
xmlMapping.add((Element) idProperty.clone());
}
}
private String getMiddleTableName(Collection value, String entityName) {
// We check how Hibernate maps the collection.
if (value.getElement() instanceof OneToMany && !value.isInverse()) {
// This must be a @JoinColumn+@OneToMany mapping. Generating the table name, as Hibernate doesn't use a
// middle table for mapping this relation.
return StringTools.getLastComponent(entityName) + "_" + StringTools.getLastComponent(getReferencedEntityName(value.getElement()));
} else {
// Hibernate uses a middle table for mapping this relation, so we get it's name directly.
return value.getCollectionTable().getName();
}
}
@SuppressWarnings({"unchecked"})
private void addWithMiddleTable() {
// Generating the name of the middle table
String versionsMiddleTableName;
String versionsMiddleEntityName;
if (!StringTools.isEmpty(joinTable.name())) {
versionsMiddleTableName = joinTable.name();
versionsMiddleEntityName = joinTable.name();
} else {
String middleTableName = getMiddleTableName(propertyValue, referencingEntityName);
versionsMiddleTableName = mainGenerator.getVerEntCfg().getVersionsTableName(null, middleTableName);
versionsMiddleEntityName = mainGenerator.getVerEntCfg().getVersionsEntityName(middleTableName);
}
// Generating the XML mapping for the middle entity, only if the relation isn't inverse.
// If the relation is inverse, will be later checked by comparing middleEntityXml with null.
Element middleEntityXml;
if (!propertyValue.isInverse()) {
middleEntityXml = createMiddleEntityXml(versionsMiddleTableName, versionsMiddleEntityName);
} else {
middleEntityXml = null;
}
// ******
// Generating the mapping for the referencing entity (it must be an entity).
// ******
// Getting the id-mapping data of the referencing entity (the entity that "owns" this collection).
IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
// Only valid for an inverse relation; null otherwise.
String mappedBy;
// The referencing prefix is always for a related entity. So it has always the "_" at the end added.
String referencingPrefixRelated;
String referencedPrefix;
if (propertyValue.isInverse()) {
// If the relation is inverse, then referencedEntityName is not null.
mappedBy = getMappedBy(propertyValue.getCollectionTable(), mainGenerator.getCfg().getClassMapping(referencedEntityName));
referencingPrefixRelated = mappedBy + "_";
referencedPrefix = StringTools.getLastComponent(referencedEntityName);
} else {
mappedBy = null;
referencingPrefixRelated = StringTools.getLastComponent(referencingEntityName) + "_";
referencedPrefix = referencedEntityName == null ? "element" : propertyName;
}
// Storing the id data of the referencing entity: original mapper, prefixed mapper and entity name.
MiddleIdData referencingIdData = new MiddleIdData(mainGenerator.getVerEntCfg(), referencingIdMapping,
referencingPrefixRelated, referencingEntityName);
// Creating a query generator builder, to which additional id data will be added, in case this collection
// references some entities (either from the element or index). At the end, this will be used to build
// a query generator to read the raw data collection from the middle table.
QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.getGlobalCfg(),
mainGenerator.getVerEntCfg(), referencingIdData, versionsMiddleEntityName);
// Adding the XML mapping for the referencing entity, if the relation isn't inverse.
if (middleEntityXml != null) {
// Adding related-entity (in this case: the referencing's entity id) id mapping to the xml.
addRelatedToXmlMapping(middleEntityXml, referencingPrefixRelated,
MetadataTools.getColumnNameIterator(propertyValue.getKey().getColumnIterator()),
referencingIdMapping);
}
// ******
// Generating the element mapping.
// ******
MiddleComponentData elementComponentData = addValueToMiddleTable(propertyValue.getElement(), middleEntityXml,
queryGeneratorBuilder, referencedPrefix, joinTable.inverseJoinColumns());
// ******
// Generating the index mapping, if an index exists.
// ******
MiddleComponentData indexComponentData = addIndex(middleEntityXml, queryGeneratorBuilder);
// ******
// Generating the property mapper.
// ******
// Building the query generator.
RelationQueryGenerator queryGenerator = queryGeneratorBuilder.build(elementComponentData, indexComponentData);
// Creating common data
CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(
mainGenerator.getVerEntCfg(), versionsMiddleEntityName, propertyName, referencingIdData, queryGenerator);
// Checking the type of the collection and adding an appropriate mapper.
addMapper(commonCollectionMapperData, elementComponentData, indexComponentData);
// ******
// Storing information about this relation.
// ******
storeMiddleEntityRelationInformation(mappedBy);
}
private MiddleComponentData addIndex(Element middleEntityXml, QueryGeneratorBuilder queryGeneratorBuilder) {
if (propertyValue instanceof IndexedCollection) {
IndexedCollection indexedValue = (IndexedCollection) propertyValue;
if (mapKey == null) {
// This entity doesn't specify a javax.persistence.MapKey. Mapping it to the middle entity.
return addValueToMiddleTable(indexedValue.getIndex(), middleEntityXml,
queryGeneratorBuilder, "mapkey", null);
} else {
IdMappingData referencedIdMapping = mainGenerator.getEntitiesConfigurations()
.get(referencedEntityName).getIdMappingData();
int currentIndex = queryGeneratorBuilder == null ? 0 : queryGeneratorBuilder.getCurrentIndex();
if ("".equals(mapKey)) {
// The key of the map is the id of the entity.
return new MiddleComponentData(new MiddleMapKeyIdComponentMapper(mainGenerator.getVerEntCfg(),
referencedIdMapping.getIdMapper()), currentIndex);
} else {
// The key of the map is a property of the entity.
return new MiddleComponentData(new MiddleMapKeyPropertyComponentMapper(mapKey), currentIndex);
}
}
} else {
// No index - creating a dummy mapper.
return new MiddleComponentData(new MiddleDummyComponentMapper(), 0);
}
}
/**
*
* @param value Value, which should be mapped to the middle-table, either as a relation to another entity,
* or as a simple value.
* @param xmlMapping If not <code>null</code>, xml mapping for this value is added to this element.
* @param queryGeneratorBuilder In case <code>value</code> is a relation to another entity, information about it
* should be added to the given.
* @param prefix Prefix for proeprty names of related entities identifiers.
* @param joinColumns Names of columns to use in the xml mapping, if this array isn't null and has any elements.
* @return Data for mapping this component.
*/
@SuppressWarnings({"unchecked"})
private MiddleComponentData addValueToMiddleTable(Value value, Element xmlMapping,
QueryGeneratorBuilder queryGeneratorBuilder,
String prefix, JoinColumn[] joinColumns) {
Type type = value.getType();
if (type instanceof ManyToOneType) {
String prefixRelated = prefix + "_";
String referencedEntityName = getReferencedEntityName(value);
IdMappingData referencedIdMapping = mainGenerator.getEntitiesConfigurations()
.get(referencedEntityName).getIdMappingData();
// Adding related-entity (in this case: the referenced entities id) id mapping to the xml only if the
// relation isn't inverse (so when <code>xmlMapping</code> is not null).
if (xmlMapping != null) {
addRelatedToXmlMapping(xmlMapping, prefixRelated,
joinColumns != null && joinColumns.length > 0
? MetadataTools.getColumnNameIterator(joinColumns)
: MetadataTools.getColumnNameIterator(value.getColumnIterator()),
referencedIdMapping);
}
// Storing the id data of the referenced entity: original mapper, prefixed mapper and entity name.
MiddleIdData referencedIdData = new MiddleIdData(mainGenerator.getVerEntCfg(), referencedIdMapping,
prefixRelated, referencedEntityName);
// And adding it to the generator builder.
queryGeneratorBuilder.addRelation(referencedIdData);
return new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData),
queryGeneratorBuilder.getCurrentIndex());
} else {
// Last but one parameter: collection components are always insertable
boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasicNoComponent(xmlMapping, prefix, value, null,
ModificationStore.FULL, true, true);
if (mapped) {
// Simple values are always stored in the first item of the array returned by the query generator.
return new MiddleComponentData(new MiddleSimpleComponentMapper(mainGenerator.getVerEntCfg(), prefix), 0);
} else {
mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
// Impossible to get here.
throw new AssertionError();
}
}
}
private void addMapper(CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData,
MiddleComponentData indexComponentData) {
Type type = propertyValue.getType();
if (type instanceof SortedSetType) {
currentMapper.addComposite(propertyName, new BasicCollectionMapper<Set>(commonCollectionMapperData,
TreeSet.class, SortedSetProxy.class, elementComponentData));
} else if (type instanceof SetType) {
currentMapper.addComposite(propertyName, new BasicCollectionMapper<Set>(commonCollectionMapperData,
HashSet.class, SetProxy.class, elementComponentData));
} else if (type instanceof SortedMapType) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyName, new MapCollectionMapper<Map>(commonCollectionMapperData,
TreeMap.class, SortedMapProxy.class, elementComponentData, indexComponentData));
} else if (type instanceof MapType) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyName, new MapCollectionMapper<Map>(commonCollectionMapperData,
HashMap.class, MapProxy.class, elementComponentData, indexComponentData));
} else if (type instanceof BagType) {
currentMapper.addComposite(propertyName, new BasicCollectionMapper<List>(commonCollectionMapperData,
ArrayList.class, ListProxy.class, elementComponentData));
} else if (type instanceof ListType) {
// Indexed collection, so <code>indexComponentData</code> is not null.
currentMapper.addComposite(propertyName, new ListCollectionMapper(commonCollectionMapperData,
elementComponentData, indexComponentData));
} else {
mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
}
}
private void storeMiddleEntityRelationInformation(String mappedBy) {
// Only if this is a relation (when there is a referenced entity).
if (referencedEntityName != null) {
if (propertyValue.isInverse()) {
referencingEntityConfiguration.addToManyMiddleNotOwningRelation(propertyName, mappedBy, referencedEntityName);
} else {
referencingEntityConfiguration.addToManyMiddleRelation(propertyName, referencedEntityName);
}
}
}
private Element createMiddleEntityXml(String versionsMiddleTableName, String versionsMiddleEntityName) {
String schema = StringTools.isEmpty(joinTable.schema()) ? propertyValue.getCollectionTable().getSchema() : joinTable.schema();
String catalog = StringTools.isEmpty(joinTable.catalog()) ? propertyValue.getCollectionTable().getCatalog() : joinTable.catalog();
Element middleEntityXml = MetadataTools.createEntity(xmlMappingData.newAdditionalMapping(),
versionsMiddleEntityName, versionsMiddleTableName, schema, catalog, null);
Element middleEntityXmlId = middleEntityXml.addElement("composite-id");
middleEntityXmlId.addAttribute("name", mainGenerator.getVerEntCfg().getOriginalIdPropName());
// Adding the revision number as a foreign key to the revision info entity to the composite id of the
// middle table.
mainGenerator.addRevisionInfoRelation(middleEntityXmlId);
// Adding the revision type property to the entity xml.
mainGenerator.addRevisionType(middleEntityXml);
// All other properties should also be part of the primary key of the middle entity.
return middleEntityXmlId;
}
private VersionsJoinTable getDefaultVersionsJoinTable() {
return new VersionsJoinTable() {
public String name() { return ""; }
public String schema() { return ""; }
public String catalog() { return ""; }
public JoinColumn[] inverseJoinColumns() { return new JoinColumn[0]; }
public Class<? extends Annotation> annotationType() { return this.getClass(); }
};
}
@SuppressWarnings({"unchecked"})
private String getMappedBy(Collection collectionValue) {
Iterator<Property> assocClassProps =
((OneToMany) collectionValue.getElement()).getAssociatedClass().getPropertyIterator();
while (assocClassProps.hasNext()) {
Property property = assocClassProps.next();
if (Tools.iteratorsContentEqual(property.getValue().getColumnIterator(),
collectionValue.getKey().getColumnIterator())) {
return property.getName();
}
}
throw new MappingException("Unable to read the mapped by attribute for " + propertyName + " in "
+ referencingEntityName + "!");
}
@SuppressWarnings({"unchecked"})
private String getMappedBy(Table collectionTable, PersistentClass referencedClass) {
Iterator<Property> properties = referencedClass.getPropertyIterator();
while (properties.hasNext()) {
Property property = properties.next();
if (property.getValue() instanceof Collection) {
// The equality is intentional. We want to find a collection property with the same collection table.
//noinspection ObjectEquality
if (((Collection) property.getValue()).getCollectionTable() == collectionTable) {
return property.getName();
}
}
}
throw new MappingException("Unable to read the mapped by attribute for " + propertyName + " in "
+ referencingEntityName + "!");
}
}

View File

@ -0,0 +1,58 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import java.util.List;
import java.util.ArrayList;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class EntityXmlMappingData {
private Document mainXmlMapping;
private List<Document> additionalXmlMappings;
public EntityXmlMappingData() {
mainXmlMapping = DocumentHelper.createDocument();
additionalXmlMappings = new ArrayList<Document>();
}
public Document getMainXmlMapping() {
return mainXmlMapping;
}
public List<Document> getAdditionalXmlMappings() {
return additionalXmlMappings;
}
public Document newAdditionalMapping() {
Document additionalMapping = DocumentHelper.createDocument();
additionalXmlMappings.add(additionalMapping);
return additionalMapping;
}
}

View File

@ -0,0 +1,122 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Component;
import org.hibernate.type.Type;
import org.hibernate.type.ImmutableType;
import org.hibernate.MappingException;
import org.jboss.envers.entities.mapper.SimpleMapperBuilder;
import org.jboss.envers.entities.mapper.id.SimpleIdMapperBuilder;
import org.jboss.envers.entities.mapper.id.MultipleIdMapper;
import org.jboss.envers.entities.mapper.id.EmbeddedIdMapper;
import org.jboss.envers.entities.mapper.id.SingleIdMapper;
import org.jboss.envers.entities.IdMappingData;
import org.jboss.envers.ModificationStore;
import java.util.Iterator;
/**
* Generates metadata for primary identifiers (ids) of versions entities.
* @author Adam Warski (adam at warski dot org)
*/
public final class IdMetadataGenerator {
private final VersionsMetadataGenerator mainGenerator;
IdMetadataGenerator(VersionsMetadataGenerator versionsMetadataGenerator) {
mainGenerator = versionsMetadataGenerator;
}
@SuppressWarnings({"unchecked"})
private void addIdProperties(Element parent, Iterator<Property> properties, SimpleMapperBuilder mapper, boolean key) {
while (properties.hasNext()) {
Property property = properties.next();
Type propertyType = property.getType();
if (!"_identifierMapper".equals(property.getName())) {
if (propertyType instanceof ImmutableType) {
// Last but one parameter: ids are always insertable
mainGenerator.getBasicMetadataGenerator().addBasicNoComponent(parent, property.getName(),
property.getValue(), mapper, ModificationStore.FULL, true, key);
} else {
throw new MappingException("Type not supported: " + propertyType.getClass().getName());
}
}
}
}
@SuppressWarnings({"unchecked"})
IdMappingData addId(PersistentClass pc) {
// Xml mapping which will be used for relations
Element rel_id_mapping = new DefaultElement("properties");
// Xml mapping which will be used for the primary key of the versions table
Element orig_id_mapping = new DefaultElement("composite-id");
Property id_prop = pc.getIdentifierProperty();
Component id_mapper = pc.getIdentifierMapper();
SimpleIdMapperBuilder mapper;
if (id_mapper != null) {
// Multiple id
mapper = new MultipleIdMapper(((Component) pc.getIdentifier()).getComponentClassName());
addIdProperties(rel_id_mapping, (Iterator<Property>) id_mapper.getPropertyIterator(), mapper, false);
// null mapper - the mapping where already added the first time, now we only want to generate the xml
addIdProperties(orig_id_mapping, (Iterator<Property>) id_mapper.getPropertyIterator(), null, true);
} else if (id_prop.isComposite()) {
// Embedded id
Component id_component = (Component) id_prop.getValue();
mapper = new EmbeddedIdMapper(id_prop.getName(), id_component.getComponentClassName());
addIdProperties(rel_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), mapper, false);
// null mapper - the mapping where already added the first time, now we only want to generate the xml
addIdProperties(orig_id_mapping, (Iterator<Property>) id_component.getPropertyIterator(), null, true);
} else {
// Single id
mapper = new SingleIdMapper();
// Last but one parameter: ids are always insertable
mainGenerator.getBasicMetadataGenerator().addBasicNoComponent(rel_id_mapping, id_prop.getName(),
id_prop.getValue(), mapper, ModificationStore.FULL, true, false);
// null mapper - the mapping where already added the first time, now we only want to generate the xml
mainGenerator.getBasicMetadataGenerator().addBasicNoComponent(orig_id_mapping, id_prop.getName(),
id_prop.getValue(), null, ModificationStore.FULL, true, true);
}
orig_id_mapping.addAttribute("name", mainGenerator.getVerEntCfg().getOriginalIdPropName());
// Adding a relation to the revision entity (effectively: the "revision number" property)
mainGenerator.addRevisionInfoRelation(orig_id_mapping);
return new IdMappingData(mapper, orig_id_mapping, rel_id_mapping);
}
}

View File

@ -0,0 +1,60 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.hibernate.mapping.*;
import org.hibernate.MappingException;
/**
* @author Adam Warski (adam at warski dot org)
*/
public enum InheritanceType {
NONE,
JOINED,
SINGLE,
TABLE_PER_CLASS;
/**
* @param pc The class for which to get the inheritance type.
* @return The inheritance type of this class. NONE, if this class does not inherit from
* another persisten class.
*/
public static InheritanceType get(PersistentClass pc) {
PersistentClass superclass = pc.getSuperclass();
if (superclass == null) {
return InheritanceType.NONE;
}
// We assume that every subclass is of the same type.
Subclass subclass = (Subclass) superclass.getSubclassIterator().next();
if (subclass instanceof SingleTableSubclass) {
return InheritanceType.SINGLE;
} else if (subclass instanceof JoinedSubclass) {
return InheritanceType.JOINED;
} else if (subclass instanceof UnionSubclass) {
return InheritanceType.TABLE_PER_CLASS;
}
throw new MappingException("Unknown subclass class: " + subclass.getClass());
}
}

View File

@ -0,0 +1,207 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.dom4j.Element;
import org.dom4j.Document;
import org.dom4j.Attribute;
import org.jboss.envers.tools.StringTools;
import org.hibernate.mapping.Column;
import javax.persistence.JoinColumn;
import java.util.Iterator;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class MetadataTools {
public static Element addNativelyGeneratedId(Element parent, String name, String type) {
Element id_mapping = parent.addElement("id");
id_mapping.addAttribute("name", name).addAttribute("type", type);
Element generator_mapping = id_mapping.addElement("generator");
generator_mapping.addAttribute("class", "native");
/*generator_mapping.addAttribute("class", "sequence");
generator_mapping.addElement("param").addAttribute("name", "sequence").setText("custom");*/
return id_mapping;
}
public static Element addProperty(Element parent, String name, String type, boolean insertable, boolean key) {
Element prop_mapping;
if (key) {
prop_mapping = parent.addElement("key-property");
} else {
prop_mapping = parent.addElement("property");
}
prop_mapping.addAttribute("name", name);
prop_mapping.addAttribute("insert", Boolean.toString(insertable));
if (type != null) {
prop_mapping.addAttribute("type", type);
}
return prop_mapping;
}
public static Element addColumn(Element parent, String name, Integer length) {
Element column_mapping = parent.addElement("column");
column_mapping.addAttribute("name", name);
if (length != null) {
column_mapping.addAttribute("length", length.toString());
}
return column_mapping;
}
private static Element createEntityCommon(Document document, String type, String entityName,
String tableName, String schema, String catalog,
String discriminatorValue) {
Element hibernate_mapping = document.addElement("hibernate-mapping");
hibernate_mapping.addAttribute("auto-import", "false");
Element class_mapping = hibernate_mapping.addElement(type);
if (entityName != null) {
class_mapping.addAttribute("entity-name", entityName);
}
if (discriminatorValue != null) {
class_mapping.addAttribute("discriminator-value", discriminatorValue);
}
if (!StringTools.isEmpty(tableName)) {
class_mapping.addAttribute("table", tableName);
}
if (!StringTools.isEmpty(schema)) {
class_mapping.addAttribute("schema", schema);
}
if (!StringTools.isEmpty(catalog)) {
class_mapping.addAttribute("catalog", catalog);
}
return class_mapping;
}
public static Element createEntity(Document document, String entityName, String tableName,
String schema, String catalog, String discriminatorValue) {
return createEntityCommon(document, "class", entityName, tableName, schema, catalog, discriminatorValue);
}
public static Element createSubclassEntity(Document document, String entityName, String tableName,
String schema, String catalog, String extendsEntityName,
String discriminatorValue) {
Element class_mapping = createEntityCommon(document, "subclass", entityName, tableName, schema, catalog,
discriminatorValue);
class_mapping.addAttribute("extends", extendsEntityName);
return class_mapping;
}
public static Element createJoin(Element parent, String tableName,
String schema, String catalog) {
Element join_mapping = parent.addElement("join");
join_mapping.addAttribute("table", tableName);
if (!StringTools.isEmpty(schema)) {
join_mapping.addAttribute("schema", schema);
}
if (!StringTools.isEmpty(catalog)) {
join_mapping.addAttribute("catalog", catalog);
}
return join_mapping;
}
public static void addColumns(Element any_mapping, Iterator<Column> columns) {
while (columns.hasNext()) {
Column column = columns.next();
addColumn(any_mapping, column.getName(), column.getLength());
}
}
@SuppressWarnings({"unchecked"})
private static void changeNamesInColumnElement(Element element, ColumnNameIterator columnNameIterator) {
Iterator<Element> properties = element.elementIterator();
while (properties.hasNext()) {
Element property = properties.next();
if ("column".equals(property.getName())) {
Attribute nameAttr = property.attribute("name");
if (nameAttr != null) {
nameAttr.setText(columnNameIterator.next());
}
}
}
}
@SuppressWarnings({"unchecked"})
public static void prefixNamesInPropertyElement(Element element, String prefix, ColumnNameIterator columnNameIterator,
boolean changeToKey) {
Iterator<Element> properties = element.elementIterator();
while (properties.hasNext()) {
Element property = properties.next();
if ("property".equals(property.getName())) {
Attribute nameAttr = property.attribute("name");
if (nameAttr != null) {
nameAttr.setText(prefix + nameAttr.getText());
}
changeNamesInColumnElement(property, columnNameIterator);
if (changeToKey) {
property.setName("key-property");
}
}
}
}
/**
* An iterator over column names.
*/
public static abstract class ColumnNameIterator implements Iterator<String> { }
public static ColumnNameIterator getColumnNameIterator(final Iterator<Column> columnIterator) {
return new ColumnNameIterator() {
public boolean hasNext() { return columnIterator.hasNext(); }
public String next() { return columnIterator.next().getName(); }
public void remove() { columnIterator.remove(); }
};
}
public static ColumnNameIterator getColumnNameIterator(final JoinColumn[] joinColumns) {
return new ColumnNameIterator() {
int counter = 0;
public boolean hasNext() { return counter < joinColumns.length; }
public String next() { return joinColumns[counter++].name(); }
public void remove() { throw new UnsupportedOperationException(); }
};
}
}

View File

@ -0,0 +1,65 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.jboss.envers.ModificationStore;
import org.jboss.envers.VersionsJoinTable;
import org.jboss.envers.VersionsTable;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
/**
* @author Adam Warski (adam at warski dot org)
* @author Sebastian Komander
*/
public class PersistentClassVersioningData {
public PersistentClassVersioningData() {
propertyStoreInfo = new PropertyStoreInfo(new HashMap<String, ModificationStore>());
secondaryTableDictionary = new HashMap<String, String>();
unversionedProperties = new ArrayList<String>();
versionsJoinTables = new HashMap<String, VersionsJoinTable>();
mapKeys = new HashMap<String, String>();
}
public PropertyStoreInfo propertyStoreInfo;
public VersionsTable versionsTable;
public Map<String, String> secondaryTableDictionary;
public List<String> unversionedProperties;
/**
* A map from property names to custom join tables definitions.
*/
public Map<String, VersionsJoinTable> versionsJoinTables;
/**
* A map from property names to the value of the related property names in a map key annotation. An empty string,
* if the property name is not specified in the mapkey annotation.
*/
public Map<String, String> mapKeys;
public boolean isVersioned() {
if (propertyStoreInfo.propertyStores.size() > 0) { return true; }
if (propertyStoreInfo.defaultStore != null) { return true; }
return false;
}
}

View File

@ -0,0 +1,46 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.jboss.envers.ModificationStore;
import java.util.Map;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class PropertyStoreInfo {
// Not null if the whole class is versioned
public ModificationStore defaultStore;
// Maps property names to their stores defined in per-field versioned annotations
public Map<String, ModificationStore> propertyStores;
public PropertyStoreInfo(Map<String, ModificationStore> propertyStores) {
this.propertyStores = propertyStores;
}
public PropertyStoreInfo(ModificationStore defaultStore, Map<String, ModificationStore> propertyStores) {
this.defaultStore = defaultStore;
this.propertyStores = propertyStores;
}
}

View File

@ -0,0 +1,86 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.jboss.envers.entities.mapper.relation.MiddleIdData;
import org.jboss.envers.entities.mapper.relation.MiddleComponentData;
import org.jboss.envers.entities.mapper.relation.query.RelationQueryGenerator;
import org.jboss.envers.entities.mapper.relation.query.OneEntityQueryGenerator;
import org.jboss.envers.entities.mapper.relation.query.ThreeEntityQueryGenerator;
import org.jboss.envers.entities.mapper.relation.query.TwoEntityQueryGenerator;
import org.jboss.envers.configuration.VersionsEntitiesConfiguration;
import org.jboss.envers.configuration.GlobalConfiguration;
import java.util.List;
import java.util.ArrayList;
/**
* Builds query generators, for reading collection middle tables, along with any related entities.
* The related entities information can be added gradually, and when complete, the query generator can be built.
* @author Adam Warski (adam at warski dot org)
*/
public final class QueryGeneratorBuilder {
private final GlobalConfiguration globalCfg;
private final VersionsEntitiesConfiguration verEntCfg;
private final MiddleIdData referencingIdData;
private final String versionsMiddleEntityName;
private final List<MiddleIdData> idDatas;
QueryGeneratorBuilder(GlobalConfiguration globalCfg, VersionsEntitiesConfiguration verEntCfg,
MiddleIdData referencingIdData, String versionsMiddleEntityName) {
this.globalCfg = globalCfg;
this.verEntCfg = verEntCfg;
this.referencingIdData = referencingIdData;
this.versionsMiddleEntityName = versionsMiddleEntityName;
idDatas = new ArrayList<MiddleIdData>();
}
void addRelation(MiddleIdData idData) {
idDatas.add(idData);
}
RelationQueryGenerator build(MiddleComponentData... componentDatas) {
if (idDatas.size() == 0) {
return new OneEntityQueryGenerator(verEntCfg, versionsMiddleEntityName, referencingIdData,
componentDatas);
} else if (idDatas.size() == 1) {
return new TwoEntityQueryGenerator(globalCfg, verEntCfg, versionsMiddleEntityName, referencingIdData,
idDatas.get(0), componentDatas);
} else if (idDatas.size() == 2) {
return new ThreeEntityQueryGenerator(globalCfg, verEntCfg, versionsMiddleEntityName, referencingIdData,
idDatas.get(0), idDatas.get(1), componentDatas);
} else {
throw new IllegalStateException("Illegal number of related entities.");
}
}
/**
* @return Current index of data in the array, which will be the element of a list, returned when executing a query
* generated by the built query generator.
*/
int getCurrentIndex() {
return idDatas.size();
}
}

View File

@ -0,0 +1,111 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.dom4j.Element;
import org.hibernate.mapping.Value;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.OneToOne;
import org.hibernate.MappingException;
import org.jboss.envers.entities.mapper.CompositeMapperBuilder;
import org.jboss.envers.entities.mapper.relation.ToOneIdMapper;
import org.jboss.envers.entities.mapper.relation.OneToOneNotOwningMapper;
import org.jboss.envers.entities.mapper.id.IdMapper;
import org.jboss.envers.entities.EntityConfiguration;
import org.jboss.envers.entities.IdMappingData;
/**
* Generates metadata for to-one relations (reference-valued properties).
* @author Adam Warski (adam at warski dot org)
*/
public final class ToOneRelationMetadataGenerator {
private final VersionsMetadataGenerator mainGenerator;
ToOneRelationMetadataGenerator(VersionsMetadataGenerator versionsMetadataGenerator) {
mainGenerator = versionsMetadataGenerator;
}
@SuppressWarnings({"unchecked"})
void addToOne(Element parent, String name, Value value, CompositeMapperBuilder mapper, String entityName) {
String referencedEntityName = ((ToOne) value).getReferencedEntityName();
EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(referencedEntityName);
if (configuration == null) {
throw new MappingException("A versioned relation to a non-versioned entity " + referencedEntityName + "!");
}
IdMappingData idMapping = configuration.getIdMappingData();
String lastPropertyPrefix = name + "_";
// Generating the id mapper for the relation
IdMapper relMapper = idMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneRelation(name, referencedEntityName, relMapper);
// Adding an element to the mapping corresponding to the references entity id's
Element properties = (Element) idMapping.getXmlRelationMapping().clone();
properties.addAttribute("name", name);
MetadataTools.prefixNamesInPropertyElement(properties, lastPropertyPrefix,
MetadataTools.getColumnNameIterator(value.getColumnIterator()), false);
parent.add(properties);
// Adding mapper for the id
mapper.addComposite(name, new ToOneIdMapper(relMapper, name, referencedEntityName));
}
@SuppressWarnings({"unchecked"})
void addOneToOneNotOwning(String name, Value value, CompositeMapperBuilder mapper, String entityName) {
OneToOne propertyValue = (OneToOne) value;
String owningReferencePropertyName = propertyValue.getReferencedPropertyName(); // mappedBy
EntityConfiguration configuration = mainGenerator.getEntitiesConfigurations().get(entityName);
if (configuration == null) {
throw new MappingException("A versioned relation to a non-versioned entity " + entityName + "!");
}
IdMappingData ownedIdMapping = configuration.getIdMappingData();
if (ownedIdMapping == null) {
throw new MappingException("A versioned relation to a non-versioned entity " + entityName + "!");
}
String lastPropertyPrefix = owningReferencePropertyName + "_";
String referencedEntityName = propertyValue.getReferencedEntityName();
// Generating the id mapper for the relation
IdMapper ownedIdMapper = ownedIdMapping.getIdMapper().prefixMappedProperties(lastPropertyPrefix);
// Storing information about this relation
mainGenerator.getEntitiesConfigurations().get(entityName).addToOneNotOwningRelation(name, owningReferencePropertyName,
referencedEntityName, ownedIdMapper);
// Adding mapper for the id
mapper.addComposite(name, new OneToOneNotOwningMapper(owningReferencePropertyName,
referencedEntityName, name));
}
}

View File

@ -0,0 +1,372 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.configuration.metadata;
import org.hibernate.type.*;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import org.hibernate.mapping.*;
import org.hibernate.mapping.Collection;
import org.dom4j.Element;
import org.jboss.envers.entities.EntityConfiguration;
import org.jboss.envers.entities.IdMappingData;
import org.jboss.envers.configuration.GlobalConfiguration;
import org.jboss.envers.configuration.VersionsEntitiesConfiguration;
import org.jboss.envers.entities.mapper.*;
import org.jboss.envers.tools.StringTools;
import org.jboss.envers.ModificationStore;
import org.jboss.envers.VersionsJoinTable;
import org.jboss.envers.entity.VersionsInheritanceEntityPersister;
import org.jboss.envers.tools.log.YLog;
import org.jboss.envers.tools.log.YLogManager;
import java.util.*;
import java.util.List;
import java.util.Map;
/**
* @author Adam Warski (adam at warski dot org)
* @author Sebastian Komander
*/
public final class VersionsMetadataGenerator {
private final Configuration cfg;
private final GlobalConfiguration globalCfg;
private final VersionsEntitiesConfiguration verEntCfg;
private final Element revisionInfoRelationMapping;
private final BasicMetadataGenerator basicMetadataGenerator;
private final IdMetadataGenerator idMetadataGenerator;
private final ToOneRelationMetadataGenerator toOneRelationMetadataGenerator;
private final Map<String, EntityConfiguration> entitiesConfigurations;
// Map entity name -> (join descriptor -> element describing the "versioned" join)
private final Map<String, Map<Join, Element>> entitiesJoins;
private YLog log = YLogManager.getLogManager().getLog(VersionsMetadataGenerator.class);
public VersionsMetadataGenerator(Configuration cfg, GlobalConfiguration globalCfg,
VersionsEntitiesConfiguration verEntCfg,
Element revisionInfoRelationMapping) {
this.cfg = cfg;
this.globalCfg = globalCfg;
this.verEntCfg = verEntCfg;
this.revisionInfoRelationMapping = revisionInfoRelationMapping;
this.basicMetadataGenerator = new BasicMetadataGenerator();
this.idMetadataGenerator = new IdMetadataGenerator(this);
this.toOneRelationMetadataGenerator = new ToOneRelationMetadataGenerator(this);
entitiesConfigurations = new HashMap<String, EntityConfiguration>();
entitiesJoins = new HashMap<String, Map<Join, Element>>();
}
void addRevisionInfoRelation(Element any_mapping) {
Element rev_mapping = (Element) revisionInfoRelationMapping.clone();
rev_mapping.addAttribute("name", verEntCfg.getRevisionPropName());
MetadataTools.addColumn(rev_mapping, verEntCfg.getRevisionPropName(), null);
any_mapping.add(rev_mapping);
}
void addRevisionType(Element any_mapping) {
Element revTypeProperty = MetadataTools.addProperty(any_mapping, verEntCfg.getRevisionTypePropName(),
verEntCfg.getRevisionTypePropType(), true, false);
revTypeProperty.addAttribute("type", "org.jboss.envers.entities.RevisionTypeType");
}
private ModificationStore getStoreForProperty(Property property, PropertyStoreInfo propertyStoreInfo,
List<String> unversionedProperties) {
/*
* Checks if a property is versioned, which is when:
* - the property isn't unversioned
* - the whole entity is versioned, then the default store is not null
* - there is a store defined for this entity, which is when this property is annotated
*/
if (unversionedProperties.contains(property.getName())) {
return null;
}
ModificationStore store = propertyStoreInfo.propertyStores.get(property.getName());
if (store == null) {
return propertyStoreInfo.defaultStore;
}
return store;
}
@SuppressWarnings({"unchecked"})
void addValue(Element parent, String name, Value value, CompositeMapperBuilder currentMapper,
ModificationStore store, String entityName, EntityXmlMappingData xmlMappingData,
VersionsJoinTable joinTable, String mapKey, boolean insertable, boolean firstPass) {
Type type = value.getType();
// only first pass
if (firstPass) {
if (basicMetadataGenerator.addBasic(parent, name, value, currentMapper, store, entityName, insertable,
false)) {
// The property was mapped by the basic generator.
return;
}
}
if (type instanceof ManyToOneType) {
// only second pass
if (!firstPass) {
toOneRelationMetadataGenerator.addToOne(parent, name, value, currentMapper, entityName);
}
} else if (type instanceof OneToOneType) {
// only second pass
if (!firstPass) {
toOneRelationMetadataGenerator.addOneToOneNotOwning(name, value, currentMapper, entityName);
}
} else if (type instanceof CollectionType) {
// only second pass
if (!firstPass) {
CollectionMetadataGenerator collectionMetadataGenerator = new CollectionMetadataGenerator(this,
name, (Collection) value, currentMapper, entityName, xmlMappingData, joinTable, mapKey);
collectionMetadataGenerator.addCollection();
}
} else {
if (firstPass) {
// If we got here in the first pass, it means the basic mapper didn't map it, and none of the
// above branches either.
throwUnsupportedTypeException(type, entityName, name);
}
}
}
@SuppressWarnings({"unchecked"})
private void addProperties(Element parent, Iterator<Property> properties, CompositeMapperBuilder currentMapper,
PersistentClassVersioningData versioningData, String entityName, EntityXmlMappingData xmlMappingData,
boolean firstPass) {
while (properties.hasNext()) {
Property property = properties.next();
if (!"_identifierMapper".equals(property.getName())) {
ModificationStore store = getStoreForProperty(property, versioningData.propertyStoreInfo,
versioningData.unversionedProperties);
if (store != null) {
addValue(parent, property.getName(), property.getValue(), currentMapper, store, entityName,
xmlMappingData, versioningData.versionsJoinTables.get(property.getName()),
versioningData.mapKeys.get(property.getName()), property.isInsertable(), firstPass);
}
}
}
}
@SuppressWarnings({"unchecked"})
private void createJoins(PersistentClass pc, Element parent, PersistentClassVersioningData versioningData) {
Iterator<Join> joins = pc.getJoinIterator();
Map<Join, Element> joinElements = new HashMap<Join, Element>();
entitiesJoins.put(pc.getEntityName(), joinElements);
while (joins.hasNext()) {
Join join = joins.next();
// Determining the table name. If there is no entry in the dictionary, just constructing the table name
// as if it was an entity (by appending/prepending configured strings).
String originalTableName = join.getTable().getName();
String versionedTableName = versioningData.secondaryTableDictionary.get(originalTableName);
if (versionedTableName == null) {
versionedTableName = verEntCfg.getVersionsEntityName(originalTableName);
}
String schema = versioningData.versionsTable.schema();
if (StringTools.isEmpty(schema)) {
schema = join.getTable().getSchema();
}
String catalog = versioningData.versionsTable.catalog();
if (StringTools.isEmpty(catalog)) {
catalog = join.getTable().getCatalog();
}
Element joinElement = MetadataTools.createJoin(parent, versionedTableName, schema, catalog);
joinElements.put(join, joinElement);
Element joinKey = joinElement.addElement("key");
MetadataTools.addColumns(joinKey, join.getKey().getColumnIterator());
MetadataTools.addColumn(joinKey, verEntCfg.getRevisionPropName(), null);
}
}
@SuppressWarnings({"unchecked"})
private void addJoins(PersistentClass pc, CompositeMapperBuilder currentMapper, PersistentClassVersioningData versioningData,
String entityName, EntityXmlMappingData xmlMappingData,boolean firstPass) {
Iterator<Join> joins = pc.getJoinIterator();
while (joins.hasNext()) {
Join join = joins.next();
Element joinElement = entitiesJoins.get(entityName).get(join);
addProperties(joinElement, join.getPropertyIterator(), currentMapper, versioningData, entityName,
xmlMappingData, firstPass);
}
}
private void addPersisterHack(Element class_mapping) {
class_mapping.addAttribute("persister", VersionsInheritanceEntityPersister.class.getName() );
}
@SuppressWarnings({"unchecked"})
public void generateFirstPass(PersistentClass pc, PersistentClassVersioningData versioningData,
EntityXmlMappingData xmlMappingData) {
String schema = versioningData.versionsTable.schema();
if (StringTools.isEmpty(schema)) {
schema = pc.getTable().getSchema();
}
String catalog = versioningData.versionsTable.catalog();
if (StringTools.isEmpty(catalog)) {
catalog = pc.getTable().getCatalog();
}
String entityName = pc.getEntityName();
String versionsEntityName = verEntCfg.getVersionsEntityName(entityName);
String versionsTableName = verEntCfg.getVersionsTableName(entityName, pc.getTable().getName());
// Generating a mapping for the id
IdMappingData idMapper = idMetadataGenerator.addId(pc);
Element class_mapping;
ExtendedPropertyMapper propertyMapper;
InheritanceType inheritanceType = InheritanceType.get(pc);
String parentEntityName = null;
switch (inheritanceType) {
case NONE:
class_mapping = MetadataTools.createEntity(xmlMappingData.getMainXmlMapping(), versionsEntityName, versionsTableName,
schema, catalog, pc.getDiscriminatorValue());
propertyMapper = new MultiPropertyMapper();
// Checking if there is a discriminator column
if (pc.getDiscriminator() != null) {
Element discriminator_element = class_mapping.addElement("discriminator");
MetadataTools.addColumns(discriminator_element, pc.getDiscriminator().getColumnIterator());
discriminator_element.addAttribute("type", pc.getDiscriminator().getType().getName());
// If so, there is some inheritance scheme -> using the persister hack.
addPersisterHack(class_mapping);
}
// Adding the id mapping
class_mapping.add((Element) idMapper.getXmlMapping().clone());
// Adding the "revision type" property
addRevisionType(class_mapping);
break;
case SINGLE:
String extendsEntityName = verEntCfg.getVersionsEntityName(pc.getSuperclass().getEntityName());
class_mapping = MetadataTools.createSubclassEntity(xmlMappingData.getMainXmlMapping(), versionsEntityName,
versionsTableName, schema, catalog, extendsEntityName, pc.getDiscriminatorValue());
addPersisterHack(class_mapping);
// The id and revision type is already mapped in the parent
// Getting the property mapper of the parent - when mapping properties, they need to be included
parentEntityName = pc.getSuperclass().getEntityName();
ExtendedPropertyMapper parentPropertyMapper = entitiesConfigurations.get(parentEntityName).getPropertyMapper();
propertyMapper = new SubclassPropertyMapper(new MultiPropertyMapper(), parentPropertyMapper);
break;
case JOINED:
throw new MappingException("Joined inheritance strategy not supported for versioning!");
case TABLE_PER_CLASS:
throw new MappingException("Table-per-class inheritance strategy not supported for versioning!");
default:
throw new AssertionError("Impossible enum value.");
}
// Mapping unjoined properties
addProperties(class_mapping, (Iterator<Property>) pc.getUnjoinedPropertyIterator(), propertyMapper,
versioningData, pc.getEntityName(), xmlMappingData,
true);
// Creating and mapping joins (first pass)
createJoins(pc, class_mapping, versioningData);
addJoins(pc, propertyMapper, versioningData, pc.getEntityName(), xmlMappingData, true);
// Storing the generated configuration
EntityConfiguration entityCfg = new EntityConfiguration(versionsEntityName, idMapper,
propertyMapper, parentEntityName);
entitiesConfigurations.put(pc.getEntityName(), entityCfg);
}
@SuppressWarnings({"unchecked"})
public void generateSecondPass(PersistentClass pc, PersistentClassVersioningData versioningData,
EntityXmlMappingData xmlMappingData) {
String entityName = pc.getEntityName();
CompositeMapperBuilder propertyMapper = entitiesConfigurations.get(entityName).getPropertyMapper();
// Mapping unjoined properties
Element parent = xmlMappingData.getMainXmlMapping().getRootElement().element("class");
if (parent == null) {
parent = xmlMappingData.getMainXmlMapping().getRootElement().element("subclass");
}
addProperties(parent, (Iterator<Property>) pc.getUnjoinedPropertyIterator(),
propertyMapper, versioningData, entityName, xmlMappingData, false);
// Mapping joins (second pass)
addJoins(pc, propertyMapper, versioningData, entityName, xmlMappingData, false);
}
public Map<String, EntityConfiguration> getEntitiesConfigurations() {
return entitiesConfigurations;
}
// Getters for generators and configuration
BasicMetadataGenerator getBasicMetadataGenerator() {
return basicMetadataGenerator;
}
Configuration getCfg() {
return cfg;
}
GlobalConfiguration getGlobalCfg() {
return globalCfg;
}
VersionsEntitiesConfiguration getVerEntCfg() {
return verEntCfg;
}
void throwUnsupportedTypeException(Type type, String entityName, String propertyName) {
String message = "Type not supported for versioning: " + type.getClass().getName() +
", on entity " + entityName + ", property '" + propertyName + "'.";
if (globalCfg.isWarnOnUnsupportedTypes()) {
log.warn(message);
} else {
throw new MappingException(message);
}
}
}

View File

@ -0,0 +1,99 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities;
import java.util.Map;
import java.util.HashMap;
/**
* Configuration of the user entities: property mapping of the entities, relations, inheritance.
* @author Adam Warski (adam at warski dot org)
*/
public class EntitiesConfigurations {
private Map<String, EntityConfiguration> entitiesConfigurations;
// Map versions entity name -> entity name
private Map<String, String> entityNamesForVersionsEntityNames = new HashMap<String, String>();
public EntitiesConfigurations(Map<String, EntityConfiguration> entitiesConfigurations) {
this.entitiesConfigurations = entitiesConfigurations;
generateBidirectionRelationInfo();
generateVersionsEntityToEntityNames();
}
private void generateVersionsEntityToEntityNames() {
entityNamesForVersionsEntityNames = new HashMap<String, String>();
for (String entityName : entitiesConfigurations.keySet()) {
entityNamesForVersionsEntityNames.put(entitiesConfigurations.get(entityName).getVersionsEntityName(),
entityName);
}
}
private void generateBidirectionRelationInfo() {
// Checking each relation if it is bidirectional. If so, storing that information.
for (String entityName : entitiesConfigurations.keySet()) {
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
// Iterating over all relations from that entity
for (RelationDescription relDesc : entCfg.getRelationsIterator()) {
// If this is an "owned" relation, checking the related entity, if it has a relation that has
// a mapped-by attribute to the currently checked. If so, this is a bidirectional relation.
if (relDesc.getRelationType() == RelationType.TO_ONE ||
relDesc.getRelationType() == RelationType.TO_MANY_MIDDLE) {
for (RelationDescription other : entitiesConfigurations.get(relDesc.getToEntityName()).getRelationsIterator()) {
if (relDesc.getFromPropertyName().equals(other.getMappedByPropertyName()) &&
(entityName.equals(other.getToEntityName()))) {
relDesc.setBidirectional(true);
other.setBidirectional(true);
}
}
}
}
}
}
public EntityConfiguration get(String entityName) {
return entitiesConfigurations.get(entityName);
}
public String getEntityNameForVersionsEntityName(String versionsEntityName) {
return entityNamesForVersionsEntityNames.get(versionsEntityName);
}
public boolean isVersioned(String entityName) {
return get(entityName) != null;
}
public RelationDescription getRelationDescription(String entityName, String propertyName) {
EntityConfiguration entCfg = entitiesConfigurations.get(entityName);
RelationDescription relDesc = entCfg.getRelationDescription(propertyName);
if (relDesc != null) {
return relDesc;
} else if (entCfg.getParentEntityName() != null) {
// The field may be declared in a superclass ...
return getRelationDescription(entCfg.getParentEntityName(), propertyName);
} else {
return null;
}
}
}

View File

@ -0,0 +1,111 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities;
import org.jboss.envers.entities.mapper.ExtendedPropertyMapper;
import org.jboss.envers.entities.mapper.id.IdMapper;
import java.util.Map;
import java.util.HashMap;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class EntityConfiguration {
private String versionsEntityName;
private IdMappingData idMappingData;
private ExtendedPropertyMapper propertyMapper;
// Maps from property name
private Map<String, RelationDescription> relations;
private String parentEntityName;
public EntityConfiguration(String versionsEntityName, IdMappingData idMappingData,
ExtendedPropertyMapper propertyMapper, String parentEntityName) {
this.versionsEntityName = versionsEntityName;
this.idMappingData = idMappingData;
this.propertyMapper = propertyMapper;
this.parentEntityName = parentEntityName;
this.relations = new HashMap<String, RelationDescription>();
}
public void addToOneRelation(String fromPropertyName, String toEntityName, IdMapper idMapper) {
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE,
toEntityName, null, idMapper));
}
public void addToOneNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName,
IdMapper idMapper) {
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_ONE_NOT_OWNING,
toEntityName, mappedByPropertyName, idMapper));
}
public void addToManyNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName,
IdMapper idMapper) {
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_NOT_OWNING,
toEntityName, mappedByPropertyName, idMapper));
}
public void addToManyMiddleRelation(String fromPropertyName, String toEntityName) {
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE,
toEntityName, null, null));
}
public void addToManyMiddleNotOwningRelation(String fromPropertyName, String mappedByPropertyName, String toEntityName) {
relations.put(fromPropertyName, new RelationDescription(fromPropertyName, RelationType.TO_MANY_MIDDLE_NOT_OWNING,
toEntityName, mappedByPropertyName, null));
}
public boolean isRelation(String propertyName) {
return relations.get(propertyName) != null;
}
public RelationDescription getRelationDescription(String propertyName) {
return relations.get(propertyName);
}
public IdMappingData getIdMappingData() {
return idMappingData;
}
public IdMapper getIdMapper() {
return idMappingData.getIdMapper();
}
public ExtendedPropertyMapper getPropertyMapper() {
return propertyMapper;
}
// For use by EntitiesConfigurations
String getParentEntityName() {
return parentEntityName;
}
String getVersionsEntityName() {
return versionsEntityName;
}
Iterable<RelationDescription> getRelationsIterator() {
return relations.values();
}
}

View File

@ -0,0 +1,103 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities;
import org.jboss.envers.exception.VersionsException;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.jboss.envers.entities.mapper.id.IdMapper;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.tools.reflection.ReflectionTools;
import java.util.Map;
import java.util.List;
import java.util.Collection;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class EntityInstantiator {
private final VersionsConfiguration verCfg;
private final VersionsReaderImplementor versionsReader;
public EntityInstantiator(VersionsConfiguration verCfg, VersionsReaderImplementor versionsReader) {
this.verCfg = verCfg;
this.versionsReader = versionsReader;
}
/**
* Creates an entity instance based on an entry from the versions table.
* @param entityName Name of the entity, which instances should be read
* @param versionsEntity An entry in the versions table, from which data should be mapped.
* @param revision Revision at which this entity was read.
* @return An entity instance, with versioned properties set as in the versionsEntity map, and proxies
* created for collections.
*/
public Object createInstanceFromVersionsEntity(String entityName, Map versionsEntity, Number revision) {
if (versionsEntity == null) {
return null;
}
// The $type$ property holds the name of the (versions) entity
String type = verCfg.getEntCfg().getEntityNameForVersionsEntityName((String) versionsEntity.get("$type$"));
if (type != null) {
entityName = type;
}
// First mapping the primary key
IdMapper idMapper = verCfg.getEntCfg().get(entityName).getIdMapper();
Map originalId = (Map) versionsEntity.get(verCfg.getVerEntCfg().getOriginalIdPropName());
Object primaryKey = idMapper.mapToIdFromMap(originalId);
// Checking if the entity is in cache
if (versionsReader.getFirstLevelCache().contains(entityName, revision, primaryKey)) {
return versionsReader.getFirstLevelCache().get(entityName, revision, primaryKey);
}
// If it is not in the cache, creating a new entity instance
Object ret;
try {
Class<?> cls = ReflectionTools.loadClass(entityName);
ret = cls.newInstance();
} catch (Exception e) {
throw new VersionsException(e);
}
// Putting the newly created entity instance into the first level cache, in case a one-to-one bidirectional
// relation is present (which is eagerly loaded).
versionsReader.getFirstLevelCache().put(entityName, revision, primaryKey, ret);
verCfg.getEntCfg().get(entityName).getPropertyMapper().mapToEntityFromMap(verCfg, ret, versionsEntity, primaryKey,
versionsReader, revision);
idMapper.mapToEntityFromMap(ret, originalId);
return ret;
}
@SuppressWarnings({"unchecked"})
public void addInstancesFromVersionsEntities(String entityName, Collection addTo, List<Map> versionsEntities, Number revision) {
for (Map versionsEntity : versionsEntities) {
addTo.add(createInstanceFromVersionsEntity(entityName, versionsEntity, revision));
}
}
}

View File

@ -0,0 +1,54 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities;
import org.jboss.envers.entities.mapper.id.IdMapper;
import org.dom4j.Element;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class IdMappingData {
private final IdMapper idMapper;
// Mapping which will be used to generate the entity
private final Element xmlMapping;
// Mapping which will be used to generate references to the entity in related entities
private final Element xmlRelationMapping;
public IdMappingData(IdMapper idMapper, Element xmlMapping, Element xmlRelationMapping) {
this.idMapper = idMapper;
this.xmlMapping = xmlMapping;
this.xmlRelationMapping = xmlRelationMapping;
}
public IdMapper getIdMapper() {
return idMapper;
}
public Element getXmlMapping() {
return xmlMapping;
}
public Element getXmlRelationMapping() {
return xmlRelationMapping;
}
}

View File

@ -0,0 +1,75 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities;
import org.jboss.envers.entities.mapper.id.IdMapper;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class RelationDescription {
private final String fromPropertyName;
private final RelationType relationType;
private final String toEntityName;
private final String mappedByPropertyName;
private final IdMapper idMapper;
private boolean bidirectional;
public RelationDescription(String fromPropertyName, RelationType relationType, String toEntityName,
String mappedByPropertyName, IdMapper idMapper) {
this.fromPropertyName = fromPropertyName;
this.relationType = relationType;
this.toEntityName = toEntityName;
this.mappedByPropertyName = mappedByPropertyName;
this.idMapper = idMapper;
this.bidirectional = false;
}
public String getFromPropertyName() {
return fromPropertyName;
}
public RelationType getRelationType() {
return relationType;
}
public String getToEntityName() {
return toEntityName;
}
public String getMappedByPropertyName() {
return mappedByPropertyName;
}
public IdMapper getIdMapper() {
return idMapper;
}
public boolean isBidirectional() {
return bidirectional;
}
void setBidirectional(boolean bidirectional) {
this.bidirectional = bidirectional;
}
}

View File

@ -0,0 +1,54 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities;
/**
* Type of a relation between two entities.
* @author Adam Warski (adam at warski dot org)
*/
public enum RelationType {
/**
* A single-reference-valued relation. The entity owns the relation.
*/
TO_ONE,
/**
* A single-reference-valued relation. The entity doesn't own the relation. It is directly mapped in the related
* entity.
*/
TO_ONE_NOT_OWNING,
/**
* A collection-of-references-valued relation. The entity doesn't own the relation. It is directly mapped in the
* related entity.
*/
TO_MANY_NOT_OWNING,
/**
* A collection-of-references-valued relation. The entity owns the relation. It is mapped using a middle table.
*/
TO_MANY_MIDDLE,
/**
* A collection-of-references-valued relation. The entity doesn't own the relation. It is mapped using a middle
* table.
*/
TO_MANY_MIDDLE_NOT_OWNING
}

View File

@ -0,0 +1,108 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities;
import org.hibernate.usertype.UserType;
import org.hibernate.HibernateException;
import org.jboss.envers.RevisionType;
import java.sql.ResultSet;
import java.sql.Types;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.io.Serializable;
/**
* A hibernate type for the {@link RevisionType} enum.
* @author Adam Warski (adam at warski dot org)
*/
public class RevisionTypeType implements UserType {
private static final int[] SQL_TYPES = { Types.TINYINT };
public int[] sqlTypes() {
return SQL_TYPES;
}
public Class returnedClass() {
return RevisionType.class;
}
public RevisionType nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {
byte representation = (byte) resultSet.getInt(names[0]);
RevisionType result = null;
if (!resultSet.wasNull()) {
result = RevisionType.fromRepresentation(representation);
}
return result;
}
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index) throws HibernateException, SQLException {
if (null == value) {
preparedStatement.setNull(index, Types.TINYINT);
} else {
preparedStatement.setInt(index, ((RevisionType) value).getRepresentation());
}
}
public Object deepCopy(Object value) throws HibernateException{
return value;
}
public boolean isMutable() {
return false;
}
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable)value;
}
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public boolean equals(Object x, Object y) throws HibernateException {
//noinspection ObjectEquality
if (x == y) {
return true;
}
if (null == x || null == y) {
return false;
}
return x.equals(y);
}
}

View File

@ -0,0 +1,30 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface CompositeMapperBuilder extends SimpleMapperBuilder {
public CompositeMapperBuilder addComposite(String propertyName);
public void addComposite(String propertyName, PropertyMapper propertyMapper);
}

View File

@ -0,0 +1,31 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper;
import java.util.Map;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface ExtendedPropertyMapper extends PropertyMapper, CompositeMapperBuilder {
public boolean map(Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState);
}

View File

@ -0,0 +1,94 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper;
import org.jboss.envers.ModificationStore;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.jboss.envers.tools.reflection.ReflectionTools;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.exception.VersionsException;
import org.hibernate.property.Getter;
import org.hibernate.property.Setter;
import org.hibernate.util.ReflectHelper;
import org.hibernate.collection.PersistentCollection;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class MapPropertyMapper implements PropertyMapper, CompositeMapperBuilder {
private String propertyName;
private ExtendedPropertyMapper delegate;
public MapPropertyMapper(String propertyName) {
this.propertyName = propertyName;
this.delegate = new MultiPropertyMapper();
}
public void add(String propertyName, ModificationStore modStore) {
delegate.add(propertyName, modStore);
}
public CompositeMapperBuilder addComposite(String propertyName) {
return delegate.addComposite(propertyName);
}
public void addComposite(String propertyName, PropertyMapper propertyMapper) {
delegate.addComposite(propertyName, propertyMapper);
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
Map<String, Object> newData = new HashMap<String, Object>();
data.put(propertyName, newData);
return delegate.mapToMapFromEntity(newData, newObj, oldObj);
}
public void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey, VersionsReaderImplementor versionsReader, Number revision) {
if (data == null || obj == null) {
return;
}
Getter getter = ReflectionTools.getGetter(obj.getClass(), propertyName);
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyName);
try {
Object subObj = ReflectHelper.getDefaultConstructor(getter.getReturnType()).newInstance();
setter.set(obj, subObj, null);
delegate.mapToEntityFromMap(verCfg, subObj, (Map) data.get(propertyName), primaryKey, versionsReader, revision);
} catch (Exception e) {
throw new VersionsException(e);
}
}
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
return delegate.mapCollectionChanges(referencingPropertyName, newColl, oldColl, id);
}
}

View File

@ -0,0 +1,122 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper;
import org.hibernate.property.Getter;
import org.hibernate.MappingException;
import org.hibernate.collection.PersistentCollection;
import org.jboss.envers.ModificationStore;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.jboss.envers.tools.reflection.ReflectionTools;
import org.jboss.envers.reader.VersionsReaderImplementor;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class MultiPropertyMapper implements ExtendedPropertyMapper {
protected Map<String, PropertyMapper> properties;
public MultiPropertyMapper() {
properties = new HashMap<String, PropertyMapper>();
}
public void add(String propertyName, ModificationStore modStore) {
SinglePropertyMapper single = new SinglePropertyMapper();
single.add(propertyName, modStore);
properties.put(propertyName, single);
}
public CompositeMapperBuilder addComposite(String propertyName) {
if (properties.get(propertyName) != null) {
throw new MappingException("Mapping for " + propertyName + " already added!");
}
MapPropertyMapper mapperBuilder = new MapPropertyMapper(propertyName);
properties.put(propertyName, mapperBuilder);
return mapperBuilder;
}
public void addComposite(String propertyName, PropertyMapper propertyMapper) {
properties.put(propertyName, propertyMapper);
}
private Object getAtIndexOrNull(Object[] array, int index) { return array == null ? null : array[index]; }
public boolean map(Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
boolean ret = false;
for (int i=0; i<propertyNames.length; i++) {
String propertyName = propertyNames[i];
if (properties.containsKey(propertyName)) {
ret |= properties.get(propertyName).mapToMapFromEntity(data,
getAtIndexOrNull(newState, i),
getAtIndexOrNull(oldState, i));
}
}
return ret;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
boolean ret = false;
for (String propertyName : properties.keySet()) {
Getter getter;
if (newObj != null) {
getter = ReflectionTools.getGetter(newObj.getClass(), propertyName);
} else if (oldObj != null) {
getter = ReflectionTools.getGetter(oldObj.getClass(), propertyName);
} else {
return false;
}
ret |= properties.get(propertyName).mapToMapFromEntity(data,
newObj == null ? null : getter.get(newObj),
oldObj == null ? null : getter.get(oldObj));
}
return ret;
}
public void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey, VersionsReaderImplementor versionsReader, Number revision) {
for (String propertyName : properties.keySet()) {
properties.get(propertyName).mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
}
}
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
PropertyMapper mapper = properties.get(referencingPropertyName);
if (mapper != null) {
return mapper.mapCollectionChanges(referencingPropertyName, newColl, oldColl, id);
} else {
return null;
}
}
}

View File

@ -0,0 +1,63 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper;
import java.util.Map;
/**
* Data describing the change of a single object in a persisten collection (when the object was added, removed or
* modified in the collection).
* @author Adam Warski (adam at warski dot org)
*/
public class PersistentCollectionChangeData {
private final String entityName;
private final Map<String, Object> data;
private final Object changedElement;
public PersistentCollectionChangeData(String entityName, Map<String, Object> data, Object changedElement) {
this.entityName = entityName;
this.data = data;
this.changedElement = changedElement;
}
/**
*
* @return Name of the (middle) entity that holds the collection data.
*/
public String getEntityName() {
return entityName;
}
public Map<String, Object> getData() {
return data;
}
/**
* For use by bi-directional associations.
* @return The affected element, which was changed (added, removed, modified) in the collection.
*/
public Object getChangedElement() {
return changedElement;
}
}

View File

@ -0,0 +1,68 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.hibernate.collection.PersistentCollection;
import java.util.Map;
import java.util.List;
import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface PropertyMapper {
/**
* Maps properties to the given map, basing on differences between properties of new and old objects.
* @param data Data to map to.
* @param newObj New state of the entity.
* @param oldObj Old state of the entity.
* @return True if there are any differences between the states represented by newObj and oldObj.
*/
boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj);
/**
* Maps properties from the given map to the given object.
* @param verCfg Versions configuration.
* @param obj Object to map to.
* @param data Data to map from.
* @param primaryKey Primary key of the object to which we map (for relations)
* @param versionsReader VersionsReader for reading relations
* @param revision Revision at which the object is read, for reading relations
*/
void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey,
VersionsReaderImplementor versionsReader, Number revision);
/**
* Maps collection changes
* @param referencingPropertyName Name of the field, which holds the collection in the entity.
* @param newColl New collection, after updates.
* @param oldColl Old collection, before updates.
* @param id Id of the object owning the collection.
* @return List of changes that need to be performed on the persistent store.
*/
List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id);
}

View File

@ -0,0 +1,31 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper;
import org.jboss.envers.ModificationStore;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface SimpleMapperBuilder {
public void add(String propertyName, ModificationStore modStore);
}

View File

@ -0,0 +1,76 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper;
import org.jboss.envers.ModificationStore;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.jboss.envers.tools.reflection.ReflectionTools;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.tools.Tools;
import org.jboss.envers.exception.VersionsException;
import org.hibernate.property.Setter;
import org.hibernate.collection.PersistentCollection;
import java.util.Map;
import java.util.List;
import java.io.Serializable;
/**
* TODO: diff
* @author Adam Warski (adam at warski dot org)
*/
public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder {
private String propertyName;
public SinglePropertyMapper() { }
public void add(String propertyName, ModificationStore modStore) {
if (this.propertyName != null) {
throw new VersionsException("Only one property can be added!");
}
this.propertyName = propertyName;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
data.put(propertyName, newObj);
return !Tools.objectsEqual(newObj, oldObj);
}
public void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey, VersionsReaderImplementor versionsReader, Number revision) {
if (data == null || obj == null) {
return;
}
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyName);
setter.set(obj, data.get(propertyName), null);
}
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
return null;
}
}

View File

@ -0,0 +1,91 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.ModificationStore;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.hibernate.collection.PersistentCollection;
import java.util.Map;
import java.util.List;
import java.io.Serializable;
/**
* A mapper which maps from a parent mapper and a "main" one, but adds only to the "main". The "main" mapper
* should be the mapper of the subclass.
* @author Adam Warski (adam at warski dot org)
*/
public class SubclassPropertyMapper implements ExtendedPropertyMapper {
private ExtendedPropertyMapper main;
private ExtendedPropertyMapper parentMapper;
public SubclassPropertyMapper(ExtendedPropertyMapper main, ExtendedPropertyMapper parentMapper) {
this.main = main;
this.parentMapper = parentMapper;
}
public boolean map(Map<String, Object> data, String[] propertyNames, Object[] newState, Object[] oldState) {
boolean parentDiffs = parentMapper.map(data, propertyNames, newState, oldState);
boolean mainDiffs = main.map(data, propertyNames, newState, oldState);
return parentDiffs || mainDiffs;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
boolean parentDiffs = parentMapper.mapToMapFromEntity(data, newObj, oldObj);
boolean mainDiffs = main.mapToMapFromEntity(data, newObj, oldObj);
return parentDiffs || mainDiffs;
}
public void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey, VersionsReaderImplementor versionsReader, Number revision) {
parentMapper.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
main.mapToEntityFromMap(verCfg, obj, data, primaryKey, versionsReader, revision);
}
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
List<PersistentCollectionChangeData> collectionChanges = parentMapper.mapCollectionChanges(
referencingPropertyName, newColl, oldColl, id);
if (collectionChanges == null) {
return main.mapCollectionChanges(referencingPropertyName, newColl, oldColl, id);
} else {
return collectionChanges;
}
}
public CompositeMapperBuilder addComposite(String propertyName) {
return main.addComposite(propertyName);
}
public void addComposite(String propertyName, PropertyMapper propertyMapper) {
main.addComposite(propertyName, propertyMapper);
}
public void add(String propertyName, ModificationStore modStore) {
main.add(propertyName, modStore);
}
}

View File

@ -0,0 +1,61 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.id;
import org.jboss.envers.ModificationStore;
import org.jboss.envers.exception.VersionsException;
import java.util.Map;
import java.util.LinkedHashMap;
/**
* @author Adam Warski (adam at warski dot org)
*/
public abstract class AbstractCompositeIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
protected Map<String, SingleIdMapper> ids;
protected String compositeIdClass;
protected AbstractCompositeIdMapper(String compositeIdClass) {
ids = new LinkedHashMap<String, SingleIdMapper>();
this.compositeIdClass = compositeIdClass;
}
public void add(String propertyName, ModificationStore modStore) {
ids.put(propertyName, new SingleIdMapper(propertyName));
}
public Object mapToIdFromMap(Map data) {
Object ret;
try {
ret = Thread.currentThread().getContextClassLoader().loadClass(compositeIdClass).newInstance();
} catch (Exception e) {
throw new VersionsException(e);
}
for (SingleIdMapper mapper : ids.values()) {
mapper.mapToEntityFromMap(ret, data);
}
return ret;
}
}

View File

@ -0,0 +1,86 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.id;
import org.jboss.envers.tools.query.Parameters;
import java.util.Iterator;
import java.util.List;
/**
* @author Adam Warski (adam at warski dot org)
*/
public abstract class AbstractIdMapper implements IdMapper {
private Parameters getParametersToUse(Parameters parameters, List<QueryParameterData> paramDatas) {
if (paramDatas.size() > 1) {
return parameters.addSubParameters("and");
} else {
return parameters;
}
}
public void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null);
Parameters parametersToUse = getParametersToUse(parameters, paramDatas);
for (QueryParameterData paramData : paramDatas) {
parametersToUse.addWhere(paramData.getProperty(prefix1), false, "=", paramData.getProperty(prefix2), false);
}
}
public void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2) {
List<QueryParameterData> paramDatas1 = mapToQueryParametersFromId(null);
List<QueryParameterData> paramDatas2 = mapper2.mapToQueryParametersFromId(null);
Parameters parametersToUse = getParametersToUse(parameters, paramDatas1);
Iterator<QueryParameterData> paramDataIter1 = paramDatas1.iterator();
Iterator<QueryParameterData> paramDataIter2 = paramDatas2.iterator();
while (paramDataIter1.hasNext()) {
QueryParameterData paramData1 = paramDataIter1.next();
QueryParameterData paramData2 = paramDataIter2.next();
parametersToUse.addWhere(paramData1.getProperty(prefix1), false, "=", paramData2.getProperty(prefix2), false);
}
}
public void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals) {
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(id);
Parameters parametersToUse = getParametersToUse(parameters, paramDatas);
for (QueryParameterData paramData : paramDatas) {
parametersToUse.addWhereWithParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getValue());
}
}
public void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals) {
List<QueryParameterData> paramDatas = mapToQueryParametersFromId(null);
Parameters parametersToUse = getParametersToUse(parameters, paramDatas);
for (QueryParameterData paramData : paramDatas) {
parametersToUse.addWhereWithNamedParam(paramData.getProperty(prefix), equals ? "=" : "<>", paramData.getQueryParameterName());
}
}
}

View File

@ -0,0 +1,110 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.id;
import org.hibernate.property.Getter;
import org.hibernate.property.Setter;
import org.hibernate.util.ReflectHelper;
import org.jboss.envers.exception.VersionsException;
import org.jboss.envers.tools.reflection.ReflectionTools;
import java.util.*;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
private String idPropertyName;
public EmbeddedIdMapper(String idPropertyName, String compositeIdClass) {
super(compositeIdClass);
this.idPropertyName = idPropertyName;
}
public void mapToMapFromId(Map<String, Object> data, Object obj) {
for (IdMapper idMapper : ids.values()) {
idMapper.mapToMapFromEntity(data, obj);
}
}
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
if (obj == null) {
return;
}
Getter getter = ReflectionTools.getGetter(obj.getClass(), idPropertyName);
mapToMapFromId(data, getter.get(obj));
}
public void mapToEntityFromMap(Object obj, Map data) {
if (data == null || obj == null) {
return;
}
Getter getter = ReflectionTools.getGetter(obj.getClass(), idPropertyName);
Setter setter = ReflectionTools.getSetter(obj.getClass(), idPropertyName);
try {
Object subObj = ReflectHelper.getDefaultConstructor(getter.getReturnType()).newInstance();
setter.set(obj, subObj, null);
for (IdMapper idMapper : ids.values()) {
idMapper.mapToEntityFromMap(subObj, data);
}
} catch (Exception e) {
throw new VersionsException(e);
}
}
public IdMapper prefixMappedProperties(String prefix) {
EmbeddedIdMapper ret = new EmbeddedIdMapper(idPropertyName, compositeIdClass);
for (String propertyName : ids.keySet()) {
ret.ids.put(propertyName, new SingleIdMapper(propertyName, prefix + propertyName));
}
return ret;
}
public Object mapToIdFromEntity(Object data) {
if (data == null) {
return null;
}
Getter getter = ReflectionTools.getGetter(data.getClass(), idPropertyName);
return getter.get(data);
}
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
Map<String, Object> data = new LinkedHashMap<String, Object>();
mapToMapFromId(data, obj);
List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
for (Map.Entry<String, Object> propertyData : data.entrySet()) {
ret.add(new QueryParameterData(propertyData.getKey(), propertyData.getValue()));
}
return ret;
}
}

View File

@ -0,0 +1,97 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.id;
import org.jboss.envers.tools.query.Parameters;
import java.util.Map;
import java.util.List;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface IdMapper {
void mapToMapFromId(Map<String, Object> data, Object obj);
void mapToMapFromEntity(Map<String, Object> data, Object obj);
void mapToEntityFromMap(Object obj, Map data);
Object mapToIdFromEntity(Object data);
Object mapToIdFromMap(Map data);
/**
* Creates a mapper with all mapped properties prefixed. A mapped property is a property which
* is directly mapped to values (not composite).
* @param prefix Prefix to add to mapped properties
* @return A copy of the current property mapper, with mapped properties prefixed.
*/
IdMapper prefixMappedProperties(String prefix);
/**
* @param obj Id from which to map.
* @return A set parameter data, needed to build a query basing on the given id.
*/
List<QueryParameterData> mapToQueryParametersFromId(Object obj);
/**
* Adds query statements, which contains restrictions, which express the property that the id of the entity
* with alias prefix1, is equal to the id of the entity with alias prefix2 (the entity is the same).
* @param parameters Parameters, to which to add the statements.
* @param prefix1 First alias of the entity + prefix to add to the properties.
* @param prefix2 Second alias of the entity + prefix to add to the properties.
*/
void addIdsEqualToQuery(Parameters parameters, String prefix1, String prefix2);
/**
* Adds query statements, which contains restrictions, which express the property that the id of the entity
* with alias prefix1, is equal to the id of the entity with alias prefix2 mapped by the second mapper
* (the second mapper must be for the same entity, but it can have, for example, prefixed properties).
* @param parameters Parameters, to which to add the statements.
* @param prefix1 First alias of the entity + prefix to add to the properties.
* @param mapper2 Second mapper for the same entity, which will be used to get properties for the right side
* of the equation.
* @param prefix2 Second alias of the entity + prefix to add to the properties.
*/
void addIdsEqualToQuery(Parameters parameters, String prefix1, IdMapper mapper2, String prefix2);
/**
* Adds query statements, which contains restrictions, which express the property that the id of the entity
* with alias prefix, is equal to the given object.
* @param parameters Parameters, to which to add the statements.
* @param id Value of id.
* @param prefix Prefix to add to the properties (may be null).
* @param equals Should this query express the "=" relation or the "<>" relation.
*/
void addIdEqualsToQuery(Parameters parameters, Object id, String prefix, boolean equals);
/**
* Adds query statements, which contains named parameters, which express the property that the id of the entity
* with alias prefix, is equal to the given object. It is the responsibility of the using method to read
* parameter values from the id and specify them on the final query object.
* @param parameters Parameters, to which to add the statements.
* @param prefix Prefix to add to the properties (may be null).
* @param equals Should this query express the "=" relation or the "<>" relation.
*/
void addNamedIdEqualsToQuery(Parameters parameters, String prefix, boolean equals);
}

View File

@ -0,0 +1,93 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.id;
import org.jboss.envers.exception.VersionsException;
import java.util.*;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class MultipleIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
public MultipleIdMapper(String compositeIdClass) {
super(compositeIdClass);
}
public void mapToMapFromId(Map<String, Object> data, Object obj) {
for (IdMapper idMapper : ids.values()) {
idMapper.mapToMapFromEntity(data, obj);
}
}
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
mapToMapFromId(data, obj);
}
public void mapToEntityFromMap(Object obj, Map data) {
for (IdMapper idMapper : ids.values()) {
idMapper.mapToEntityFromMap(obj, data);
}
}
public IdMapper prefixMappedProperties(String prefix) {
MultipleIdMapper ret = new MultipleIdMapper(compositeIdClass);
for (String propertyName : ids.keySet()) {
ret.ids.put(propertyName, new SingleIdMapper(propertyName, prefix + propertyName));
}
return ret;
}
public Object mapToIdFromEntity(Object data) {
if (data == null) {
return null;
}
Object ret;
try {
ret = Thread.currentThread().getContextClassLoader().loadClass(compositeIdClass).newInstance();
} catch (Exception e) {
throw new VersionsException(e);
}
for (SingleIdMapper mapper : ids.values()) {
mapper.mapToEntityFromEntity(ret, data);
}
return ret;
}
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
Map<String, Object> data = new LinkedHashMap<String, Object>();
mapToMapFromId(data, obj);
List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
for (Map.Entry<String, Object> propertyData : data.entrySet()) {
ret.add(new QueryParameterData(propertyData.getKey(), propertyData.getValue()));
}
return ret;
}
}

View File

@ -0,0 +1,73 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.id;
import org.hibernate.Query;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class QueryParameterData {
private String flatEntityPropertyName;
private Object value;
public QueryParameterData(String flatEntityPropertyName, Object value) {
this.flatEntityPropertyName = flatEntityPropertyName;
this.value = value;
}
public String getProperty(String prefix) {
if (prefix != null) {
return prefix + "." + flatEntityPropertyName;
} else {
return flatEntityPropertyName;
}
}
public Object getValue() {
return value;
}
public void setParameterValue(Query query) {
query.setParameter(flatEntityPropertyName, value);
}
public String getQueryParameterName() {
return flatEntityPropertyName;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof QueryParameterData)) return false;
QueryParameterData that = (QueryParameterData) o;
if (flatEntityPropertyName != null ? !flatEntityPropertyName.equals(that.flatEntityPropertyName) : that.flatEntityPropertyName != null)
return false;
return true;
}
public int hashCode() {
return (flatEntityPropertyName != null ? flatEntityPropertyName.hashCode() : 0);
}
}

View File

@ -0,0 +1,30 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.id;
import org.jboss.envers.entities.mapper.SimpleMapperBuilder;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface SimpleIdMapperBuilder extends IdMapper, SimpleMapperBuilder {
}

View File

@ -0,0 +1,123 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.id;
import org.jboss.envers.ModificationStore;
import org.jboss.envers.tools.reflection.ReflectionTools;
import org.jboss.envers.exception.VersionsException;
import org.hibernate.property.Setter;
import org.hibernate.property.Getter;
import java.util.*;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBuilder {
private String beanPropertyName;
private String propertyName;
public SingleIdMapper() {
}
public SingleIdMapper(String beanPropertyName, String propertyName) {
this.beanPropertyName = beanPropertyName;
this.propertyName = propertyName;
}
public SingleIdMapper(String propertyName) {
this.beanPropertyName = propertyName;
this.propertyName = propertyName;
}
public void add(String propertyName, ModificationStore modStore) {
if (this.propertyName != null) {
throw new VersionsException("Only one property can be added!");
}
this.propertyName = propertyName;
this.beanPropertyName = propertyName;
}
public void mapToEntityFromMap(Object obj, Map data) {
if (data == null || obj == null) {
return;
}
Setter setter = ReflectionTools.getSetter(obj.getClass(), beanPropertyName);
setter.set(obj, data.get(propertyName), null);
}
public Object mapToIdFromMap(Map data) {
if (data == null) {
return null;
}
return data.get(propertyName);
}
public Object mapToIdFromEntity(Object data) {
if (data == null) {
return null;
}
Getter getter = ReflectionTools.getGetter(data.getClass(), beanPropertyName);
return getter.get(data);
}
public void mapToMapFromId(Map<String, Object> data, Object obj) {
if (data != null) {
data.put(propertyName, obj);
}
}
public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
if (obj == null) {
data.put(propertyName, null);
} else {
Getter getter = ReflectionTools.getGetter(obj.getClass(), beanPropertyName);
data.put(propertyName, getter.get(obj));
}
}
public void mapToEntityFromEntity(Object objTo, Object objFrom) {
if (objTo == null || objFrom == null) {
return;
}
Getter getter = ReflectionTools.getGetter(objFrom.getClass(), beanPropertyName);
Setter setter = ReflectionTools.getSetter(objTo.getClass(), beanPropertyName);
setter.set(objTo, getter.get(objFrom), null);
}
public IdMapper prefixMappedProperties(String prefix) {
return new SingleIdMapper(propertyName, prefix + propertyName);
}
public List<QueryParameterData> mapToQueryParametersFromId(Object obj) {
List<QueryParameterData> ret = new ArrayList<QueryParameterData>();
ret.add(new QueryParameterData(propertyName, obj));
return ret;
}
}

View File

@ -0,0 +1,145 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation;
import org.jboss.envers.entities.mapper.PersistentCollectionChangeData;
import org.jboss.envers.entities.mapper.PropertyMapper;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
import org.jboss.envers.RevisionType;
import org.jboss.envers.exception.VersionsException;
import org.jboss.envers.tools.reflection.ReflectionTools;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.property.Setter;
import java.util.*;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Constructor;
/**
* @author Adam Warski (adam at warski dot org)
*/
public abstract class AbstractCollectionMapper<T> implements PropertyMapper {
protected final CommonCollectionMapperData commonCollectionMapperData;
protected final Class<? extends T> collectionClass;
private final Constructor<? extends T> proxyConstructor;
protected AbstractCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass) {
this.commonCollectionMapperData = commonCollectionMapperData;
this.collectionClass = collectionClass;
try {
proxyConstructor = proxyClass.getConstructor(Initializor.class);
} catch (NoSuchMethodException e) {
throw new VersionsException(e);
}
}
protected abstract Collection getNewCollectionContent(PersistentCollection newCollection);
protected abstract Collection getOldCollectionContent(Serializable oldCollection);
protected abstract Object getElement(Object changedObject);
/**
* Maps the changed collection element to the given map.
* @param data Where to map the data.
* @param changed The changed collection element to map.
*/
protected abstract void mapToMapFromObject(Map<String, Object> data, Object changed);
private void addCollectionChanges(List<PersistentCollectionChangeData> collectionChanges, Set<Object> changed,
RevisionType revisionType, Serializable id) {
for (Object changedObj : changed) {
Map<String, Object> entityData = new HashMap<String, Object>();
Map<String, Object> originalId = new HashMap<String, Object>();
entityData.put(commonCollectionMapperData.getVerEntCfg().getOriginalIdPropName(), originalId);
collectionChanges.add(new PersistentCollectionChangeData(
commonCollectionMapperData.getVersionsMiddleEntityName(), entityData, getElement(changedObj)));
// Mapping the collection owner's id.
commonCollectionMapperData.getReferencingIdData().getPrefixedMapper().mapToMapFromId(originalId, id);
// Mapping collection element and index (if present).
mapToMapFromObject(originalId, changedObj);
entityData.put(commonCollectionMapperData.getVerEntCfg().getRevisionTypePropName(), revisionType);
}
}
@SuppressWarnings({"unchecked"})
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Serializable id) {
if (!commonCollectionMapperData.getCollectionReferencingPropertyName().equals(referencingPropertyName)) {
return null;
}
List<PersistentCollectionChangeData> collectionChanges = new ArrayList<PersistentCollectionChangeData>();
// Comparing new and old collection content.
Collection newCollection = getNewCollectionContent(newColl);
Collection oldCollection = getOldCollectionContent(oldColl);
Set<Object> added = new HashSet<Object>();
if (newColl != null) { added.addAll(newCollection); }
if (oldColl != null) { added.removeAll(oldCollection); }
addCollectionChanges(collectionChanges, added, RevisionType.ADD, id);
Set<Object> deleted = new HashSet<Object>();
if (oldColl != null) { deleted.addAll(oldCollection); }
if (newColl != null) { deleted.removeAll(newCollection); }
addCollectionChanges(collectionChanges, deleted, RevisionType.DEL, id);
return collectionChanges;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
// Changes are mapped in the "mapCollectionChanges" method.
return false;
}
protected abstract Initializor<T> getInitializor(VersionsConfiguration verCfg,
VersionsReaderImplementor versionsReader, Object primaryKey,
Number revision);
public void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey,
VersionsReaderImplementor versionsReader, Number revision) {
Setter setter = ReflectionTools.getSetter(obj.getClass(),
commonCollectionMapperData.getCollectionReferencingPropertyName());
try {
setter.set(obj, proxyConstructor.newInstance(getInitializor(verCfg, versionsReader, primaryKey, revision)), null);
} catch (InstantiationException e) {
throw new VersionsException(e);
} catch (IllegalAccessException e) {
throw new VersionsException(e);
} catch (InvocationTargetException e) {
throw new VersionsException(e);
}
}
}

View File

@ -0,0 +1,77 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation;
import org.jboss.envers.entities.mapper.PropertyMapper;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.BasicCollectionInitializor;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.hibernate.collection.PersistentCollection;
import java.util.Map;
import java.util.Collection;
import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
public final class BasicCollectionMapper<T extends Collection> extends AbstractCollectionMapper<T> implements PropertyMapper {
private final MiddleComponentData elementComponentData;
public BasicCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass,
MiddleComponentData elementComponentData) {
super(commonCollectionMapperData, collectionClass, proxyClass);
this.elementComponentData = elementComponentData;
}
protected Initializor<T> getInitializor(VersionsConfiguration verCfg, VersionsReaderImplementor versionsReader,
Object primaryKey, Number revision) {
return new BasicCollectionInitializor<T>(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
primaryKey, revision, collectionClass, elementComponentData);
}
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
return (Collection) newCollection;
}
protected Collection getOldCollectionContent(Serializable oldCollection) {
if (oldCollection == null) {
return null;
} else if (oldCollection instanceof Map) {
return ((Map) oldCollection).keySet();
} else {
return (Collection) oldCollection;
}
}
protected void mapToMapFromObject(Map<String, Object> data, Object changed) {
elementComponentData.getComponentMapper().mapToMapFromObject(data, changed);
}
protected Object getElement(Object changedObject) {
return changedObject;
}
}

View File

@ -0,0 +1,69 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation;
import org.jboss.envers.configuration.VersionsEntitiesConfiguration;
import org.jboss.envers.entities.mapper.relation.query.RelationQueryGenerator;
/**
* Data that is used by all collection mappers, regardless of the type.
* @author Adam Warski (adam at warski dot org)
*/
public final class CommonCollectionMapperData {
private final VersionsEntitiesConfiguration verEntCfg;
private final String versionsMiddleEntityName;
private final String collectionReferencingPropertyName;
private final MiddleIdData referencingIdData;
private final RelationQueryGenerator queryGenerator;
public CommonCollectionMapperData(VersionsEntitiesConfiguration verEntCfg, String versionsMiddleEntityName,
String collectionReferencingPropertyName, MiddleIdData referencingIdData,
RelationQueryGenerator queryGenerator) {
this.verEntCfg = verEntCfg;
this.versionsMiddleEntityName = versionsMiddleEntityName;
this.collectionReferencingPropertyName = collectionReferencingPropertyName;
this.referencingIdData = referencingIdData;
this.queryGenerator = queryGenerator;
}
public VersionsEntitiesConfiguration getVerEntCfg() {
return verEntCfg;
}
public String getVersionsMiddleEntityName() {
return versionsMiddleEntityName;
}
public String getCollectionReferencingPropertyName() {
return collectionReferencingPropertyName;
}
public MiddleIdData getReferencingIdData() {
return referencingIdData;
}
public RelationQueryGenerator getQueryGenerator() {
return queryGenerator;
}
}

View File

@ -0,0 +1,90 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation;
import org.jboss.envers.entities.mapper.PropertyMapper;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.ListCollectionInitializor;
import org.jboss.envers.entities.mapper.relation.lazy.proxy.ListProxy;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.tools.Tools;
import org.jboss.envers.tools.Pair;
import org.hibernate.collection.PersistentCollection;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
public final class ListCollectionMapper extends AbstractCollectionMapper<List> implements PropertyMapper {
private final MiddleComponentData elementComponentData;
private final MiddleComponentData indexComponentData;
public ListCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData) {
super(commonCollectionMapperData, List.class, ListProxy.class);
this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData;
}
protected Initializor<List> getInitializor(VersionsConfiguration verCfg, VersionsReaderImplementor versionsReader,
Object primaryKey, Number revision) {
return new ListCollectionInitializor(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
primaryKey, revision, elementComponentData, indexComponentData);
}
@SuppressWarnings({"unchecked"})
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
if (newCollection == null) {
return null;
} else {
return Tools.listToIndexElementPairList((List<Object>) newCollection);
}
}
@SuppressWarnings({"unchecked"})
protected Collection getOldCollectionContent(Serializable oldCollection) {
if (oldCollection == null) {
return null;
} else {
return Tools.listToIndexElementPairList((List<Object>) oldCollection);
}
}
@SuppressWarnings({"unchecked"})
protected void mapToMapFromObject(Map<String, Object> data, Object changed) {
Pair<Integer, Object> indexValuePair = (Pair<Integer, Object>) changed;
elementComponentData.getComponentMapper().mapToMapFromObject(data, indexValuePair.getSecond());
indexComponentData.getComponentMapper().mapToMapFromObject(data, indexValuePair.getFirst());
}
@SuppressWarnings({"unchecked"})
protected Object getElement(Object changedObject) {
return ((Pair<Integer, Object>) changedObject).getFirst();
}
}

View File

@ -0,0 +1,82 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation;
import org.jboss.envers.entities.mapper.PropertyMapper;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.MapCollectionInitializor;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.hibernate.collection.PersistentCollection;
import java.util.Map;
import java.util.Collection;
import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
public final class MapCollectionMapper<T extends Map> extends AbstractCollectionMapper<T> implements PropertyMapper {
private final MiddleComponentData elementComponentData;
private final MiddleComponentData indexComponentData;
public MapCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
Class<? extends T> collectionClass, Class<? extends T> proxyClass,
MiddleComponentData elementComponentData, MiddleComponentData indexComponentData) {
super(commonCollectionMapperData, collectionClass, proxyClass);
this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData;
}
protected Initializor<T> getInitializor(VersionsConfiguration verCfg, VersionsReaderImplementor versionsReader,
Object primaryKey, Number revision) {
return new MapCollectionInitializor<T>(verCfg, versionsReader, commonCollectionMapperData.getQueryGenerator(),
primaryKey, revision, collectionClass, elementComponentData, indexComponentData);
}
protected Collection getNewCollectionContent(PersistentCollection newCollection) {
if (newCollection == null) {
return null;
} else {
return ((Map) newCollection).entrySet();
}
}
protected Collection getOldCollectionContent(Serializable oldCollection) {
if (oldCollection == null) {
return null;
} else {
return ((Map) oldCollection).entrySet();
}
}
protected void mapToMapFromObject(Map<String, Object> data, Object changed) {
elementComponentData.getComponentMapper().mapToMapFromObject(data, ((Map.Entry) changed).getValue());
indexComponentData.getComponentMapper().mapToMapFromObject(data, ((Map.Entry) changed).getKey());
}
protected Object getElement(Object changedObject) {
return ((Map.Entry) changedObject).getValue();
}
}

View File

@ -0,0 +1,51 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation;
import org.jboss.envers.entities.mapper.relation.component.MiddleComponentMapper;
/**
* A data holder for a middle relation component (which is either the collection element or index):
* - component mapper used to map the component to and from versions entities
* - an index, which specifies in which element of the array returned by the query for reading the collection the data
* of the component is
* @author Adam Warski (adam at warski dot org)
*/
public final class MiddleComponentData {
private final MiddleComponentMapper componentMapper;
private final int componentIndex;
public MiddleComponentData(MiddleComponentMapper componentMapper, int componentIndex) {
this.componentMapper = componentMapper;
this.componentIndex = componentIndex;
}
public MiddleComponentMapper getComponentMapper() {
return componentMapper;
}
public int getComponentIndex() {
return componentIndex;
}
}

View File

@ -0,0 +1,76 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation;
import org.jboss.envers.entities.mapper.id.IdMapper;
import org.jboss.envers.entities.IdMappingData;
import org.jboss.envers.configuration.VersionsEntitiesConfiguration;
/**
* A class holding information about ids, which form a virtual "relation" from a middle-table. Middle-tables are used
* when mapping collections.
* @author Adam Warski (adam at warski dot org)
*/
public final class MiddleIdData {
/**
* Original id mapper of the related entity.
*/
private final IdMapper originalMapper;
/**
* Prefixed id mapper (with the names for the id fields that are used in the middle table) of the related entity.
*/
private final IdMapper prefixedMapper;
/**
* Name of the related entity.
*/
private final String entityName;
/**
* Versions name of the related entity.
*/
private final String versionsEntityName;
public MiddleIdData(VersionsEntitiesConfiguration verEntCfg, IdMappingData mappingData, String prefix,
String entityName) {
this.originalMapper = mappingData.getIdMapper();
this.prefixedMapper = mappingData.getIdMapper().prefixMappedProperties(prefix);
this.entityName = entityName;
this.versionsEntityName = verEntCfg.getVersionsEntityName(entityName);
}
public IdMapper getOriginalMapper() {
return originalMapper;
}
public IdMapper getPrefixedMapper() {
return prefixedMapper;
}
public String getEntityName() {
return entityName;
}
public String getVersionsEntityName() {
return versionsEntityName;
}
}

View File

@ -0,0 +1,87 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation;
import org.jboss.envers.entities.mapper.PropertyMapper;
import org.jboss.envers.entities.mapper.PersistentCollectionChangeData;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.tools.reflection.ReflectionTools;
import org.jboss.envers.query.VersionsRestrictions;
import org.jboss.envers.exception.VersionsException;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.hibernate.property.Setter;
import org.hibernate.NonUniqueResultException;
import org.hibernate.collection.PersistentCollection;
import javax.persistence.NoResultException;
import java.util.Map;
import java.util.List;
import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class OneToOneNotOwningMapper implements PropertyMapper {
private String owningReferencePropertyName;
private String owningEntityName;
private String propertyName;
public OneToOneNotOwningMapper(String owningReferencePropertyName, String owningEntityName, String propertyName) {
this.owningReferencePropertyName = owningReferencePropertyName;
this.owningEntityName = owningEntityName;
this.propertyName = propertyName;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
return false;
}
public void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey, VersionsReaderImplementor versionsReader, Number revision) {
if (obj == null) {
return;
}
Class<?> entityClass = ReflectionTools.loadClass(owningEntityName);
Object value;
try {
value = versionsReader.createQuery().forEntitiesAtRevision(entityClass, revision)
.add(VersionsRestrictions.relatedIdEq(owningReferencePropertyName, primaryKey)).getSingleResult();
} catch (NoResultException e) {
value = null;
} catch (NonUniqueResultException e) {
throw new VersionsException("Many versions results for one-to-one relationship: (" + owningEntityName +
", " + owningReferencePropertyName + ")");
}
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyName);
setter.set(obj, value, null);
}
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
return null;
}
}

View File

@ -0,0 +1,94 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation;
import org.jboss.envers.entities.mapper.PropertyMapper;
import org.jboss.envers.entities.mapper.PersistentCollectionChangeData;
import org.jboss.envers.entities.mapper.id.IdMapper;
import org.jboss.envers.tools.Tools;
import org.jboss.envers.tools.reflection.ReflectionTools;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.entities.mapper.relation.lazy.ToOneDelegateSessionImplementor;
import org.jboss.envers.configuration.VersionsConfiguration;
import org.hibernate.property.Setter;
import org.hibernate.collection.PersistentCollection;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class ToOneIdMapper implements PropertyMapper {
private final IdMapper delegate;
private final String propertyName;
private final String referencedEntityName;
public ToOneIdMapper(IdMapper delegate, String propertyName, String referencedEntityName) {
this.delegate = delegate;
this.propertyName = propertyName;
this.referencedEntityName = referencedEntityName;
}
public boolean mapToMapFromEntity(Map<String, Object> data, Object newObj, Object oldObj) {
HashMap<String, Object> newData = new HashMap<String, Object>();
data.put(propertyName, newData);
delegate.mapToMapFromEntity(newData, newObj);
return !Tools.objectsEqual(newObj, oldObj);
}
public void mapToEntityFromMap(VersionsConfiguration verCfg, Object obj, Map data, Object primaryKey,
VersionsReaderImplementor versionsReader, Number revision) {
if (obj == null) {
return;
}
Object entityId = delegate.mapToIdFromMap((Map) data.get(propertyName));
Object value;
if (entityId == null) {
value = null;
} else {
if (versionsReader.getFirstLevelCache().contains(referencedEntityName, revision, entityId)) {
value = versionsReader.getFirstLevelCache().get(referencedEntityName, revision, entityId);
} else {
Class<?> entityClass = ReflectionTools.loadClass(referencedEntityName);
value = versionsReader.getSessionImplementor().getFactory().getEntityPersister(referencedEntityName).
createProxy(null, new ToOneDelegateSessionImplementor(versionsReader, entityClass, entityId, revision));
}
}
Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyName);
setter.set(obj, value, null);
}
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {
return null;
}
}

View File

@ -0,0 +1,63 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.component;
import org.jboss.envers.entities.EntityInstantiator;
import org.jboss.envers.tools.query.Parameters;
import java.util.Map;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface MiddleComponentMapper {
/**
* Maps from full object data, contained in the given map (or object representation of the map, if
* available), to an object.
* @param entityInstantiator An entity instatiator bound with an open versions reader.
* @param data Full object data.
* @param dataObject An optional object representation of the data.
* @param revision Revision at which the data is read.
* @return An object with data corresponding to the one found in the given map.
*/
Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<String, Object> data,
Object dataObject, Number revision);
/**
* Maps from an object to the object's map representation (for an entity - only its id).
* @param data Map to which data should be added.
* @param obj Object to map from.
*/
void mapToMapFromObject(Map<String, Object> data, Object obj);
/**
* Adds query statements, which contains restrictions, which express the property that part of the middle
* entity with alias prefix1, is equal to part of the middle entity with alias prefix2 (the entity is the same).
* The part is the component's representation in the middle entity.
* @param parameters Parameters, to which to add the statements.
* @param prefix1 First alias of the entity + prefix to add to the properties.
* @param prefix2 Second alias of the entity + prefix to add to the properties.
*/
void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2);
}

View File

@ -0,0 +1,45 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.component;
import org.jboss.envers.entities.EntityInstantiator;
import org.jboss.envers.tools.query.Parameters;
import java.util.Map;
/**
* @author Adam Warski (adam at warski dot org)
*/
public final class MiddleDummyComponentMapper implements MiddleComponentMapper {
public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<String, Object> data,
Object dataObject, Number revision) {
return null;
}
public void mapToMapFromObject(Map<String, Object> data, Object obj) {
}
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
}
}

View File

@ -0,0 +1,60 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.component;
import org.jboss.envers.entities.EntityInstantiator;
import org.jboss.envers.entities.mapper.id.IdMapper;
import org.jboss.envers.tools.query.Parameters;
import org.jboss.envers.configuration.VersionsEntitiesConfiguration;
import java.util.Map;
/**
* A component mapper for the @MapKey mapping: the value of the map's key is the id of the entity. This
* doesn't have an effect on the data stored in the versions tables, so <code>mapToMapFromObject</code> is
* empty.
* @author Adam Warski (adam at warski dot org)
*/
public final class MiddleMapKeyIdComponentMapper implements MiddleComponentMapper {
private final VersionsEntitiesConfiguration verEntCfg;
private final IdMapper relatedIdMapper;
public MiddleMapKeyIdComponentMapper(VersionsEntitiesConfiguration verEntCfg, IdMapper relatedIdMapper) {
this.verEntCfg = verEntCfg;
this.relatedIdMapper = relatedIdMapper;
}
public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<String, Object> data,
Object dataObject, Number revision) {
return relatedIdMapper.mapToIdFromMap((Map) data.get(verEntCfg.getOriginalIdPropName()));
}
public void mapToMapFromObject(Map<String, Object> data, Object obj) {
// Doing nothing.
}
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
// Doing nothing.
}
}

View File

@ -0,0 +1,58 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.component;
import org.jboss.envers.entities.EntityInstantiator;
import org.jboss.envers.tools.query.Parameters;
import org.jboss.envers.tools.reflection.ReflectionTools;
import java.util.Map;
/**
* A component mapper for the @MapKey mapping with the name parameter specified: the value of the map's key
* is a property of the entity. This doesn't have an effect on the data stored in the versions tables,
* so <code>mapToMapFromObject</code> is empty.
* @author Adam Warski (adam at warski dot org)
*/
public final class MiddleMapKeyPropertyComponentMapper implements MiddleComponentMapper {
private final String propertyName;
public MiddleMapKeyPropertyComponentMapper(String propertyName) {
this.propertyName = propertyName;
}
public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<String, Object> data,
Object dataObject, Number revision) {
// dataObject is not null, as this mapper can only be used in an index.
return ReflectionTools.getGetter(dataObject.getClass(), propertyName).get(dataObject);
}
public void mapToMapFromObject(Map<String, Object> data, Object obj) {
// Doing nothing.
}
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
// Doing nothing.
}
}

View File

@ -0,0 +1,54 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.component;
import org.jboss.envers.entities.EntityInstantiator;
import org.jboss.envers.entities.mapper.relation.MiddleIdData;
import org.jboss.envers.tools.query.Parameters;
import java.util.Map;
/**
* @author Adam Warski (adam at warski dot org)
*/
public final class MiddleRelatedComponentMapper implements MiddleComponentMapper {
private final MiddleIdData relatedIdData;
public MiddleRelatedComponentMapper(MiddleIdData relatedIdData) {
this.relatedIdData = relatedIdData;
}
public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<String, Object> data,
Object dataObject, Number revision) {
return entityInstantiator.createInstanceFromVersionsEntity(relatedIdData.getEntityName(), data, revision);
}
public void mapToMapFromObject(Map<String, Object> data, Object obj) {
relatedIdData.getPrefixedMapper().mapToMapFromEntity(data, obj);
}
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
relatedIdData.getPrefixedMapper().addIdsEqualToQuery(parameters, prefix1, prefix2);
}
}

View File

@ -0,0 +1,57 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.component;
import org.jboss.envers.entities.EntityInstantiator;
import org.jboss.envers.configuration.VersionsEntitiesConfiguration;
import org.jboss.envers.tools.query.Parameters;
import java.util.Map;
/**
* @author Adam Warski (adam at warski dot org)
*/
public final class MiddleSimpleComponentMapper implements MiddleComponentMapper {
private final String propertyName;
private final VersionsEntitiesConfiguration verEntCfg;
public MiddleSimpleComponentMapper(VersionsEntitiesConfiguration verEntCfg, String propertyName) {
this.propertyName = propertyName;
this.verEntCfg = verEntCfg;
}
@SuppressWarnings({"unchecked"})
public Object mapToObjectFromFullMap(EntityInstantiator entityInstantiator, Map<String, Object> data,
Object dataObject, Number revision) {
return ((Map<String, Object>) data.get(verEntCfg.getOriginalIdPropName())).get(propertyName);
}
public void mapToMapFromObject(Map<String, Object> data, Object obj) {
data.put(propertyName, obj);
}
public void addMiddleEqualToQuery(Parameters parameters, String prefix1, String prefix2) {
parameters.addWhere(prefix1 + "." + propertyName, false, "=", prefix2 + "." + propertyName, false);
}
}

View File

@ -0,0 +1,271 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy;
import org.hibernate.engine.*;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.*;
import org.hibernate.event.EventListeners;
import org.hibernate.type.Type;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.jdbc.Batcher;
import org.hibernate.jdbc.JDBCContext;
import org.hibernate.collection.PersistentCollection;
import java.io.Serializable;
import java.util.List;
import java.util.Iterator;
import java.util.Map;
import java.sql.Connection;
/**
* @author Adam Warski (adam at warski dot org)
*/
public abstract class AbstractDelegateSessionImplementor implements SessionImplementor {
private SessionImplementor delegate;
public AbstractDelegateSessionImplementor(SessionImplementor delegate) {
this.delegate = delegate;
}
public abstract Object doImmediateLoad(String entityName);
public Object immediateLoad(String entityName, Serializable id) throws HibernateException {
return doImmediateLoad(entityName);
}
// Delegate methods
public LoadQueryInfluencers getLoadQueryInfluencers() {
return delegate.getLoadQueryInfluencers();
}
public Interceptor getInterceptor() {
return delegate.getInterceptor();
}
public void setAutoClear(boolean enabled) {
delegate.setAutoClear(enabled);
}
public boolean isTransactionInProgress() {
return delegate.isTransactionInProgress();
}
public void initializeCollection(PersistentCollection collection, boolean writing) throws HibernateException {
delegate.initializeCollection(collection, writing);
}
public Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) throws HibernateException {
return delegate.internalLoad(entityName, id, eager, nullable);
}
public long getTimestamp() {
return delegate.getTimestamp();
}
public SessionFactoryImplementor getFactory() {
return delegate.getFactory();
}
public Batcher getBatcher() {
return delegate.getBatcher();
}
public List list(String query, QueryParameters queryParameters) throws HibernateException {
return delegate.list(query, queryParameters);
}
public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException {
return delegate.iterate(query, queryParameters);
}
public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
return delegate.scroll(query, queryParameters);
}
public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) {
return delegate.scroll(criteria, scrollMode);
}
public List list(CriteriaImpl criteria) {
return delegate.list(criteria);
}
public List listFilter(Object collection, String filter, QueryParameters queryParameters) throws HibernateException {
return delegate.listFilter(collection, filter, queryParameters);
}
public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters) throws HibernateException {
return delegate.iterateFilter(collection, filter, queryParameters);
}
public EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException {
return delegate.getEntityPersister(entityName, object);
}
public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException {
return delegate.getEntityUsingInterceptor(key);
}
public void afterTransactionCompletion(boolean successful, Transaction tx) {
delegate.afterTransactionCompletion(successful, tx);
}
public void beforeTransactionCompletion(Transaction tx) {
delegate.beforeTransactionCompletion(tx);
}
public Serializable getContextEntityIdentifier(Object object) {
return delegate.getContextEntityIdentifier(object);
}
public String bestGuessEntityName(Object object) {
return delegate.bestGuessEntityName(object);
}
public String guessEntityName(Object entity) throws HibernateException {
return delegate.guessEntityName(entity);
}
public Object instantiate(String entityName, Serializable id) throws HibernateException {
return delegate.instantiate(entityName, id);
}
public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException {
return delegate.listCustomQuery(customQuery, queryParameters);
}
public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException {
return delegate.scrollCustomQuery(customQuery, queryParameters);
}
public List list(NativeSQLQuerySpecification spec, QueryParameters queryParameters) throws HibernateException {
return delegate.list(spec, queryParameters);
}
public ScrollableResults scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters) throws HibernateException {
return delegate.scroll(spec, queryParameters);
}
public Object getFilterParameterValue(String filterParameterName) {
return delegate.getFilterParameterValue(filterParameterName);
}
public Type getFilterParameterType(String filterParameterName) {
return delegate.getFilterParameterType(filterParameterName);
}
public Map getEnabledFilters() {
return delegate.getEnabledFilters();
}
public int getDontFlushFromFind() {
return delegate.getDontFlushFromFind();
}
public EventListeners getListeners() {
return delegate.getListeners();
}
public PersistenceContext getPersistenceContext() {
return delegate.getPersistenceContext();
}
public int executeUpdate(String query, QueryParameters queryParameters) throws HibernateException {
return delegate.executeUpdate(query, queryParameters);
}
public int executeNativeUpdate(NativeSQLQuerySpecification specification, QueryParameters queryParameters) throws HibernateException {
return delegate.executeNativeUpdate(specification, queryParameters);
}
public EntityMode getEntityMode() {
return delegate.getEntityMode();
}
public CacheMode getCacheMode() {
return delegate.getCacheMode();
}
public void setCacheMode(CacheMode cm) {
delegate.setCacheMode(cm);
}
public boolean isOpen() {
return delegate.isOpen();
}
public boolean isConnected() {
return delegate.isConnected();
}
public FlushMode getFlushMode() {
return delegate.getFlushMode();
}
public void setFlushMode(FlushMode fm) {
delegate.setFlushMode(fm);
}
public Connection connection() {
return delegate.connection();
}
public void flush() {
delegate.flush();
}
public Query getNamedQuery(String name) {
return delegate.getNamedQuery(name);
}
public Query getNamedSQLQuery(String name) {
return delegate.getNamedSQLQuery(name);
}
public boolean isEventSource() {
return delegate.isEventSource();
}
public void afterScrollOperation() {
delegate.afterScrollOperation();
}
public void setFetchProfile(String name) {
delegate.setFetchProfile(name);
}
public String getFetchProfile() {
return delegate.getFetchProfile();
}
public JDBCContext getJDBCContext() {
return delegate.getJDBCContext();
}
public boolean isClosed() {
return delegate.isClosed();
}
}

View File

@ -0,0 +1,48 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy;
import org.hibernate.HibernateException;
import org.jboss.envers.reader.VersionsReaderImplementor;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class ToOneDelegateSessionImplementor extends AbstractDelegateSessionImplementor {
private final VersionsReaderImplementor versionsReader;
private final Class<?> entityClass;
private final Object entityId;
private final Number revision;
public ToOneDelegateSessionImplementor(VersionsReaderImplementor versionsReader,
Class<?> entityClass, Object entityId, Number revision) {
super(versionsReader.getSessionImplementor());
this.versionsReader = versionsReader;
this.entityClass = entityClass;
this.entityId = entityId;
this.revision = revision;
}
public Object doImmediateLoad(String entityName) throws HibernateException {
return versionsReader.find(entityClass, entityId, revision);
}
}

View File

@ -0,0 +1,72 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.initializor;
import org.jboss.envers.entities.mapper.relation.query.RelationQueryGenerator;
import org.jboss.envers.entities.EntityInstantiator;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.configuration.VersionsConfiguration;
import java.util.List;
/**
* Initializes a persistent collection.
* @author Adam Warski (adam at warski dot org)
*/
public abstract class AbstractCollectionInitializor<T> implements Initializor<T> {
private final VersionsReaderImplementor versionsReader;
private final RelationQueryGenerator queryGenerator;
private final Object primaryKey;
protected final Number revision;
protected final EntityInstantiator entityInstantiator;
public AbstractCollectionInitializor(VersionsConfiguration verCfg,
VersionsReaderImplementor versionsReader,
RelationQueryGenerator queryGenerator,
Object primaryKey, Number revision) {
this.versionsReader = versionsReader;
this.queryGenerator = queryGenerator;
this.primaryKey = primaryKey;
this.revision = revision;
entityInstantiator = new EntityInstantiator(verCfg, versionsReader);
}
protected abstract T initializeCollection(int size);
protected abstract void addToCollection(T collection, Object collectionRow);
public T initialize() {
List<?> collectionContent = queryGenerator.getQuery(versionsReader, primaryKey, revision).list();
T collection = initializeCollection(collectionContent.size());
for (Object collectionRow : collectionContent) {
addToCollection(collection, collectionRow);
}
return collection;
}
}

View File

@ -0,0 +1,70 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.initializor;
import org.jboss.envers.entities.mapper.relation.query.RelationQueryGenerator;
import org.jboss.envers.entities.mapper.relation.MiddleComponentData;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.configuration.VersionsConfiguration;
import java.util.*;
/**
* Initializes a map.
* @author Adam Warski (adam at warski dot org)
*/
public class ArrayCollectionInitializor extends AbstractCollectionInitializor<Object[]> {
private final MiddleComponentData elementComponentData;
private final MiddleComponentData indexComponentData;
public ArrayCollectionInitializor(VersionsConfiguration verCfg,
VersionsReaderImplementor versionsReader,
RelationQueryGenerator queryGenerator,
Object primaryKey, Number revision,
MiddleComponentData elementComponentData,
MiddleComponentData indexComponentData) {
super(verCfg, versionsReader, queryGenerator, primaryKey, revision);
this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData;
}
protected Object[] initializeCollection(int size) {
return new Object[size];
}
@SuppressWarnings({"unchecked"})
protected void addToCollection(Object[] collection, Object collectionRow) {
Object elementData = ((List) collectionRow).get(elementComponentData.getComponentIndex());
Object element = elementComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
(Map<String, Object>) elementData, null, revision);
Object indexData = ((List) collectionRow).get(indexComponentData.getComponentIndex());
Object indexObj = indexComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
(Map<String, Object>) indexData, element, revision);
int index = ((Number) indexObj).intValue();
collection[index] = element;
}
}

View File

@ -0,0 +1,71 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.initializor;
import org.jboss.envers.entities.mapper.relation.query.RelationQueryGenerator;
import org.jboss.envers.entities.mapper.relation.MiddleComponentData;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.exception.VersionsException;
import org.jboss.envers.configuration.VersionsConfiguration;
import java.util.*;
/**
* Initializes a non-indexed java collection (set or list, eventually sorted).
* @author Adam Warski (adam at warski dot org)
*/
public class BasicCollectionInitializor<T extends Collection> extends AbstractCollectionInitializor<T> {
private final Class<? extends T> collectionClass;
private final MiddleComponentData elementComponentData;
public BasicCollectionInitializor(VersionsConfiguration verCfg,
VersionsReaderImplementor versionsReader,
RelationQueryGenerator queryGenerator,
Object primaryKey, Number revision,
Class<? extends T> collectionClass,
MiddleComponentData elementComponentData) {
super(verCfg, versionsReader, queryGenerator, primaryKey, revision);
this.collectionClass = collectionClass;
this.elementComponentData = elementComponentData;
}
protected T initializeCollection(int size) {
try {
return collectionClass.newInstance();
} catch (InstantiationException e) {
throw new VersionsException(e);
} catch (IllegalAccessException e) {
throw new VersionsException(e);
}
}
@SuppressWarnings({"unchecked"})
protected void addToCollection(T collection, Object collectionRow) {
Object elementData = ((List) collectionRow).get(elementComponentData.getComponentIndex());
Object element = elementComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
(Map<String, Object>) elementData, null, revision);
collection.add(element);
}
}

View File

@ -0,0 +1,29 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.initializor;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface Initializor<T> {
T initialize();
}

View File

@ -0,0 +1,75 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.initializor;
import org.jboss.envers.entities.mapper.relation.query.RelationQueryGenerator;
import org.jboss.envers.entities.mapper.relation.MiddleComponentData;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.configuration.VersionsConfiguration;
import java.util.*;
/**
* Initializes a map.
* @author Adam Warski (adam at warski dot org)
*/
public class ListCollectionInitializor extends AbstractCollectionInitializor<List> {
private final MiddleComponentData elementComponentData;
private final MiddleComponentData indexComponentData;
public ListCollectionInitializor(VersionsConfiguration verCfg,
VersionsReaderImplementor versionsReader,
RelationQueryGenerator queryGenerator,
Object primaryKey, Number revision,
MiddleComponentData elementComponentData,
MiddleComponentData indexComponentData) {
super(verCfg, versionsReader, queryGenerator, primaryKey, revision);
this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData;
}
@SuppressWarnings({"unchecked"})
protected List initializeCollection(int size) {
// Creating a list of the given capacity with all elements null initially. This ensures that we can then
// fill the elements safely using the <code>List.set</code> method.
List list = new ArrayList(size);
for (int i=0; i<size; i++) { list.add(null); }
return list;
}
@SuppressWarnings({"unchecked"})
protected void addToCollection(List collection, Object collectionRow) {
Object elementData = ((List) collectionRow).get(elementComponentData.getComponentIndex());
Object element = elementComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
(Map<String, Object>) elementData, null, revision);
Object indexData = ((List) collectionRow).get(indexComponentData.getComponentIndex());
Object indexObj = indexComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
(Map<String, Object>) indexData, element, revision);
int index = ((Number) indexObj).intValue();
collection.set(index, element);
}
}

View File

@ -0,0 +1,79 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.initializor;
import org.jboss.envers.entities.mapper.relation.query.RelationQueryGenerator;
import org.jboss.envers.entities.mapper.relation.MiddleComponentData;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.exception.VersionsException;
import org.jboss.envers.configuration.VersionsConfiguration;
import java.util.*;
/**
* Initializes a map.
* @author Adam Warski (adam at warski dot org)
*/
public class MapCollectionInitializor<T extends Map> extends AbstractCollectionInitializor<T> {
private final Class<? extends T> collectionClass;
private final MiddleComponentData elementComponentData;
private final MiddleComponentData indexComponentData;
public MapCollectionInitializor(VersionsConfiguration verCfg,
VersionsReaderImplementor versionsReader,
RelationQueryGenerator queryGenerator,
Object primaryKey, Number revision,
Class<? extends T> collectionClass,
MiddleComponentData elementComponentData,
MiddleComponentData indexComponentData) {
super(verCfg, versionsReader, queryGenerator, primaryKey, revision);
this.collectionClass = collectionClass;
this.elementComponentData = elementComponentData;
this.indexComponentData = indexComponentData;
}
protected T initializeCollection(int size) {
try {
return collectionClass.newInstance();
} catch (InstantiationException e) {
throw new VersionsException(e);
} catch (IllegalAccessException e) {
throw new VersionsException(e);
}
}
@SuppressWarnings({"unchecked"})
protected void addToCollection(T collection, Object collectionRow) {
Object elementData = ((List) collectionRow).get(elementComponentData.getComponentIndex());
Object element = elementComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
(Map<String, Object>) elementData, null, revision);
Object indexData = ((List) collectionRow).get(indexComponentData.getComponentIndex());
Object index = indexComponentData.getComponentMapper().mapToObjectFromFullMap(entityInstantiator,
(Map<String, Object>) indexData, element, revision);
collection.put(index, element);
}
}

View File

@ -0,0 +1,129 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.proxy;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
import java.util.Collection;
import java.util.Iterator;
/**
* @author Adam Warski (adam at warski dot org)
*/
public abstract class CollectionProxy<U, T extends Collection<U>> implements Collection<U> {
private org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor<T> initializor;
protected T delegate;
public CollectionProxy(Initializor<T> initializor) {
this.initializor = initializor;
}
protected void checkInit() {
if (delegate == null) {
delegate = initializor.initialize();
}
}
public int size() {
checkInit();
return delegate.size();
}
public boolean isEmpty() {
checkInit();
return delegate.isEmpty();
}
public boolean contains(Object o) {
checkInit();
return delegate.contains(o);
}
public Iterator<U> iterator() {
checkInit();
return delegate.iterator();
}
public Object[] toArray() {
checkInit();
return delegate.toArray();
}
public <V> V[] toArray(V[] a) {
checkInit();
return delegate.toArray(a);
}
public boolean add(U o) {
checkInit();
return delegate.add(o);
}
public boolean remove(Object o) {
checkInit();
return delegate.remove(o);
}
public boolean containsAll(Collection<?> c) {
checkInit();
return delegate.containsAll(c);
}
public boolean addAll(Collection<? extends U> c) {
checkInit();
return delegate.addAll(c);
}
public boolean removeAll(Collection<?> c) {
checkInit();
return delegate.removeAll(c);
}
public boolean retainAll(Collection<?> c) {
checkInit();
return delegate.retainAll(c);
}
public void clear() {
checkInit();
delegate.clear();
}
@Override
public String toString() {
checkInit();
return delegate.toString();
}
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"})
@Override
public boolean equals(Object obj) {
checkInit();
return delegate.equals(obj);
}
@Override
public int hashCode() {
checkInit();
return delegate.hashCode();
}
}

View File

@ -0,0 +1,85 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.proxy;
import java.util.List;
import java.util.Collection;
import java.util.ListIterator;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class ListProxy<U> extends CollectionProxy<U, List<U>> implements List<U> {
public ListProxy(org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor<List<U>> initializor) {
super(initializor);
}
public boolean addAll(int index, Collection<? extends U> c) {
checkInit();
return delegate.addAll(index, c);
}
public U get(int index) {
checkInit();
return delegate.get(index);
}
public U set(int index, U element) {
checkInit();
return delegate.set(index, element);
}
public void add(int index, U element) {
checkInit();
delegate.add(index, element);
}
public U remove(int index) {
checkInit();
return delegate.remove(index);
}
public int indexOf(Object o) {
checkInit();
return delegate.indexOf(o);
}
public int lastIndexOf(Object o) {
checkInit();
return delegate.lastIndexOf(o);
}
public ListIterator<U> listIterator() {
checkInit();
return delegate.listIterator();
}
public ListIterator<U> listIterator(int index) {
checkInit();
return delegate.listIterator(index);
}
public List<U> subList(int fromIndex, int toIndex) {
checkInit();
return delegate.subList(fromIndex, toIndex);
}
}

View File

@ -0,0 +1,127 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.proxy;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class MapProxy<K, V> implements Map<K, V> {
private Initializor<Map<K, V>> initializor;
protected Map<K, V> delegate;
public MapProxy(org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor<Map<K, V>> initializor) {
this.initializor = initializor;
}
private void checkInit() {
if (delegate == null) {
delegate = initializor.initialize();
}
}
public int size() {
checkInit();
return delegate.size();
}
public boolean isEmpty() {
checkInit();
return delegate.isEmpty();
}
public boolean containsKey(Object o) {
checkInit();
return delegate.containsKey(o);
}
public boolean containsValue(Object o) {
checkInit();
return delegate.containsValue(o);
}
public V get(Object o) {
checkInit();
return delegate.get(o);
}
public V put(K k, V v) {
checkInit();
return delegate.put(k, v);
}
public V remove(Object o) {
checkInit();
return delegate.remove(o);
}
public void putAll(Map<? extends K, ? extends V> map) {
checkInit();
delegate.putAll(map);
}
public void clear() {
checkInit();
delegate.clear();
}
public Set<K> keySet() {
checkInit();
return delegate.keySet();
}
public Collection<V> values() {
checkInit();
return delegate.values();
}
public Set<Entry<K, V>> entrySet() {
checkInit();
return delegate.entrySet();
}
@Override
public String toString() {
checkInit();
return delegate.toString();
}
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"})
@Override
public boolean equals(Object obj) {
checkInit();
return delegate.equals(obj);
}
@Override
public int hashCode() {
checkInit();
return delegate.hashCode();
}
}

View File

@ -0,0 +1,33 @@
/*
* Envers. http://www.jboss.org/envers
*
* Copyright 2008 Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.proxy;
import java.util.Set;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class SetProxy<U> extends CollectionProxy<U, Set<U>> implements Set<U> {
public SetProxy(org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor<Set<U>> initializor) {
super(initializor);
}
}

View File

@ -0,0 +1,147 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.proxy;
import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
import java.util.*;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class SortedMapProxy<K, V> implements SortedMap<K, V> {
private Initializor<SortedMap<K, V>> initializor;
protected SortedMap<K, V> delegate;
public SortedMapProxy(org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor<SortedMap<K, V>> initializor) {
this.initializor = initializor;
}
private void checkInit() {
if (delegate == null) {
delegate = initializor.initialize();
}
}
public int size() {
checkInit();
return delegate.size();
}
public boolean isEmpty() {
checkInit();
return delegate.isEmpty();
}
public boolean containsKey(Object o) {
checkInit();
return delegate.containsKey(o);
}
public boolean containsValue(Object o) {
checkInit();
return delegate.containsValue(o);
}
public V get(Object o) {
checkInit();
return delegate.get(o);
}
public V put(K k, V v) {
checkInit();
return delegate.put(k, v);
}
public V remove(Object o) {
checkInit();
return delegate.remove(o);
}
public void putAll(Map<? extends K, ? extends V> map) {
checkInit();
delegate.putAll(map);
}
public void clear() {
checkInit();
delegate.clear();
}
public Set<K> keySet() {
checkInit();
return delegate.keySet();
}
public Collection<V> values() {
checkInit();
return delegate.values();
}
public Set<Entry<K, V>> entrySet() {
checkInit();
return delegate.entrySet();
}
public Comparator<? super K> comparator() {
checkInit();
return delegate.comparator();
}
public SortedMap<K, V> subMap(K k, K k1) {
checkInit();
return delegate.subMap(k, k1);
}
public SortedMap<K, V> headMap(K k) {
checkInit();
return delegate.headMap(k);
}
public SortedMap<K, V> tailMap(K k) {
checkInit();
return delegate.tailMap(k);
}
public K firstKey() {
checkInit();
return delegate.firstKey();
}
public K lastKey() {
checkInit();
return delegate.lastKey();
}
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"})
public boolean equals(Object o) {
checkInit();
return delegate.equals(o);
}
public int hashCode() {
checkInit();
return delegate.hashCode();
}
}

View File

@ -0,0 +1,66 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.lazy.proxy;
import java.util.SortedSet;
import java.util.Comparator;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class SortedSetProxy<U> extends CollectionProxy<U, SortedSet<U>> implements SortedSet<U> {
public SortedSetProxy(org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor<SortedSet<U>> initializor) {
super(initializor);
}
public Comparator<? super U> comparator() {
checkInit();
return delegate.comparator();
}
public SortedSet<U> subSet(U u, U u1) {
checkInit();
return delegate.subSet(u, u1);
}
public SortedSet<U> headSet(U u) {
checkInit();
return delegate.headSet(u);
}
public SortedSet<U> tailSet(U u) {
checkInit();
return delegate.tailSet(u);
}
public U first() {
checkInit();
return delegate.first();
}
public U last() {
checkInit();
return delegate.last();
}
}

View File

@ -0,0 +1,107 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.query;
import org.jboss.envers.entities.mapper.relation.MiddleIdData;
import org.jboss.envers.entities.mapper.relation.MiddleComponentData;
import org.jboss.envers.entities.mapper.id.QueryParameterData;
import org.jboss.envers.configuration.VersionsEntitiesConfiguration;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.RevisionType;
import org.jboss.envers.tools.query.QueryBuilder;
import org.jboss.envers.tools.query.Parameters;
import org.hibernate.Query;
import java.util.Collections;
/**
* Selects data from a relation middle-table only.
* @author Adam Warski (adam at warski dot org)
*/
public final class OneEntityQueryGenerator implements RelationQueryGenerator {
private final String queryString;
private final MiddleIdData referencingIdData;
public OneEntityQueryGenerator(VersionsEntitiesConfiguration verEntCfg,
String versionsMiddleEntityName,
MiddleIdData referencingIdData,
MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData;
/*
* The query that we need to create:
* SELECT new list(ee) FROM middleEntity ee WHERE
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
* ee.originalId.id_ref_ing = :id_ref_ing AND
* (the association at revision :revision)
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*) AND
* (only non-deleted entities and associations)
* ee.revision_type != DEL
*/
String revisionPropertyPath = verEntCfg.getRevisionPropPath();
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
// SELECT new list(ee) FROM middleEntity ee
QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, "ee");
qb.addProjection("new list", "ee", false, false);
// WHERE
Parameters rootParameters = qb.getRootParameters();
// ee.originalId.id_ref_ing = :id_ref_ing
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
// SELECT max(ee2.revision) FROM middleEntity ee2
QueryBuilder maxRevQb = qb.newSubQueryBuilder(versionsMiddleEntityName, "ee2");
maxRevQb.addProjection("max", revisionPropertyPath, false);
// WHERE
Parameters maxRevQbParameters = maxRevQb.getRootParameters();
// ee2.revision <= :revision
maxRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
// ee2.originalId.* = ee.originalId.*
String eeOriginalIdPropertyPath = "ee." + originalIdPropertyName;
String ee2OriginalIdPropertyPath = "ee2." + originalIdPropertyName;
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
for (MiddleComponentData componentData : componentDatas) {
componentData.getComponentMapper().addMiddleEqualToQuery(maxRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
}
// ee.revision = (SELECT max(...) ...)
rootParameters.addWhere(revisionPropertyPath, "=", maxRevQb);
// ee.revision_type != DEL
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap());
queryString = sb.toString();
}
public Query getQuery(VersionsReaderImplementor versionsReader, Object primaryKey, Number revision) {
Query query = versionsReader.getSession().createQuery(queryString);
query.setParameter("revision", revision);
query.setParameter("delrevisiontype", RevisionType.DEL);
for (QueryParameterData paramData: referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
paramData.setParameterValue(query);
}
return query;
}
}

View File

@ -0,0 +1,109 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.query;
import org.jboss.envers.entities.mapper.id.QueryParameterData;
import org.jboss.envers.entities.mapper.id.IdMapper;
import org.jboss.envers.entities.mapper.relation.MiddleIdData;
import org.jboss.envers.configuration.VersionsEntitiesConfiguration;
import org.jboss.envers.configuration.GlobalConfiguration;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.RevisionType;
import org.jboss.envers.tools.query.QueryBuilder;
import org.jboss.envers.tools.query.Parameters;
import org.hibernate.Query;
import java.util.Collections;
/**
* Selects data from a versions entity.
* @author Adam Warski (adam at warski dot org)
*/
public final class OneVersionsEntityQueryGenerator implements RelationQueryGenerator {
private final String queryString;
private final MiddleIdData referencingIdData;
public OneVersionsEntityQueryGenerator(GlobalConfiguration globalCfg, VersionsEntitiesConfiguration verEntCfg,
MiddleIdData referencingIdData, String referencedEntityName,
IdMapper referencedIdMapper) {
this.referencingIdData = referencingIdData;
/*
* The query that we need to create:
* SELECT new list(e) FROM versionsReferencedEntity e
* WHERE
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
* e.id_ref_ing = :id_ref_ing AND
* (selecting e entities at revision :revision)
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
* WHERE e2.revision <= :revision AND e2.id = e.id) AND
* (only non-deleted entities)
* e.revision_type != DEL
*/
String revisionPropertyPath = verEntCfg.getRevisionPropPath();
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
String versionsReferencedEntityName = verEntCfg.getVersionsEntityName(referencedEntityName);
// SELECT new list(e) FROM versionsEntity e
QueryBuilder qb = new QueryBuilder(versionsReferencedEntityName, "e");
qb.addProjection("new list", "e", false, false);
// WHERE
Parameters rootParameters = qb.getRootParameters();
// e.id_ref_ed = :id_ref_ed
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, null, true);
// SELECT max(e.revision) FROM versionsReferencedEntity e2
QueryBuilder maxERevQb = qb.newSubQueryBuilder(versionsReferencedEntityName, "e2");
maxERevQb.addProjection("max", revisionPropertyPath, false);
// WHERE
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
// e2.revision <= :revision
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
// e2.id = e.id
referencedIdMapper.addIdsEqualToQuery(maxERevQbParameters,
"e." + originalIdPropertyName, "e2." + originalIdPropertyName);
// e.revision = (SELECT max(...) ...)
rootParameters.addWhere(revisionPropertyPath, false, globalCfg.getCorrelatedSubqueryOperator(), maxERevQb);
// e.revision_type != DEL
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), false, "!=", "delrevisiontype");
StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap());
queryString = sb.toString();
}
public Query getQuery(VersionsReaderImplementor versionsReader, Object primaryKey, Number revision) {
Query query = versionsReader.getSession().createQuery(queryString);
query.setParameter("revision", revision);
query.setParameter("delrevisiontype", RevisionType.DEL);
for (QueryParameterData paramData: referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
paramData.setParameterValue(query);
}
return query;
}
}

View File

@ -0,0 +1,75 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.query;
import org.jboss.envers.tools.query.QueryBuilder;
import org.jboss.envers.tools.query.Parameters;
import org.jboss.envers.entities.mapper.relation.MiddleIdData;
import org.jboss.envers.entities.mapper.relation.MiddleComponentData;
import org.jboss.envers.configuration.GlobalConfiguration;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class QueryGeneratorTools {
public static void addEntityAtRevision(GlobalConfiguration globalCfg, QueryBuilder qb, Parameters rootParameters,
MiddleIdData idData, String revisionPropertyPath, String originalIdPropertyName,
String alias1, String alias2) {
// SELECT max(e.revision) FROM versionsReferencedEntity e2
QueryBuilder maxERevQb = qb.newSubQueryBuilder(idData.getVersionsEntityName(), alias2);
maxERevQb.addProjection("max", revisionPropertyPath, false);
// WHERE
Parameters maxERevQbParameters = maxERevQb.getRootParameters();
// e2.revision <= :revision
maxERevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
// e2.id_ref_ed = e.id_ref_ed
idData.getOriginalMapper().addIdsEqualToQuery(maxERevQbParameters,
alias1 + "." + originalIdPropertyName, alias2 +"." + originalIdPropertyName);
// e.revision = (SELECT max(...) ...)
rootParameters.addWhere("e." + revisionPropertyPath, false, globalCfg.getCorrelatedSubqueryOperator(), maxERevQb);
}
public static void addAssociationAtRevision(QueryBuilder qb, Parameters rootParameters,
MiddleIdData referencingIdData, String versionsMiddleEntityName,
String eeOriginalIdPropertyPath, String revisionPropertyPath,
String originalIdPropertyName, MiddleComponentData... componentDatas) {
// SELECT max(ee2.revision) FROM middleEntity ee2
QueryBuilder maxEeRevQb = qb.newSubQueryBuilder(versionsMiddleEntityName, "ee2");
maxEeRevQb.addProjection("max", revisionPropertyPath, false);
// WHERE
Parameters maxEeRevQbParameters = maxEeRevQb.getRootParameters();
// ee2.revision <= :revision
maxEeRevQbParameters.addWhereWithNamedParam(revisionPropertyPath, "<=", "revision");
// ee2.originalId.* = ee.originalId.*
String ee2OriginalIdPropertyPath = "ee2." + originalIdPropertyName;
referencingIdData.getPrefixedMapper().addIdsEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
for (MiddleComponentData componentData : componentDatas) {
componentData.getComponentMapper().addMiddleEqualToQuery(maxEeRevQbParameters, eeOriginalIdPropertyPath, ee2OriginalIdPropertyPath);
}
// ee.revision = (SELECT max(...) ...)
rootParameters.addWhere(revisionPropertyPath, "=", maxEeRevQb);
}
}

View File

@ -0,0 +1,37 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.query;
import org.hibernate.Query;
import org.jboss.envers.reader.VersionsReaderImplementor;
/**
* Implementations of this interface provide a method to generate queries on a relation table (a table used
* for mapping relations). The query can select, apart from selecting the content of the relation table, also data of
* other "related" entities.
* @author Adam Warski (adam at warski dot org)
*/
public interface RelationQueryGenerator {
Query getQuery(VersionsReaderImplementor versionsReader, Object primaryKey, Number revision);
}

View File

@ -0,0 +1,135 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
*
* See the copyright.txt in the distribution for a full listing of individual
* contributors. 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, v. 2.1.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT A 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, v.2.1 along with this distribution; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Red Hat Author(s): Adam Warski
*/
package org.jboss.envers.entities.mapper.relation.query;
import org.jboss.envers.entities.mapper.id.QueryParameterData;
import org.jboss.envers.entities.mapper.relation.MiddleIdData;
import org.jboss.envers.entities.mapper.relation.MiddleComponentData;
import org.jboss.envers.configuration.VersionsEntitiesConfiguration;
import org.jboss.envers.configuration.GlobalConfiguration;
import org.jboss.envers.reader.VersionsReaderImplementor;
import org.jboss.envers.RevisionType;
import org.jboss.envers.tools.query.QueryBuilder;
import org.jboss.envers.tools.query.Parameters;
import org.hibernate.Query;
import java.util.Collections;
/**
* Selects data from a relation middle-table and a two related versions entity.
* @author Adam Warski (adam at warski dot org)
*/
public final class ThreeEntityQueryGenerator implements RelationQueryGenerator {
private final String queryString;
private final MiddleIdData referencingIdData;
public ThreeEntityQueryGenerator(GlobalConfiguration globalCfg,
VersionsEntitiesConfiguration verEntCfg,
String versionsMiddleEntityName,
MiddleIdData referencingIdData,
MiddleIdData referencedIdData,
MiddleIdData indexIdData,
MiddleComponentData... componentDatas) {
this.referencingIdData = referencingIdData;
/*
* The query that we need to create:
* SELECT new list(ee, e, f) FROM versionsReferencedEntity e, versionsIndexEntity f, middleEntity ee
* WHERE
* (entities referenced by the middle table; id_ref_ed = id of the referenced entity)
* ee.id_ref_ed = e.id_ref_ed AND
* (entities referenced by the middle table; id_ref_ind = id of the index entity)
* ee.id_ref_ind = f.id_ref_ind AND
* (only entities referenced by the association; id_ref_ing = id of the referencing entity)
* ee.id_ref_ing = :id_ref_ing AND
* (selecting e entities at revision :revision)
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
* WHERE e2.revision <= :revision AND e2.id_ref_ed = e.id_ref_ed) AND
* (selecting f entities at revision :revision)
* f.revision = (SELECT max(f2.revision) FROM versionsIndexEntity f2
* WHERE f2.revision <= :revision AND f2.id_ref_ed = f.id_ref_ed) AND
* (the association at revision :revision)
* ee.revision = (SELECT max(ee2.revision) FROM middleEntity ee2
* WHERE ee2.revision <= :revision AND ee2.originalId.* = ee.originalId.*) AND
* (only non-deleted entities and associations)
* ee.revision_type != DEL AND
* e.revision_type != DEL AND
* f.revision_type != DEL
*/
String revisionPropertyPath = verEntCfg.getRevisionPropPath();
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
String eeOriginalIdPropertyPath = "ee." + originalIdPropertyName;
// SELECT new list(ee) FROM middleEntity ee
QueryBuilder qb = new QueryBuilder(versionsMiddleEntityName, "ee");
qb.addFrom(referencedIdData.getVersionsEntityName(), "e");
qb.addFrom(indexIdData.getVersionsEntityName(), "f");
qb.addProjection("new list", "ee, e, f", false, false);
// WHERE
Parameters rootParameters = qb.getRootParameters();
// ee.id_ref_ed = e.id_ref_ed
referencedIdData.getPrefixedMapper().addIdsEqualToQuery(rootParameters, eeOriginalIdPropertyPath,
referencedIdData.getOriginalMapper(), "e." + originalIdPropertyName);
// ee.id_ref_ind = f.id_ref_ind
indexIdData.getPrefixedMapper().addIdsEqualToQuery(rootParameters, eeOriginalIdPropertyPath,
indexIdData.getOriginalMapper(), "f." + originalIdPropertyName);
// ee.originalId.id_ref_ing = :id_ref_ing
referencingIdData.getPrefixedMapper().addNamedIdEqualsToQuery(rootParameters, originalIdPropertyName, true);
// e.revision = (SELECT max(...) ...)
QueryGeneratorTools.addEntityAtRevision(globalCfg, qb, rootParameters, referencedIdData, revisionPropertyPath,
originalIdPropertyName, "e", "e2");
// f.revision = (SELECT max(...) ...)
QueryGeneratorTools.addEntityAtRevision(globalCfg, qb, rootParameters, indexIdData, revisionPropertyPath,
originalIdPropertyName, "f", "f2");
// ee.revision = (SELECT max(...) ...)
QueryGeneratorTools.addAssociationAtRevision(qb, rootParameters, referencingIdData, versionsMiddleEntityName,
eeOriginalIdPropertyPath, revisionPropertyPath, originalIdPropertyName, componentDatas);
// ee.revision_type != DEL
rootParameters.addWhereWithNamedParam(verEntCfg.getRevisionTypePropName(), "!=", "delrevisiontype");
// e.revision_type != DEL
rootParameters.addWhereWithNamedParam("e." + verEntCfg.getRevisionTypePropName(), false, "!=", "delrevisiontype");
// f.revision_type != DEL
rootParameters.addWhereWithNamedParam("f." + verEntCfg.getRevisionTypePropName(), false, "!=", "delrevisiontype");
StringBuilder sb = new StringBuilder();
qb.build(sb, Collections.<String, Object>emptyMap());
queryString = sb.toString();
}
public Query getQuery(VersionsReaderImplementor versionsReader, Object primaryKey, Number revision) {
Query query = versionsReader.getSession().createQuery(queryString);
query.setParameter("revision", revision);
query.setParameter("delrevisiontype", RevisionType.DEL);
for (QueryParameterData paramData: referencingIdData.getPrefixedMapper().mapToQueryParametersFromId(primaryKey)) {
paramData.setParameterValue(query);
}
return query;
}
}

Some files were not shown because too many files have changed in this diff Show More