com.ocadotechnology.indexedcache.OneToOneJoinView Maven / Gradle / Ivy
/*
* Copyright © 2017-2023 Ocado (Ocava)
*
* 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.ocadotechnology.indexedcache;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.google.common.base.Preconditions;
import com.ocadotechnology.id.Identified;
import com.ocadotechnology.id.Identity;
import com.ocadotechnology.wrappers.Pair;
public class OneToOneJoinView, A_ID, B extends Identified, B_ID, Z> {
private final OptionalOneToOneIndex zAOneToOneIndex;
private final OptionalOneToOneIndex zBOneToOneIndex;
private final Map, Pair> aIdToPair = new HashMap<>();
private final Map, Pair> bIdToPair = new HashMap<>();
private final List>> stateChangeListeners = new ArrayList<>();
private final List>> stateRemovedListeners = new ArrayList<>();
private final List>> stateAddedListeners = new ArrayList<>();
public OneToOneJoinView(StateChangeListenable aCache, StateChangeListenable bCache, OptionalOneToOneIndex zAOneToOneIndex, OptionalOneToOneIndex zBOneToOneIndex) {
this.zAOneToOneIndex = zAOneToOneIndex;
this.zBOneToOneIndex = zBOneToOneIndex;
aCache.registerStateChangeListener(this::aHasChanged);
bCache.registerStateChangeListener(this::bHasChanged);
aCache.stream().forEach(this::aWasAdded);
}
private void aHasChanged(A previous, A updated) {
Pair oldMapping = previous != null ? aWasRemoved(previous) : null;
Pair updatedMapping = updated != null ? aWasAdded(updated) : null;
updateStateChangeListeners(oldMapping, updatedMapping);
}
private void bHasChanged(B previous, B updated) {
Pair oldMapping = previous != null ? bWasRemoved(previous) : null;
Pair updatedMapping = updated != null ? bWasAdded(updated) : null;
updateStateChangeListeners(oldMapping, updatedMapping);
}
private Pair aWasRemoved(A a) {
Preconditions.checkNotNull(a);
Pair removed = aIdToPair.remove(a.getId());
if (removed != null) {
bIdToPair.remove(removed.b.getId());
}
return removed;
}
private Pair bWasRemoved(B b) {
Preconditions.checkNotNull(b);
Pair removed = bIdToPair.remove(b.getId());
if (removed != null) {
aIdToPair.remove(removed.a.getId());
}
return removed;
}
private Pair aWasAdded(A a) {
return zAOneToOneIndex.getKeyFor(a)
.flatMap(zBOneToOneIndex::get)
.map(b -> add(a, b))
.orElse(null);
}
private Pair bWasAdded(B b) {
return zBOneToOneIndex.getKeyFor(b)
.flatMap(zAOneToOneIndex::get)
.map(a -> add(a, b))
.orElse(null);
}
private Pair add(A a, B b) {
Pair newPair = Pair.of(a, b);
Pair putA = aIdToPair.put(a.getId(), newPair);
Pair putB = bIdToPair.put(b.getId(), newPair);
Preconditions.checkState(putA == null, "Trying to add new pair [%s] to the OneToOneJoinView, but [%s] already exists in pair [%s].", newPair, a, putA);
Preconditions.checkState(putB == null, "Trying to add new pair [%s] to the OneToOneJoinView, but [%s] already exists in pair [%s].", newPair, b, putB);
return newPair;
}
private void updateStateChangeListeners(Pair old, Pair updated) {
if (updated == null) {
if (old != null) {
stateRemovedListeners.forEach(l -> l.stateRemoved(old));
}
return;
}
if (old == null) {
stateAddedListeners.forEach(l -> l.stateAdded(updated));
return;
}
stateChangeListeners.forEach(l -> l.stateChanged(old, updated));
}
public Optional getA(Identity bId) {
return Optional.ofNullable(bIdToPair.get(bId)).map(p -> p.a);
}
public Optional getB(Identity aId) {
return Optional.ofNullable(aIdToPair.get(aId)).map(p -> p.b);
}
public void registerStateChangeListener(CacheStateChangeListener> listener) {
stateChangeListeners.add(listener);
}
public void registerStateAddedListener(CacheStateAddedListener> stateAddedListener) {
stateAddedListeners.add(stateAddedListener);
}
public void registerStateRemovedListener(CacheStateRemovedListener> stateRemovedListener) {
stateRemovedListeners.add(stateRemovedListener);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy