Changeset 2592
- Timestamp:
- 07/05/08 22:16:04 (3 months ago)
- Location:
- trunk/components
- Files:
-
- 8 modified
-
blitz/src/ome/services/blitz/impl/ServiceFactoryI.java (modified) (1 diff)
-
server/src/ome/services/sessions/SessionContext.java (modified) (1 diff)
-
server/src/ome/services/sessions/SessionContextImpl.java (modified) (2 diffs)
-
server/src/ome/services/sessions/SessionManager.java (modified) (1 diff)
-
server/src/ome/services/sessions/SessionManagerImpl.java (modified) (8 diffs)
-
server/test/ome/server/utests/sessions/SessMgrUnitTest.java (modified) (11 diffs)
-
tools/OmeroPy/src/omero/__init__.py (modified) (5 diffs)
-
tools/OmeroPy/test/integration/isession.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/components/blitz/src/ome/services/blitz/impl/ServiceFactoryI.java
r2397 r2592 524 524 } 525 525 526 /** 527 * Destruction simply decrements the reference count for a session to allow 528 * reconnecting to it. This means that the Glacier timeout property is 529 * fairly unimportant. If a Glacier connection times out or is otherwise 530 * destroyed, a client can attempt to reconnect 531 */ 526 532 public void destroy(Ice.Current current) { 527 if (log.isInfoEnabled()) { 528 log.info(String.format("Destroying %s session", current.id.name)); 529 } 530 close(current); 533 sessionManager.detach(this.principal.getName()); 531 534 } 532 535 -
trunk/components/server/src/ome/services/sessions/SessionContext.java
r2124 r2592 24 24 25 25 Session getSession(); 26 26 27 List<String> getUserRoles(); 27 28 29 // Reference counting 30 31 /** 32 * Return the current number of references which this session is aware of. 33 */ 34 int refCount(); 35 36 /** 37 * Increment the current {@link #refCount() reference count} and return the 38 * new value atomically. 39 */ 40 int increment(); 41 42 /** 43 * Decrement the current {@link #refCount() reference count} and return the 44 * new value atomically. 45 */ 46 int decrement(); 28 47 } -
trunk/components/server/src/ome/services/sessions/SessionContextImpl.java
r2125 r2592 11 11 import java.util.Collections; 12 12 import java.util.List; 13 import java.util.concurrent.atomic.AtomicInteger; 13 14 14 15 import ome.model.meta.Session; 15 16 16 17 public class SessionContextImpl implements SessionContext { 18 19 private final AtomicInteger refCount = new AtomicInteger(0); 17 20 private final Session session; 18 21 private final List<Long> leaderOfGroups; … … 28 31 mGroups)); 29 32 this.roles = Collections.unmodifiableList(new ArrayList(roles)); 33 } 34 35 public int refCount() { 36 return refCount.get(); 37 } 38 39 public int increment() { 40 return refCount.incrementAndGet(); 41 } 42 43 public int decrement() { 44 return refCount.decrementAndGet(); 30 45 } 31 46 -
trunk/components/server/src/ome/services/sessions/SessionManager.java
r2274 r2592 51 51 Session create(Principal principal); 52 52 53 /** 54 * 55 * @param session 56 * @return 57 */ 53 58 Session update(Session session); 59 60 /** 61 * Allows decrementing the reference count for a session without calling the 62 * actual {@link #close(String)} logic. This is useful when it is assumed 63 * that another user will re-attach to the same session. A timeout can still 64 * cause the session to be removed. 65 * 66 * @param uuid 67 * @return 68 */ 69 int detach(String uuid); 54 70 55 71 /** -
trunk/components/server/src/ome/services/sessions/SessionManagerImpl.java
r2388 r2592 73 73 74 74 // Injected 75 OmeroContext context;76 Roles roles;77 SessionCache cache;78 Executor executor;79 long defaultTimeToIdle;80 long defaultTimeToLive;75 protected OmeroContext context; 76 protected Roles roles; 77 protected SessionCache cache; 78 protected Executor executor; 79 protected long defaultTimeToIdle; 80 protected long defaultTimeToLive; 81 81 82 82 /** … … 84 84 * {@link Executor} 85 85 */ 86 Principal asroot;87 SessionContext sc;86 protected Principal asroot; 87 protected SessionContext sc; 88 88 89 89 // ~ Injectors … … 155 155 SessionContext context = cache.getSessionContext(credentials); 156 156 if (context != null) { 157 context.increment(); 157 158 return context.getSession(); // EARLY EXIT! 158 159 } … … 161 162 } 162 163 163 boolean ok = executeCheckPassword(_principal, credentials); 164 // Though trusted values, if we receive a null principal, not ok; 165 boolean ok = _principal == null ? false : executeCheckPassword( 166 _principal, credentials); 164 167 165 168 if (!ok) { … … 179 182 .getName()); 180 183 if (context != null) { 184 context.increment(); 181 185 return context.getSession(); // EARLY EXIT! 182 186 } … … 205 209 throw re; 206 210 } 211 212 // All successful, increment and return. 213 ctx.increment(); 207 214 return session; 208 215 } … … 294 301 } 295 302 303 public int getReferenceCount(String uuid) { 304 SessionContext ctx = cache.getSessionContext(uuid); 305 return ctx.refCount(); 306 } 307 308 public int detach(String uuid) { 309 SessionContext ctx = cache.getSessionContext(uuid); 310 return ctx.decrement(); 311 } 312 296 313 /* 297 314 */ … … 302 319 ctx = cache.getSessionContext(uuid); 303 320 } catch (SessionException se) { 304 ctx = null; 305 } 306 307 if (ctx == null) { 308 return; 309 } 310 311 Session s = ctx.getSession(); 312 s.setClosed(new Timestamp(System.currentTimeMillis())); 313 update(s); 314 315 try { 316 context.publishEvent(new DestroySessionMessage(this, s.getUuid())); 317 } catch (RuntimeException re) { 318 log.warn("Session destruction cancelled by event listener", re); 319 throw re; 320 } 321 // This the publishEvent returns successfully, then we update our cache 322 // since ehcache is not tx-friendly. 323 cache.removeSession(uuid); 321 return; // EARLY EXIT! 322 } 323 324 int refCount = ctx.decrement(); 325 if (refCount < 1) { 326 327 Session s = ctx.getSession(); 328 s.setClosed(new Timestamp(System.currentTimeMillis())); 329 update(s); 330 331 try { 332 context.publishEvent(new DestroySessionMessage(this, s 333 .getUuid())); 334 } catch (RuntimeException re) { 335 log.warn("Session destruction cancelled by event listener", re); 336 throw re; 337 } 338 // This the publishEvent returns successfully, then we update our 339 // cache 340 // since ehcache is not tx-friendly. 341 cache.removeSession(uuid); 342 } 324 343 } 325 344 -
trunk/components/server/test/ome/server/utests/sessions/SessMgrUnitTest.java
r2126 r2592 10 10 import java.util.List; 11 11 12 import ome.conditions.ApiUsageException; 12 import net.sf.ehcache.CacheManager; 13 import ome.api.local.LocalAdmin; 14 import ome.api.local.LocalQuery; 15 import ome.api.local.LocalUpdate; 16 import ome.conditions.AuthenticationException; 13 17 import ome.conditions.SecurityViolation; 14 18 import ome.conditions.SessionException; … … 20 24 import ome.model.meta.ExperimenterGroup; 21 25 import ome.model.meta.Session; 26 import ome.services.sessions.SessionContext; 22 27 import ome.services.sessions.SessionManagerImpl; 28 import ome.services.sessions.state.SessionCache; 29 import ome.services.util.Executor; 30 import ome.system.OmeroContext; 23 31 import ome.system.Principal; 24 32 import ome.system.Roles; 33 import ome.testing.MockServiceFactory; 25 34 26 35 import org.jmock.Mock; 27 36 import org.jmock.MockObjectTestCase; 28 37 import org.jmock.core.Constraint; 38 import org.jmock.core.Invocation; 39 import org.jmock.core.Stub; 29 40 import org.testng.annotations.BeforeTest; 30 41 import org.testng.annotations.Test; … … 36 47 public class SessMgrUnitTest extends MockObjectTestCase { 37 48 38 private static class TestSessionManager extends SessionManagerImpl { 39 40 } 41 42 private Mock adminMock, updateMock, queryMock; 43 private TestSessionManager mgr; 44 private Session session; 45 46 @BeforeTest 47 public void config() { 48 mgr = new TestSessionManager(); 49 mgr.setRoles(new Roles()); 50 51 session = new Session(); 52 session.setUuid("uuid"); 53 session.setId(1L); 54 } 55 49 private final class DoWorkStub implements Stub { 50 public Object invoke(Invocation i) throws Throwable { 51 Executor.Work work = (Executor.Work) i.parameterValues.get(1); 52 return work.doWork(null, null, sf); 53 } 54 55 public StringBuffer describeTo(StringBuffer sb) { 56 sb.append("calls doWork on work"); 57 return sb; 58 } 59 } 60 61 private final class TestManager extends SessionManagerImpl { 62 Session doDefine() { 63 return define("uuid", "message", System.currentTimeMillis(), 64 defaultTimeToIdle, defaultTimeToLive, "Test", "rw----"); 65 } 66 } 67 68 private final OmeroContext oc = new OmeroContext( 69 "classpath:ome/testing/empty.xml"); 70 private final MockServiceFactory sf = new MockServiceFactory(); 71 private Mock exMock; 72 private TestManager mgr; 73 private SessionCache cache; 74 75 // State 76 Session session = new Session(); 56 77 Principal principal = new Principal("u", "g", "Test"); 57 78 String credentials = "password"; … … 62 83 List<String> userRoles = Collections.singletonList("single"); 63 84 85 @BeforeTest 86 public void config() { 87 88 exMock = mock(Executor.class); 89 sf.mockAdmin = mock(LocalAdmin.class); 90 sf.mockUpdate = mock(LocalUpdate.class); 91 sf.mockQuery = mock(LocalQuery.class); 92 93 cache = new SessionCache(); 94 cache.setCacheManager(CacheManager.getInstance()); 95 96 mgr = new TestManager(); 97 mgr.setRoles(new Roles()); 98 mgr.setSessionCache(cache); 99 mgr.setExecutor((Executor) exMock.proxy()); 100 mgr.setApplicationContext(oc); 101 mgr.setDefaultTimeToIdle(100 * 1000L); 102 mgr.setDefaultTimeToLive(300 * 1000L); 103 104 session = mgr.doDefine(); 105 session.setId(1L); 106 107 user.setOmeName(principal.getName()); 108 } 109 64 110 void prepareSessionCreation() { 65 adminMock.expects(once()).method("checkPassword").will( 111 112 exMock.expects(atLeastOnce()).method("execute").will(new DoWorkStub()); 113 114 sf.mockAdmin.expects(once()).method("checkPassword").will( 66 115 returnValue(true)); 67 adminMock.expects(once()).method("userProxy").will(returnValue(user)); 68 adminMock.expects(once()).method("groupProxy").will(returnValue(group)); 69 adminMock.expects(once()).method("getMemberOfGroupIds").will( 116 sf.mockAdmin.expects(atLeastOnce()).method("userProxy").will( 117 returnValue(user)); 118 sf.mockAdmin.expects(atLeastOnce()).method("groupProxy").will( 119 returnValue(group)); 120 sf.mockAdmin.expects(atLeastOnce()).method("getMemberOfGroupIds").will( 70 121 returnValue(m_ids)); 71 adminMock.expects(once()).method("getLeaderOfGroupIds").will(122 sf.mockAdmin.expects(atLeastOnce()).method("getLeaderOfGroupIds").will( 72 123 returnValue(l_ids)); 73 adminMock.expects(once()).method("getUserRoles").will(124 sf.mockAdmin.expects(atLeastOnce()).method("getUserRoles").will( 74 125 returnValue(userRoles)); 75 adminMock.expects(once()).method("checkPassword").will(126 sf.mockAdmin.expects(once()).method("checkPassword").will( 76 127 returnValue(true)); 77 queryMock.expects(once()).method("findAllByQuery")128 sf.mockQuery.expects(once()).method("findAllByQuery") 78 129 .will( 79 130 returnValue(Collections 80 131 .singletonList(new ExperimenterGroup()))); 81 updateMock.expects(once()).method("saveObject"); 132 sf.mockUpdate.expects(atLeastOnce()).method("saveAndReturnObject") 133 .will(returnValue(session)); 134 135 } 136 137 void prepareSessionUpdate() { 138 prepareSessionCreation(); 139 // exMock.expects(atLeastOnce()).method("execute").will(new 140 // DoWorkStub()); 141 // 142 // sf.mockAdmin.expects(once()).method("userProxy") 143 // .will(returnValue(user)); 144 // sf.mockAdmin.expects(atLeastOnce()).method("groupProxy").will( 145 // returnValue(group)); 146 // sf.mockUpdate.expects(once()).method("saveAndReturnObject").will( 147 // new SetIdStub(1L)); 148 // 82 149 } 83 150 … … 91 158 92 159 prepareSessionCreation(); 93 session= mgr.create(principal, credentials);160 assert session == mgr.create(principal, credentials); 94 161 assertNotNull(session); 95 162 assertNotNull(session.getUuid()); … … 141 208 testCreateNewSession(); 142 209 session.setDefaultEventType("somethingnew"); 143 updateMock.expects(once()).method("saveAndReturnObject").will(210 sf.mockUpdate.expects(once()).method("saveAndReturnObject").will( 144 211 returnValue(rv)); 212 213 prepareSessionUpdate(); 145 214 Session test = mgr.update(session); 146 assert True(test == rv); // insists that a copy is performed215 assertFalse(test == rv); // insists that a copy is performed 147 216 } 148 217 … … 204 273 205 274 }; 206 updateMock.expects(once()).method("saveObject").with(closedSession);275 sf.mockUpdate.expects(once()).method("saveObject").with(closedSession); 207 276 mgr.close(session.getUuid()); 208 277 assertNull(mgr.find(session.getUuid())); … … 224 293 225 294 }; 226 updateMock.expects(once()).method("saveObject").with(closedSession);295 sf.mockUpdate.expects(once()).method("saveObject").with(closedSession); 227 296 mgr.close(session.getUuid()); 228 297 assertNull(mgr.find(session.getUuid())); … … 260 329 261 330 void prepareForCreateSession() { 262 adminMock.expects(once()).method("userProxy").will(returnValue(user)); 263 adminMock.expects(once()).method("groupProxy").will(returnValue(group)); 264 adminMock.expects(once()).method("getMemberOfGroupIds").will( 331 sf.mockAdmin.expects(once()).method("userProxy") 332 .will(returnValue(user)); 333 sf.mockAdmin.expects(once()).method("groupProxy").will( 334 returnValue(group)); 335 sf.mockAdmin.expects(atLeastOnce()).method("getMemberOfGroupIds").will( 265 336 returnValue(m_ids)); 266 adminMock.expects(once()).method("getLeaderOfGroupIds").will(337 sf.mockAdmin.expects(atLeastOnce()).method("getLeaderOfGroupIds").will( 267 338 returnValue(l_ids)); 268 adminMock.expects(once()).method("getUserRoles").will(339 sf.mockAdmin.expects(once()).method("getUserRoles").will( 269 340 returnValue(userRoles)); 270 adminMock.expects(once()).method("checkPassword").will(341 sf.mockAdmin.expects(once()).method("checkPassword").will( 271 342 returnValue(true)); 272 343 } 273 344 274 @Test(expectedExceptions = A piUsageException.class)345 @Test(expectedExceptions = AuthenticationException.class) 275 346 public void testCreateSessionFailsAUEOnNullPrincipal() throws Exception { 276 adminMock.expects(once()).method("checkPassword").will(347 sf.mockAdmin.expects(once()).method("checkPassword").will( 277 348 returnValue(false)); 278 349 mgr.create(null, "password"); 279 350 } 280 351 281 @Test(expectedExceptions = A piUsageException.class)352 @Test(expectedExceptions = AuthenticationException.class) 282 353 public void testCreateSessionFailsAUEOnNullOmeName() throws Exception { 283 adminMock.expects(once()).method("checkPassword").will(354 sf.mockAdmin.expects(once()).method("checkPassword").will( 284 355 returnValue(false)); 285 356 mgr.create(new Principal(null, null, null), "password"); 286 357 } 287 358 288 @Test(expectedExceptions = SecurityViolation.class)359 @Test(expectedExceptions = AuthenticationException.class) 289 360 public void testCreateSessionFailsSV() throws Exception { 290 adminMock.expects(once()).method("checkPassword").will(361 sf.mockAdmin.expects(once()).method("checkPassword").will( 291 362 returnValue(false)); 292 363 mgr.create(principal, "password"); … … 296 367 public void testChecksForDefaultGroupsOnCreation() throws Exception { 297 368 prepareForCreateSession(); 298 queryMock.expects(once()).method("findAllByQuery").will( 369 sf.mockAdmin.expects(once()).method("getDefaultGroup").will( 370 returnValue(group)); 371 sf.mockQuery.expects(once()).method("findAllByQuery").will( 299 372 returnValue(Collections.EMPTY_LIST)); 300 373 mgr.create(new Principal("user", "user", "User"), "user"); … … 321 394 fail("NYI"); 322 395 } 396 397 @Test 398 public void testReferenceCounting() throws Exception { 399 testCreateNewSession(); 400 String uuid = session.getUuid(); 401 SessionContext ctx = cache.getSessionContext(uuid); 402 403 assertEquals(1, ctx.refCount()); 404 assertNull(ctx.getSession().getClosed()); 405 406 mgr.create(new Principal(uuid)); 407 assertEquals(2, ctx.refCount()); 408 assertNull(ctx.getSession().getClosed()); 409 410 mgr.close(uuid); 411 assertEquals(1, ctx.refCount()); 412 assertNull(ctx.getSession().getClosed()); 413 414 prepareSessionUpdate(); 415 mgr.close(uuid); 416 assertEquals(0, ctx.refCount()); 417 assertNotNull(ctx.getSession().getClosed()); 418 } 323 419 } -
trunk/components/tools/OmeroPy/src/omero/__init__.py
r2396 r2592 11 11 """ 12 12 13 import exceptions 13 import exceptions, traceback 14 14 import Ice, Glacier2 15 15 import api … … 21 21 class client(object): 22 22 """ 23 Central blitz entry point 23 Central blitz entry point. Currently useful for a single session, after closing the 24 connection, create another instance. 24 25 25 26 Typical usage includes: … … 37 38 self.of.registerObjectFactory(ic) 38 39 self.ic = ic 40 self.close_on_destroy = True 41 42 def closeOnDestroy(self): 43 """ 44 Closes the blitz session when destroyConnection() is called on exit. 45 This prevents other clients from attaching to the same blitz session, 46 and is more secure. 47 """ 48 self.close_on_destroy = True 49 50 def detachOnDestroy(self): 51 """ 52 Prevents the blitz session from being closed when destroyConnection() 53 is called. This will allow other clients to attach to the session for 54 distribtued work. This is less secure, but in many cases valuable. 55 """ 39 56 self.close_on_destroy = False 40 57 41 def closeOnDestroy(self):42 self.close_on_destroy = True43 44 58 def __del__(self): 45 if self.close_on_destroy: 46 self.closeSession() 47 if self.ic: 48 try: 49 self.ic.destroy() 50 except (), msg: 51 pysys.stderr.write("Ice exception while destroying communicator:") 52 pysys.stderr.write(msg) 53 self.ic = None 59 try: 60 self.destroyConnection() 61 except exceptions.Exception, e: 62 print "Error in __del__:" + str(e.__class__) 54 63 55 64 def getCommunicator(self): … … 207 216 file.close() 208 217 218 def destroyConnection(self): 219 """ 220 Closes the Router connection created by createSession(). Due to a bug in Ice, 221 only one connection is allowed per communicator, so we also destroy the communicator. 222 """ 223 # If 'ic' does not exist we don't have anything to do 224 if not hasattr(self, 'ic') or not self.ic: 225 return 226 227 if self.close_on_destroy: 228 self.closeSession() 229 230 prx = self.ic.getDefaultRouter() 231 router = Glacier2.RouterPrx.checkedCast(prx) 232 233 # Now destroy the actual session if possible, 234 # which will always trigger an exception, 235 # regardless of actually being connected or not 236 if router: 237 try: 238 router.destroySession() 239 except exceptions.Exception, e: 240 pass 241 # SNEE happens if we call sf.close() before 242 # calling destroySession(). CLE happens since 243 # we are disconnecting 244 245 try: 246 self.ic.destroy() 247 except (), msg: 248 pysys.stderr.write("Ice exception while destroying communicator:") 249 pysys.stderr.write(msg) 250 self.ic = None 251 209 252 def closeSession(self): 253 """ 254 Call close on the session (ServiceFactoryPrx) which first decrements 255 the reference count. If its reference count becomes 0, then the session 256 will be removed from the server. 257 """ 210 258 # If 'sf' does not exist we don't have a session at all 211 259 if not hasattr(self, 'sf'): …
