001    package railo.runtime.type.scope;
002    
003    import java.io.UnsupportedEncodingException;
004    
005    import railo.commons.lang.StringList;
006    import railo.commons.lang.StringUtil;
007    import railo.commons.net.URLDecoder;
008    import railo.commons.net.URLItem;
009    import railo.runtime.PageContext;
010    import railo.runtime.dump.DumpData;
011    import railo.runtime.dump.DumpProperties;
012    import railo.runtime.exp.ExpressionException;
013    import railo.runtime.op.Caster;
014    import railo.runtime.security.ScriptProtect;
015    import railo.runtime.type.Array;
016    import railo.runtime.type.ArrayImpl;
017    import railo.runtime.type.CastableStruct;
018    import railo.runtime.type.Collection;
019    import railo.runtime.type.KeyImpl;
020    import railo.runtime.type.List;
021    import railo.runtime.type.Scope;
022    import railo.runtime.type.Sizeable;
023    import railo.runtime.type.Struct;
024    import railo.runtime.type.StructImpl;
025    import railo.runtime.type.util.StructUtil;
026    
027    
028    
029    /**
030     * Simple standart implementation of a Scope, for standart use.
031     */
032    public abstract class ScopeSupport extends StructImpl implements Scope,Sizeable {
033            
034    
035            public static final Key APPLICATION = KeyImpl.intern("application");
036            public static final Key CGI = KeyImpl.intern("cgi");
037            public static final Key COOKIE = KeyImpl.intern("cookie");
038            public static final Key CLIENT = KeyImpl.intern("client");
039            public static final Key CLUSTER = KeyImpl.intern("cluster");
040            public static final Key FORM = KeyImpl.intern("form");
041            public static final Key REQUEST = KeyImpl.intern("request");
042            public static final Key SESSION = KeyImpl.intern("session");
043            public static final Key URL = KeyImpl.intern("url");
044            
045            private String name;
046        private String dspName;
047            private static int _id=0;
048            private int id=0;
049        private static final byte[] EMPTY="".getBytes();
050            
051        public static final int SCOPE_VAR=15; // FUTURE add to interface Scope
052        public static final int SCOPE_COUNT=16;
053            
054            /**
055             * Field <code>isInit</code>
056             */
057            protected boolean isInit;
058        private int type;
059    
060        /**
061         * constructor for the Simple class
062         * @param name name of the scope
063         * @param type scope type (SCOPE_APPLICATION,SCOPE_COOKIE use)
064         */
065        public ScopeSupport(boolean sync,String name, int type) {
066            super(sync?StructImpl.TYPE_SYNC:StructImpl.TYPE_REGULAR);
067            this.name=name;
068            this.type=type;
069            
070            id=++_id;
071        }
072        /**
073         * constructor for ScopeSupport
074         * @param name name of the scope
075         * @param type scope type (SCOPE_APPLICATION,SCOPE_COOKIE use)
076         * @param doubleLinked mean that the struct has predictable iteration order this make the input order fix
077         */
078        public ScopeSupport(String name, int type, int mapType) {
079            super(mapType);
080            this.name=name;
081            this.type=type;
082            
083            id=++_id;
084        }
085            
086        /**
087             * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int)
088             */
089    
090            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
091                    return toDumpData(pageContext, maxlevel, dp, this, dspName);
092            }
093            
094            public static DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp, Struct sct,String dspName) {
095                    if(StringUtil.isEmpty(dspName))dspName="Scope";
096                    
097                    return StructUtil.toDumpTable(sct, dspName, pageContext, maxlevel, dp);
098                    
099            }
100                    
101            /**
102             * @see railo.runtime.type.StructImpl#invalidKey(java.lang.String)
103             */
104            protected ExpressionException invalidKey(String key) {
105                    return new ExpressionException("variable ["+key+"] doesn't exist in "+StringUtil.ucFirst(name)+" Scope (keys:"+List.arrayToList(keysAsString(), ",")+")");
106            }
107    
108        /**
109         * write parameter defined in a query string (name1=value1&name2=value2) to the scope
110         * @param qs Query String
111         * @return parsed name value pair
112         */
113            protected static URLItem[] setFromQueryString(String str) {
114                    return setFrom___(str, '&');
115            }
116    
117            protected static URLItem[] setFromTextPlain(String str) {
118                    return setFrom___(str, '\n');
119            }
120            protected static URLItem[] setFrom___(String tp,char delimeter) {
121            if(tp==null) return new URLItem[0];
122            Array arr=List.listToArrayRemoveEmpty(tp,delimeter);
123            URLItem[] pairs=new URLItem[arr.size()];
124            
125            //Array item;
126            int index;
127            String name;
128            
129            for(int i=1;i<=pairs.length;i++) {
130                name=Caster.toString(arr.get(i,""),"");
131                //if(name.length()==0) continue;
132                
133                index=name.indexOf('=');
134                if(index!=-1) pairs[i-1]=new URLItem(name.substring(0,index),name.substring(index+1),true);
135                else pairs[i-1]=new URLItem(name,"",true);
136              
137            }
138            return pairs;
139        }
140    
141        protected static byte[] getBytes(String str) {
142            return str.getBytes();
143        }
144        protected static byte[] getBytes(String str,String encoding) {
145            try {
146                return str.getBytes(encoding);
147            } catch (UnsupportedEncodingException e) {
148                return EMPTY;
149            }
150        }
151        
152        protected void fillDecodedEL(URLItem[] raw, String encoding, boolean scriptProteced) {
153            try {
154                            fillDecoded(raw, encoding,scriptProteced);
155                    } catch (UnsupportedEncodingException e) {
156                            try {
157                                    fillDecoded(raw, "iso-8859-1",scriptProteced);
158                            } catch (UnsupportedEncodingException e1) {}
159                    }
160        }
161            
162        
163        /**
164         * fill th data from given strut and decode it
165         * @param raw
166         * @param encoding
167         * @throws UnsupportedEncodingException
168         */
169        protected void fillDecoded(URLItem[] raw, String encoding, boolean scriptProteced) throws UnsupportedEncodingException {
170            clear();
171            String name,value;
172            //Object curr;
173            for(int i=0;i<raw.length;i++) {
174                name=raw[i].getName();
175                value=raw[i].getValue();
176                if(raw[i].isUrlEncoded()) {
177                    name=URLDecoder.decode(name,encoding,true);
178                    value=URLDecoder.decode(value,encoding,true);
179                }
180                // MUST valueStruct
181                if(name.indexOf('.')!=-1) {
182                    StringList list=List.listToStringListRemoveEmpty(name,'.');
183                    Struct parent=this;
184                    while(list.hasNextNext()) {
185                        parent=_fill(parent,list.next(),new CastableStruct(),false,scriptProteced);
186                    }
187                    _fill(parent,list.next(),value,true,scriptProteced);
188                } 
189                //else 
190                    _fill(this,name,value,true,scriptProteced);
191            }
192        }
193        
194        private Struct _fill(Struct parent, String name, Object value, boolean isLast, boolean scriptProteced) {
195            Object curr;
196            boolean isArrayDef=false;
197            Collection.Key key=KeyImpl.getInstance(name);
198            
199            // script protect
200            if(scriptProteced && value instanceof String) {
201                    value=ScriptProtect.translate((String)value);
202            }
203            
204            if(name.length() >2 && name.endsWith("[]")) {
205                isArrayDef=true;
206                name=name.substring(0,name.length()-2);
207                key=KeyImpl.getInstance(name);
208                curr=parent.get(key,null);                
209            }
210            else {
211                curr=parent.get(key,null);
212            }
213            
214            if(curr==null) {
215                    if(isArrayDef) {
216                            Array arr = new ArrayImpl();
217                            arr.appendEL(value);
218                            parent.setEL(key,arr);
219                    }
220                else parent.setEL(key,value); 
221            }
222            else if(curr instanceof Array){
223                ((Array) curr).appendEL(value);
224            }
225            else if(curr instanceof CastableStruct){
226                    if(isLast) ((CastableStruct)curr).setValue(value);
227                else return (Struct) curr;
228                    
229            }
230            else if(curr instanceof Struct){
231                if(isLast) parent.setEL(key,value);
232                else return (Struct) curr;
233            }
234            else if(curr instanceof String){
235                if(isArrayDef) {
236                    Array arr = new ArrayImpl();
237                    arr.appendEL(curr);
238                    arr.appendEL(value);
239                    parent.setEL(key,arr);
240                }
241                else if(value instanceof Struct) {
242                    parent.setEL(key,value);
243                }
244                else {
245                    if(!StringUtil.isEmpty(value)) {
246                            String existing=Caster.toString(curr,"");
247                            if(StringUtil.isEmpty(existing))
248                                    parent.setEL(key,value);
249                            else 
250                                    parent.setEL(key,Caster.toString(curr,"")+','+value);
251                    }
252                }
253            }
254            if(!isLast) {
255                return (Struct)value;
256            }
257            return null;
258        }
259        
260        /*
261        private String decode(Object value,String encoding) throws UnsupportedEncodingException {
262            return URLDecoder.decode(new String(Caster.toString(value,"").getBytes("ISO-8859-1"),encoding),encoding);
263        }*/
264        
265        /**
266             * @see railo.runtime.type.Scope#isInitalized()
267             */
268            public boolean isInitalized() {
269                    return isInit;
270            }
271    
272            /**
273             * @see railo.runtime.type.Scope#initialize(railo.runtime.PageContext)
274             */
275            public void initialize(PageContext pc) {
276            isInit=true;
277            }
278    
279            /**
280             * @see railo.runtime.type.Scope#release()
281             */
282            public void release() {
283                    clear();
284                    isInit=false;
285            }
286    
287    
288        /**
289         * @return Returns the id.
290         */
291        public int _getId() {
292            return id;
293        }
294        
295        /**
296         * display name for dump
297         * @param dspName
298         */
299        protected void setDisplayName(String dspName) {
300            this.dspName=dspName;
301        }
302        
303        /**
304         * @see railo.runtime.type.Scope#getType()
305         */
306        public int getType() {
307            return type;
308        }
309        
310        /**
311         * @see railo.runtime.type.Scope#getTypeAsString()
312         */
313        public String getTypeAsString() {
314            return name;
315        }
316            public long sizeOf() {
317                    return StructUtil.sizeOf(this);
318            }
319        
320    }