001 package railo.runtime.type.scope.storage; 002 003 import java.util.ArrayList; 004 import java.util.HashSet; 005 import java.util.Iterator; 006 import java.util.List; 007 import java.util.Set; 008 009 import railo.commons.lang.SizeOf; 010 import railo.commons.lang.StringUtil; 011 import railo.runtime.PageContext; 012 import railo.runtime.config.Config; 013 import railo.runtime.dump.DumpData; 014 import railo.runtime.dump.DumpProperties; 015 import railo.runtime.engine.ThreadLocalPageContext; 016 import railo.runtime.exp.PageException; 017 import railo.runtime.listener.ApplicationContextPro; 018 import railo.runtime.op.Caster; 019 import railo.runtime.type.KeyImpl; 020 import railo.runtime.type.Sizeable; 021 import railo.runtime.type.Struct; 022 import railo.runtime.type.StructImpl; 023 import railo.runtime.type.dt.DateTime; 024 import railo.runtime.type.dt.DateTimeImpl; 025 import railo.runtime.type.util.StructSupport; 026 import railo.runtime.type.util.StructUtil; 027 028 public abstract class StorageScopeImpl extends StructSupport implements StorageScope,Sizeable { 029 030 031 032 private static int _id=0; 033 private int id=0; 034 035 private static final long serialVersionUID = 7874930250042576053L; 036 private static Set<String> FIX_KEYS=new HashSet<String>(); 037 static { 038 FIX_KEYS.add("cfid"); 039 FIX_KEYS.add("cftoken"); 040 FIX_KEYS.add("urltoken"); 041 FIX_KEYS.add("lastvisit"); 042 FIX_KEYS.add("hitcount"); 043 FIX_KEYS.add("timecreated"); 044 } 045 046 047 protected static Set<String> ignoreSet=new HashSet<String>(); 048 static { 049 ignoreSet.add("cfid"); 050 ignoreSet.add("cftoken"); 051 ignoreSet.add("urltoken"); 052 } 053 054 055 protected boolean isinit=true; 056 protected Struct sct; 057 protected long lastvisit; 058 protected DateTime _lastvisit; 059 protected int hitcount=0; 060 protected DateTime timecreated; 061 private boolean hasChanges=false; 062 private String strType; 063 private int type; 064 private long timeSpan=-1; 065 private String storage; 066 067 068 /** 069 * Constructor of the class 070 * @param sct 071 * @param timecreated 072 * @param _lastvisit 073 * @param lastvisit 074 * @param hitcount 075 */ 076 public StorageScopeImpl(Struct sct, DateTime timecreated, DateTime _lastvisit, long lastvisit, int hitcount,String strType,int type) { 077 this.sct=sct; 078 this.timecreated=timecreated; 079 if(_lastvisit==null) this._lastvisit=timecreated; 080 else this._lastvisit=_lastvisit; 081 082 if(lastvisit==-1) this.lastvisit=this._lastvisit.getTime(); 083 else this.lastvisit=lastvisit; 084 085 this.hitcount=hitcount; 086 this.strType=strType; 087 this.type=type; 088 id=++_id; 089 } 090 091 /** 092 * Constructor of the class 093 * @param other 094 * @param deepCopy 095 */ 096 public StorageScopeImpl(StorageScopeImpl other, boolean deepCopy) { 097 this.sct=(Struct)other.sct.duplicate(deepCopy); 098 this.timecreated=other.timecreated; 099 this._lastvisit=other._lastvisit; 100 this.hitcount=other.hitcount; 101 this.isinit=other.isinit; 102 this.lastvisit=other.lastvisit; 103 this.strType=other.strType; 104 this.type=other.type; 105 this.timeSpan=other.timeSpan; 106 id=++_id; 107 } 108 109 /** 110 * @see railo.runtime.type.Scope#initialize(railo.runtime.PageContext) 111 */ 112 public void touchBeforeRequest(PageContext pc) { 113 114 hasChanges=false; 115 setTimeSpan(pc); 116 117 118 //lastvisit=System.currentTimeMillis(); 119 if(sct==null) sct=new StructImpl(); 120 sct.setEL(KeyImpl.CFID, pc.getCFID()); 121 sct.setEL(KeyImpl.CFTOKEN, pc.getCFToken()); 122 sct.setEL(URLTOKEN, pc.getURLToken()); 123 sct.setEL(LASTVISIT, _lastvisit); 124 _lastvisit=new DateTimeImpl(pc.getConfig()); 125 lastvisit=System.currentTimeMillis(); 126 127 if(type==SCOPE_CLIENT){ 128 sct.setEL(HITCOUNT, new Double(hitcount++)); 129 sct.setEL(TIMECREATED, timecreated); 130 } 131 else { 132 sct.setEL(SESSION_ID, pc.getApplicationContext().getName()+"_"+pc.getCFID()+"_"+pc.getCFToken()); 133 } 134 } 135 136 void setTimeSpan(PageContext pc) { 137 ApplicationContextPro ac=(ApplicationContextPro) pc.getApplicationContext(); 138 this.timeSpan=getType()==SCOPE_SESSION? 139 ac.getSessionTimeout().getMillis(): 140 ac.getClientTimeout().getMillis(); 141 } 142 143 144 /** 145 * @see railo.runtime.type.scope.storage.StorageScope#setMaxInactiveInterval(int) 146 */ 147 @Override 148 public void setMaxInactiveInterval(int interval) { 149 this.timeSpan=interval*1000L; 150 } 151 152 /** 153 * @see railo.runtime.type.scope.storage.StorageScope#getMaxInactiveInterval() 154 */ 155 @Override 156 public int getMaxInactiveInterval() { 157 return (int)(this.timeSpan/1000L); 158 } 159 160 161 162 163 /** 164 * @see railo.runtime.type.Scope#isInitalized() 165 */ 166 public final boolean isInitalized() { 167 return isinit; 168 } 169 170 /** 171 * @see railo.runtime.type.Scope#initialize(railo.runtime.PageContext) 172 */ 173 public final void initialize(PageContext pc) { 174 // StorageScopes need only request initialisation no global init, they are not reused; 175 } 176 177 /** 178 * @see railo.runtime.type.SharedScope#release(railo.runtime.PageContext) 179 */ 180 public void touchAfterRequest(PageContext pc) { 181 182 sct.setEL(LASTVISIT, _lastvisit); 183 184 if(type==SCOPE_CLIENT){ 185 sct.setEL(HITCOUNT, new Double(hitcount)); 186 sct.setEL(TIMECREATED, timecreated); 187 } 188 } 189 190 /** 191 * @see railo.runtime.type.Scope#release() 192 */ 193 public final void release() { 194 clear(); 195 isinit=false; 196 } 197 198 199 /** 200 * @return returns if the scope is empty or not, this method ignore the "constant" entries of the scope (cfid,cftoken,urltoken) 201 */ 202 public boolean hasContent() { 203 if(sct.size()==(type==SCOPE_CLIENT?6:4) && sct.containsKey(URLTOKEN) && sct.containsKey(KeyImpl.CFTOKEN) && sct.containsKey(KeyImpl.CFID)) { 204 return false; 205 } 206 return true; 207 } 208 209 /** 210 * @see railo.runtime.type.Collection#clear() 211 */ 212 public void clear() { 213 sct.clear(); 214 } 215 216 /** 217 * 218 * @see railo.runtime.type.Collection#containsKey(railo.runtime.type.Collection.Key) 219 */ 220 public boolean containsKey(Key key) { 221 return sct.containsKey(key); 222 } 223 224 /** 225 * 226 * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key) 227 */ 228 public Object get(Key key) throws PageException { 229 return sct.get(key); 230 } 231 232 /** 233 * 234 * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key, java.lang.Object) 235 */ 236 public Object get(Key key, Object defaultValue) { 237 return sct.get(key, defaultValue); 238 } 239 240 /** 241 * @see railo.runtime.type.Collection#keyIterator() 242 */ 243 public Iterator keyIterator() { 244 return sct.keyIterator(); 245 } 246 247 /** 248 * @see railo.runtime.type.Collection#keysAsString() 249 */ 250 public String[] keysAsString() { 251 return sct.keysAsString(); 252 } 253 254 /** 255 * @see railo.runtime.type.Collection#keys() 256 */ 257 public railo.runtime.type.Collection.Key[] keys() { 258 return sct.keys(); 259 } 260 261 262 /** 263 * 264 * @see railo.runtime.type.Collection#remove(railo.runtime.type.Collection.Key) 265 */ 266 public Object remove(Key key) throws PageException { 267 hasChanges=true; 268 return sct.remove(key); 269 } 270 271 /** 272 * 273 * @see railo.runtime.type.Collection#removeEL(railo.runtime.type.Collection.Key) 274 */ 275 public Object removeEL(Key key) { 276 hasChanges=true; 277 return sct.removeEL(key); 278 } 279 280 /** 281 * 282 * @see railo.runtime.type.Collection#set(railo.runtime.type.Collection.Key, java.lang.Object) 283 */ 284 public Object set(Key key, Object value) throws PageException { 285 hasChanges=true; 286 return sct.set(key, value); 287 } 288 289 /** 290 * 291 * @see railo.runtime.type.Collection#setEL(railo.runtime.type.Collection.Key, java.lang.Object) 292 */ 293 public Object setEL(Key key, Object value) { 294 hasChanges=true; 295 return sct.setEL(key, value); 296 } 297 298 /** 299 * @see railo.runtime.type.Collection#size() 300 */ 301 public int size() { 302 return sct.size(); 303 } 304 305 306 /** 307 * @see railo.runtime.op.Castable#castToBooleanValue() 308 */ 309 public boolean castToBooleanValue() throws PageException { 310 return sct.castToBooleanValue(); 311 } 312 313 /** 314 * @see railo.runtime.op.Castable#castToBoolean(java.lang.Boolean) 315 */ 316 public Boolean castToBoolean(Boolean defaultValue) { 317 return sct.castToBoolean(defaultValue); 318 } 319 320 /** 321 * 322 * @see railo.runtime.op.Castable#castToDateTime() 323 */ 324 public DateTime castToDateTime() throws PageException { 325 return sct.castToDateTime(); 326 } 327 328 /** 329 * @see railo.runtime.op.Castable#castToDateTime(railo.runtime.type.dt.DateTime) 330 */ 331 public DateTime castToDateTime(DateTime defaultValue) { 332 return sct.castToDateTime(defaultValue); 333 } 334 335 /** 336 * 337 * @see railo.runtime.op.Castable#castToDoubleValue() 338 */ 339 public double castToDoubleValue() throws PageException { 340 return sct.castToDoubleValue(); 341 } 342 343 /** 344 * @see railo.runtime.op.Castable#castToDoubleValue(double) 345 */ 346 public double castToDoubleValue(double defaultValue) { 347 return sct.castToDoubleValue(defaultValue); 348 } 349 350 /** 351 * 352 * @see railo.runtime.op.Castable#castToString() 353 */ 354 public String castToString() throws PageException { 355 return sct.castToString(); 356 } 357 358 /** 359 * @see railo.runtime.type.util.StructSupport#castToString(java.lang.String) 360 */ 361 public String castToString(String defaultValue) { 362 return sct.castToString(defaultValue); 363 } 364 365 /** 366 * @throws PageException 367 * @see railo.runtime.op.Castable#compare(boolean) 368 */ 369 public int compareTo(boolean b) throws PageException { 370 return sct.compareTo(b); 371 } 372 373 /** 374 * @see railo.runtime.op.Castable#compareTo(railo.runtime.type.dt.DateTime) 375 */ 376 public int compareTo(DateTime dt) throws PageException { 377 return sct.compareTo(dt); 378 } 379 380 /** 381 * @see railo.runtime.op.Castable#compareTo(double) 382 */ 383 public int compareTo(double d) throws PageException { 384 return sct.compareTo(d); 385 } 386 387 /** 388 * @see railo.runtime.op.Castable#compareTo(java.lang.String) 389 */ 390 public int compareTo(String str) throws PageException { 391 return sct.compareTo(str); 392 } 393 394 /** 395 * @see railo.runtime.type.scope.storage.StorageScope#lastVisit() 396 */ 397 public long lastVisit() { 398 return lastvisit; 399 } 400 401 public String[] pureKeys() { 402 List keys=new ArrayList(); 403 Iterator it = keyIterator(); 404 String key; 405 while(it.hasNext()){ 406 key=Caster.toString(it.next(),"").toLowerCase(); 407 if(!FIX_KEYS.contains(key))keys.add(key); 408 } 409 return (String[]) keys.toArray(new String[keys.size()]); 410 } 411 412 /** 413 * @see railo.runtime.type.scope.storage.StorageScope#store(railo.runtime.config.Config) 414 */ 415 public void store(Config config){ 416 //do nothing 417 } 418 419 /** 420 * @see railo.runtime.type.scope.storage.StorageScope#unstore(railo.runtime.config.Config) 421 */ 422 public void unstore(Config config){ 423 //do nothing 424 } 425 426 /** 427 * @return the hasChanges 428 */ 429 public boolean hasChanges() { 430 return hasChanges; 431 } 432 433 434 /** 435 * @see java.util.Map#containsValue(java.lang.Object) 436 */ 437 public boolean containsValue(Object value) { 438 return sct.containsValue(value); 439 } 440 441 /** 442 * @see java.util.Map#values() 443 */ 444 public java.util.Collection values() { 445 return sct.values(); 446 } 447 448 /** 449 * @see railo.runtime.type.Sizeable#sizeOf() 450 */ 451 public long sizeOf() { 452 return SizeOf.size(sct); 453 } 454 455 public final int getType() { 456 return type; 457 } 458 459 public final String getTypeAsString() { 460 return strType; 461 } 462 463 464 465 /** 466 * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int) 467 */ 468 public final DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 469 return StructUtil.toDumpTable(this, StringUtil.ucFirst(getTypeAsString())+" Scope ("+getStorageType()+")", pageContext, maxlevel, dp); 470 } 471 472 473 public long getLastAccess() { return lastvisit;} 474 public long getTimeSpan() { return timeSpan;} 475 476 477 public void touch() { 478 lastvisit=System.currentTimeMillis(); 479 _lastvisit=new DateTimeImpl(ThreadLocalPageContext.getConfig()); 480 } 481 482 public boolean isExpired() { 483 return (getLastAccess()+getTimeSpan())<System.currentTimeMillis(); 484 } 485 486 487 488 /** 489 * @see railo.runtime.type.scope.storage.StorageScope#setStorage(java.lang.String) 490 */ 491 public void setStorage(String storage) { 492 this.storage=storage; 493 } 494 495 /** 496 * @see railo.runtime.type.scope.storage.StorageScope#getStorage() 497 */ 498 public String getStorage() { 499 return storage; 500 } 501 502 public static String encode(String input) { 503 int len=input.length(); 504 StringBuilder sb=new StringBuilder(); 505 char c; 506 for(int i=0;i<len;i++){ 507 c=input.charAt(i); 508 if((c>='0' && c<='9') || (c>='a' && c<='z') || (c>='A' && c<='Z') || c=='_' || c=='-') 509 sb.append(c); 510 else { 511 sb.append('$'); 512 sb.append(Integer.toString(((int)c),Character.MAX_RADIX)); 513 sb.append('$'); 514 } 515 } 516 517 return sb.toString(); 518 } 519 520 public static String decode(String input) { 521 int len=input.length(); 522 StringBuilder sb=new StringBuilder(); 523 char c; 524 int ni; 525 for(int i=0;i<len;i++){ 526 c=input.charAt(i); 527 if(c=='$') { 528 ni=input.indexOf('$',i+1); 529 sb.append((char)Integer.parseInt(input.substring(i+1,ni),Character.MAX_RADIX)); 530 i=ni; 531 } 532 533 else { 534 sb.append(c); 535 } 536 } 537 return sb.toString(); 538 } 539 540 public int _getId() { 541 return id; 542 } 543 }