package org.intellimate.izou.resource; import org.intellimate.izou.util.AddonThreadPoolUser; import org.intellimate.izou.util.IzouModule; import org.intellimate.izou.events.EventModel; import org.intellimate.izou.identification.IllegalIDException; import org.intellimate.izou.main.Main; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; import java.util.stream.Collectors; /** * this class manages all the ResourceBuilders. */ public class ResourceManager extends IzouModule implements AddonThreadPoolUser { /** * this object maps all the eventIDs to ResourceBuilders * the key is the registered event (or noEvent) */ private HashMap<String, LinkedList<ResourceBuilderModel>> eventSubscribers = new HashMap<>(); /** * this object maps all the resourceID to ResourceBuilders * the key is the registered event (or noEvent) * the List contains all the ResourceBuilders registered */ private HashMap<String, LinkedList<ResourceBuilderModel>> resourceIDs= new HashMap<>(); public ResourceManager(Main main) { super(main); } /** * generates all the resources for an event * @param event the Event to generate the resources for * @return a List containing all the generated resources */ public List<ResourceModel> generateResources(EventModel<?> event) { if(!event.getAllInformations().stream() .anyMatch(eventSubscribers::containsKey)) return new LinkedList<>(); List<ResourceBuilderModel> resourceBuilders = event.getAllInformations().stream() .map(eventSubscribers::get) .filter(Objects::nonNull) .flatMap(Collection::stream) .distinct() .collect(Collectors.toList()); return generateResources(resourceBuilders, event); } /** * generates the resources with a 1 sec. timeout for each ResourceBuilder * @param resourceBuilders the ResourceBuilders * @param event the event or null if not present * @return a List of generated resources */ private List<ResourceModel> generateResources(List<ResourceBuilderModel> resourceBuilders, EventModel event) { Optional<EventModel> parameter = event != null ? Optional.of(event) : Optional.empty(); List<CompletableFuture<List<ResourceModel>>> futures = resourceBuilders.stream() .map(resourceB -> submit(() -> resourceB.provideResource(resourceB.announceResources(), parameter))) .collect(Collectors.toList()); try { futures = timeOut(futures, 3000); } catch (InterruptedException e) { debug("interrupted while doing an time-out", e); } return futures.stream() .map(future -> { try { return future.get(); } catch (InterruptedException | ExecutionException e) { debug("exception while trying to get the result from the future", e); return null; } }) .filter(Objects::nonNull) .flatMap(Collection::stream) .collect(Collectors.toList()); } /** * generates a resources * <p> * It will use the first matching resource! So if you really want to be sure, set the provider * Identification * </p> * @param resource the resource to request * @param consumer the callback when the ResourceBuilder finishes * @throws IllegalIDException not yet implemented */ @Deprecated public void generatedResource(ResourceModel resource, Consumer<List<ResourceModel>> consumer) throws IllegalIDException { generateResource(resource) .ifPresent(completableFuture -> completableFuture.thenAccept(consumer)); } /** * generates a resources * <p> * It will use the first matching resource! So if you really want to be sure, set the provider * Identification * </p> * @param resource the resource to request * @return an optional of an CompletableFuture * @throws IllegalIDException not yet implemented */ public Optional<CompletableFuture<List<ResourceModel>>> generateResource (ResourceModel resource) throws IllegalIDException { if(resourceIDs.get(resource.getResourceID()) == null) return Optional.empty(); return resourceIDs.get(resource.getResourceID()).stream() //return true if resource has no provider, if not check provider .filter(resourceS -> !resource.hasProvider() || resourceS.isOwner(resource.getProvider())) .findFirst() .map(resourceB -> submit(() -> resourceB.provideResource(Collections.singletonList(resource), Optional.empty()))); } /** * registers a ResourceBuilder. * <p> * this method registers all the events, resourcesID etc. * @param resourceBuilder an instance of the ResourceBuilder * @throws IllegalIDException not yet implemented */ public void registerResourceBuilder(ResourceBuilderModel resourceBuilder) throws IllegalIDException { registerResourceIDsForResourceBuilder(resourceBuilder); registerEventsForResourceBuilder(resourceBuilder); } /** * registers all ResourceIDs for the ResourceBuilders * @param resourceBuilder an instance of ResourceBuilder */ private void registerResourceIDsForResourceBuilder(ResourceBuilderModel resourceBuilder) { List<? extends ResourceModel> resources = resourceBuilder.announceResources(); if(resources == null) return; resources.stream() .map(this::getRegisteredListForResource) .forEach(list -> list.add(resourceBuilder)); } /** * returns the list with all the ResourceBuilders listening to the Resource * @param resource the resource to listen to * @return a List of ResourceBuilders */ private List<ResourceBuilderModel> getRegisteredListForResource(ResourceModel resource) { if(resourceIDs.containsKey(resource.getResourceID())) { return resourceIDs.get(resource.getResourceID()); } else { LinkedList<ResourceBuilderModel> tempList = new LinkedList<>(); resourceIDs.put(resource.getResourceID(), tempList); return tempList; } } /** * Registers the events for the ResourceBuilder * * @param resourceBuilder an instance of ResourceBuilder */ private void registerEventsForResourceBuilder(ResourceBuilderModel resourceBuilder) { List<? extends EventModel<?>> events = resourceBuilder.announceEvents(); if(events == null) return; events.stream() .filter(event -> event.getAllInformations() != null) .flatMap(event -> event.getAllInformations().stream()) .map(this::getRegisteredListForEvent) .forEach(list -> list.add(resourceBuilder)); } /** * returns a list of all the ResourceBuilders listening to the Event-ID * @param event the eventID * @return a List of ResourceBuilders */ private List<ResourceBuilderModel> getRegisteredListForEvent(String event) { if(eventSubscribers.containsKey(event)) { return eventSubscribers.get(event); } else { LinkedList<ResourceBuilderModel> tempList = new LinkedList<>(); eventSubscribers.put(event, tempList); return tempList; } } /** * unregister a ResourceBuilder. * <p> * this method unregisters all the events, resourcesID etc. * @param resourceBuilder an instance of the ResourceBuilder */ public void unregisterResourceBuilder(ResourceBuilderModel resourceBuilder) { unregisterResourceIDForResourceBuilder(resourceBuilder); unregisterEventsForResourceBuilder(resourceBuilder); } /** * Unregisters all ResourceIDs for the ResourceBuilders * * @param resourceBuilder an instance of ResourceBuilder */ private void unregisterResourceIDForResourceBuilder(ResourceBuilderModel resourceBuilder) { List<? extends ResourceModel> resources = resourceBuilder.announceResources(); resources.stream().map(resource -> resourceIDs.get(resource.getResourceID())) .filter(Objects::nonNull) .forEach(list -> list.remove(resourceBuilder)); } /** * unregisters the events for the ResourceBuilder * @param resourceBuilder an instance of ResourceBuilder */ private void unregisterEventsForResourceBuilder(ResourceBuilderModel resourceBuilder) { resourceBuilder.announceEvents().stream() .map(eventSubscribers::get) .filter(Objects::nonNull) .forEach(list -> list.remove(resourceBuilder)); } }