View Javadoc

1   /*
2    * Copyright (c) 2005 Regents of the University of California (Regents). Created
3    * by TELS, Graduate School of Education, University of California at Berkeley.
4    *
5    * This software is distributed under the GNU Lesser General Public License, v2.
6    *
7    * Permission is hereby granted, without written agreement and without license
8    * or royalty fees, to use, copy, modify, and distribute this software and its
9    * documentation for any purpose, provided that the above copyright notice and
10   * the following two paragraphs appear in all copies of this software.
11   *
12   * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
13   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14   * PURPOSE. THE SOFTWAREAND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
15   * HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
16   * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17   *
18   * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
19   * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
20   * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
21   * REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22   */
23  package net.sf.sail.core.beans;
24  
25  import java.beans.beancontext.BeanContextServiceProvider;
26  import java.beans.beancontext.BeanContextServices;
27  import java.beans.beancontext.BeanContextServicesSupport;
28  import java.io.File;
29  import java.io.FileOutputStream;
30  import java.io.PrintStream;
31  import java.util.ArrayList;
32  import java.util.Date;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.logging.Level;
36  import java.util.logging.Logger;
37  
38  import net.sf.sail.core.beans.event.SessionEvent;
39  import net.sf.sail.core.beans.event.SessionEventListener;
40  import net.sf.sail.core.beans.service.AgentService;
41  import net.sf.sail.core.beans.service.AnnotationService;
42  import net.sf.sail.core.beans.service.SessionService;
43  import net.sf.sail.core.entity.Offering;
44  import net.sf.sail.core.entity.User;
45  import net.sf.sail.core.session.DefaultSessionService;
46  import net.sf.sail.core.session.SessionDataService;
47  import net.sf.sail.core.uuid.SessionUuid;
48  
49  import org.apache.commons.lang.builder.ReflectionToStringBuilder;
50  
51  /**
52   * Provides services to beans within the pod. Allows beans and pods to listen for session events. a life cycle manager for sail. The parent
53   * bean for all javabeans.
54   * 
55   * @author turadg
56   * AUDIT07-
57   */
58  public class SessionContext extends BeanContextServicesSupport {
59  	/**
60  	 * Logger for this class
61  	 */
62  	private static final Logger logger = Logger.getLogger(SessionContext.class
63  			.getName());
64  
65  	private static final long serialVersionUID = 1L;
66  
67  	/**
68  	 * @author turadg
69  	 */
70  	class ServiceProvider implements BeanContextServiceProvider {
71  
72  		SessionService sessionService = new DefaultSessionService(
73  				SessionContext.this);
74  
75  		AgentService agentService = null;
76  		AnnotationService annotationService = null;
77  		
78  		void register(BeanContextServices bcs) {
79  			bcs.addService(SessionService.class, serviceProvider);
80  			bcs.addService(AgentService.class, serviceProvider);
81  			bcs.addService(AnnotationService.class, serviceProvider);
82  		}
83  
84  		/**
85  		 * This will be called if a pod is added to more than one SessionContext.
86  		 * The pod can only associated with a single session context at time.
87  		 */
88  		public void releaseService(BeanContextServices bcs, Object requestor,
89  				Object service) {
90  			// because we are not keeping track of the requestor and the services
91  			// are not tracking the requestor either we don't need to do anything
92  			// here. 
93  			return;
94  		}
95  
96  		@SuppressWarnings("unchecked")
97  		public Iterator getCurrentServiceSelectors(BeanContextServices bcs,
98  				Class serviceClass) {
99  			throw new UnsupportedOperationException();
100 		}
101 
102 		@SuppressWarnings("unchecked")
103 		public Object getService(BeanContextServices bcs, Object requestor,
104 				Class serviceClass, Object serviceSelector) {
105 			if (serviceClass == SessionService.class) {
106 				return sessionService;
107 			} else if (serviceClass == AgentService.class) {
108 				return agentService;
109 			} else if (serviceClass == AnnotationService.class) {
110 				return annotationService;
111 			} else {
112 				return null;
113 			}
114 		}
115 	}
116 
117 	private final ServiceProvider serviceProvider = new ServiceProvider();
118 
119 	SessionUuid sessionId;
120 
121 	SessionDataService sessionDataService;
122 
123 	Offering offering;
124 
125 	protected Date startTime;
126 
127 	protected Date stopTime;
128 	
129 	// FIXME TODO get rid of this hack
130 	public static boolean exitOnClose = true;
131 
132 	public Offering getOffering() {
133 		return offering;
134 	}
135 
136 	public void setOffering(Offering offering) {
137 		this.offering = offering;
138 	}
139 
140 	List<SessionEventListener> sessionEventListeners = new ArrayList<SessionEventListener>();
141 
142 	private boolean initiated;
143 
144 	private boolean terminationInProgress = false;
145 
146 	// timeDrift is the approximate difference in the SDS's clock and the local clock
147 	private long timeDrift;
148 
149 	public void addSessionEventListener(SessionEventListener sel) {
150 		sessionEventListeners.add(sel);
151 	}
152 
153 	protected void fireSessionEvent(SessionEvent se) {
154 		for (Object element : sessionEventListeners) {
155 			SessionEventListener listener = (SessionEventListener) element;
156 			switch (se.getID()) {
157 			case SessionEvent.INITIATE:
158 				listener.sessionInitiated(se);
159 				break;
160 			case SessionEvent.START:
161 				listener.sessionStarted(se);
162 				break;
163 			case SessionEvent.END:
164 				listener.sessionStopped(se);
165 				break;
166 			}
167 		}
168 	}
169 
170 	public void addUser(User user) {
171 		serviceProvider.sessionService.addUser(user);
172 	}
173 
174 	public void initiate() {
175 		if (sessionDataService == null)
176 			throw new IllegalStateException(
177 					"initiate() called before sessionDataService property set");
178 		BeanContextServices bcs = getBeanContextServicesPeer();
179 		serviceProvider.register(bcs);
180 		fireSessionEvent(new SessionEvent(this, SessionEvent.INITIATE));
181 		initiated = true;
182 	}
183 
184 	public void start() {
185 		if (!initiated)
186 			throw new IllegalStateException("start() called before initiate()");
187 		if (startTime == null) {
188 			initStartTime();
189 		}
190 		fireSessionEvent(new SessionEvent(this, SessionEvent.START));
191 		logger.info("Session started at " + startTime); //$NON-NLS-1$
192 	}
193 
194 	public void tryToTerminate() {
195 		logger.info("trying to terminate"); //$NON-NLS-1$
196 		if (terminationInProgress) {
197 			logger.severe("already trying to terminate. ignoring.");
198 			return;
199 		}
200 		terminationInProgress = true;
201 		stopTime = new Date();
202 		fireSessionEvent(new SessionEvent(this, SessionEvent.END));
203 		logger.info("Session ended at " + stopTime); //$NON-NLS-1$
204 		// dumpPersistance() should be called in a new thread for the progress bar to work correctly
205 		Thread t = new Thread() {
206 			public void run() {
207 				dumpPersistance();
208 				if (exitOnClose) System.exit(0);
209 				terminationInProgress = false;
210 			}
211 		};
212 		t.start();
213 	}
214 
215 	public Date getStartTime() {
216 		return startTime;
217 	}
218 	
219 	public void initStartTime() {
220 		if (startTime == null) {
221 			String strTime = ((DefaultSessionService)(serviceProvider.sessionService)).getProperty("sds_time", "0");
222 			long sdsTime = Long.parseLong(strTime); 
223 			if (sdsTime == 0) {
224 				startTime = new Date();
225 				timeDrift = 0;
226 			} else {
227 				startTime = new Date(sdsTime);
228 				timeDrift = java.lang.System.currentTimeMillis() - startTime.getTime();
229 			}
230 		}
231 	}
232 	
233 	public long getTimeDifference() {
234 		return timeDrift;
235 	}
236 
237 	public Date getStopTime() {
238 		return stopTime;
239 	}
240 
241 	public SessionUuid getSessionId() {
242 		return sessionId;
243 	}
244 
245 	public void setSessionId(SessionUuid sessionId) {
246 		this.sessionId = sessionId;
247 	}
248 
249 	public SessionDataService getSessionDataService() {
250 		return sessionDataService;
251 	}
252 
253 	public void setSessionDataService(SessionDataService sessionDataService) {
254 		this.sessionDataService = sessionDataService;
255 		serviceProvider.agentService = 
256 			sessionDataService.getPersistenceService(this);
257 		serviceProvider.annotationService = 
258 			sessionDataService.getAnnotationService();
259 	}
260 
261 	/**
262 	 * This is a hack until all this service mess is cleaned up
263 	 * @param key
264 	 * @param value
265 	 */
266 	public void setProperty(String key, String value)
267 	{
268 		((DefaultSessionService)(serviceProvider.sessionService)).setProperty(key, value);
269 	}
270 	
271 	/**
272 	 * Again this is a something that seems hacky.  Hopefully it can be clarified when
273 	 * the service mess is cleaned up or clarified.
274 	 * 
275 	 */
276 	public SessionService getSessionService()
277 	{
278 		return serviceProvider.sessionService;
279 	}
280 	
281 	/**
282 	 * @return milliseconds since the session started
283 	 */
284 	public long getOffsetMilliseconds() {
285 		return java.lang.System.currentTimeMillis() - startTime.getTime() - timeDrift;
286 	}
287 
288 	/**
289 	 * 
290 	 */
291 	protected void dumpPersistance() {
292 		try {
293 			File file = File.createTempFile("saildump", ".xml");
294 			logger.info("dumping persistance data to " + file); //$NON-NLS-1$
295 			PrintStream ps = new PrintStream(new FileOutputStream(file));
296 			serviceProvider.agentService.dump(this, ps);
297 			if (logger.isLoggable(Level.CONFIG)) {
298 				logger.info("done."); //$NON-NLS-1$
299 			}
300 		} catch (Exception e) {
301 			logger.log(Level.SEVERE, "FAILED to dump persistance data", e); //$NON-NLS-1$
302 		}
303 	}
304 
305 	@Override
306 	public String toString() {
307 		return ReflectionToStringBuilder.toString(this);
308 	}
309 }
310