001    package org.LiveGraph.events;
002    
003    import java.lang.reflect.Field;
004    import java.util.ArrayList;
005    import java.util.Collections;
006    import java.util.List;
007    
008    import com.softnetConsult.utils.exceptions.Bug;
009    
010    
011    public class Event<ET extends EventType> {
012    
013    public static final boolean SAFE_EVENT_CAST = true;
014    
015    private EventProducer producer;
016    private Class<? extends ET> domain;
017    private ET type;
018    
019    private boolean hasValidated;
020    
021    public boolean infoBoolean;
022    public long infoLong;
023    public double infoDouble;
024    public Object infoObject;
025    
026    private List<EventAnnotation> annotations;
027    private List<EventAnnotation> exposedAnnotations;
028    
029    public Event(EventProducer producer, Class<? extends ET> domain, ET type) {
030            
031            if (null == producer)   throw new NullPointerException("Cannot construct event for a null producer");
032            if (null == domain)             throw new NullPointerException("Cannot construct event for a null domain");
033            if (null == type)               throw new NullPointerException("Cannot construct event for a null type");
034            
035            this.producer = producer;
036            this.domain = domain;
037            this.type = type;
038            
039            this.hasValidated = false;
040            
041            this.infoBoolean = false;
042            this.infoLong = 0L;
043            this.infoDouble = Double.NaN;
044            this.infoObject = null;
045            
046            this.annotations = null;
047            this.exposedAnnotations = null;
048    }
049    
050    public Event(EventProducer producer, Class<? extends ET> domain, ET type, boolean info) {
051            this(producer, domain, type);
052            this.infoBoolean = info;
053    }
054    
055    public Event(EventProducer producer, Class<? extends ET> domain, ET type, long info) {
056            this(producer, domain, type);
057            this.infoLong = info;
058    }
059    
060    public Event(EventProducer producer, Class<? extends ET> domain, ET type, double info) {
061            this(producer, domain, type);
062            this.infoDouble = info;
063    }
064    
065    public Event(EventProducer producer, Class<? extends ET> domain, ET type, Object info) {
066            this(producer, domain, type);
067            this.infoObject = info;
068    }
069    
070    public Event(EventProducer producer, Class<? extends ET> domain, ET type,
071                             boolean infoBoolean, long infoLong, double infoDouble, Object infoObject) {
072            this(producer, domain, type);
073            this.infoBoolean = infoBoolean;
074            this.infoLong = infoLong;
075            this.infoDouble = infoDouble;
076            this.infoObject = infoObject;
077    }
078    
079    @SuppressWarnings("unchecked")
080    public <T extends EventType> Event<T> cast(Class<T> domain) {
081            
082            if (SAFE_EVENT_CAST) {
083            
084                    if (null == domain)
085                            throw new NullPointerException("Cannot cast event to a null target domain");
086                    
087                    if (!getDomain().isAssignableFrom(domain)) {
088                            throw new ClassCastException("Cannot cast this event of type "
089                                                                    + this.getClass().getName() + "<" + getDomain().getName() + "> "
090                                                                    + "to Event<" + domain.getName() + ">");
091                    }
092            }
093            
094            return (Event<T>) this;
095    }
096    
097    public EventProducer getProducer() {
098            return producer;
099    }
100    
101    public Class<? extends ET> getDomain() {
102            return domain;
103    }
104    
105    public ET getType() {
106            return type;
107    }
108    
109    public boolean validated() {
110            return hasValidated;
111    }
112    
113    protected void setValidated(boolean validated) {
114            hasValidated = validated;
115    }
116    
117    public Validation.Requirement getValidationRequirement() {
118            
119            Class<? extends EventType> typeClass = type.getClass();
120            Validation validation = typeClass.getAnnotation(Validation.class);
121            if (null != validation)
122                    return validation.value();
123            
124            // If the event type is an enum, the annotation may have been attached not to the
125            // class itself, but to the "field", i.e. the enum constant:
126            if (typeClass.isEnum()) {
127                    
128                    try {
129                            Field declaringField = typeClass.getField(type.toString());
130                            validation = declaringField.getAnnotation(Validation.class);
131                    } catch(NoSuchFieldException e) {
132                            throw new Bug("This should never happen!", e);
133                    }
134                    
135                    if (null != validation)
136                            return validation.value();
137            }
138            
139            return Validation.Requirement.MAY_VALIDATE;
140    }
141    
142    public boolean getInfoBoolean() {
143            return infoBoolean;
144    }
145    
146    public long getInfoLong() {
147            return infoLong;
148    }
149    
150    public double getInfoDouble() {
151            return infoDouble;
152    }
153    
154    public Object getInfoObject() {
155            return infoObject;
156    }
157    
158    public void addAnnotation(EventListener listener, Object annotationInfo) {
159            if (null == listener)
160                    throw new NullPointerException("A null EventListener cannot add an EventAnnotation");
161            if (null == annotations)
162                    annotations = new ArrayList<EventAnnotation>();
163            annotations.add(new EventAnnotation(listener, annotationInfo));
164            exposedAnnotations = null;
165    }
166    
167    
168    public List<EventAnnotation> getAnnotations() {
169            if (null == exposedAnnotations) {
170                    
171                    if (null == annotations)
172                            return Collections.emptyList();
173                    
174                    exposedAnnotations = new ArrayList<EventAnnotation>();
175                    for (EventAnnotation annotation : annotations)
176                            exposedAnnotations.add(annotation);
177                    exposedAnnotations = Collections.unmodifiableList(exposedAnnotations);
178            }
179            return exposedAnnotations;
180    }
181    
182    public List<EventAnnotation> getAnnotations(EventListener byListener) {
183            
184            if (null == annotations)
185                    return Collections.emptyList();
186            
187            if (null == byListener)
188                    return getAnnotations();
189            
190            List<EventAnnotation> listenerAnnotations = new ArrayList<EventAnnotation>();
191            for (EventAnnotation annotation : annotations) {
192                    if (annotation.getListener() == byListener)
193                            listenerAnnotations.add(annotation);
194            }
195            return Collections.unmodifiableList(listenerAnnotations);
196    }
197    
198    @Override
199    public String toString() {
200            String s = super.toString() + "{";
201            s += "type=(" + getType().toString() + ");";
202            s += "producer=(" + getProducer().toString() + ");";
203            s += "info=(";
204            s += "bool:" + getInfoBoolean() + ";";
205            s += "long:" + getInfoLong() + ";";
206            s += "dble:" + getInfoDouble() + ";";
207            s += "objt:" + getInfoObject() + ";";
208            s += ");";
209            s += "validated=(" + (validated() ? "Y" : "N") + ");";
210            s += "valid-reqr=(" + getValidationRequirement() + ");";
211            s += "annotations=(" + (null == annotations ? 0 : annotations.size()) + ");";
212            s += "}";
213            return s;
214    }
215    
216    }