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

io.fluxcapacitor.javaclient.common.ClientUtils Maven / Gradle / Ivy

There is a newer version: 0.1072.0
Show newest version
/*
 * Copyright (c) Flux Capacitor IP B.V. or its affiliates. All Rights Reserved.
 *
 * 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.fluxcapacitor.javaclient.common;

import io.fluxcapacitor.common.MemoizingBiFunction;
import io.fluxcapacitor.common.MemoizingFunction;
import io.fluxcapacitor.common.MemoizingSupplier;
import io.fluxcapacitor.common.ObjectUtils;
import io.fluxcapacitor.common.ThrowingRunnable;
import io.fluxcapacitor.common.handling.HandlerInvoker;
import io.fluxcapacitor.javaclient.FluxCapacitor;
import io.fluxcapacitor.javaclient.modeling.SearchParameters;
import io.fluxcapacitor.javaclient.persisting.search.Searchable;
import io.fluxcapacitor.javaclient.tracking.TrackSelf;
import io.fluxcapacitor.javaclient.tracking.handling.LocalHandler;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

import java.lang.reflect.Executable;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.util.Collection;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

import static io.fluxcapacitor.common.reflection.ReflectionUtils.getAnnotation;
import static io.fluxcapacitor.common.reflection.ReflectionUtils.getAnnotationAs;
import static io.fluxcapacitor.common.reflection.ReflectionUtils.getPackageAnnotation;
import static io.fluxcapacitor.common.reflection.ReflectionUtils.getTypeAnnotation;
import static java.time.temporal.ChronoUnit.DAYS;

@Slf4j
public class ClientUtils {
    public static final Marker ignoreMarker = MarkerFactory.getMarker("ignoreError");
    private static final BiFunction, java.lang.reflect.Executable, Optional> localHandlerCache =
            memoize((target, method) -> getAnnotation(method, LocalHandler.class)
                    .or(() -> Optional.ofNullable(getTypeAnnotation(target, LocalHandler.class)))
                    .or(() -> getPackageAnnotation(target.getPackage(), LocalHandler.class)));

    private static final BiFunction, java.lang.reflect.Executable, Optional> trackSelfCache =
            memoize((target, method) -> getAnnotation(method, TrackSelf.class)
                    .or(() -> Optional.ofNullable(getTypeAnnotation(target, TrackSelf.class)))
                    .or(() -> getPackageAnnotation(target.getPackage(), TrackSelf.class)));

    private static final Function, SearchParameters> searchParametersCache =
            memoize(type -> getAnnotationAs(type, Searchable.class, SearchParameters.class)
                    .map(p -> p.getCollection() == null ? p.withCollection(type.getSimpleName()) : p)
                    .orElseGet(() -> new SearchParameters(true, type.getSimpleName(), null, null)));

    public static void waitForResults(Duration maxDuration, Collection> futures) {
        Instant deadline = Instant.now().plus(maxDuration);
        for (Future f : futures) {
            try {
                f.get(Math.max(0, Duration.between(Instant.now(), deadline).toMillis()), TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.warn("Thread was interrupted before receiving all expected results", e);
                return;
            } catch (TimeoutException e) {
                log.warn("Timed out before having received all expected results", e);
                return;
            } catch (ExecutionException ignore) {
            }
        }
    }

    public static void tryRun(Runnable task) {
        try {
            task.run();
        } catch (Exception e) {
            log.warn("Task {} failed", task, e);
        }
    }

    @SneakyThrows
    public static void runSilently(ThrowingRunnable runnable) {
        runnable.run();
    }

    public static boolean isSelfTracking(Class target, Executable method) {
        return trackSelfCache.apply(target, method).isPresent();
    }

    public static Optional getTrackSelfAnnotation(Class target, java.lang.reflect.Executable method) {
        return trackSelfCache.apply(target, method);
    }

    public static Optional getLocalHandlerAnnotation(Class target,
                                                                   java.lang.reflect.Executable method) {
        return localHandlerCache.apply(target, method);
    }

    public static boolean isLocalHandler(Class target, java.lang.reflect.Executable method) {
        return getLocalHandlerAnnotation(target, method).map(LocalHandler::value).orElse(false);
    }

    public static boolean isLocalHandler(HandlerInvoker invoker) {
        return invoker.getMethod() != null && isLocalHandler(invoker.getTargetClass(), invoker.getMethod());
    }

    public static boolean isTrackingHandler(Class target, java.lang.reflect.Executable method) {
        return getLocalHandlerAnnotation(target, method).map(l -> !l.value() || l.allowExternalMessages())
                .orElse(true);
    }

    public static  MemoizingSupplier memoize(Supplier supplier) {
        return ObjectUtils.memoize(supplier);
    }

    public static  MemoizingFunction memoize(Function supplier) {
        return ObjectUtils.memoize(supplier);
    }

    public static  MemoizingBiFunction memoize(BiFunction supplier) {
        return ObjectUtils.memoize(supplier);
    }

    public static  MemoizingSupplier memoize(Supplier supplier, Duration lifespan) {
        return new MemoizingSupplier<>(supplier, lifespan, FluxCapacitor::currentClock);
    }

    public static  MemoizingFunction memoize(Function supplier, Duration lifespan) {
        return new MemoizingFunction<>(supplier, lifespan, FluxCapacitor::currentClock);
    }

    public static  MemoizingBiFunction memoize(BiFunction supplier,
                                                                 Duration lifespan) {
        return new MemoizingBiFunction<>(supplier, lifespan, FluxCapacitor::currentClock);
    }

    public static SearchParameters getSearchParameters(Class type) {
        return searchParametersCache.apply(type);
    }

    @SuppressWarnings("unchecked")
    public static  T truncate(T timestamp, TemporalUnit unit) {
        T result = unit instanceof ChronoUnit chronoUnit ?
                switch (chronoUnit) {
                    case YEARS -> (T) timestamp.with(TemporalAdjusters.firstDayOfYear());
                    case MONTHS -> (T) timestamp.with(TemporalAdjusters.firstDayOfMonth());
                    default -> timestamp;
                } : timestamp;
        TemporalUnit truncateUnit = unit instanceof ChronoUnit chronoUnit ?
                switch (chronoUnit) {
                    case YEARS, MONTHS -> DAYS;
                    default -> chronoUnit;
                } : unit;

        if (result instanceof LocalDate) {
            return result;
        }
        if (result instanceof LocalDateTime r) {
            return (T) r.truncatedTo(truncateUnit);
        }
        if (result instanceof ZonedDateTime r) {
            return (T) r.truncatedTo(truncateUnit);
        }
        if (result instanceof OffsetDateTime r) {
            return (T) r.truncatedTo(truncateUnit);
        }
        if (result instanceof Instant r) {
            return (T) r.truncatedTo(truncateUnit);
        }
        throw new UnsupportedOperationException("Unsupported temporal type: " + result.getClass());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy