<commit_before>/**
 * Copyright (C) 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;

import io.gravitee.gateway.core.definition.Api;
import io.gravitee.gateway.core.manager.ApiManager;
import io.gravitee.repository.exceptions.TechnicalException;
import io.gravitee.repository.management.api.ApiRepository;
import io.gravitee.repository.management.api.EventRepository;
import io.gravitee.repository.management.model.Event;
import io.gravitee.repository.management.model.EventType;
import io.gravitee.repository.management.model.LifecycleState;

import java.io.IOException;
import java.net.InetAddress;
import java.text.Collator;
import java.util.*;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @author <NAME> (<EMAIL> at <EMAIL>)
 */
public class SyncManager {

    public static final String TAGS_PROP = "tags";

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

    @Autowired
    private ApiRepository apiRepository;
    
    @Autowired
    private EventRepository eventRepository;

    @Autowired
    private ApiManager apiManager;

    @Autowired
    private ObjectMapper objectMapper;

    @Value("${tags:}")
    private String propertyTags;

    public void refresh() {
        logger.debug("Refreshing gateway state...");

        try {
            Set<io.gravitee.repository.management.model.Api> apis = apiRepository.findAll();
            
            // Determine deployed APIs store into events payload
            Set<Api> deployedApis = getDeployedApis(apis);

            Map<String, Api> apisMap = deployedApis.stream()
                    .filter(api -> api != null && isConfiguredTags(api))
                    .collect(Collectors.toMap(Api::getId, api -> api));

            // Determine APIs to undeploy
            Set<String> apiToRemove = apiManager.apis().stream()
                    .filter(api -> !apisMap.containsKey(api.getId()) || !isConfiguredTags(api))
                    .map(Api::getId)
                    .collect(Collectors.toSet());

            apiToRemove.stream().forEach(apiManager::undeploy);

            // Determine APIs to update
            apisMap.keySet().stream()
                    .filter(apiId -> apiManager.get(apiId) != null)
                    .forEach(apiId -> {
                        // Get local cached API
                        Api deployedApi = apiManager.get(apiId);

                        // Get API from store
                        Api remoteApi = apisMap.get(apiId);

                        if (deployedApi.getDeployedAt().before(remoteApi.getDeployedAt())) {
                            apiManager.update(remoteApi);
                        }
                    });

            // Determine APIs to deploy
            apisMap.keySet().stream()
                    .filter(api -> apiManager.get(api) == null)
                    .forEach(api -> {
                        Api newApi = apisMap.get(api);
                        apiManager.deploy(newApi);
                    });

        } catch (TechnicalException te) {
            logger.error("Unable to sync instance", te);
        }
    }

    private boolean isConfiguredTags(Api api) {
        final String systemPropertyTags = System.getProperty(TAGS_PROP);
        final String tags = systemPropertyTags == null ? propertyTags : systemPropertyTags;
        if (tags != null && !tags.isEmpty()) {
            if (api.getTags() != null) {
                final List<String> tagList = Arrays.asList(tags.split(","));
                return tagList.stream()
                        .anyMatch(tag -> api.getTags().stream()
                                .anyMatch(apiTag -> {
                                    final Collator collator = Collator.getInstance();
                                    collator.setStrength(Collator.NO_DECOMPOSITION);
                                    return collator.compare(tag, apiTag) == 0;
                                })
                        );
            }
            // tags are configured on gateway instance but not found on api
            return false;
        }
        // no tags configured on this gateway instance
        return true;
    }
    
