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