001package org.intellimate.izou.sdk.events; 002 003import org.intellimate.izou.events.EventBehaviourControllerModel; 004import org.intellimate.izou.events.EventLifeCycle; 005import org.intellimate.izou.events.EventModel; 006import org.intellimate.izou.identification.Identification; 007import org.intellimate.izou.resource.ListResourceProvider; 008import org.intellimate.izou.resource.ResourceModel; 009import org.intellimate.izou.sdk.resource.*; 010 011import java.util.*; 012import java.util.concurrent.ConcurrentHashMap; 013import java.util.function.Consumer; 014 015/** 016 * This class represents an Event. 017 * This class is immutable! for every change it will return an new instance! 018 */ 019public class Event implements EventModel<Event> { 020 private final String type; 021 private final Identification source; 022 private final List<String> descriptors; 023 private final ListResourceProvider listResourceContainer; 024 private final EventBehaviourController eventBehaviourController; 025 private final ConcurrentHashMap<EventLifeCycle, List<Consumer<EventLifeCycle>>> lifeCycleListeners = new ConcurrentHashMap<>(); 026 027 /** 028 * Creates a new Event Object 029 * @param type the Type of the Event, try to use the predefined Event types 030 * @param source the source of the Event, most likely a this reference. 031 * @param descriptors the descriptors to initialize the Event with 032 * @throws IllegalArgumentException if one of the Arguments is null or empty 033 */ 034 protected Event(String type, Identification source, List<String> descriptors) throws IllegalArgumentException { 035 if(type == null || type.isEmpty()) throw new IllegalArgumentException("illegal type"); 036 if(source == null) throw new IllegalArgumentException("source is null"); 037 this.type = type; 038 this.source = source; 039 this.descriptors = Collections.unmodifiableList(descriptors); 040 listResourceContainer = new ListResourceProviderImpl(); 041 eventBehaviourController = new EventBehaviourController(); 042 } 043 044 /** 045 * Creates a new Event Object 046 * @param type the Type of the Event, try to use the predefined Event types 047 * @param source the source of the Event, most likely a this reference. 048 * @param listResourceContainer the ResourceContainer 049 * @param descriptors the descriptors to initialize the Event with 050 * @param eventBehaviourController the Controller of the Event 051 * @throws IllegalArgumentException if one of the Arguments is null or empty 052 */ 053 protected Event(String type, Identification source, ListResourceProvider listResourceContainer, List<String> descriptors, 054 EventBehaviourController eventBehaviourController)throws IllegalArgumentException { 055 if(type == null || type.isEmpty()) throw new IllegalArgumentException("illegal type"); 056 if(source == null) throw new IllegalArgumentException("source is null"); 057 this.type = type; 058 this.source = source; 059 this.descriptors = Collections.unmodifiableList(new ArrayList<>(descriptors)); 060 this.listResourceContainer = listResourceContainer; 061 this.eventBehaviourController = eventBehaviourController; 062 } 063 064 /** 065 * Creates a new Event Object 066 * @param type the Type of the Event, try to use the predefined Event types 067 * @param source the source of the Event, most likely a this reference. 068 * @return an Optional, that may be empty if type is null or empty or source is null 069 */ 070 public static Optional<Event> createEvent(String type, Identification source) { 071 try { 072 return Optional.of(new Event(type, source, new ArrayList<>())); 073 } catch (IllegalArgumentException e) { 074 return Optional.empty(); 075 } 076 } 077 078 /** 079 * Creates a new Event Object 080 * @param type the Type of the Event, try to use the predefined Event types 081 * @param source the source of the Event, most likely a this reference. 082 * @param descriptors the descriptors 083 * @return an Optional, that may be empty if type is null or empty or source is null 084 */ 085 public static Optional<Event> createEvent(String type, Identification source, List<String> descriptors) { 086 try { 087 return Optional.of(new Event(type, source, descriptors)); 088 } catch (IllegalArgumentException e) { 089 return Optional.empty(); 090 } 091 } 092 093 /** 094 * The ID of the Event. 095 * It describes the Type of the Event. 096 * @return A String containing an ID 097 */ 098 @Override 099 public String getID() { 100 return type; 101 } 102 103 /** 104 * The type of the Event. 105 * It describes the Type of the Event. 106 * @return A String containing an ID 107 */ 108 @Override 109 public String getType() { 110 return type; 111 } 112 113 /** 114 * returns the Source of the Event, e.g. the object who fired it. 115 * @return an identifiable 116 */ 117 @Override 118 public Identification getSource() { 119 return source; 120 } 121 122 /** 123 * returns all the Resources the Event currently has 124 * @return an instance of ListResourceContainer 125 */ 126 @Override 127 public ListResourceProvider getListResourceContainer() { 128 return listResourceContainer; 129 } 130 131 /** 132 * adds a Resource to the Container 133 * @param resource an instance of the resource to add 134 * @return the resulting Event (which is the same instance) 135 */ 136 @Override 137 public Event addResource(ResourceModel resource) { 138 listResourceContainer.addResource(resource); 139 return this; 140 } 141 142 /** 143 * adds a List of Resources to the Container 144 * @param resources a list containing all the resources 145 */ 146 @Override 147 public Event addResources(List<ResourceModel> resources) { 148 listResourceContainer.addResource(resources); 149 return this; 150 } 151 152 /** 153 * returns a List containing all the Descriptors. 154 * @return a List containing the Descriptors 155 */ 156 @Override 157 public List<String> getDescriptors() { 158 return descriptors; 159 } 160 161 /** 162 * returns a List containing all the Descriptors and the type. 163 * @return a List containing the Descriptors 164 */ 165 @Override 166 public List<String> getAllInformations() { 167 ArrayList<String> strings = new ArrayList<>(descriptors); 168 strings.add(type); 169 return strings; 170 } 171 172 /** 173 * sets the Descriptors (but not the Event-Type). 174 * <p> 175 * Replaces all existing descriptors. 176 * Since Event is immutable, it will create a new Instance. 177 * </p> 178 * @param descriptors a List containing all the Descriptors 179 * @return the resulting Event (which is the same instance) 180 */ 181 public Event setDescriptors(List<String> descriptors) { 182 return new Event(getType(), getSource(), descriptors); 183 } 184 185 /** 186 * sets the Descriptors (but not the Event-Type). 187 * @param descriptor a String describing the Event. 188 * @return the resulting Event (which is the same instance) 189 */ 190 public Event addDescriptor(String descriptor) { 191 List<String> newDescriptors = new ArrayList<>(); 192 newDescriptors.addAll(descriptors); 193 newDescriptors.add(descriptor); 194 return new Event(getType(), getSource(), newDescriptors); 195 } 196 197 198 /** 199 * replaces the Descriptors 200 * @param descriptors a list containing the Descriptors. 201 * @return the resulting Event (which is the same instance) 202 */ 203 public Event replaceDescriptors(List<String> descriptors) { 204 return new Event(getType(), getSource(), descriptors); 205 } 206 207 /** 208 * returns whether the event contains the specific descriptor. 209 * this method also checks whether it matches the type. 210 * @param descriptor a String with the ID of the Descriptor 211 * @return boolean when the Event contains the descriptor, false when not. 212 */ 213 @Override 214 public boolean containsDescriptor(String descriptor) { 215 return descriptors.contains(descriptor) || type.equals(descriptor); 216 } 217 218 /** 219 * returns the associated EventBehaviourController 220 * @return an instance of EventBehaviourController 221 */ 222 @Override 223 public EventBehaviourControllerModel getEventBehaviourController() { 224 return eventBehaviourController; 225 } 226 227 @Override 228 public void lifecycleCallback(EventLifeCycle eventLifeCycle) { 229 lifeCycleListeners.getOrDefault(eventLifeCycle, new LinkedList<>()).stream() 230 .forEach(eventLifeCycleConsumer -> eventLifeCycleConsumer.accept(eventLifeCycle)); 231 } 232 233 /** 234 * adds the Consumer to the specified EventLifeCycle. 235 * In its current implementation the invocation of the Callback method is parallel, but the notificaton of the listners not. 236 * @param eventLifeCycle the EventLifeCycle to target 237 * @param cycleCallback the callback 238 */ 239 @SuppressWarnings("unused") 240 public Event addEventLifeCycleListener(EventLifeCycle eventLifeCycle, Consumer<EventLifeCycle> cycleCallback) { 241 lifeCycleListeners.compute(eventLifeCycle, (unused, list) -> { 242 if (list == null) 243 list = new ArrayList<>(); 244 list.add(cycleCallback); 245 return list; 246 }); 247 return this; 248 } 249 250 @Override 251 public String toString() { 252 return "Event{" + 253 "type='" + type + '\'' + 254 ", source=" + source + 255 ", descriptors=" + descriptors + 256 ", listResourceContainer=" + listResourceContainer + 257 '}'; 258 } 259}