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

com.github.nagyesta.lowkeyvault.controller.common.BaseBackupRestoreController Maven / Gradle / Ivy

package com.github.nagyesta.lowkeyvault.controller.common;

import com.github.nagyesta.lowkeyvault.mapper.common.BaseEntityConverterRegistry;
import com.github.nagyesta.lowkeyvault.mapper.common.RecoveryAwareConverter;
import com.github.nagyesta.lowkeyvault.model.v7_2.BasePropertiesModel;
import com.github.nagyesta.lowkeyvault.model.v7_2.common.BaseBackupListItem;
import com.github.nagyesta.lowkeyvault.model.v7_2.common.BaseBackupModel;
import com.github.nagyesta.lowkeyvault.model.v7_2.key.BackupListContainer;
import com.github.nagyesta.lowkeyvault.service.EntityId;
import com.github.nagyesta.lowkeyvault.service.common.BaseVaultEntity;
import com.github.nagyesta.lowkeyvault.service.common.BaseVaultFake;
import com.github.nagyesta.lowkeyvault.service.common.ReadOnlyVersionedEntityMultiMap;
import com.github.nagyesta.lowkeyvault.service.vault.VaultFake;
import com.github.nagyesta.lowkeyvault.service.vault.VaultService;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;

import java.net.URI;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

/**
 * The base implementation of the backup/restore controllers.
 *
 * @param    The type of the key (not versioned).
 * @param    The versioned key type.
 * @param    The entity type.
 * @param    The entity model type.
 * @param   The deleted entity model type.
 * @param    The item model type.
 * @param   The deleted item model type.
 * @param   The model converter, converting entities to entity models.
 * @param   The item converter, converting version item entities to item models.
 * @param  The versioned item converter, converting version item entities to item models.
 * @param    The fake type holding the entities.
 * @param   The type of the PropertiesModel.
 * @param  The list item type of the backup lists.
 * @param   The type of the backup list.
 * @param    The type of the backup model.
 * @param    The ConverterRegistry used for conversions.
 */
public abstract class BaseBackupRestoreController,
        M, DM extends M, I, DI extends I, MC extends RecoveryAwareConverter,
        IC extends RecoveryAwareConverter, VIC extends RecoveryAwareConverter,
        S extends BaseVaultFake, PM extends BasePropertiesModel,
        BLI extends BaseBackupListItem, BL extends BackupListContainer,
        B extends BaseBackupModel,
        R extends BaseEntityConverterRegistry>
        extends GenericEntityController {

    protected BaseBackupRestoreController(@NonNull final R registry,
                                          @NonNull final VaultService vaultService,
                                          @NonNull final Function toEntityVault) {
        super(registry, vaultService, toEntityVault);
    }

    protected M restoreEntity(final B backupModel) {
        final URI baseUri = getSingleBaseUri(backupModel);
        final S vault = getVaultByUri(baseUri);
        final String id = getSingleEntityName(backupModel);
        final K entityId = entityId(baseUri, id);
        assertNameDoesNotExistYet(vault, entityId);
        backupModel.getValue().getVersions().forEach(entityVersion -> {
            final V versionedEntityId = versionedEntityId(baseUri, id, entityVersion.getVersion());
            restoreVersion(vault, versionedEntityId, entityVersion);
        });
        final V latestVersionOfEntity = vault.getEntities().getLatestVersionOfEntity(entityId);
        final E readOnlyEntity = vault.getEntities().getReadOnlyEntity(latestVersionOfEntity);
        return registry().modelConverter(apiVersion()).convert(readOnlyEntity, baseUri);
    }

    protected abstract void restoreVersion(S vault, V versionedEntityId, BLI entityVersion);

    protected B backupEntity(final K entityId) {
        final ReadOnlyVersionedEntityMultiMap entities = getVaultByUri(entityId.vault())
                .getEntities();
        final List list = entities.getVersions(entityId).stream()
                .map(version -> getEntityByNameAndVersion(entityId.vault(), entityId.id(), version))
                .map(registry().backupConverter(apiVersion())::convert)
                .toList();
        return wrapBackup(list);
    }

    protected abstract B getBackupModel();

    protected abstract BL getBackupList();

    protected String getSingleEntityName(final B backupModel) {
        final List entityNames = backupModel.getValue().getVersions().stream()
                .map(BLI::getId)
                .distinct()
                .toList();
        Assert.isTrue(entityNames.size() == 1, "All backup entities must belong to the same entity.");
        return entityNames.get(0);
    }

    protected URI getSingleBaseUri(final B backupModel) {
        final List uris = backupModel.getValue().getVersions().stream()
                .map(BLI::getVaultBaseUri)
                .distinct()
                .toList();
        Assert.isTrue(uris.size() == 1, "All backup entities must be from the same vault.");
        return uris.get(0);
    }

    private B wrapBackup(final List list) {
        final BL listModel = Optional.ofNullable(list)
                .map(l -> {
                    final BL backupList = getBackupList();
                    backupList.setVersions(l);
                    return backupList;
                })
                .orElse(null);
        final B backupModel = getBackupModel();
        backupModel.setValue(listModel);
        return backupModel;
    }

    private void assertNameDoesNotExistYet(final S vault, final K entityId) {
        Assert.isTrue(!vault.getEntities().containsName(entityId.id()),
                "Vault already contains entity with name: " + entityId.id());
        Assert.isTrue(!vault.getDeletedEntities().containsName(entityId.id()),
                "Vault already contains deleted entity with name: " + entityId.id());
    }

}