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

io.gravitee.gateway.services.sync.synchronizer.DictionarySynchronizer Maven / Gradle / Ivy

There is a newer version: 4.5.2
Show newest version
/*
 * Copyright © 2015 The Gravitee team (http://gravitee.io)
 *
 * 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.gravitee.gateway.services.sync.synchronizer;

import static io.gravitee.gateway.services.sync.spring.SyncConfiguration.PARALLELISM;
import static io.gravitee.repository.management.model.Event.EventProperties.DICTIONARY_ID;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.gravitee.gateway.dictionary.DictionaryManager;
import io.gravitee.repository.management.model.Event;
import io.gravitee.repository.management.model.EventType;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.io.IOException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

/**
 * @author Jeoffrey HAEYAERT (jeoffrey.haeyaert at graviteesource.com)
 * @author GraviteeSource Team
 */
public class DictionarySynchronizer extends AbstractSynchronizer {

    private final Logger logger = LoggerFactory.getLogger(DictionarySynchronizer.class);

    @Autowired
    private DictionaryManager dictionaryManager;

    @Autowired
    private ObjectMapper objectMapper;

    public void synchronize(Long lastRefreshAt, Long nextLastRefreshAt, List environments) {
        final long start = System.currentTimeMillis();
        final Long count;

        if (lastRefreshAt == -1) {
            count = initialSynchronizeDictionaries(nextLastRefreshAt, environments);
        } else {
            count =
                this.searchLatestEvents(
                        lastRefreshAt,
                        nextLastRefreshAt,
                        false,
                        DICTIONARY_ID,
                        environments,
                        EventType.PUBLISH_DICTIONARY,
                        EventType.UNPUBLISH_DICTIONARY
                    )
                    .compose(this::processDictionaryEvents)
                    .count()
                    .blockingGet();
        }

        if (lastRefreshAt == -1) {
            logger.info("{} dictionary(ies) synchronized in {}ms.", count, (System.currentTimeMillis() - start));
        } else {
            logger.debug("{} dictionary(ies) synchronized in {}ms.", count, (System.currentTimeMillis() - start));
        }
    }

    private long initialSynchronizeDictionaries(long nextLastRefreshAt, List environments) {
        // We look only for the latest PUBLISH or UNPUBLISH events for dictionaries...
        return this.searchLatestEvents(
                null,
                nextLastRefreshAt,
                false,
                DICTIONARY_ID,
                environments,
                EventType.PUBLISH_DICTIONARY,
                EventType.UNPUBLISH_DICTIONARY
            )
            .filter(e -> e.getType().equals(EventType.PUBLISH_DICTIONARY)) // ... but if the latest event of a dictionary is UNPUBLISH, it must not be loaded
            .compose(this::processDictionaryDeployEvents)
            .count()
            .blockingGet();
    }

    @NonNull
    private Flowable processDictionaryEvents(Flowable upstream) {
        return upstream
            .groupBy(Event::getType)
            .flatMap(eventsByType -> {
                if (eventsByType.getKey() == EventType.PUBLISH_DICTIONARY) {
                    return eventsByType.compose(this::processDictionaryDeployEvents);
                } else if (eventsByType.getKey() == EventType.UNPUBLISH_DICTIONARY) {
                    return eventsByType.compose(this::processDictionaryUndeployEvents);
                } else {
                    return Flowable.empty();
                }
            });
    }

    @NonNull
    private Flowable processDictionaryDeployEvents(Flowable upstream) {
        return upstream.flatMapMaybe(this::toDictionary).compose(this::deployDictionary);
    }

    @NonNull
    private Flowable processDictionaryUndeployEvents(Flowable upstream) {
        return upstream.flatMapMaybe(this::toDictionaryId).compose(this::undeployDictionary);
    }

    @NonNull
    private Flowable deployDictionary(Flowable upstream) {
        return upstream
            .parallel(PARALLELISM)
            .runOn(Schedulers.from(executor))
            .doOnNext(dictionary -> {
                try {
                    dictionaryManager.deploy(dictionary);
                } catch (Exception e) {
                    logger.error("An error occurred when trying to deploy dictionary {} [{}].", dictionary.getName(), dictionary.getId());
                }
            })
            .sequential()
            .map(io.gravitee.gateway.dictionary.model.Dictionary::getId);
    }

    @NonNull
    private Flowable undeployDictionary(Flowable upstream) {
        return upstream
            .parallel(PARALLELISM)
            .runOn(Schedulers.from(executor))
            .doOnNext(dictionaryId -> {
                try {
                    dictionaryManager.undeploy(dictionaryId);
                } catch (Exception e) {
                    logger.error("An error occurred when trying to undeploy dictionary [{}].", dictionaryId);
                }
            })
            .sequential();
    }

    private Maybe toDictionary(Event event) {
        try {
            // Read dictionary definition from event
            return Maybe.just(objectMapper.readValue(event.getPayload(), io.gravitee.gateway.dictionary.model.Dictionary.class));
        } catch (Exception ex) {
            logger.error("Error while determining deployed dictionaries into events payload", ex);
        }

        return Maybe.empty();
    }

    private Maybe toDictionaryId(Event dictionaryEvent) {
        final String dictionaryId = dictionaryEvent.getProperties().get(DICTIONARY_ID.getValue());

        if (dictionaryId == null) {
            logger.error("Unable to extract dictionary info from event [{}].", dictionaryEvent.getId());
            return Maybe.empty();
        }
        return Maybe.just(dictionaryId);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy