001    package railo.runtime.net.amf;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    import java.util.ListIterator;
006    import java.util.Map;
007    
008    import org.openamf.AMFBody;
009    import org.openamf.config.OpenAMFConfig;
010    import org.openamf.config.PageableRecordsetConfig;
011    import org.openamf.recordset.ASRecordSet;
012    
013    import railo.runtime.Component;
014    import railo.runtime.component.Property;
015    import railo.runtime.exp.ApplicationException;
016    import railo.runtime.exp.PageException;
017    import railo.runtime.op.Caster;
018    import railo.runtime.op.Decision;
019    import railo.runtime.type.Query;
020    import railo.runtime.type.QueryColumn;
021    import railo.runtime.type.QueryImpl;
022    import railo.runtime.type.UDF;
023    import railo.runtime.type.cfc.ComponentAccess;
024    import flashgateway.io.ASObject;
025    
026    /**
027     * Cast a CFML object to AMF Objects and the other way
028     */
029    public final class OpenAMFCaster implements AMFCaster {
030            
031            
032            private static OpenAMFCaster singelton;
033    
034    
035            private OpenAMFCaster(){}
036            
037            public static AMFCaster getInstance(){
038                    if(singelton==null){
039                            singelton= new OpenAMFCaster();
040                    }
041                    return singelton;
042            }
043        
044        /**
045         * cast cfml Object to AMF Object
046         * @param o
047         * @return
048         * @throws PageException
049         */
050        public Object toAMFObject(Object o) throws PageException {
051            if(o instanceof ASObject) return o;
052            if(Decision.isBinary(o))    return o;
053            if(Decision.isArray(o))     return toAMFObject(Caster.toList(o,true));
054            if(Decision.isBoolean(o))   return Caster.toBoolean(o);
055            if(Decision.isComponent(o)) return toAMFObject((Component)o);
056            if(Decision.isDateSimple(o,false))return Caster.toDate(o,null);
057            if(Decision.isNumeric(o))   return Caster.toDouble(o);
058            if(Decision.isQuery(o))     return toAMFObject(Caster.toQuery(o));
059            if(Decision.isStruct(o))    return toAMFObject(Caster.toMap(o,true));
060            if(Decision.isUserDefinedFunction(o))
061                                        return toAMFObject((UDF)o);
062            
063            
064            
065            return o;
066        }
067        
068        
069        private List toAMFObject(List list) throws PageException {
070            ListIterator it = list.listIterator();
071            while(it.hasNext()) {
072                list.set(it.nextIndex(),toAMFObject(it.next()));
073            }
074            return list;
075        }
076        private Map toAMFObject(Map map) throws PageException {
077            Object[] keys = map.keySet().toArray();
078            for(int i=0;i<keys.length;i++) {
079                Object key=keys[i];
080                Object value=map.get(key);
081                if(key instanceof String) {
082                    map.remove(key);
083                    key=((String)key).toUpperCase();
084                }
085                map.put(key,toAMFObject(value));
086            }
087            return map;
088        }
089        private Object toAMFObject(Component c) throws PageException {
090            ASObject aso = new ASObject();
091            if(c instanceof ComponentAccess) {
092                    Property[] prop = c.getProperties(false);
093                    if(prop!=null)for(int i=0;i<prop.length;i++) {
094                            aso.put(prop[i].getName().toUpperCase(), toAMFObject(c.get(prop[i].getName(),null)));
095                    }
096            }
097            return aso;
098        }
099        private ASRecordSet toAMFObject(Query qry) throws PageException {
100            PageableRecordsetConfig prsc = new PageableRecordsetConfig();
101            prsc.setInitialDataRowCount(qry.getRowCount());
102            OpenAMFConfig.getInstance().setPageableRecordsetConfig(prsc);
103            
104            
105            ASRecordSet rs=new ASRecordSet();
106            
107            String[] keys=qry.getColumns();
108            QueryColumn[] columns=new QueryColumn[keys.length];
109            for(int i=0;i<columns.length;i++) {
110                columns[i]=qry.getColumn(keys[i]);
111                //rows.add(i,new ArrayList());
112            }
113            
114            
115            int iCol;
116            ArrayList rows = new ArrayList();
117            ArrayList row;
118            int rowCount=qry.getRecordcount();
119            for(int iRow=1;iRow<=rowCount;iRow++) {
120                rows.add(row=new ArrayList());
121                for(iCol=0;iCol<columns.length;iCol++) {
122                    row.add(toAMFObject(columns[iCol].get(iRow,null)));
123                }
124            }
125            
126            
127            rs.populate(qry.getColumns(),rows);
128            
129            return rs;
130        }
131        private static Object toAMFObject(UDF udf) throws PageException {
132            throw new ApplicationException("can't send a User Defined Function ("+udf.getFunctionName()+") via flash remoting");
133        }
134        
135        public Object toCFMLObject(Object amf) throws PageException {
136            if(amf instanceof List) return toCFMLObject((List)amf);
137            if(amf instanceof Map) return toCFMLObject((Map)amf);
138            if(amf instanceof ASRecordSet) return toCFMLObject((ASRecordSet)amf);
139            
140            return amf;
141        }
142        private List toCFMLObject(List list) throws PageException {
143            ListIterator it = list.listIterator();
144            while(it.hasNext()) {
145                list.set(it.nextIndex(),toCFMLObject(it.next()));
146            }
147            return list;
148        }
149        
150        private Map toCFMLObject(Map map) throws PageException {
151            Object[] keys = map.keySet().toArray();
152            for(int i=0;i<keys.length;i++) {
153                Object key=keys[i];
154                map.put(key,toCFMLObject(map.get(key)));
155            }
156            return map;
157        }
158        
159        private Query toCFMLObject(ASRecordSet rs) throws PageException {
160            String[] columns = rs.getColumnNames();
161            List rows = rs.rows();
162            int len=0;
163            if(rows.size()>0) len=((List)rows.get(0)).size();
164            Query qry=new QueryImpl(columns,len,"query");
165            
166            List row;
167            for(int iCol=0;iCol<columns.length;iCol++) {
168                row=(List) rows.get(iCol);
169                QueryColumn column = qry.getColumn(columns[iCol]);
170                
171                for(int iRow=0;iRow<row.size();iRow++) {
172                    column.set(iRow+1,toCFMLObject(row.get(iRow)));
173                }
174            }
175            return qry;
176        }
177        
178        
179        /**
180         * translate a AMFBody type to a String type
181         * @param type
182         * @return string type
183         */
184        public static String toStringType(byte type) {
185            switch(type) {
186            case AMFBody.DATA_TYPE_ARRAY: return "array";
187            case AMFBody.DATA_TYPE_AS_OBJECT: return "as object";
188            case AMFBody.DATA_TYPE_BOOLEAN: return "boolean";
189            case AMFBody.DATA_TYPE_CUSTOM_CLASS: return "custom";
190            case AMFBody.DATA_TYPE_DATE: return "date";
191            case AMFBody.DATA_TYPE_LONG_STRING: return "long string";
192            case AMFBody.DATA_TYPE_MIXED_ARRAY: return "mixed array";
193            case AMFBody.DATA_TYPE_MOVIE_CLIP: return "movie";
194            case AMFBody.DATA_TYPE_NULL: return "null";
195            case AMFBody.DATA_TYPE_NUMBER: return "number";
196            case AMFBody.DATA_TYPE_OBJECT: return "object";
197            case AMFBody.DATA_TYPE_OBJECT_END: return "object end";
198            case AMFBody.DATA_TYPE_RECORDSET: return "recordset";
199            case AMFBody.DATA_TYPE_REFERENCE_OBJECT: return "ref object";
200            case AMFBody.DATA_TYPE_STRING: return "string";
201            case AMFBody.DATA_TYPE_UNDEFINED: return "undefined";
202            case AMFBody.DATA_TYPE_UNKNOWN: return "unknow";
203            case AMFBody.DATA_TYPE_XML: return "xml";
204            }
205    
206            return "";
207        }
208    
209            public void init(Map arguments) {
210                    // TODO Auto-generated method stub
211                    
212            }
213    }