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