001 package railo.runtime.type.scope; 002 003 import java.util.Iterator; 004 import java.util.Map; 005 import java.util.Map.Entry; 006 007 import javax.servlet.http.HttpSession; 008 009 import org.safehaus.uuid.UUIDGenerator; 010 011 import railo.commons.collections.HashTable; 012 import railo.commons.io.log.Log; 013 import railo.commons.io.log.LogAndSource; 014 import railo.commons.lang.ExceptionUtil; 015 import railo.commons.lang.SizeOf; 016 import railo.commons.lang.StringUtil; 017 import railo.commons.lang.types.RefBoolean; 018 import railo.commons.lang.types.RefBooleanImpl; 019 import railo.runtime.CFMLFactoryImpl; 020 import railo.runtime.PageContext; 021 import railo.runtime.PageContextImpl; 022 import railo.runtime.cache.CacheConnection; 023 import railo.runtime.config.Config; 024 import railo.runtime.config.ConfigImpl; 025 import railo.runtime.db.DataSource; 026 import railo.runtime.exp.ApplicationException; 027 import railo.runtime.exp.ExceptionHandler; 028 import railo.runtime.exp.ExpressionException; 029 import railo.runtime.exp.PageException; 030 import railo.runtime.exp.PageRuntimeException; 031 import railo.runtime.functions.cache.Util; 032 import railo.runtime.interpreter.VariableInterpreter; 033 import railo.runtime.listener.ApplicationContext; 034 import railo.runtime.listener.ApplicationListener; 035 import railo.runtime.net.http.ReqRspUtil; 036 import railo.runtime.op.Caster; 037 import railo.runtime.type.KeyImpl; 038 import railo.runtime.type.Struct; 039 import railo.runtime.type.StructImpl; 040 import railo.runtime.type.scope.client.ClientCache; 041 import railo.runtime.type.scope.client.ClientCookie; 042 import railo.runtime.type.scope.client.ClientDatasource; 043 import railo.runtime.type.scope.client.ClientFile; 044 import railo.runtime.type.scope.client.ClientMemory; 045 import railo.runtime.type.scope.session.SessionCache; 046 import railo.runtime.type.scope.session.SessionCookie; 047 import railo.runtime.type.scope.session.SessionDatasource; 048 import railo.runtime.type.scope.session.SessionFile; 049 import railo.runtime.type.scope.session.SessionMemory; 050 import railo.runtime.type.scope.storage.MemoryScope; 051 import railo.runtime.type.scope.storage.StorageScope; 052 import railo.runtime.type.scope.storage.StorageScopeCleaner; 053 import railo.runtime.type.scope.storage.StorageScopeEngine; 054 import railo.runtime.type.scope.storage.clean.DatasourceStorageScopeCleaner; 055 import railo.runtime.type.scope.storage.clean.FileStorageScopeCleaner; 056 import railo.runtime.type.wrap.MapAsStruct; 057 import railo.runtime.util.PageContextUtil; 058 059 /** 060 * Scope Context handle Apllication and Session Scopes 061 */ 062 public final class ScopeContext { 063 064 private static final int MINUTE = 60*1000; 065 private static final long CLIENT_MEMORY_TIMESPAN = 5*MINUTE; 066 private static final long SESSION_MEMORY_TIMESPAN = 5*MINUTE; 067 068 private static UUIDGenerator generator = UUIDGenerator.getInstance(); 069 private Map<String,Map<String,Scope>> cfSessionContextes=new HashTable(); 070 private Map<String,Map<String,Scope>> cfClientContextes=new HashTable(); 071 private Map<String,Application> applicationContextes=new HashTable(); 072 073 private int maxSessionTimeout=0; 074 075 private static Cluster cluster; 076 private static Server server=null; 077 078 079 private StorageScopeEngine client; 080 private StorageScopeEngine session; 081 private CFMLFactoryImpl factory; 082 private LogAndSource log; 083 084 085 086 public ScopeContext(CFMLFactoryImpl factory) { 087 this.factory=factory; 088 } 089 090 /** 091 * @return the log 092 */ 093 private Log getLog() { 094 if(log==null) { 095 this.log=((ConfigImpl)factory.getConfig()).getScopeLogger(); 096 097 } 098 return log; 099 } 100 101 public void info(String msg) {info(getLog(), msg);} 102 public void error(String msg) {error(getLog(),msg);} 103 public void error(Throwable t) {error(getLog(), t);} 104 105 public static void info(Log log,String msg) { 106 if(log!=null)log.info("scope-context", msg); 107 } 108 109 110 public static void error(Log log,String msg) { 111 if(log!=null)log.error("scope-context", msg); 112 } 113 114 public static void error(Log log,Throwable t) { 115 if(log!=null)log.error("scope-context",ExceptionUtil.getStacktrace(t, true)); 116 } 117 118 119 /** 120 * return a map matching key from given map 121 * @param parent 122 * @param key key of the map 123 * @return matching map, if no map exist it willbe one created 124 */ 125 private Map<String,Scope> getSubMap(Map<String,Map<String,Scope>> parent, String key) { 126 127 Map<String,Scope> context=parent.get(key); 128 if(context!=null) return context; 129 130 context = new HashTable(); 131 parent.put(key,context); 132 return context; 133 134 } 135 136 /** 137 * return the server Scope for this context 138 * @param pc 139 * @return server scope 140 */ 141 public static Server getServerScope(PageContext pc) { 142 if(server==null) { 143 server=new ServerImpl(pc); 144 } 145 return server; 146 } 147 148 /* * 149 * Returns the current Cluster Scope, if there is no current Cluster Scope, this method returns null. 150 * @param pc 151 * @param create 152 * @return 153 * @throws SecurityException 154 * / 155 public static Cluster getClusterScope() { 156 return cluster; 157 }*/ 158 159 /** 160 * Returns the current Cluster Scope, if there is no current Cluster Scope and create is true, returns a new Cluster Scope. 161 * If create is false and the request has no valid Cluster Scope, this method returns null. 162 * @param pc 163 * @param create 164 * @return 165 * @throws PageException 166 */ 167 public static Cluster getClusterScope(Config config, boolean create) throws PageException { 168 if(cluster==null && create) { 169 cluster=((ConfigImpl)config).createClusterScope(); 170 171 } 172 return cluster; 173 } 174 175 public static void clearClusterScope() { 176 cluster=null; 177 } 178 179 180 public Client getClientScope(PageContext pc) throws PageException { 181 Client client=null; 182 ApplicationContext appContext = pc.getApplicationContext(); 183 // get Context 184 Map<String, Scope> context = getSubMap(cfClientContextes,appContext.getName()); 185 186 // get Client 187 boolean isMemory=false; 188 String storage = appContext.getClientstorage(); 189 if(StringUtil.isEmpty(storage,true)){ 190 storage="file"; 191 } 192 else if("ram".equalsIgnoreCase(storage)) { 193 storage="memory"; 194 isMemory=true; 195 } 196 else if("registry".equalsIgnoreCase(storage)) { 197 storage="file"; 198 } 199 else { 200 storage=storage.toLowerCase(); 201 if("memory".equals(storage))isMemory=true; 202 } 203 204 final boolean doMemory=isMemory || !appContext.getClientCluster(); 205 client=doMemory?(Client) context.get(pc.getCFID()):null; 206 if(client==null || client.isExpired() || !client.getStorage().equalsIgnoreCase(storage)) { 207 if("file".equals(storage)){ 208 client=ClientFile.getInstance(appContext.getName(),pc,getLog()); 209 } 210 else if("cookie".equals(storage)) 211 client=ClientCookie.getInstance(appContext.getName(),pc,getLog()); 212 else if("memory".equals(storage)){ 213 client=ClientMemory.getInstance(pc,getLog()); 214 } 215 else{ 216 DataSource ds = ((PageContextImpl)pc).getDataSource(storage,null); 217 if(ds!=null)client=ClientDatasource.getInstance(storage,pc,getLog()); 218 else client=ClientCache.getInstance(storage,appContext.getName(),pc,getLog(),null); 219 220 if(client==null){ 221 // datasource not enabled for storage 222 if(ds!=null) 223 throw new ApplicationException("datasource ["+storage+"] is not enabled to be used as session/client storage, you have to enable it in the railo administrator."); 224 225 CacheConnection cc = Util.getCacheConnection(pc.getConfig(),storage,null); 226 if(cc!=null) 227 throw new ApplicationException("cache ["+storage+"] is not enabled to be used as a session/client storage, you have to enable it in the railo administrator."); 228 229 throw new ApplicationException("there is no cache or datasource with name ["+storage+"] defined."); 230 } 231 232 } 233 client.setStorage(storage); 234 if(doMemory)context.put(pc.getCFID(),client); 235 } 236 else 237 getLog().info("scope-context", "use existing client scope for "+appContext.getName()+"/"+pc.getCFID()+" from storage "+storage); 238 239 client.touchBeforeRequest(pc); 240 return client; 241 } 242 243 public Client getClientScopeEL(PageContext pc) { 244 try { 245 return getClientScope(pc); 246 } catch (PageException pe) { 247 throw new PageRuntimeException(pe); 248 } 249 } 250 251 /*public ClientPlus getClientScopeEL(PageContext pc) { 252 ClientPlus client=null; 253 ApplicationContext appContext = pc.getApplicationContext(); 254 // get Context 255 Map context=getSubMap(cfClientContextes,appContext.getName()); 256 257 // get Client 258 String storage = appContext.getClientstorage(); 259 if(!StringUtil.isEmpty(storage))storage=storage.toLowerCase(); 260 else storage=""; 261 262 client=(ClientPlus) context.get(pc.getCFID()); 263 if(client==null || client.isExpired() || !client.getStorageType().equalsIgnoreCase(storage)) { 264 if(StringUtil.isEmpty(storage) || "file".equals(storage) || "registry".equals(storage)){ 265 storage="file"; 266 client=ClientFile.getInstance(appContext.getName(),pc,getLog()); 267 } 268 else if("cookie".equals(storage)) 269 client=ClientCookie.getInstance(appContext.getName(),pc,getLog()); 270 else if("memory".equals(storage) || "ram".equals(storage)){ 271 //storage="ram"; 272 client=ClientMemory.getInstance(pc,getLog()); 273 } 274 else{ 275 DataSource ds = ((ConfigImpl)pc.getConfig()).getDataSource(storage,null); 276 if(ds!=null)client=ClientDatasource.getInstanceEL(storage,pc,getLog()); 277 else client=ClientCache.getInstanceEL(storage,appContext.getName(),pc,getLog()); 278 279 } 280 client.setStorage(storage); 281 context.put(pc.getCFID(),client); 282 } 283 else 284 getLog().info("scope-context", "use existing client scope for "+appContext.getName()+"/"+pc.getCFID()+" from storage "+storage); 285 286 287 client.initialize(pc); 288 return client; 289 }*/ 290 291 292 293 /** 294 * return the session count of all application contextes 295 * @return 296 */ 297 public int getSessionCount(PageContext pc) { 298 if(pc.getSessionType()==Config.SESSION_TYPE_J2EE) return 0; 299 300 Iterator<Entry<String, Map<String, Scope>>> it = cfSessionContextes.entrySet().iterator(); 301 Entry<String, Map<String, Scope>> entry; 302 int count=0; 303 while(it.hasNext()) { 304 entry = it.next(); 305 count+=getSessionCount(entry.getValue()); 306 } 307 return count; 308 } 309 310 /** 311 * return the session count of this application context 312 * @return 313 */ 314 public int getAppContextSessionCount(PageContext pc) { 315 ApplicationContext appContext = pc.getApplicationContext(); 316 if(pc.getSessionType()==Config.SESSION_TYPE_J2EE) return 0; 317 318 Map<String, Scope> context = getSubMap(cfSessionContextes,appContext.getName()); 319 return getSessionCount(context); 320 } 321 322 private int getSessionCount(Map<String, Scope> context) { 323 Iterator<Entry<String, Scope>> it = context.entrySet().iterator(); 324 Entry<String, Scope> entry; 325 int count=0; 326 Session s; 327 while(it.hasNext()) { 328 entry = it.next(); 329 s=(Session)entry.getValue(); 330 if(!s.isExpired()) 331 count++; 332 } 333 return count; 334 } 335 336 337 338 /** 339 * return all session context of this application context 340 * @param pc 341 * @return 342 */ 343 public Struct getAllSessionScopes(PageContext pc) { 344 return getAllSessionScopes(pc.getApplicationContext().getName()); 345 } 346 347 public Struct getAllApplicationScopes() { 348 Struct trg=new StructImpl(); 349 StructImpl.copy(MapAsStruct.toStruct(applicationContextes, true), trg, false); 350 return trg; 351 } 352 353 public Struct getAllCFSessionScopes() { 354 Struct trg=new StructImpl(); 355 StructImpl.copy(MapAsStruct.toStruct(this.cfSessionContextes, true), trg, false); 356 return trg; 357 } 358 359 /** 360 * return the size in bytes of all session contextes 361 * @return size in bytes 362 * @throws ExpressionException 363 */ 364 public long getScopesSize(int scope) throws ExpressionException { 365 if(scope==Scope.SCOPE_APPLICATION)return SizeOf.size(applicationContextes); 366 if(scope==Scope.SCOPE_CLUSTER)return SizeOf.size(cluster); 367 if(scope==Scope.SCOPE_SERVER)return SizeOf.size(server); 368 if(scope==Scope.SCOPE_SESSION)return SizeOf.size(this.cfSessionContextes); 369 if(scope==Scope.SCOPE_CLIENT)return SizeOf.size(this.cfClientContextes); 370 371 throw new ExpressionException("can only return information of scope that are not request dependent"); 372 } 373 374 /** 375 * get all session contexts of given applicaton name 376 * @param pc 377 * @param appName 378 * @return 379 * @deprecated use instead getAllSessionScopes(String appName) 380 */ 381 public Struct getAllSessionScopes(PageContext pc, String appName) { 382 return getAllSessionScopes(appName); 383 } 384 385 /** 386 * get all session contexts of given applicaton name 387 * @param pc 388 * @param appName 389 * @return 390 */ 391 public Struct getAllSessionScopes(String appName) { 392 //if(pc.getSessionType()==Config.SESSION_TYPE_J2EE)return new StructImpl(); 393 return getAllSessionScopes(getSubMap(cfSessionContextes,appName),appName); 394 } 395 396 private Struct getAllSessionScopes(Map<String,Scope> context, String appName) { 397 Iterator<Entry<String, Scope>> it = context.entrySet().iterator(); 398 Entry<String, Scope> entry; 399 Struct sct=new StructImpl(); 400 Session s; 401 while(it.hasNext()) { 402 entry = it.next(); 403 s=(Session)entry.getValue(); 404 if(!s.isExpired()) 405 sct.setEL(KeyImpl.init(appName+"_"+entry.getKey()+"_0"), s); 406 } 407 return sct; 408 } 409 410 /** 411 * return the session Scope for this context (cfid,cftoken,contextname) 412 * @param pc PageContext 413 * @return session matching the context 414 * @throws PageException 415 */ 416 public Session getSessionScope(PageContext pc,RefBoolean isNew) throws PageException { 417 if(pc.getSessionType()==Config.SESSION_TYPE_CFML)return getCFSessionScope(pc,isNew); 418 return getJSessionScope(pc,isNew); 419 } 420 421 public boolean hasExistingSessionScope(PageContext pc) { 422 if(pc.getSessionType()==Config.SESSION_TYPE_CFML)return hasExistingCFSessionScope(pc); 423 return hasExistingJSessionScope(pc); 424 } 425 426 private synchronized boolean hasExistingJSessionScope(PageContext pc) { 427 HttpSession httpSession=pc.getSession(); 428 if(httpSession==null) return false; 429 430 Session session=(Session) httpSession.getAttribute(pc.getApplicationContext().getName()); 431 return session instanceof JSession; 432 } 433 434 435 private boolean hasExistingCFSessionScope(PageContext pc) { 436 437 ApplicationContext appContext = pc.getApplicationContext(); 438 // get Context 439 Map<String, Scope> context = getSubMap(cfSessionContextes,appContext.getName()); 440 441 // get Session 442 String storage = appContext.getSessionstorage(); 443 if(StringUtil.isEmpty(storage,true))storage="memory"; 444 else if("ram".equalsIgnoreCase(storage)) storage="memory"; 445 else if("registry".equalsIgnoreCase(storage)) storage="file"; 446 else storage=storage.toLowerCase(); 447 448 449 450 Session session=(Session) context.get(pc.getCFID()); 451 452 if(!(session instanceof StorageScope) || session.isExpired() || !((StorageScope)session).getStorage().equalsIgnoreCase(storage)) { 453 454 if("memory".equals(storage)) return false; 455 else if("file".equals(storage)) 456 return SessionFile.hasInstance(appContext.getName(),pc); 457 else if("cookie".equals(storage)) 458 return SessionCookie.hasInstance(appContext.getName(),pc); 459 else { 460 DataSource ds = ((ConfigImpl)pc.getConfig()).getDataSource(storage,null); 461 if(ds!=null && ds.isStorage()){ 462 if(SessionDatasource.hasInstance(storage,pc)) return true; 463 } 464 return SessionCache.hasInstance(storage,appContext.getName(),pc); 465 } 466 } 467 return true; 468 } 469 470 471 /** 472 * return cf session scope 473 * @param pc PageContext 474 * @param checkExpires 475 * @param listener 476 * @return cf session matching the context 477 * @throws PageException 478 */ 479 private synchronized Session getCFSessionScope(PageContext pc, RefBoolean isNew) throws PageException { 480 481 ApplicationContext appContext = pc.getApplicationContext(); 482 // get Context 483 Map<String, Scope> context = getSubMap(cfSessionContextes,appContext.getName()); 484 485 // get Session 486 boolean isMemory=false; 487 String storage = appContext.getSessionstorage(); 488 if(StringUtil.isEmpty(storage,true)){ 489 storage="memory"; 490 isMemory=true; 491 } 492 else if("ram".equalsIgnoreCase(storage)) { 493 storage="memory"; 494 isMemory=true; 495 } 496 else if("registry".equalsIgnoreCase(storage)) { 497 storage="file"; 498 } 499 else { 500 storage=storage.toLowerCase(); 501 if("memory".equals(storage))isMemory=true; 502 } 503 504 final boolean doMemory=isMemory || !appContext.getSessionCluster(); 505 Session session=doMemory?appContext.getSessionCluster()?null:(Session) context.get(pc.getCFID()):null; 506 507 if(!(session instanceof StorageScope) || session.isExpired() || !((StorageScope)session).getStorage().equalsIgnoreCase(storage)) { 508 if(isMemory){ 509 session=SessionMemory.getInstance(pc,isNew,getLog()); 510 } 511 else if("file".equals(storage)){ 512 session=SessionFile.getInstance(appContext.getName(),pc,getLog()); 513 } 514 else if("cookie".equals(storage)) 515 session=SessionCookie.getInstance(appContext.getName(),pc,getLog()); 516 else{ 517 DataSource ds = ((PageContextImpl)pc).getDataSource(storage,null); 518 if(ds!=null && ds.isStorage())session=SessionDatasource.getInstance(storage,pc,getLog(),null); 519 else session=SessionCache.getInstance(storage,appContext.getName(),pc,getLog(),null); 520 521 if(session==null){ 522 // datasource not enabled for storage 523 if(ds!=null) 524 throw new ApplicationException( 525 "datasource ["+storage+"] is not enabled to be used as session/client storage, " + 526 "you have to enable it in the railo administrator or define key \"storage=true\" for datasources defined in Application.cfc ."); 527 528 CacheConnection cc = Util.getCacheConnection(pc.getConfig(),storage,null); 529 if(cc!=null) 530 throw new ApplicationException("cache ["+storage+"] is not enabled to be used as a session/client storage, you have to enable it in the railo administrator."); 531 532 throw new ApplicationException("there is no cache or datasource with name ["+storage+"] defined."); 533 } 534 } 535 ((StorageScope)session).setStorage(storage); 536 if(doMemory)context.put(pc.getCFID(),session); 537 isNew.setValue(true); 538 } 539 else { 540 getLog().info("scope-context", "use existing session scope for "+appContext.getName()+"/"+pc.getCFID()+" from storage "+storage); 541 } 542 session.touchBeforeRequest(pc); 543 return session; 544 } 545 546 public synchronized void removeSessionScope(PageContext pc) throws PageException { 547 548 //CFSession 549 Session sess = getCFSessionScope(pc, new RefBooleanImpl()); 550 ApplicationContext appContext = pc.getApplicationContext(); 551 Map<String, Scope> context = getSubMap(cfSessionContextes,appContext.getName()); 552 if(context!=null) { 553 context.remove(pc.getCFID()); 554 if(sess instanceof StorageScope)((StorageScope)sess).unstore(pc.getConfig()); 555 } 556 557 // JSession 558 HttpSession httpSession=pc.getSession(); 559 if(httpSession!=null) { 560 httpSession.removeAttribute(appContext.getName()); 561 } 562 } 563 564 public synchronized void removeClientScope(PageContext pc) throws PageException { 565 Client cli = getClientScope(pc); 566 ApplicationContext appContext = pc.getApplicationContext(); 567 Map<String, Scope> context = getSubMap(cfClientContextes,appContext.getName()); 568 if(context!=null) { 569 context.remove(pc.getCFID()); 570 if(cli!=null)cli.unstore(pc.getConfig()); 571 } 572 } 573 574 575 public boolean remove(int type, String appName, String cfid) { 576 Map<String, Map<String, Scope>> contextes = type==Scope.SCOPE_CLIENT?cfClientContextes:cfSessionContextes; 577 Map<String, Scope> context = getSubMap(contextes,appName); 578 Object res = context.remove(cfid); 579 getLog().info("scope-context", "remove "+VariableInterpreter.scopeInt2String(type)+" scope "+appName+"/"+cfid+" from memory"); 580 581 return res!=null; 582 } 583 584 /** 585 * return j session scope 586 * @param pc PageContext 587 * @param listener 588 * @return j session matching the context 589 * @throws PageException 590 */ 591 private synchronized Session getJSessionScope(PageContext pc, RefBoolean isNew) throws PageException { 592 HttpSession httpSession=pc.getSession(); 593 ApplicationContext appContext = pc.getApplicationContext(); 594 Object session=null;// this is from type object, because it is possible that httpSession return object from prior restart 595 596 int s=(int) appContext.getSessionTimeout().getSeconds(); 597 if(maxSessionTimeout<s)maxSessionTimeout=s; 598 599 if(httpSession!=null) { 600 httpSession.setMaxInactiveInterval(maxSessionTimeout); 601 session= httpSession.getAttribute(appContext.getName()); 602 } 603 else { 604 Map<String, Scope> context = getSubMap(cfSessionContextes,appContext.getName()); 605 session=context.get(pc.getCFID()); 606 } 607 608 JSession jSession=null; 609 if(session instanceof JSession) { 610 jSession=(JSession) session; 611 try { 612 if(jSession.isExpired()) { 613 jSession.touch(); 614 } 615 info(getLog(), "use existing JSession for "+appContext.getName()+"/"+pc.getCFID()); 616 617 } 618 catch(ClassCastException cce) { 619 error(getLog(), cce); 620 // if there is no HTTPSession 621 if(httpSession==null) return getCFSessionScope(pc, isNew); 622 623 jSession=new JSession(); 624 httpSession.setAttribute(appContext.getName(),jSession); 625 isNew.setValue(true); 626 } 627 } 628 else { 629 // if there is no HTTPSession 630 if(httpSession==null) return getCFSessionScope(pc, isNew); 631 632 info(getLog(), "create new JSession for "+appContext.getName()+"/"+pc.getCFID()); 633 jSession=new JSession(); 634 httpSession.setAttribute(appContext.getName(),jSession); 635 isNew.setValue(true); 636 Map<String, Scope> context = getSubMap(cfSessionContextes,appContext.getName()); 637 context.put(pc.getCFID(),jSession); 638 } 639 jSession.touchBeforeRequest(pc); 640 return jSession; 641 } 642 643 /** 644 * return the application Scope for this context (cfid,cftoken,contextname) 645 * @param pc PageContext 646 * @param listener 647 * @param isNew 648 * @return session matching the context 649 * @throws PageException 650 */ 651 public synchronized Application getApplicationScope(PageContext pc, RefBoolean isNew) { 652 ApplicationContext appContext = pc.getApplicationContext(); 653 // getApplication Scope from Context 654 ApplicationImpl application; 655 Object objApp=applicationContextes.get(appContext.getName()); 656 if(objApp!=null) { 657 application=(ApplicationImpl)objApp; 658 if(application.isExpired()) { 659 application.release(); 660 isNew.setValue(true); 661 } 662 } 663 else { 664 application=new ApplicationImpl(); 665 applicationContextes.put(appContext.getName(),application); 666 isNew.setValue(true); 667 } 668 application.touchBeforeRequest(pc); 669 //if(newApplication)listener.onApplicationStart(pc); 670 671 return application; 672 } 673 674 public void removeApplicationScope(PageContext pc) { 675 applicationContextes.remove(pc.getApplicationContext().getName()); 676 } 677 678 679 /** 680 * remove all unused scope objects 681 */ 682 public void clearUnused() { 683 684 Log log=getLog(); 685 try{ 686 // create cleaner engine for session/client scope 687 if(session==null)session=new StorageScopeEngine(factory,log,new StorageScopeCleaner[]{ 688 new FileStorageScopeCleaner(Scope.SCOPE_SESSION, null)//new SessionEndListener()) 689 ,new DatasourceStorageScopeCleaner(Scope.SCOPE_SESSION, null)//new SessionEndListener()) 690 //,new CacheStorageScopeCleaner(Scope.SCOPE_SESSION, new SessionEndListener()) 691 }); 692 if(client==null)client=new StorageScopeEngine(factory,log,new StorageScopeCleaner[]{ 693 new FileStorageScopeCleaner(Scope.SCOPE_CLIENT, null) 694 ,new DatasourceStorageScopeCleaner(Scope.SCOPE_CLIENT, null) 695 //,new CacheStorageScopeCleaner(Scope.SCOPE_CLIENT, null) //Cache storage need no control, if there is no listener 696 }); 697 698 699 700 // store session/client scope and remove from memory 701 storeUnusedStorageScope(factory, Scope.SCOPE_CLIENT); 702 storeUnusedStorageScope(factory, Scope.SCOPE_SESSION); 703 704 // remove unused memory based client/session scope (invoke onSessonEnd) 705 clearUnusedMemoryScope(factory, Scope.SCOPE_CLIENT); 706 clearUnusedMemoryScope(factory, Scope.SCOPE_SESSION); 707 708 709 // session must be executed first, because session creates a reference from client scope 710 session.clean(); 711 client.clean(); 712 713 // clean all unused application scopes 714 clearUnusedApplications(factory); 715 } 716 catch(Throwable t){ 717 error(t); 718 } 719 } 720 721 /** 722 * remove all scope objects 723 */ 724 public void clear() { 725 try{ 726 Scope scope; 727 //Map.Entry entry,e; 728 //Map context; 729 730 // release all session scopes 731 Iterator<Entry<String, Map<String, Scope>>> sit = cfSessionContextes.entrySet().iterator(); 732 Entry<String, Map<String, Scope>> sentry; 733 Map<String, Scope> context; 734 Iterator<Entry<String, Scope>> itt; 735 Entry<String, Scope> e; 736 737 while(sit.hasNext()){ 738 sentry=sit.next(); 739 context = sentry.getValue(); 740 itt = context.entrySet().iterator(); 741 while(itt.hasNext()){ 742 e = itt.next(); 743 scope=e.getValue(); 744 scope.release(); 745 } 746 } 747 cfSessionContextes.clear(); 748 749 // release all application scopes 750 Iterator<Entry<String, Application>> ait = applicationContextes.entrySet().iterator(); 751 Entry<String, Application> aentry; 752 while(ait.hasNext()){ 753 aentry = ait.next(); 754 scope=aentry.getValue(); 755 scope.release(); 756 } 757 applicationContextes.clear(); 758 759 // release server scope 760 if(server!=null){ 761 server.release(); 762 server=null; 763 } 764 765 } 766 catch(Throwable t){t.printStackTrace();} 767 } 768 769 770 771 private void storeUnusedStorageScope(CFMLFactoryImpl cfmlFactory, int type) { 772 Map<String, Map<String, Scope>> contextes = type==Scope.SCOPE_CLIENT?cfClientContextes:cfSessionContextes; 773 long timespan = type==Scope.SCOPE_CLIENT?CLIENT_MEMORY_TIMESPAN:SESSION_MEMORY_TIMESPAN; 774 String strType=VariableInterpreter.scopeInt2String(type); 775 776 if(contextes.size()==0)return; 777 long now = System.currentTimeMillis(); 778 Object[] arrContextes= contextes.keySet().toArray(); 779 Object applicationName,cfid,o; 780 Map<String, Scope> fhm; 781 for(int i=0;i<arrContextes.length;i++) { 782 783 applicationName=arrContextes[i]; 784 fhm = contextes.get(applicationName); 785 if(fhm.size()>0){ 786 Object[] arrClients= fhm.keySet().toArray(); 787 int count=arrClients.length; 788 for(int y=0;y<arrClients.length;y++) { 789 cfid=arrClients[y]; 790 o=fhm.get(cfid); 791 if(!(o instanceof StorageScope)) continue; 792 StorageScope scope=(StorageScope)o; 793 if(scope.lastVisit()+timespan<now && !(scope instanceof MemoryScope)) { 794 getLog().info("scope-context", "remove from memory "+strType+" scope for "+applicationName+"/"+cfid+" from storage "+scope.getStorage()); 795 796 //if(scope instanceof StorageScope)((StorageScope)scope).store(cfmlFactory.getConfig()); 797 fhm.remove(arrClients[y]); 798 count--; 799 } 800 } 801 if(count==0)contextes.remove(arrContextes[i]); 802 } 803 } 804 } 805 806 /** 807 * @param cfmlFactory 808 * 809 */ 810 private void clearUnusedMemoryScope(CFMLFactoryImpl cfmlFactory, int type) { 811 Map<String, Map<String, Scope>> contextes = type==Scope.SCOPE_CLIENT?cfClientContextes:cfSessionContextes; 812 if(contextes.size()==0)return; 813 814 815 816 Object[] arrContextes= contextes.keySet().toArray(); 817 ApplicationListener listener = cfmlFactory.getConfig().getApplicationListener(); 818 Object applicationName,cfid,o; 819 Map<String, Scope> fhm; 820 821 for(int i=0;i<arrContextes.length;i++) { 822 applicationName=arrContextes[i]; 823 fhm = contextes.get(applicationName); 824 825 if(fhm.size()>0){ 826 Object[] cfids= fhm.keySet().toArray(); 827 int count=cfids.length; 828 for(int y=0;y<cfids.length;y++) { 829 cfid=cfids[y]; 830 o=fhm.get(cfid); 831 if(!(o instanceof MemoryScope)) continue; 832 MemoryScope scope=(MemoryScope) o; 833 // close 834 if(scope.isExpired()) { 835 // TODO macht das sinn? ist das nicht kopierleiche? 836 ApplicationImpl application=(ApplicationImpl) applicationContextes.get(applicationName); 837 long appLastAccess=0; 838 if(application!=null){ 839 appLastAccess=application.getLastAccess(); 840 application.touch(); 841 } 842 scope.touch(); 843 844 try { 845 if(type==Scope.SCOPE_SESSION)listener.onSessionEnd(cfmlFactory,(String)applicationName,(String)cfid); 846 } 847 catch (Throwable t) {t.printStackTrace(); 848 ExceptionHandler.log(cfmlFactory.getConfig(),Caster.toPageException(t)); 849 } 850 finally { 851 if(application!=null)application.setLastAccess(appLastAccess); 852 fhm.remove(cfids[y]); 853 scope.release(); 854 getLog().info("scope-context", "remove memory based "+VariableInterpreter.scopeInt2String(type)+" scope for "+applicationName+"/"+cfid); 855 count--; 856 } 857 } 858 } 859 if(count==0)contextes.remove(arrContextes[i]); 860 } 861 } 862 } 863 864 private void clearUnusedApplications(CFMLFactoryImpl jspFactory) { 865 866 if(applicationContextes.size()==0)return; 867 868 long now=System.currentTimeMillis(); 869 Object[] arrContextes= applicationContextes.keySet().toArray(); 870 ApplicationListener listener = jspFactory.getConfig().getApplicationListener(); 871 for(int i=0;i<arrContextes.length;i++) { 872 Application application=applicationContextes.get(arrContextes[i]); 873 874 if(application.getLastAccess()+application.getTimeSpan()<now) { 875 //SystemOut .printDate(jspFactory.getConfigWebImpl().getOut(),"Clear application scope:"+arrContextes[i]+"-"+this); 876 application.touch(); 877 try { 878 listener.onApplicationEnd(jspFactory,(String)arrContextes[i]); 879 } 880 catch (Throwable t) { 881 ExceptionHandler.log(jspFactory.getConfig(),Caster.toPageException(t)); 882 } 883 finally { 884 applicationContextes.remove(arrContextes[i]); 885 application.release(); 886 } 887 888 } 889 } 890 } 891 892 893 public void clearApplication(PageContext pc) throws PageException { 894 895 if(applicationContextes.size()==0) throw new ApplicationException("there is no application context defined"); 896 897 String name = pc.getApplicationContext().getName(); 898 CFMLFactoryImpl jspFactory = (CFMLFactoryImpl)pc.getCFMLFactory(); 899 900 Application application=applicationContextes.get(name); 901 if(application==null) throw new ApplicationException("there is no application context defined with name ["+name+"]"); 902 ApplicationListener listener = PageContextUtil.getApplicationListener(pc); 903 application.touch(); 904 try { 905 listener.onApplicationEnd(jspFactory,name); 906 } 907 finally { 908 applicationContextes.remove(name); 909 application.release(); 910 } 911 } 912 913 /** 914 * @return returns a new CFIs 915 */ 916 public static String getNewCFId() { 917 return generator.generateRandomBasedUUID().toString(); 918 } 919 920 /** 921 * @return returns a new CFToken 922 */ 923 public static String getNewCFToken() { 924 return "0"; 925 } 926 927 public synchronized void invalidateUserScope(PageContextImpl pc,boolean migrateSessionData,boolean migrateClientData) throws PageException { 928 ApplicationContext appContext = pc.getApplicationContext(); 929 930 // get in memory scopes 931 Map<String, Scope> clientContext = getSubMap(cfClientContextes,appContext.getName()); 932 UserScope clientScope = (UserScope) clientContext.get(pc.getCFID()); 933 Map<String, Scope> sessionContext = getSubMap(cfSessionContextes,appContext.getName()); 934 UserScope sessionScope = (UserScope) sessionContext.get(pc.getCFID()); 935 936 // remove Scopes completly 937 removeSessionScope(pc); 938 removeClientScope(pc); 939 940 pc.resetIdAndToken(); 941 942 _migrate(pc,clientContext,clientScope,migrateClientData); 943 _migrate(pc,sessionContext,sessionScope,migrateSessionData); 944 } 945 946 private static void _migrate(PageContextImpl pc, Map<String, Scope> context, UserScope scope, boolean migrate) { 947 if(scope==null) return; 948 if(!migrate) scope.clear(); 949 scope.resetEnv(pc); 950 context.put(pc.getCFID(), scope); 951 } 952 953 954 }