alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (FakeBidirectionalRelationWorkUnit.java)

This example Hibernate source code file (FakeBidirectionalRelationWorkUnit.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

auditconfiguration, auditworkunit, auditworkunit, fakebidirectionalrelationworkunit, fakerelationchange, fakerelationchange, hashmap, io, map, map, object, object, relationdescription, revisiontype, string, util

The Hibernate FakeBidirectionalRelationWorkUnit.java source code

package org.hibernate.envers.synchronization.work;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.RelationDescription;

/**
 * A work unit that handles "fake" bidirectional one-to-many relations (mapped with {@code @OneToMany+@JoinColumn} and
 * {@code @ManyToOne+@Column(insertable=false, updatable=false)}.
 * @author Adam Warski (adam at warski dot org)
 */
public class FakeBidirectionalRelationWorkUnit extends AbstractAuditWorkUnit implements AuditWorkUnit {
    private final Map<String, FakeRelationChange> fakeRelationChanges;

    /*
     * The work unit responsible for generating the "raw" entity data to be saved.
     */
    private final AuditWorkUnit nestedWorkUnit;

    public FakeBidirectionalRelationWorkUnit(SessionImplementor sessionImplementor, String entityName,
                                             AuditConfiguration verCfg, Serializable id,
                                             String referencingPropertyName, Object owningEntity,
                                             RelationDescription rd, RevisionType revisionType,
                                             Object index,
                                             AuditWorkUnit nestedWorkUnit) {
        super(sessionImplementor, entityName, verCfg, id, revisionType);
        this.nestedWorkUnit = nestedWorkUnit;

        // Adding the change for the relation.
        fakeRelationChanges = new HashMap<String, FakeRelationChange>();
        fakeRelationChanges.put(referencingPropertyName, new FakeRelationChange(owningEntity, rd, revisionType, index));
    }

    public FakeBidirectionalRelationWorkUnit(FakeBidirectionalRelationWorkUnit original,
                                             Map<String, FakeRelationChange> fakeRelationChanges,
                                             AuditWorkUnit nestedWorkUnit) {
        super(original.sessionImplementor, original.entityName, original.verCfg, original.id, original.revisionType);

        this.fakeRelationChanges = fakeRelationChanges;
        this.nestedWorkUnit = nestedWorkUnit;
    }

    public FakeBidirectionalRelationWorkUnit(FakeBidirectionalRelationWorkUnit original, AuditWorkUnit nestedWorkUnit) {
        super(original.sessionImplementor, original.entityName, original.verCfg, original.id, original.revisionType);

        this.nestedWorkUnit = nestedWorkUnit;

        fakeRelationChanges = new HashMap<String, FakeRelationChange>(original.getFakeRelationChanges());
    }

    public AuditWorkUnit getNestedWorkUnit() {
        return nestedWorkUnit;
    }

    public Map<String, FakeRelationChange> getFakeRelationChanges() {
        return fakeRelationChanges;
    }

    public boolean containsWork() {
        return true;
    }

    public Map<String, Object> generateData(Object revisionData) {
        // Generating data with the nested work unit. This data contains all data except the fake relation.
        // Making a defensive copy not to modify the data held by the nested work unit.
        Map<String, Object> nestedData = new HashMap(nestedWorkUnit.generateData(revisionData));

        // Now adding data for all fake relations.
        for (FakeRelationChange fakeRelationChange : fakeRelationChanges.values()) {
            fakeRelationChange.generateData(sessionImplementor, nestedData);
        }

        return nestedData;
    }

    public AuditWorkUnit merge(AddWorkUnit second) {
        return merge(this, nestedWorkUnit, second);
    }

    public AuditWorkUnit merge(ModWorkUnit second) {
        return merge(this, nestedWorkUnit, second);
    }

    public AuditWorkUnit merge(DelWorkUnit second) {
        return second;
    }

    public AuditWorkUnit merge(CollectionChangeWorkUnit second) {
        return this;
    }

    public AuditWorkUnit merge(FakeBidirectionalRelationWorkUnit second) {
        // First merging the nested work units.
        AuditWorkUnit mergedNested = second.getNestedWorkUnit().dispatch(nestedWorkUnit);

        // Now merging the fake relation changes from both work units.
        Map<String, FakeRelationChange> secondFakeRelationChanges = second.getFakeRelationChanges();
        Map<String, FakeRelationChange> mergedFakeRelationChanges = new HashMap();
        Set<String> allPropertyNames = new HashSet(fakeRelationChanges.keySet());
        allPropertyNames.addAll(secondFakeRelationChanges.keySet());

        for (String propertyName : allPropertyNames) {
            mergedFakeRelationChanges.put(propertyName,
                    FakeRelationChange.merge(
                            fakeRelationChanges.get(propertyName),
                            secondFakeRelationChanges.get(propertyName)));
        }

        return new FakeBidirectionalRelationWorkUnit(this, mergedFakeRelationChanges, mergedNested);
    }

    public AuditWorkUnit dispatch(WorkUnitMergeVisitor first) {
        return first.merge(this);
    }

    public static AuditWorkUnit merge(FakeBidirectionalRelationWorkUnit frwu, AuditWorkUnit nestedFirst,
                                    AuditWorkUnit nestedSecond) {
        AuditWorkUnit nestedMerged = nestedSecond.dispatch(nestedFirst);

        // Creating a new fake relation work unit with the nested merged data
        return new FakeBidirectionalRelationWorkUnit(frwu, nestedMerged);
    }

    /**
     * Describes a change to a single fake bidirectional relation.
     */
    private static class FakeRelationChange {
        private final Object owningEntity;
        private final RelationDescription rd;
        private final RevisionType revisionType;
        private final Object index;

        public FakeRelationChange(Object owningEntity, RelationDescription rd, RevisionType revisionType,
                                  Object index) {
            this.owningEntity = owningEntity;
            this.rd = rd;
            this.revisionType = revisionType;
            this.index = index;
        }

        public RevisionType getRevisionType() {
            return revisionType;
        }

        public void generateData(SessionImplementor sessionImplementor, Map<String, Object> data) {
            // If the revision type is "DEL", it means that the object is removed from the collection. Then the
            // new owner will in fact be null.
            rd.getFakeBidirectionalRelationMapper().mapToMapFromEntity(sessionImplementor, data,
                    revisionType == RevisionType.DEL ? null : owningEntity, null);

            // Also mapping the index, if the collection is indexed.
            if (rd.getFakeBidirectionalRelationIndexMapper() != null) {
                rd.getFakeBidirectionalRelationIndexMapper().mapToMapFromEntity(sessionImplementor, data,
                        revisionType == RevisionType.DEL ? null : index, null);
            }
        }

        public static FakeRelationChange merge(FakeRelationChange first, FakeRelationChange second) {
            if (first == null) { return second; }
            if (second == null) { return first; }

            /*
             * The merging rules are the following (revision types of the first and second changes):
             * - DEL, DEL - return any (the work units are the same)
             * - DEL, ADD - return ADD (points to new owner)
             * - ADD, DEL - return ADD (points to new owner)
             * - ADD, ADD - return second (points to newer owner)
             */
            if (first.getRevisionType() == RevisionType.DEL || second.getRevisionType() == RevisionType.ADD) {
                return second;
            } else {
                return first;
            }
        }
    }
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate FakeBidirectionalRelationWorkUnit.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.