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    }