package cloudone.cumulonimbus; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.WebTarget; import cloudone.cumulonimbus.later.LaterService; import cloudone.cumulonimbus.model.Cluster; import cloudone.cumulonimbus.model.HttpMethod; import cloudone.cumulonimbus.model.PathRegistry; import cloudone.cumulonimbus.model.RegisteredRuntime; import cloudone.cumulonimbus.model.RestResourceDescription; import cloudone.cumulonimbus.model.ServiceRestResources; import cloudone.cumulonimbus.provider.ServiceRestResourcesProvider; import cloudone.internal.ApplicationFullName; import org.slf4j.LoggerFactory; /** * Manages catalogue of REST resources from various services. * * @author Martin Mares (martin.mares at oracle.com) */ public class ResourceRegistryService { private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ResourceRegistryService.class); private static final ResourceRegistryService INSTANCE = new ResourceRegistryService(); private final Client client; private final ExecutorService executor; private final ConcurrentMap<ApplicationFullName, ServiceRestResources> register = new ConcurrentHashMap<>(); private final PathRegistry pathRegistry = new PathRegistry(); public ResourceRegistryService() { client = ClientBuilder.newClient() .register(ServiceRestResourcesProvider.class); executor = Executors.newSingleThreadExecutor(); } ServiceRegistryService.RegistrationListener getNewListener() { return new ServiceRegistryService.RegistrationListener() { @Override public void register(final RegisteredRuntime runtime, final Cluster cluster) throws Exception { for (String appName : runtime.getApplicationPorts().keySet()) { final ApplicationFullName appFullName = new ApplicationFullName(runtime.getServiceName(), appName); if (!register.containsKey(appFullName)) { executor.submit( () -> doLoadServiceContract(appFullName, runtime.getApplicationPort(appFullName.getApplicationName()))); } } } @Override public void unregister(final RegisteredRuntime runtime, final Cluster cluster) { executor.submit(() -> {if (cluster.getRuntimes().isEmpty() || cluster.getRuntimes().size() == 1 && cluster.getRuntimes().get(0).equals(runtime)) { doUnloadServiceContract(runtime); }}); } }; } private void doLoadServiceContract(final ApplicationFullName appFullName, final int port) { LOGGER.info("doLoadServiceContract(" + appFullName + ", " + port + ")"); if (!register.containsKey(appFullName)) { try { WebTarget target = client.target("http://localhost:" + port); ServiceRestResources serviceRestResources = target.path("application.wadl") .request() //TODO: Define media type of WADL .get(ServiceRestResources.class); serviceRestResources = new ServiceRestResources(appFullName, serviceRestResources.getResources()); register.put(appFullName, serviceRestResources); for (RestResourceDescription restResourceDescription : serviceRestResources.getResources()) { pathRegistry.register(restResourceDescription.getPath(), restResourceDescription.getMethod(), appFullName); } //This direct call is very ugly - MUST BE REDESIGNED LaterService.getInstance().processQueuesForNewApp(appFullName); } catch (Exception e) { LOGGER.warn("doLoadServiceContract(" + appFullName + "): Cannot load wadl!", e); } } } private void doUnloadServiceContract(RegisteredRuntime registeredRuntime) { LOGGER.info("doUnloadServiceContract(" + registeredRuntime + ")"); for (String app : registeredRuntime.getApplicationPorts().keySet()) { final ApplicationFullName appFullName = new ApplicationFullName(registeredRuntime.getServiceName(), app); ServiceRestResources serviceRestResources = register.remove(appFullName); pathRegistry.unregister(appFullName); } } public Set<ApplicationFullName> getApplicationsForResource(final String path, final HttpMethod method) { return pathRegistry.get(path, method); } public List<RestResourceDescription> getResourcesForApplication(ApplicationFullName appName) { ServiceRestResources result = register.get(appName); if (result == null) { return Collections.emptyList(); } else { return Collections.unmodifiableList(result.getResources()); } } public static ResourceRegistryService getInstance() { return INSTANCE; } }