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

io.activej.ot.system.MergedOTSystem Maven / Gradle / Ivy

Go to download

Implementation of operational transformation technology. Allows building collaborative software systems.

There is a newer version: 6.0-rc2
Show newest version
/*
 * 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 leftDiffs, List 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 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 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