    private Set<Api> getDeployedApis(Set<io.gravitee.repository.management.model.Api> apis) {
    	Set<Api> deployedApis = new HashSet<Api>();
    	
    	Collection<Event> events = eventRepository.findByType(Arrays.asList(EventType.PUBLISH_API, EventType.UNPUBLISH_API));
    	List<Event> eventsSorted = events.stream().sorted((e1, e2) -> e1.getCreatedAt().compareTo(e2.getCreatedAt())).collect(Collectors.toList());
    	Collections.reverse(eventsSorted);
    	try {
    		for (io.gravitee.repository.management.model.Api api : apis) {
	    		for (Event _event : eventsSorted) {
	    			JsonNode node = objectMapper.readTree(_event.getPayload());
	    			io.gravitee.repository.management.model.Api payloadApi = objectMapper.convertValue(node, io.gravitee.repository.management.model.Api.class);
	    			if (api.getId().equals(payloadApi.getId())) {
	    				deployedApis.add(convert(payloadApi));
	    				// create success publish API event
	    				String hostAddress = InetAddress.getLocalHost().getHostAddress();
	    				Event event = new Event();
	    				event.setType(EventType.PUBLISH_API_RESULT);
	    				event.setPayload("API : " + api.getId() + " deployed");
	    				event.setParentId(event.getId());

                        Map<String, String> eventProps = new HashMap<>();
                        eventProps.put(Event.EventProperties.ORIGIN.getValue(), hostAddress);

	    				eventRepository.create(event);
	    				break;
	    			}
	    		}
    		}<commit_msg>fix(events-sync): do not create published events every time into the sync manager<commit_after>/**
 * Copyright (C) 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;

import io.gravitee.gateway.core.definition.Api;
import io.gravitee.gateway.core.manager.ApiManager;
import io.gravitee.repository.exceptions.TechnicalException;
import io.gravitee.repository.management.api.ApiRepository;
import io.gravitee.repository.management.api.EventRepository;
import io.gravitee.repository.management.model.Event;
import io.gravitee.repository.management.model.EventType;
import io.gravitee.repository.management.model.LifecycleState;

import java.io.IOException;
import java.text.Collator;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @author <NAME> (<EMAIL>)
 */
public class SyncManager {

    public static final String TAGS_PROP = "tags";

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

    @Autowired
    private ApiRepository apiRepository;
    
    @Autowired
    private EventRepository eventRepository;

    @Autowired
    private ApiManager apiManager;

    @Autowired
    private ObjectMapper objectMapper;

    @Value("${tags:}")
    private String propertyTags;

    public void refresh() {
        logger.debug("Refreshing gateway state...");

        try {
            Set<io.gravitee.repository.management.model.Api> apis = apiRepository.findAll();
            
            // Determine deployed APIs store into events payload
            Set<Api> deployedApis = getDeployedApis(apis);

            Map<String, Api> apisMap = deployedApis.stream()
                    .filter(api -> api != null && isConfiguredTags(api))
                    .collect(Collectors.toMap(Api::getId, api -> api));

            // Determine APIs to undeploy
            Set<String> apiToRemove = apiManager.apis().stream()
                    .filter(api -> !apisMap.containsKey(api.getId()) || !isConfiguredTags(api))
                    .map(Api::getId)
                    .collect(Collectors.toSet());

            apiToRemove.stream().forEach(apiManager::undeploy);

            // Determine APIs to update
            apisMap.keySet().stream()
                    .filter(apiId -> apiManager.get(apiId) != null)
                    .forEach(apiId -> {
                        // Get local cached API
                        Api deployedApi = apiManager.get(apiId);

                        // Get API from store
                        Api remoteApi = apisMap.get(apiId);

                        if (deployedApi.getDeployedAt().before(remoteApi.getDeployedAt())) {
                            apiManager.update(remoteApi);
                        }
                    });

            // Determine APIs to deploy
            apisMap.keySet().stream()
                    .filter(api -> apiManager.get(api) == null)
                    .forEach(api -> {
                        Api newApi = apisMap.get(api);
                        apiManager.deploy(newApi);
                    });

        } catch (TechnicalException te) {
            logger.error("Unable to sync instance", te);
        }
    }

    private boolean isConfiguredTags(Api api) {
        final String systemPropertyTags = System.getProperty(TAGS_PROP);
        final String tags = systemPropertyTags == null ? propertyTags : systemPropertyTags;
        if (tags != null && !tags.isEmpty()) {
            if (api.getTags() != null) {
                final List<String> tagList = Arrays.asList(tags.split(","));
                return tagList.stream()
                        .anyMatch(tag -> api.getTags().stream()
                                .anyMatch(apiTag -> {
                                    final Collator collator = Collator.getInstance();
                                    collator.setStrength(Collator.NO_DECOMPOSITION);
                                    return collator.compare(tag, apiTag) == 0;
                                })
                        );
            }
            // tags are configured on gateway instance but not found on api
            return false;
        }
        // no tags configured on this gateway instance
        return true;
    }
    
    private Set<Api> getDeployedApis(Set<io.gravitee.repository.management.model.Api> apis) {
    	Set<Api> deployedApis = new HashSet<Api>();
    	
    	Collection<Event> events = eventRepository.findByType(Arrays.asList(EventType.PUBLISH_API, EventType.UNPUBLISH_API));
    	List<Event> eventsSorted = events.stream().sorted((e1, e2) -> e1.getCreatedAt().compareTo(e2.getCreatedAt())).collect(Collectors.toList());
    	Collections.reverse(eventsSorted);
    	try {
    		for (io.gravitee.repository.management.model.Api api : apis) {
	    		for (Event _event : eventsSorted) {
	    			JsonNode node = objectMapper.readTree(_event.getPayload());
	    			io.gravitee.repository.management.model.Api payloadApi = objectMapper.convertValue(node, io.gravitee.repository.management.model.Api.class);
	    			if (api.getId().equals(payloadApi.getId())) {
	    				deployedApis.add(convert(payloadApi));
	    				break;
	    			}
	    		}
    		}
{'fraction_non_alphanumeric': 0.10576393803570025, 'fraction_numerical': 0.0023590469450342063, 'mean_word_length': 2.2173033139387806, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 52, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2685074', 'n_tokens_mistral': 3560, 'n_tokens_neox': 3382, 'n_words': 756}