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