View Javadoc

1   package cz.cuni.amis.pogamut.base.communication.worldview.react;
2   
3   import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
4   import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEvent;
5   import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObject;
6   import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
7   import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
8   import cz.cuni.amis.pogamut.base.communication.worldview.object.WorldObjectId;
9   
10  /**
11   * This abstract class allows you to easily hook a specific event-handling behavior. It automatically
12   * register a listener for a specified {@link IWorldObjectEvent} for you and calls {@link ObjectEventReact#react(IWorldObjectEvent)}
13   * method automatically.
14   * <p><p>
15   * If you need to react only once to the event, use {@link ObjectEventReactOnce}.
16   * <p><p>
17   * Use {@link ObjectEventReact#enable()} and {@link ObjectEventReact#disable()} to enable react / disable react. The reaction is enabled
18   * as default.
19   * <p><p>
20   * <b>WARNING:</b>Use as anonymous class, but <b>save it as a field</b> of your class! Note, that we're using weak-references to 
21   * listeners and if you do not save pointer to the object, it will be gc()ed!
22   * 
23   * @author Jimmy
24   *
25   * @param <EVENT>
26   */
27  public abstract class ObjectEventReact<OBJECT extends IWorldObject, EVENT extends IWorldObjectEvent<OBJECT>> {
28  
29  	protected static final int LEVEL_B_EVENT = 1;
30  	protected static final int LEVEL_C_EVENT = 2;
31  	protected static final int LEVEL_D_EVENT = 3;
32  	protected static final int LEVEL_E_EVENT = 4;
33  	
34  	protected IWorldObjectEventListener<OBJECT, EVENT> reactListener = new IWorldObjectEventListener<OBJECT, EVENT>() {
35  
36  		@Override
37  		public void notify(EVENT event) {
38  			preReact(event);
39  			react(event);
40  			postReact(event);
41  		}
42  	
43  	};
44  	
45  	protected IWorldView reactWorldView;
46  
47  	protected Class reactEventClass;
48  	
49  	protected Class reactObjectClass;
50  	
51  	protected WorldObjectId reactObjectId;
52  	
53  	protected final int reactObjectEventType;
54  	
55  	private boolean reactHooked = false;
56  	
57  	public ObjectEventReact(Class<?> objectClass, IWorldView worldView) {
58  		this.reactWorldView = worldView;
59  		this.reactObjectClass = objectClass;
60  		reactObjectEventType = LEVEL_B_EVENT;
61  		enable();
62  	}
63  	
64  
65  	public ObjectEventReact(Class<?> objectClass, Class<?> eventClass, IWorldView worldView) {
66  		this.reactWorldView = worldView;
67  		this.reactObjectClass = objectClass;
68  		this.reactEventClass = eventClass;
69  		reactObjectEventType = LEVEL_C_EVENT;
70  		enable();
71  	}
72  
73  	public ObjectEventReact(WorldObjectId objectId, IWorldView worldView) {
74  		this.reactWorldView = worldView;
75  		this.reactObjectId = objectId;
76  		reactObjectEventType = LEVEL_D_EVENT;
77  		enable();
78  	}
79  
80  	public ObjectEventReact(WorldObjectId objectId, Class<?> eventClass, IWorldView worldView) {
81  		this.reactWorldView = worldView;
82  		this.reactObjectId = objectId;
83  		this.reactEventClass = eventClass;
84  		reactObjectEventType = LEVEL_E_EVENT;
85  		enable();
86  	}
87  	
88  	/**
89  	 * Disables the reaction.
90  	 */
91  	public synchronized void disable() {
92  		if (reactHooked) {
93  			reactHooked = false;
94  			switch(reactObjectEventType) {
95  			case LEVEL_B_EVENT:
96  				reactWorldView.removeObjectListener(reactObjectClass, reactListener);
97  				break;
98  			case LEVEL_C_EVENT:
99  				reactWorldView.removeObjectListener(reactObjectClass, reactEventClass, reactListener);
100 				break;
101 			case LEVEL_D_EVENT:
102 				reactWorldView.removeObjectListener(reactObjectId, reactListener);
103 				break;
104 			case LEVEL_E_EVENT:
105 				reactWorldView.removeObjectListener(reactObjectId, reactEventClass, reactListener);
106 				break;
107 			default:
108 				throw new IllegalStateException("Unhandled objectEventType = " + reactObjectEventType + ".");
109 			}
110 		}
111 	}
112 	
113 	/**
114 	 * Enables the reaction.
115 	 */
116 	public synchronized void enable() {
117 		if (!reactHooked) {
118 			reactHooked = true;
119 			switch(reactObjectEventType) {
120 			case LEVEL_B_EVENT:
121 				if (!reactWorldView.isListening(reactEventClass, reactListener)) {
122 					reactWorldView.addObjectListener(reactObjectClass, reactListener);
123 				}
124 				break;
125 			case LEVEL_C_EVENT:
126 				if (!reactWorldView.isListening(reactObjectClass, reactListener)) {
127 					reactWorldView.addObjectListener(reactObjectClass, reactEventClass, reactListener);
128 				}
129 				break;
130 			case LEVEL_D_EVENT:
131 				if (!reactWorldView.isListening(reactObjectId, reactListener)) {
132 					reactWorldView.addObjectListener(reactObjectId, reactListener);
133 				}
134 				break;
135 			case LEVEL_E_EVENT:
136 				if (!reactWorldView.isListening(reactObjectId, reactEventClass, reactListener)) {
137 					reactWorldView.addObjectListener(reactObjectId, reactEventClass, reactListener);
138 				}
139 				break;
140 			default:
141 				throw new IllegalStateException("Unhandled objectEventType = " + reactObjectEventType + ".");
142 				
143 			}
144 		}
145 	}
146 	
147 	/**
148 	 * pre-{@link ObjectEventReact#react(IWorldEvent)} hook allowing you to do additional work before the react method.
149 	 * @param event
150 	 */
151 	protected void preReact(EVENT event) {
152 	}
153 
154 	/**
155 	 * React upon event notification.
156 	 * @param event
157 	 */
158 	protected abstract void react(EVENT event);
159 	
160 	/**
161 	 * post-{@link ObjectEventReact#react(IWorldEvent)} hook allowing you to do additional work after the react method.
162 	 * @param event
163 	 */
164 	protected void postReact(EVENT event) {
165 	}
166 
167 }