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

org.teamapps.universaldb.pojo.AbstractUdbEntity Maven / Gradle / Ivy

There is a newer version: 0.7.3
Show newest version
/*-
 * ========================LICENSE_START=================================
 * UniversalDB
 * ---
 * Copyright (C) 2014 - 2019 TeamApps.org
 * ---
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * =========================LICENSE_END==================================
 */
package org.teamapps.universaldb.pojo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.teamapps.universaldb.index.ColumnIndex;
import org.teamapps.universaldb.index.SortEntry;
import org.teamapps.universaldb.index.TableIndex;
import org.teamapps.universaldb.index.reference.multi.MultiReferenceIndex;
import org.teamapps.universaldb.index.reference.single.SingleReferenceIndex;
import org.teamapps.universaldb.index.reference.value.*;
import org.teamapps.universaldb.record.EntityBuilder;
import org.teamapps.universaldb.transaction.Transaction;
import org.teamapps.universaldb.transaction.TransactionRecord;
import org.teamapps.universaldb.transaction.TransactionRecordValue;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public abstract class AbstractUdbEntity implements Entity {

	private static final Logger log = LoggerFactory.getLogger(AbstractUdbEntity.class);
	private static final AtomicInteger correlationIdGenerator = new AtomicInteger();
	private static final int MAX_CORRELATION_ID = 2_000_000_000;

	private int id;
	private boolean createEntity;
	private int correlationId;
	private EntityChangeSet entityChangeSet;
	private Transaction transaction;

	public static  List sort(TableIndex table, List list, String sortFieldName, boolean ascending, String ... path) {
		return sort(table, list, sortFieldName, ascending, null, path);
	}

	public static  List sort(TableIndex table, List list, String sortFieldName, boolean ascending, Locale locale, String ... path) {
		SingleReferenceIndex[] referencePath = getReferenceIndices(table, path);
		ColumnIndex column = getSortColumn(table, sortFieldName, referencePath);
		List> sortEntries = SortEntry.createSortEntries(list, referencePath);
		sortEntries = column.sortRecords(sortEntries, ascending, locale);
		return sortEntries.stream().map(SortEntry::getEntity).collect(Collectors.toList());
	}

	public static  List sort(TableIndex table, EntityBuilder builder, BitSet recordIds, String sortFieldName, boolean ascending, String ... path) {
		return sort(table, builder, recordIds, sortFieldName, ascending, null, path);
	}

	public static  List sort(TableIndex table, EntityBuilder builder, BitSet recordIds, String sortFieldName, boolean ascending, Locale locale, String ... path) {
		SingleReferenceIndex[] referencePath = getReferenceIndices(table, path);
		ColumnIndex column = getSortColumn(table, sortFieldName, referencePath);
		List sortEntries = SortEntry.createSortEntries(recordIds, referencePath);
		sortEntries = column.sortRecords(sortEntries, ascending, locale);
		List list = new ArrayList<>();
		for (SortEntry entry : sortEntries) {
			list.add(builder.build(entry.getId()));
		}
		return list;
	}

	private static SingleReferenceIndex[] getReferenceIndices(TableIndex table, String[] path) {
		SingleReferenceIndex[] referencePath = null;
		if (path != null && path.length > 0) {
			referencePath = new SingleReferenceIndex[path.length];
			TableIndex pathTable = table;
			for (int i = 0; i < path.length; i++) {
				referencePath[i] = (SingleReferenceIndex) pathTable.getColumnIndex(path[i]);
				pathTable = referencePath[i].getReferencedTable();
			}
		}
		return referencePath;
	}

	private static ColumnIndex getSortColumn(TableIndex table, String sortFieldName, SingleReferenceIndex[] referencePath) {
		ColumnIndex column;
		if (referencePath != null && referencePath.length > 0) {
			column = referencePath[referencePath.length - 1].getReferencedTable().getColumnIndex(sortFieldName);
		} else {
			column = table.getColumnIndex(sortFieldName);
		}
		return column;
	}

	public AbstractUdbEntity() {
		createEntity = true;
		createCorrelationId();
	}

	public AbstractUdbEntity(int id, boolean createEntity) {
		this.id = id;
		this.createEntity = createEntity;
		if (createEntity) {
			createCorrelationId();
		}
	}

	private void createCorrelationId() {
		if (correlationId > 0) {
			return;
		}
		correlationId = correlationIdGenerator.incrementAndGet();
		if (correlationId == MAX_CORRELATION_ID) {
			correlationIdGenerator.set(0);
		}
	}

	@Override
	public int getId() {
		if (id == 0 && transaction != null) {
			id = transaction.getResolvedRecordIdByCorrelationId(correlationId);
		}
		return id;
	}

	private int getCorrelationId() {
		return correlationId;
	}

	protected void setChangeValue(ColumnIndex index, Object value, TableIndex tableIndex) {
		checkChangeSet();
		entityChangeSet.addChangeValue(index, value);
	}

	protected void setSingleReferenceValue(ColumnIndex index, Entity reference, TableIndex tableIndex) {
		AbstractUdbEntity entity = (AbstractUdbEntity) reference;
		RecordReference recordReference = null;
		if (entity != null) {
			recordReference = new RecordReference(entity.getId(), entity.getCorrelationId());
		}
		checkChangeSet();
		entityChangeSet.addChangeValue(index, recordReference);
		entityChangeSet.setReferenceChange(index, entity);
	}

	protected void setReferenceChangeValue(ColumnIndex index, Entity reference, TableIndex tableIndex) {
		AbstractUdbEntity entity = (AbstractUdbEntity) reference;
		if (entity.getId() == 0) {
			if (entity.getTransaction() == null) {
				throw new RuntimeException("ERROR: Cannot add unsaved new entity:" + entity);
			} else {

			}
		}
		checkChangeSet();
		entityChangeSet.setReferenceChange(index, entity);
	}

	protected  List createEntityList(ColumnIndex index, EntityBuilder entityBuilder) {
		TransactionRecordValue changeValue = getChangeValue(index);
		MultiReferenceEditValue editValue = (MultiReferenceEditValue) changeValue.getValue();
		MultiReferenceIndex multiReferenceIndex = (MultiReferenceIndex) index;
		PrimitiveIterator.OfInt references = multiReferenceIndex.getReferences(getId());
		return createEntityList(editValue, references, entityBuilder);
	}

	protected  List createEntityList(MultiReferenceEditValue editValue, PrimitiveIterator.OfInt referenceIterator, EntityBuilder entityBuilder) {
		Map entityByReference = (Map) entityChangeSet.getEntityByReference();
		List list = new ArrayList<>();
		if (!editValue.getSetReferences().isEmpty() || editValue.isRemoveAll()) {
			List references = editValue.isRemoveAll() ? editValue.getAddReferences() : editValue.getSetReferences();
			references.forEach(reference -> {
				OTHER_ENTITY entity = entityByReference.get(reference);
				if (entity == null && reference.getRecordId() > 0) {
					entity = entityBuilder.build(reference.getRecordId());
				}
				if (entity != null) {
					list.add(entity);
				} else {
					log.error("Cannot add reference to list: no record id and no matching correlation id!");
				}
			});
			return list;
		} else {
			Set removeSet = new HashSet<>();
			editValue.getRemoveReferences().forEach(reference -> {
				if (reference.getRecordId() > 0) {
					removeSet.add(reference.getRecordId());
				} else {
					OTHER_ENTITY entity = entityByReference.get(reference);
					if (entity != null) {
						removeSet.add(entity.getId());
					}
				}
			});
			List addEntities = new ArrayList<>();
			editValue.getAddReferences().forEach(reference -> {
				OTHER_ENTITY entity = entityByReference.get(reference);
				if (entity == null && reference.getRecordId() > 0) {
					entity = entityBuilder.build(reference.getRecordId());
				}
				if (entity != null) {
					addEntities.add(entity);
				}
			});
			Set addEntitySet = new HashSet<>();
			addEntities.forEach(entity -> addEntitySet.add(entity.getId()));
			if (referenceIterator != null) {
				while (referenceIterator.hasNext()) {
					int recordId = referenceIterator.nextInt();
					if (!removeSet.contains(recordId) && !addEntitySet.contains(recordId)) {
						list.add(entityBuilder.build(recordId));
					}
				}
			}
			list.addAll(addEntities);
			return list;
		}
	}

	protected TransactionRecordValue getChangeValue(ColumnIndex index) {
		if (entityChangeSet == null) {
			return null;
		} else {
			return entityChangeSet.getChangeValue(index);
		}
	}

	protected Object getChangedValue(ColumnIndex index) {
		if (entityChangeSet == null) {
			return null;
		} else {
			return entityChangeSet.getChangeValue(index).getValue();
		}
	}

	protected AbstractUdbEntity getReferenceChangeValue(ColumnIndex index) {
		if (entityChangeSet == null) {
			return null;
		} else {
			return entityChangeSet.getReferenceChange(index);
		}
	}

	protected void addMultiReferenceValue(List entities, MultiReferenceIndex multiReferenceIndex, TableIndex tableIndex) {
		if (entities == null || entities.isEmpty()) {
			return;
		}
		MultiReferenceEditValue editValue = getOrCreateMultiReferenceEditValue(multiReferenceIndex, tableIndex);
		List references = createRecordReferences(entities);

		editValue.addReferences(references);
	}

	protected void removeMultiReferenceValue(List entities, MultiReferenceIndex multiReferenceIndex, TableIndex tableIndex) {
		if (entities == null || entities.isEmpty()) {
			return;
		}
		MultiReferenceEditValue editValue = getOrCreateMultiReferenceEditValue(multiReferenceIndex, tableIndex);
		List references = createRecordReferences(entities);
		editValue.removeReferences(references);
	}

	protected void setMultiReferenceValue(List entities, MultiReferenceIndex multiReferenceIndex, TableIndex tableIndex) {
		if (entities == null || entities.isEmpty()) {
			return;
		}
		MultiReferenceEditValue editValue = getOrCreateMultiReferenceEditValue(multiReferenceIndex, tableIndex);
		List references = createRecordReferences(entities);
		editValue.setReferences(references);
	}

	protected void removeAllMultiReferenceValue(MultiReferenceIndex multiReferenceIndex, TableIndex tableIndex) {
		MultiReferenceEditValue editValue = getOrCreateMultiReferenceEditValue(multiReferenceIndex, tableIndex);
		editValue.setRemoveAll();
	}

	private List createRecordReferences(List entities) {
		List references = new ArrayList<>();
		for (Entity entity : entities) {
			AbstractUdbEntity udbEntity = (AbstractUdbEntity) entity;
			RecordReference recordReference = new RecordReference(udbEntity.getId(), udbEntity.getCorrelationId());
			references.add(recordReference);
			entityChangeSet.addRecordReference(recordReference, entity);
		}
		return references;
	}

	private MultiReferenceEditValue getOrCreateMultiReferenceEditValue(MultiReferenceIndex multiReferenceIndex, TableIndex tableIndex) {
		MultiReferenceEditValue editValue;
		TransactionRecordValue changeValue = getChangeValue(multiReferenceIndex);
		if (changeValue != null) {
			editValue = (MultiReferenceEditValue) changeValue.getValue();
		} else {
			editValue = new MultiReferenceEditValue();
			setChangeValue(multiReferenceIndex, editValue, tableIndex);
		}
		return editValue;
	}


	protected boolean isChanged(ColumnIndex index) {
		return entityChangeSet != null && entityChangeSet.isChanged(index);
	}

	protected int getEntityId(Entity entity) {
		if (entity == null) {
			return 0;
		} else {
			return entity.getId();
		}
	}

	protected Transaction getTransaction() {
		return transaction;
	}

	@Override
	public void clearChanges() {
		entityChangeSet = null;
		if (transaction != null) {
			//todo remove changes from transaction
		}
	}

	@Override
	public boolean isModified() {
		return entityChangeSet != null;
	}

	private void checkChangeSet() {
		if (entityChangeSet == null) {
			entityChangeSet = new EntityChangeSet();
			createCorrelationId();
		}
	}

	public void save(Transaction transaction, TableIndex tableIndex, boolean strictChangeVerification) {
		if (entityChangeSet != null) {
			this.transaction = transaction;
			boolean update = !createEntity;
			TransactionRecord transactionRecord = new TransactionRecord(tableIndex, id, correlationId, transaction.getUserId(), update, false, strictChangeVerification);
			entityChangeSet.setTransactionRecordValues(transactionRecord);
			transaction.addTransactionRecord(transactionRecord);
			entityChangeSet = null;
			//createEntity = false;
		}
	}

	public void save(TableIndex tableIndex) {
		if (entityChangeSet != null) {
			transaction = Transaction.create();
			save(transaction, tableIndex, false);
			transaction.execute();
			if (id == 0) {
				id = transaction.getResolvedRecordIdByCorrelationId(correlationId);
			}
		}
	}

	public void delete(Transaction transaction, TableIndex tableIndex) {
		TransactionRecord transactionRecord = new TransactionRecord(tableIndex, id, 0, transaction.getUserId(), true);
		transaction.addTransactionRecord(transactionRecord);
		entityChangeSet = null;
	}

	public void delete(TableIndex tableIndex) {
		Transaction transaction = Transaction.create();
		delete(transaction, tableIndex);
		transaction.execute();
	}

	@Override
	public boolean isCommitted() {
		return entityChangeSet == null;
	}

	@Override
	public boolean isStored() {
		return id > 0 && !createEntity;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		AbstractUdbEntity that = (AbstractUdbEntity) o;
		if (getId() > 0 && getId() == that.getId()) {
			return true;
		}
		return getCorrelationId() > 0 && getCorrelationId() == that.getCorrelationId();
	}

	@Override
	public int hashCode() {
		if (getId() > 0) {
			return getId();
		} else {
			return getCorrelationId();
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy