All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.permazen.change.ChangeCopier Maven / Gradle / Ivy

There is a newer version: 5.1.0
Show newest version

/*
 * Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
 */

package io.permazen.change;

import com.google.common.base.Preconditions;

import io.permazen.CopyState;
import io.permazen.JObject;
import io.permazen.JTransaction;
import io.permazen.core.ObjId;

/**
 * Creates a new {@link Change} object based on an existing one where the {@link JObject}s referred to by the
 * new {@link Change} are copies in a different transaction of the originals. This is useful to allow database
 * change information to be accessed after the transaction in which the change occured has completed.
 *
 * 

* Each instance has an internal {@link CopyState} used to avoid redundant copies, accessible via {@link #getCopyState}. */ public class ChangeCopier implements ChangeSwitch> { protected final JTransaction dest; protected final String cascadeName; protected final int recursionLimit; protected CopyState copyState = new CopyState(); /** * Non-cascading constructor. * *

* Equivalent to: {@code ChangeCopier(dest, null, 0)}. * * @param dest destination transaction for copied {@link JObject}s * @throws IllegalArgumentException if {@code dest} is null */ public ChangeCopier(JTransaction dest) { this(dest, null, 0); } /** * Primary constructor. * * @param dest destination transaction for copied {@link JObject}s * @param cascadeName cascade to use when copying objects, or null to not cascade * @param recursionLimit the maximum number of references to hop through, or -1 for infinity * @throws IllegalArgumentException if {@code recursionLimit} is less that -1 * @throws IllegalArgumentException if {@code dest} is null */ public ChangeCopier(JTransaction dest, String cascadeName, int recursionLimit) { Preconditions.checkArgument(dest != null, "null dest"); Preconditions.checkArgument(recursionLimit >= -1, "recursionLimit < -1"); this.dest = dest; this.cascadeName = cascadeName; this.recursionLimit = recursionLimit; } /** * "Snapshot" constructor for when the destination transaction is the "snapshot" transaction of the transaction * associated with the current thread and no copy cascade is needed * *

* This is a convenience constructor, equivalent to: *

* ChangeCopier(JTransaction.getCurrent().getSnapshotTransaction()) *
* * @throws IllegalStateException if this is not a snapshot instance and there is no {@link JTransaction} * associated with the current thread */ public ChangeCopier() { this(JTransaction.getCurrent().getSnapshotTransaction()); } /** * "Snapshot" constructor for when the destination transaction is the "snapshot" transaction of the transaction * associated with the current thread. * *

* This is a convenience constructor, equivalent to: *

* ChangeCopier(JTransaction.getCurrent().getSnapshotTransaction(), cascadeName, recursionLimit) *
* * @param cascadeName cascade to use when copying objects, or null to not cascade * @param recursionLimit the maximum number of cascaded references to traverse, or -1 for infinity * @throws IllegalArgumentException if {@code recursionLimit} is less that -1 * @throws IllegalStateException if this is not a snapshot instance and there is no {@link JTransaction} * associated with the current thread */ public ChangeCopier(String cascadeName, int recursionLimit) { this(JTransaction.getCurrent().getSnapshotTransaction(), cascadeName, recursionLimit); } /** * Get the destination transaction configured in this instance. * * @return destination transaction */ public JTransaction getDestinationTransaction() { return this.dest; } /** * Get the configured cascade name, if any. * * @return configured cascade name, or null if none */ public String getCascadeName() { return this.cascadeName; } /** * Set the {@link CopyState} used by this instance. * * @param copyState copy state * @throws IllegalArgumentException if {@code copyState} is null */ public void setCopyState(CopyState copyState) { this.copyState = copyState; } /** * Get the {@link CopyState} used by this instance. * * @return associated copy state */ public CopyState getCopyState() { return this.copyState; } @Override public ObjectCreate caseObjectCreate(ObjectCreate change) { return new ObjectCreate<>(this.copyIfReference(change.getObject())); } @Override public ObjectDelete caseObjectDelete(ObjectDelete change) { return new ObjectDelete<>(this.copyIfReference(change.getObject())); } @Override public ListFieldAdd caseListFieldAdd(ListFieldAdd change) { return new ListFieldAdd<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(), change.getIndex(), this.copyIfReference(change.getElement())); } @Override public ListFieldClear caseListFieldClear(ListFieldClear change) { return new ListFieldClear<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName()); } @Override public ListFieldRemove caseListFieldRemove(ListFieldRemove change) { return new ListFieldRemove<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(), change.getIndex(), this.copyIfReference(change.getElement())); } @Override public ListFieldReplace caseListFieldReplace(ListFieldReplace change) { return new ListFieldReplace<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(), change.getIndex(), this.copyIfReference(change.getOldValue()), this.copyIfReference(change.getNewValue())); } @Override public MapFieldAdd caseMapFieldAdd(MapFieldAdd change) { return new MapFieldAdd<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(), this.copyIfReference(change.getKey()), this.copyIfReference(change.getValue())); } @Override public MapFieldClear caseMapFieldClear(MapFieldClear change) { return new MapFieldClear<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName()); } @Override public MapFieldRemove caseMapFieldRemove(MapFieldRemove change) { return new MapFieldRemove<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(), this.copyIfReference(change.getKey()), this.copyIfReference(change.getValue())); } @Override public MapFieldReplace caseMapFieldReplace(MapFieldReplace change) { return new MapFieldReplace<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(), this.copyIfReference(change.getKey()), this.copyIfReference(change.getOldValue()), this.copyIfReference(change.getNewValue())); } @Override public SetFieldAdd caseSetFieldAdd(SetFieldAdd change) { return new SetFieldAdd<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(), this.copyIfReference(change.getElement())); } @Override public SetFieldClear caseSetFieldClear(SetFieldClear change) { return new SetFieldClear<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName()); } @Override public SetFieldRemove caseSetFieldRemove(SetFieldRemove change) { return new SetFieldRemove<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(), this.copyIfReference(change.getElement())); } @Override public SimpleFieldChange caseSimpleFieldChange(SimpleFieldChange change) { return new SimpleFieldChange<>(this.copyIfReference(change.getObject()), change.getStorageId(), change.getFieldName(), this.copyIfReference(change.getOldValue()), this.copyIfReference(change.getNewValue())); } @SuppressWarnings("unchecked") private T copyIfReference(T obj) { return obj instanceof JObject ? (T)this.copy((JObject)obj) : obj; } /** * Copy the given {@link JObject} into the destination transaction. * *

* The implementation in {@link ChangeCopier} copies {@code jobj} and objects reachable via the configured copy cascade, * unless {@code jobj} does not exist, in which case it is not copied (but the * {@linkplain JTransaction#get(ObjId) corresponding} {@link JObject} is still returned). * Subclasses may override as needed. * * @param jobj original object * @return copied object in {@link #dest} * @throws IllegalArgumentException if {@code jobj} is null */ @SuppressWarnings("unchecked") protected JObject copy(JObject jobj) { Preconditions.checkArgument(jobj != null, "null jobj"); final ObjId id = jobj.getObjId(); if (jobj.exists()) { final JTransaction jtx = jobj.getTransaction(); jtx.copyTo(this.dest, this.copyState, jtx.cascadeFindAll(id, this.cascadeName, this.recursionLimit)); } return dest.get(this.copyState.getDestinationId(id)); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy