package cloudone.cumulonimbus.later; import java.io.ByteArrayInputStream; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.concurrent.atomic.AtomicInteger; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import cloudone.C1Services; import cloudone.ServiceFullName; import cloudone.cumulonimbus.ResourceRegistryService; import cloudone.cumulonimbus.ServiceRegistryService; import cloudone.cumulonimbus.model.Cluster; import cloudone.cumulonimbus.model.HttpMethod; import cloudone.cumulonimbus.model.RegisteredRuntime; import cloudone.internal.ApplicationFullName; import org.slf4j.LoggerFactory; /** * Service for queued invocation. * * @author Martin Mares (martin.mares at oracle.com) */ public class LaterService { private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(LaterService.class); private static final LaterService INSTANCE = new LaterService(); private final long baseId = System.currentTimeMillis(); private final AtomicInteger seqId = new AtomicInteger(0); private final Client client = ClientBuilder.newClient(); private final Map<String, List<LaterItem>> callAllItems = new HashMap<>(); public String addAllItem(String contentType, String methodName, String uri, String services, int retentionCount, byte[] payload) { List<ServiceFullName> servicesList = new ArrayList<>(); if (services != null) { StringTokenizer stok = new StringTokenizer(services, ";"); while (stok.hasMoreTokens()) { servicesList.add(new ServiceFullName(stok.nextToken())); } } LaterItem item = new LaterItem(baseId + "-" + seqId.incrementAndGet(), contentType, methodName, URI.create(uri), servicesList.toArray(new ServiceFullName[servicesList.size()]), retentionCount, payload); LOGGER.info("add: " + item); synchronized (callAllItems) { String path = item.getPath(); List<LaterItem> items = callAllItems.get(path); if (items == null) { items = new ArrayList<LaterItem>(); callAllItems.put(path, items); } items.add(item); List<LaterItem> toRemove = new ArrayList<>(); for (int i = 0; i < items.size(); i++) { int rc = items.get(i).getRetentionCount(); if (rc >= 0 && (items.size() - i - 1) >= rc) { toRemove.add(items.get(i)); } } items.removeAll(toRemove); } C1Services.getInstance().getExecutorService().submit(() -> processAllItem(item)); return item.getId(); } private void processAllItem(LaterItem item) { HttpMethod httpMethod = HttpMethod.valueOf(item.getMethod()); Collection<ApplicationFullName> apps; synchronized (callAllItems) { apps = ResourceRegistryService.getInstance() .getApplicationsForResource(item.getPath(), httpMethod); } apps = item.filterApps(apps); for (ApplicationFullName app : apps) { call(app, item); } } private void call(ApplicationFullName app, LaterItem item) { LOGGER.info("call(" + app + ", " + item.getId() + ")"); Cluster cluster = ServiceRegistryService.getInstance().getCluster(app.getServiceName()); UriBuilder uriBuilder = UriBuilder.fromUri(item.getUri()); for (RegisteredRuntime runtime : cluster.getRuntimes()) { int port = runtime.getApplicationPort(app.getApplicationName()); Response response = client .target(uriBuilder.host("localhost").port(port).scheme("http")) .request() .method(item.getMethod(), Entity.entity(new ByteArrayInputStream(item.getPayload()), item.getContentType())); if (response.getStatus() == 200) { //TODO: process entity item.deliveredTo(app); break; } } } public void processQueuesForNewApp(ApplicationFullName appFullName) { Collection<LaterItem> toProcess = new ArrayList<>(); //Process all synchronized (callAllItems) { for (List<LaterItem> laterItems : callAllItems.values()) { for (LaterItem item : laterItems) { HttpMethod httpMethod = HttpMethod.valueOf(item.getMethod()); Collection<ApplicationFullName> apps; synchronized (callAllItems) { apps = ResourceRegistryService.getInstance() .getApplicationsForResource(item.getPath(), httpMethod); } apps = item.filterApps(apps); for (ApplicationFullName app : apps) { if (app.equals(appFullName)) { toProcess.add(item); } } } } } //Execute for (LaterItem item : toProcess) { call(appFullName, item); } } public static LaterService getInstance() { return INSTANCE; } }