001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.impl.cloud;
018
019import java.util.Collection;
020import java.util.Comparator;
021import java.util.List;
022import java.util.Map;
023import java.util.Optional;
024import java.util.stream.Collectors;
025
026import org.apache.camel.cloud.ServiceRegistry;
027import org.apache.camel.util.ObjectHelper;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031public final class ServiceRegistrySelectors {
032    public static final ServiceRegistry.Selector DEFAULT_SELECTOR = new SelectSingle();
033    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceRegistrySelectors.class);
034
035    private ServiceRegistrySelectors() {
036    }
037
038    public static final class SelectSingle implements ServiceRegistry.Selector {
039        @Override
040        public Optional<ServiceRegistry> select(Collection<ServiceRegistry> services) {
041            if (services != null && services.size() == 1) {
042                return Optional.of(services.iterator().next());
043            } else {
044                LOGGER.warn("Multiple ServiceRegistry instances available (items={})", services);
045            }
046
047            return Optional.empty();
048        }
049    }
050
051    public static final class SelectFirst implements ServiceRegistry.Selector {
052        @Override
053        public Optional<ServiceRegistry> select(Collection<ServiceRegistry> services) {
054            return ObjectHelper.isNotEmpty(services)
055                ? Optional.of(services.iterator().next())
056                : Optional.empty();
057        }
058    }
059
060    public static final class SelectByOrder implements ServiceRegistry.Selector {
061        @Override
062        public Optional<ServiceRegistry> select(Collection<ServiceRegistry> services) {
063            Optional<Map.Entry<Integer, List<ServiceRegistry>>> highPriorityServices = services.stream()
064                .collect(Collectors.groupingBy(ServiceRegistry::getOrder))
065                .entrySet().stream()
066                    .min(Comparator.comparingInt(Map.Entry::getKey));
067
068
069            if (highPriorityServices.isPresent()) {
070                if (highPriorityServices.get().getValue().size() == 1) {
071                    return Optional.of(highPriorityServices.get().getValue().iterator().next());
072                } else {
073                    LOGGER.warn("Multiple ServiceRegistry instances available for highest priority (order={}, items={})",
074                        highPriorityServices.get().getKey(),
075                        highPriorityServices.get().getValue()
076                    );
077                }
078            }
079
080            return Optional.empty();
081        }
082    }
083
084    public static final class SelectByType implements ServiceRegistry.Selector {
085        private final Class<? extends ServiceRegistry> type;
086
087        public SelectByType(Class<? extends ServiceRegistry> type) {
088            this.type = type;
089        }
090
091        @Override
092        public Optional<ServiceRegistry> select(Collection<ServiceRegistry> services) {
093            for (ServiceRegistry service : services) {
094                if (type.isInstance(service)) {
095                    return Optional.of(service);
096                }
097            }
098
099            return Optional.empty();
100        }
101    }
102
103    public static final class SelectByAttribute implements ServiceRegistry.Selector {
104        private final String key;
105        private final Object value;
106
107        public SelectByAttribute(String key, Object value) {
108            this.key = key;
109            this.value = value;
110        }
111
112        @Override
113        public Optional<ServiceRegistry> select(Collection<ServiceRegistry> services) {
114            for (ServiceRegistry service : services) {
115                Map<String, Object> attributes = service.getAttributes();
116
117                if (ObjectHelper.equal(attributes.get(key), value)) {
118                    return Optional.of(service);
119                }
120            }
121
122            return Optional.empty();
123        }
124    }
125
126    // **********************************
127    // Helpers
128    // **********************************
129
130    public static ServiceRegistry.Selector defaultSelector() {
131        return DEFAULT_SELECTOR;
132    }
133
134    public static ServiceRegistry.Selector single() {
135        return new SelectSingle();
136    }
137
138    public static ServiceRegistry.Selector first() {
139        return new SelectFirst();
140    }
141
142    public static ServiceRegistry.Selector order() {
143        return new SelectByOrder();
144    }
145
146    public static ServiceRegistry.Selector type(Class<? extends ServiceRegistry> type) {
147        return new SelectByType(type);
148    }
149
150    public static ServiceRegistry.Selector attribute(String key, Object value) {
151        return new SelectByAttribute(key, value);
152    }
153}