com.jetbrains.teamsys.dnq.database.ReadonlyTransientEntityImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dnq-transient-store Show documentation
Show all versions of dnq-transient-store Show documentation
Data definition and queries Kotlin DSL over Xodus
/**
* Copyright 2006 - 2017 JetBrains s.r.o.
*
* 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.
*/
package com.jetbrains.teamsys.dnq.database;
import jetbrains.exodus.core.dataStructures.hash.HashSet;
import jetbrains.exodus.database.LinkChange;
import jetbrains.exodus.database.TransientEntity;
import jetbrains.exodus.database.TransientEntityChange;
import jetbrains.exodus.database.TransientEntityStore;
import jetbrains.exodus.entitystore.*;
import jetbrains.exodus.entitystore.iterate.EntityIterableBase;
import jetbrains.exodus.entitystore.iterate.EntityIterableDecoratorBase;
import jetbrains.exodus.entitystore.iterate.EntityIteratorBase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.InputStream;
import java.util.Collection;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
public class ReadonlyTransientEntityImpl extends TransientEntityImpl {
private Boolean hasChanges = null;
private Map linksDetaled;
private Set changedProperties;
public ReadonlyTransientEntityImpl(@NotNull ReadOnlyPersistentEntity snapshot, @NotNull TransientEntityStore store) {
this(null, snapshot, store);
}
public ReadonlyTransientEntityImpl(@Nullable TransientEntityChange change, @NotNull PersistentEntity snapshot, @NotNull TransientEntityStore store) {
super(snapshot, store);
if (change != null) {
this.changedProperties = change.getChangedProperties();
this.linksDetaled = change.getChangedLinksDetaled();
}
}
public boolean isReadonly() {
return true;
}
@Override
public boolean setProperty(@NotNull String propertyName, @NotNull Comparable value) {
throw createReadonlyException();
}
@Override
public void setBlob(@NotNull String blobName, @NotNull InputStream blob) {
throw createReadonlyException();
}
@Override
public void setBlob(@NotNull String blobName, @NotNull File file) {
throw createReadonlyException();
}
@Override
public boolean setBlobString(@NotNull String blobName, @NotNull String blobString) {
throw createReadonlyException();
}
@Override
public boolean setLink(@NotNull String linkName, @Nullable Entity target) {
throw createReadonlyException();
}
@Override
public boolean addLink(@NotNull String linkName, @NotNull Entity target) {
throw createReadonlyException();
}
@Override
public boolean deleteProperty(@NotNull String propertyName) {
throw createReadonlyException();
}
@Override
public boolean deleteBlob(@NotNull String blobName) {
throw createReadonlyException();
}
@Override
public boolean deleteLink(@NotNull String linkName, @NotNull Entity target) {
throw createReadonlyException();
}
@Override
public void deleteLinks(@NotNull String linkName) {
throw createReadonlyException();
}
@Override
public Entity getLink(@NotNull String linkName) {
final PersistentEntity link = (PersistentEntity) getPersistentEntity().getLink(linkName);
return link == null ? null : new ReadonlyTransientEntityImpl(getSnapshotPersistentEntity(link), store);
}
@NotNull
@Override
public EntityIterable getLinks(@NotNull String linkName) {
return new PersistentEntityIterableWrapper(store, wrapWithReadOnlyIterable(getPersistentEntity().getLinks(linkName)));
}
@NotNull
@Override
public EntityIterable getLinks(@NotNull final Collection linkNames) {
throw new UnsupportedOperationException();
}
@Override
public boolean delete() {
throw createReadonlyException();
}
@Override
public boolean hasChanges() {
// lazy hasChanges evaluation
if (hasChanges == null) {
evaluateHasChanges();
}
return hasChanges;
}
@Override
public boolean hasChanges(final String property) {
if (super.hasChanges(property)) {
return true;
} else {
if (linksDetaled != null && linksDetaled.containsKey(property)) {
LinkChange change = linksDetaled.get(property);
return change.getAddedEntitiesSize() > 0 || change.getRemovedEntitiesSize() > 0 || change.getDeletedEntitiesSize() > 0;
}
return changedProperties != null && changedProperties.contains(property);
}
}
@Override
public boolean hasChangesExcepting(String[] properties) {
if (super.hasChangesExcepting(properties)) {
return true;
} else {
if (linksDetaled != null) {
if (linksDetaled.size() > properties.length) {
// by Dirichlet principle, even if 'properties' param is malformed
return true;
}
final Set linksDetaledCopy = new HashSet(linksDetaled.keySet());
for (String property : properties) {
linksDetaledCopy.remove(property);
}
if (!linksDetaledCopy.isEmpty()) {
return true;
}
}
if (changedProperties != null) {
if (changedProperties.size() > properties.length) {
// by Dirichlet principle, even if 'properties' param is malformed
return true;
}
final Set propertiesDetailedCopy = new HashSet(changedProperties);
for (String property : properties) {
propertiesDetailedCopy.remove(property);
}
if (!propertiesDetailedCopy.isEmpty()) {
return true;
}
}
return false;
}
}
@Override
public EntityIterable getAddedLinks(String name) {
if (linksDetaled != null) {
final LinkChange c = linksDetaled.get(name);
if (c != null) {
Set added = c.getAddedEntities();
if (added != null) {
return new TransientEntityIterable(added) {
@Override
public long size() {
return c.getAddedEntitiesSize();
}
@Override
public long count() {
return c.getAddedEntitiesSize();
}
};
}
}
}
return EntityIterableBase.EMPTY;
}
@Override
public EntityIterable getRemovedLinks(String name) {
if (linksDetaled != null) {
final LinkChange c = linksDetaled.get(name);
if (c != null) {
Set removed = c.getRemovedEntities();
if (removed != null) {
return new TransientEntityIterable(removed) {
@Override
public long size() {
return c.getRemovedEntitiesSize();
}
@Override
public long count() {
return c.getRemovedEntitiesSize();
}
};
}
}
}
return EntityIterableBase.EMPTY;
}
@Override
public EntityIterable getAddedLinks(Set linkNames) {
if (linksDetaled != null) {
return AddedOrRemovedLinksFromSetTransientEntityIterable.get(linksDetaled, linkNames, false);
}
return UniversalEmptyEntityIterable.INSTANCE;
}
@Override
public EntityIterable getRemovedLinks(Set linkNames) {
if (linksDetaled != null) {
return AddedOrRemovedLinksFromSetTransientEntityIterable.get(linksDetaled, linkNames, true);
}
return UniversalEmptyEntityIterable.INSTANCE;
}
private void evaluateHasChanges() {
boolean hasChanges = false;
if (linksDetaled != null) {
for (String linkName : linksDetaled.keySet()) {
LinkChange linkChange = linksDetaled.get(linkName);
if (linkChange != null) {
if (linkChange.getAddedEntitiesSize() > 0 || linkChange.getRemovedEntitiesSize() > 0 || linkChange.getDeletedEntitiesSize() > 0) {
hasChanges = true;
break;
}
}
}
}
if (changedProperties != null && changedProperties.size() > 0) {
hasChanges = true;
}
this.hasChanges = hasChanges;
}
private ReadOnlyPersistentEntity getSnapshotPersistentEntity(@Nullable final PersistentEntity entity) {
return entity == null ? null : new ReadOnlyPersistentEntity(getPersistentEntity().getTransaction(), entity.getId());
}
private static IllegalStateException createReadonlyException() {
return new IllegalStateException("Entity is readonly.");
}
private EntityIterable wrapWithReadOnlyIterable(@NotNull final EntityIterable source) {
return source == EntityIterableBase.EMPTY ? source : new ReadOnlyIterable((EntityIterableBase) source);
}
private class ReadOnlyIterable extends EntityIterableDecoratorBase {
private ReadOnlyIterable(@NotNull final EntityIterableBase source) {
super(source.getTransaction(), source);
}
@Override
public boolean isSortedById() {
return source.isSortedById();
}
@Override
public boolean canBeCached() {
return false;
}
@NotNull
@Override
public EntityIterator getIteratorImpl(@NotNull PersistentStoreTransaction txn) {
return new ReadOnlyIterator(this);
}
@NotNull
@Override
protected EntityIterableHandle getHandleImpl() {
return source.getHandle();
}
@Nullable
@Override
public Entity getFirst() {
return getSnapshotPersistentEntity((PersistentEntity) source.getFirst());
}
@Nullable
@Override
public Entity getLast() {
return getSnapshotPersistentEntity((PersistentEntity) source.getLast());
}
}
private class ReadOnlyIterator extends EntityIteratorBase {
private final EntityIteratorBase source;
private ReadOnlyIterator(ReadOnlyIterable source) {
super(source);
this.source = (EntityIteratorBase) source.getDecorated().iterator();
}
@Override
public Entity next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return getSnapshotPersistentEntity((PersistentEntity) source.next());
}
@Override
protected boolean hasNextImpl() {
return source.hasNext();
}
@Nullable
@Override
protected EntityId nextIdImpl() {
return source.nextId();
}
@Override
public boolean shouldBeDisposed() {
return false;
}
}
}