/*
* Copyright 2014 Avanza Bank AB
*
* 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 com.avanza.astrix.beans.registry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.avanza.astrix.beans.core.AstrixBeanKey;
import com.avanza.astrix.beans.core.AstrixSettings;
import com.avanza.astrix.beans.service.DirectComponent;
import com.avanza.astrix.beans.service.ServiceConsumerProperties;
import com.avanza.astrix.beans.service.ServiceProperties;
import com.avanza.astrix.config.BooleanSetting;
import com.avanza.astrix.config.DynamicConfigSource;
import com.avanza.astrix.config.DynamicPropertyListener;
import com.avanza.astrix.config.GlobalConfigSourceRegistry;
import com.avanza.astrix.config.LongSetting;
import com.avanza.astrix.config.MapConfigSource;
import com.avanza.astrix.config.MutableConfigSource;
import com.avanza.astrix.config.Setting;
import com.avanza.astrix.provider.component.AstrixServiceComponentNames;
import com.avanza.astrix.provider.core.AstrixServiceExport;
/**
*
* @author Elias Lindholm (elilin)
*
*/
@AstrixServiceExport(AstrixServiceRegistry.class)
public class InMemoryServiceRegistry implements DynamicConfigSource, AstrixServiceRegistry, MutableConfigSource {
private final MapConfigSource configSource = new MapConfigSource();
private String id;
private String configSourceId;
private InMemoryServiceRegistryRepo repo = new InMemoryServiceRegistryRepo();
private AstrixServiceRegistry serviceRegistry = new AstrixServiceRegistryImpl(repo);
public InMemoryServiceRegistry() {
this.id = DirectComponent.register(AstrixServiceRegistry.class, this);
this.configSourceId = GlobalConfigSourceRegistry.register(this);
this.configSource.set(AstrixSettings.SERVICE_REGISTRY_URI, getServiceUri());
}
@Override
public List<AstrixServiceRegistryEntry> listServices() {
return serviceRegistry.listServices();
}
@Override
public <T> AstrixServiceRegistryEntry lookup(String type, String qualifier, ServiceConsumerProperties consumerProperties) {
return serviceRegistry.lookup(type, qualifier, consumerProperties);
}
@Override
public <T> void register(AstrixServiceRegistryEntry properties, long lease) {
serviceRegistry.register(properties, lease);
}
@Override
public <T> void deregister(AstrixServiceRegistryEntry properties) {
serviceRegistry.deregister(properties);
}
@Override
public List<AstrixServiceRegistryEntry> listServices(String type, String qualifier) {
return this.serviceRegistry.listServices(type, qualifier);
}
public String getConfigSourceId() {
return configSourceId;
}
public void clear() {
this.repo.clear();
}
/**
*
* @return
* @deprecated replaced by {@link AstrixSettings#SERVICE_REGISTRY_URI}
*/
@Deprecated
public String getConfigEntryName() {
return AstrixSettings.SERVICE_REGISTRY_URI_PROPERTY_NAME;
}
public String getServiceUri() {
return AstrixServiceComponentNames.DIRECT + ":" + this.id;
}
public void set(String settingName, String value) {
this.configSource.set(settingName, value);
}
public void set(String settingName, long value) {
this.configSource.set(settingName, Long.toString(value));
}
@Override
public <T> void set(Setting<T> setting, T value) {
this.configSource.set(setting, value);
}
@Override
public void set(BooleanSetting setting, boolean value) {
this.configSource.set(setting, value);
}
@Override
public void set(LongSetting setting, long value) {
this.configSource.set(setting, value);
}
public <T> void registerProvider(Class<T> api, T provider, String subsystem) {
// TODO: remove this method?
registerProvider(AstrixBeanKey.create(api), provider, subsystem);
}
public <T> void registerProvider(Class<T> api, ServiceProperties serviceProperties) {
// TODO: remove this method?
registerServiceProvider(AstrixBeanKey.create(api), "default", serviceProperties);
}
private <T> void registerProvider(AstrixBeanKey<T> beanKey, T provider, String subsystem) {
ServiceProperties serviceProperties = DirectComponent.registerAndGetProperties(beanKey.getBeanType(), provider);
registerServiceProvider(beanKey, subsystem, serviceProperties);
}
private <T> void registerServiceProvider(AstrixBeanKey<T> beanKey, String subsystem, ServiceProperties serviceProperties) {
ServiceRegistryExporterClient serviceRegistryClient = new ServiceRegistryExporterClient(this.serviceRegistry, subsystem, beanKey.toString());
serviceProperties.setQualifier(beanKey.getQualifier());
serviceRegistryClient.register(beanKey.getBeanType(), serviceProperties, 60_000);
}
/**
* Registers a provider for a given service that belongs to the 'default' subsystem.
*
* @param api
* @param provider
*/
public <T> void registerProvider(Class<T> api, T provider) {
registerProvider(api, provider, "default");
}
public <T> void registerProvider(Class<T> api, String qualifier, T provider) {
registerProvider(AstrixBeanKey.create(api, qualifier), provider, "default");
}
@Override
public String get(String propertyName) {
return configSource.get(propertyName);
}
@Override
public String get(String propertyName, DynamicPropertyListener<String> propertyChangeListener) {
return configSource.get(propertyName, propertyChangeListener);
}
private static class InMemoryServiceRegistryRepo implements ServiceRegistryEntryRepository {
private Map<ServiceProviderKey, AstrixServiceRegistryEntry> servicePropertiesByApplicationInstanceId = new ConcurrentHashMap<>();
@Override
public List<AstrixServiceRegistryEntry> findAll() {
return new ArrayList<>(servicePropertiesByApplicationInstanceId.values());
}
@Override
public List<AstrixServiceRegistryEntry> findByServiceKey(ServiceKey serviceKey) {
List<AstrixServiceRegistryEntry> result = new ArrayList<>();
for (AstrixServiceRegistryEntry entry : this.servicePropertiesByApplicationInstanceId.values()) {
if (serviceKey.equals(getServiceKey(entry))) {
result.add(entry);
}
}
return result;
}
@Override
public void insertOrUpdate(AstrixServiceRegistryEntry entry, long lease) {
this.servicePropertiesByApplicationInstanceId.put(getServiceProviderKey(entry), entry);
}
@Override
public void remove(ServiceProviderKey serviceProviderKey) {
this.servicePropertiesByApplicationInstanceId.remove(serviceProviderKey);
}
private ServiceProviderKey getServiceProviderKey(AstrixServiceRegistryEntry properties) {
String appInstanceId = properties.getServiceProperties().get(ServiceProperties.APPLICATION_INSTANCE_ID);
return ServiceProviderKey.create(getServiceKey(properties), appInstanceId);
}
private ServiceKey getServiceKey(AstrixServiceRegistryEntry properties) {
String api = properties.getServiceBeanType();
String qualifier = properties.getServiceProperties().get(ServiceProperties.QUALIFIER);
return new ServiceKey(api, qualifier);
}
void clear() {
this.servicePropertiesByApplicationInstanceId.clear();
}
}
}