001package org.intellimate.izou.resource; 002 003import org.intellimate.izou.util.AddonThreadPoolUser; 004import org.intellimate.izou.util.IzouModule; 005import org.intellimate.izou.events.EventModel; 006import org.intellimate.izou.identification.IllegalIDException; 007import org.intellimate.izou.main.Main; 008 009import java.util.*; 010import java.util.concurrent.CompletableFuture; 011import java.util.concurrent.ExecutionException; 012import java.util.function.Consumer; 013import java.util.stream.Collectors; 014 015/** 016 * this class manages all the ResourceBuilders. 017 */ 018public class ResourceManager extends IzouModule implements AddonThreadPoolUser { 019 /** 020 * this object maps all the eventIDs to ResourceBuilders 021 * the key is the registered event (or noEvent) 022 */ 023 private HashMap<String, LinkedList<ResourceBuilderModel>> eventSubscribers = new HashMap<>(); 024 /** 025 * this object maps all the resourceID to ResourceBuilders 026 * the key is the registered event (or noEvent) 027 * the List contains all the ResourceBuilders registered 028 */ 029 private HashMap<String, LinkedList<ResourceBuilderModel>> resourceIDs= new HashMap<>(); 030 031 public ResourceManager(Main main) { 032 super(main); 033 } 034 035 /** 036 * generates all the resources for an event 037 * @param event the Event to generate the resources for 038 * @return a List containing all the generated resources 039 */ 040 public List<ResourceModel> generateResources(EventModel<?> event) { 041 if(!event.getAllInformations().stream() 042 .anyMatch(eventSubscribers::containsKey)) return new LinkedList<>(); 043 044 List<ResourceBuilderModel> resourceBuilders = event.getAllInformations().stream() 045 .map(eventSubscribers::get) 046 .filter(Objects::nonNull) 047 .flatMap(Collection::stream) 048 .distinct() 049 .collect(Collectors.toList()); 050 051 return generateResources(resourceBuilders, event); 052 } 053 054 /** 055 * generates the resources with a 1 sec. timeout for each ResourceBuilder 056 * @param resourceBuilders the ResourceBuilders 057 * @param event the event or null if not present 058 * @return a List of generated resources 059 */ 060 private List<ResourceModel> generateResources(List<ResourceBuilderModel> resourceBuilders, EventModel event) { 061 Optional<EventModel> parameter = event != null ? Optional.of(event) : Optional.empty(); 062 List<CompletableFuture<List<ResourceModel>>> futures = resourceBuilders.stream() 063 .map(resourceB -> submit(() -> resourceB.provideResource(resourceB.announceResources(), parameter))) 064 .collect(Collectors.toList()); 065 066 try { 067 futures = timeOut(futures, 3000); 068 } catch (InterruptedException e) { 069 debug("interrupted while doing an time-out", e); 070 } 071 072 return futures.stream() 073 .map(future -> { 074 try { 075 return future.get(); 076 } catch (InterruptedException | ExecutionException e) { 077 debug("exception while trying to get the result from the future", e); 078 return null; 079 } 080 }) 081 .filter(Objects::nonNull) 082 .flatMap(Collection::stream) 083 .collect(Collectors.toList()); 084 } 085 086 /** 087 * generates a resources 088 * <p> 089 * It will use the first matching resource! So if you really want to be sure, set the provider 090 * Identification 091 * </p> 092 * @param resource the resource to request 093 * @param consumer the callback when the ResourceBuilder finishes 094 * @throws IllegalIDException not yet implemented 095 */ 096 @Deprecated 097 public void generatedResource(ResourceModel resource, Consumer<List<ResourceModel>> consumer) throws IllegalIDException { 098 generateResource(resource) 099 .ifPresent(completableFuture -> completableFuture.thenAccept(consumer)); 100 } 101 102 /** 103 * generates a resources 104 * <p> 105 * It will use the first matching resource! So if you really want to be sure, set the provider 106 * Identification 107 * </p> 108 * @param resource the resource to request 109 * @return an optional of an CompletableFuture 110 * @throws IllegalIDException not yet implemented 111 */ 112 public Optional<CompletableFuture<List<ResourceModel>>> generateResource (ResourceModel resource) throws IllegalIDException { 113 if(resourceIDs.get(resource.getResourceID()) == null) return Optional.empty(); 114 return resourceIDs.get(resource.getResourceID()).stream() 115 //return true if resource has no provider, if not check provider 116 .filter(resourceS -> !resource.hasProvider() || resourceS.isOwner(resource.getProvider())) 117 .findFirst() 118 .map(resourceB -> submit(() -> resourceB.provideResource(Collections.singletonList(resource), Optional.empty()))); 119 } 120 121 /** 122 * registers a ResourceBuilder. 123 * <p> 124 * this method registers all the events, resourcesID etc. 125 * @param resourceBuilder an instance of the ResourceBuilder 126 * @throws IllegalIDException not yet implemented 127 */ 128 public void registerResourceBuilder(ResourceBuilderModel resourceBuilder) throws IllegalIDException { 129 registerResourceIDsForResourceBuilder(resourceBuilder); 130 registerEventsForResourceBuilder(resourceBuilder); 131 } 132 133 /** 134 * registers all ResourceIDs for the ResourceBuilders 135 * @param resourceBuilder an instance of ResourceBuilder 136 */ 137 private void registerResourceIDsForResourceBuilder(ResourceBuilderModel resourceBuilder) { 138 List<? extends ResourceModel> resources = resourceBuilder.announceResources(); 139 if(resources == null) return; 140 resources.stream() 141 .map(this::getRegisteredListForResource) 142 .forEach(list -> list.add(resourceBuilder)); 143 } 144 145 /** 146 * returns the list with all the ResourceBuilders listening to the Resource 147 * @param resource the resource to listen to 148 * @return a List of ResourceBuilders 149 */ 150 private List<ResourceBuilderModel> getRegisteredListForResource(ResourceModel resource) { 151 if(resourceIDs.containsKey(resource.getResourceID())) { 152 return resourceIDs.get(resource.getResourceID()); 153 } else { 154 LinkedList<ResourceBuilderModel> tempList = new LinkedList<>(); 155 resourceIDs.put(resource.getResourceID(), tempList); 156 return tempList; 157 } 158 } 159 160 /** 161 * Registers the events for the ResourceBuilder 162 * 163 * @param resourceBuilder an instance of ResourceBuilder 164 */ 165 private void registerEventsForResourceBuilder(ResourceBuilderModel resourceBuilder) { 166 List<? extends EventModel<?>> events = resourceBuilder.announceEvents(); 167 if(events == null) return; 168 events.stream() 169 .filter(event -> event.getAllInformations() != null) 170 .flatMap(event -> event.getAllInformations().stream()) 171 .map(this::getRegisteredListForEvent) 172 .forEach(list -> list.add(resourceBuilder)); 173 } 174 175 /** 176 * returns a list of all the ResourceBuilders listening to the Event-ID 177 * @param event the eventID 178 * @return a List of ResourceBuilders 179 */ 180 private List<ResourceBuilderModel> getRegisteredListForEvent(String event) { 181 if(eventSubscribers.containsKey(event)) { 182 return eventSubscribers.get(event); 183 } else { 184 LinkedList<ResourceBuilderModel> tempList = new LinkedList<>(); 185 eventSubscribers.put(event, tempList); 186 return tempList; 187 } 188 } 189 190 /** 191 * unregister a ResourceBuilder. 192 * <p> 193 * this method unregisters all the events, resourcesID etc. 194 * @param resourceBuilder an instance of the ResourceBuilder 195 */ 196 public void unregisterResourceBuilder(ResourceBuilderModel resourceBuilder) { 197 unregisterResourceIDForResourceBuilder(resourceBuilder); 198 unregisterEventsForResourceBuilder(resourceBuilder); 199 } 200 201 /** 202 * Unregisters all ResourceIDs for the ResourceBuilders 203 * 204 * @param resourceBuilder an instance of ResourceBuilder 205 */ 206 private void unregisterResourceIDForResourceBuilder(ResourceBuilderModel resourceBuilder) { 207 List<? extends ResourceModel> resources = resourceBuilder.announceResources(); 208 resources.stream().map(resource -> resourceIDs.get(resource.getResourceID())) 209 .filter(Objects::nonNull) 210 .forEach(list -> list.remove(resourceBuilder)); 211 } 212 213 /** 214 * unregisters the events for the ResourceBuilder 215 * @param resourceBuilder an instance of ResourceBuilder 216 */ 217 private void unregisterEventsForResourceBuilder(ResourceBuilderModel resourceBuilder) { 218 resourceBuilder.announceEvents().stream() 219 .map(eventSubscribers::get) 220 .filter(Objects::nonNull) 221 .forEach(list -> list.remove(resourceBuilder)); 222 } 223}