io.activej.ot.system.MergedOTSystem Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of activej-ot Show documentation
Show all versions of activej-ot Show documentation
Implementation of operational transformation technology. Allows building collaborative software systems.
/*
* Copyright (C) 2020 ActiveJ LLC.
*
* 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 io.activej.ot.system;
import io.activej.common.tuple.*;
import io.activej.ot.TransformResult;
import io.activej.ot.exception.TransformException;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.function.Function;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
public final class MergedOTSystem implements OTSystem {
private final TupleConstructor2, List, D> constructor;
private final Function> getter1;
private final OTSystem otSystem1;
private final Function> getter2;
private final OTSystem otSystem2;
private MergedOTSystem(TupleConstructor2, List, D> constructor,
Function> getter1, OTSystem otSystem1,
Function> getter2, OTSystem otSystem2) {
this.constructor = constructor;
this.getter1 = getter1;
this.otSystem1 = otSystem1;
this.getter2 = getter2;
this.otSystem2 = otSystem2;
}
public static OTSystem mergeOtSystems(TupleConstructor2, List, D> constructor,
Function> getter1, OTSystem otSystem1,
Function> getter2, OTSystem otSystem2) {
return new MergedOTSystem<>(constructor, getter1, otSystem1, getter2, otSystem2);
}
public static OTSystem mergeOtSystems(TupleConstructor3, List, List, D> constructor,
Function> getter1, OTSystem otSystem1,
Function> getter2, OTSystem otSystem2,
Function> getter3, OTSystem otSystem3) {
OTSystem, List>> premerged = mergeOtSystems(Tuple2::new,
Tuple2::getValue1, otSystem1,
Tuple2::getValue2, otSystem2);
return mergeOtSystems((tuples, list) -> {
Tuple2, List> tuple = extractTuple2(tuples);
return constructor.create(tuple.getValue1(), tuple.getValue2(), list);
},
d -> combineLists2(getter1.apply(d), getter2.apply(d), Tuple2::new), premerged,
getter3, otSystem3);
}
public static OTSystem mergeOtSystems(TupleConstructor4, List, List, List, D> constructor,
Function> getter1, OTSystem otSystem1,
Function> getter2, OTSystem otSystem2,
Function> getter3, OTSystem otSystem3,
Function> getter4, OTSystem otSystem4) {
OTSystem, List>> premerged1 = mergeOtSystems(Tuple2::new,
Tuple2::getValue1, otSystem1,
Tuple2::getValue2, otSystem2);
OTSystem, List>> premerged2 = mergeOtSystems(Tuple2::new,
Tuple2::getValue1, otSystem3,
Tuple2::getValue2, otSystem4);
return mergeOtSystems((tuples1, tuples2) -> {
Tuple2, List> tuple1 = extractTuple2(tuples1);
Tuple2, List> tuple2 = extractTuple2(tuples2);
return constructor.create(tuple1.getValue1(), tuple1.getValue2(), tuple2.getValue1(), tuple2.getValue2());
},
d -> combineLists2(getter1.apply(d), getter2.apply(d), Tuple2::new), premerged1,
d -> combineLists2(getter3.apply(d), getter4.apply(d), Tuple2::new), premerged2);
}
public static OTSystem mergeOtSystems(TupleConstructor5, List, List, List, List, D> constructor,
Function> getter1, OTSystem otSystem1,
Function> getter2, OTSystem otSystem2,
Function> getter3, OTSystem otSystem3,
Function> getter4, OTSystem otSystem4,
Function> getter5, OTSystem otSystem5) {
OTSystem, List, List>> premerged1 = mergeOtSystems(Tuple3::new,
Tuple3::getValue1, otSystem1,
Tuple3::getValue2, otSystem2,
Tuple3::getValue3, otSystem3);
OTSystem, List>> premerged2 = mergeOtSystems(Tuple2::new,
Tuple2::getValue1, otSystem4,
Tuple2::getValue2, otSystem5);
return mergeOtSystems((tuples1, tuples2) -> {
Tuple3, List, List> tuple1 = extractTuple3(tuples1);
Tuple2, List> tuple2 = extractTuple2(tuples2);
return constructor.create(tuple1.getValue1(), tuple1.getValue2(), tuple1.getValue3(), tuple2.getValue1(), tuple2.getValue2());
},
d -> combineLists3(getter1.apply(d), getter2.apply(d), getter3.apply(d), Tuple3::new), premerged1,
d -> combineLists2(getter4.apply(d), getter5.apply(d), Tuple2::new), premerged2);
}
@Override
public TransformResult transform(List extends D> leftDiffs, List extends D> rightDiffs) throws
TransformException {
List leftDiffs1 = collect(leftDiffs, getter1);
List leftDiffs2 = collect(leftDiffs, getter2);
List rightDiffs1 = collect(rightDiffs, getter1);
List rightDiffs2 = collect(rightDiffs, getter2);
TransformResult transform1 = otSystem1.transform(leftDiffs1, rightDiffs1);
TransformResult transform2 = otSystem2.transform(leftDiffs2, rightDiffs2);
List left = combineLists2(transform1.left, transform2.left, constructor);
List right = combineLists2(transform1.right, transform2.right, constructor);
return TransformResult.of(left, right);
}
@Override
public List squash(List extends D> ops) {
if (ops.isEmpty()) {
return emptyList();
}
List squashed1 = otSystem1.squash(collect(ops, getter1));
List squashed2 = otSystem2.squash(collect(ops, getter2));
return combineLists2(squashed1, squashed2, constructor);
}
@Override
public boolean isEmpty(D op) {
for (D1 operation : getter1.apply(op)) {
if (!otSystem1.isEmpty(operation)) {
return false;
}
}
for (D2 operation : getter2.apply(op)) {
if (!otSystem2.isEmpty(operation)) {
return false;
}
}
return true;
}
@Override
public List invert(List ops) {
if (ops.isEmpty()) {
return emptyList();
}
List inverted1 = otSystem1.invert(collect(ops, getter1));
List inverted2 = otSystem2.invert(collect(ops, getter2));
return combineLists2(inverted1, inverted2, constructor);
}
private List collect(List extends D> ops, Function> getter) {
return ops.stream()
.flatMap(op -> getter.apply(op).stream())
.collect(toList());
}
private static @NotNull List combineLists2(List list1, List list2, TupleConstructor2, List, D> constructor) {
return list1.isEmpty() && list2.isEmpty() ?
emptyList() :
singletonList(constructor.create(list1, list2));
}
private static @NotNull List combineLists3(List list1, List list2, List list3, TupleConstructor3, List, List, D> constructor) {
return list1.isEmpty() && list2.isEmpty() && list3.isEmpty() ?
emptyList() :
singletonList(constructor.create(list1, list2, list3));
}
private static Tuple2, List> extractTuple2(List, List>> tuples) {
assert tuples.size() < 2;
return tuples.isEmpty() ? new Tuple2<>(emptyList(), emptyList()) : tuples.get(0);
}
private static Tuple3, List, List> extractTuple3(List, List, List>> tuples) {
assert tuples.size() < 2;
return tuples.isEmpty() ? new Tuple3<>(emptyList(), emptyList(), emptyList()) : tuples.get(0);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy