001 package railo.runtime.net.amf; 002 003 import java.util.ArrayList; 004 import java.util.Date; 005 import java.util.Iterator; 006 import java.util.List; 007 import java.util.ListIterator; 008 import java.util.Map; 009 import java.util.Map.Entry; 010 011 import org.w3c.dom.Node; 012 013 import railo.commons.lang.CFTypes; 014 import railo.commons.lang.StringUtil; 015 import railo.runtime.Component; 016 import railo.runtime.ComponentWrap; 017 import railo.runtime.Page; 018 import railo.runtime.PageContext; 019 import railo.runtime.PageContextImpl; 020 import railo.runtime.PagePlus; 021 import railo.runtime.PageSourceImpl; 022 import railo.runtime.component.ComponentLoader; 023 import railo.runtime.component.Property; 024 import railo.runtime.config.ConfigWeb; 025 import railo.runtime.engine.ThreadLocalPageContext; 026 import railo.runtime.exp.ApplicationException; 027 import railo.runtime.exp.PageException; 028 import railo.runtime.img.Image; 029 import railo.runtime.op.Caster; 030 import railo.runtime.op.Decision; 031 import railo.runtime.op.Duplicator; 032 import railo.runtime.text.xml.XMLCaster; 033 import railo.runtime.type.Array; 034 import railo.runtime.type.ArrayImpl; 035 import railo.runtime.type.Collection; 036 import railo.runtime.type.Collection.Key; 037 import railo.runtime.type.KeyImpl; 038 import railo.runtime.type.Query; 039 import railo.runtime.type.Struct; 040 import railo.runtime.type.StructImpl; 041 import railo.runtime.type.UDF; 042 import railo.runtime.type.cfc.ComponentAccess; 043 import railo.runtime.type.dt.DateTimeImpl; 044 import railo.runtime.type.util.ArrayUtil; 045 import railo.runtime.type.util.ComponentUtil; 046 import railo.runtime.type.wrap.ArrayAsList; 047 import railo.runtime.type.wrap.ListAsArray; 048 import railo.runtime.type.wrap.MapAsStruct; 049 import flex.messaging.io.amf.ASObject; 050 051 052 /** 053 * Cast a CFML object to AMF Objects and the other way 054 */ 055 public class ClassicAMFCaster implements AMFCaster { 056 057 058 059 private static final Collection.Key REMOTING_FETCH = KeyImpl.intern("remotingFetch"); 060 061 private static ClassicAMFCaster singelton; 062 063 protected boolean forceCFCLower; 064 protected boolean forceStructLower; 065 protected boolean forceQueryLower; 066 067 private int methodAccessLevel; 068 069 /** 070 * @see railo.runtime.net.amf.AMFCaster#init(java.util.Map) 071 */ 072 public void init(Map arguments){ 073 forceCFCLower=Caster.toBooleanValue(arguments.get("force-cfc-lowercase"),false); 074 forceQueryLower=Caster.toBooleanValue(arguments.get("force-query-lowercase"),false); 075 forceStructLower=Caster.toBooleanValue(arguments.get("force-struct-lowercase"),false); 076 // method access level 077 String str=Caster.toString(arguments.get("method-access-level"),"remote"); 078 if("private".equalsIgnoreCase(str))methodAccessLevel=Component.ACCESS_PRIVATE; 079 else if("package".equalsIgnoreCase(str))methodAccessLevel=Component.ACCESS_PACKAGE; 080 else if("public".equalsIgnoreCase(str))methodAccessLevel=Component.ACCESS_PUBLIC; 081 else methodAccessLevel=Component.ACCESS_REMOTE; 082 083 } 084 085 086 /** 087 * @see railo.runtime.net.amf.AMFCaster#toAMFObject(java.lang.Object) 088 */ 089 public Object toAMFObject(Object cf) throws PageException { 090 if(cf instanceof Node) return toAMFObject((Node)cf); 091 if(cf instanceof List) return toAMFObject((List)cf); 092 if(cf instanceof Array) return toAMFObject(ArrayAsList.toList((Array)cf)); 093 if(cf instanceof Component) return toAMFObject((Component)cf); 094 if(cf instanceof Query) return toAMFObject((Query)cf); 095 if(cf instanceof Image) return toAMFObject((Image)cf); 096 if(cf instanceof Map) return toAMFObject((Map)cf); 097 if(cf instanceof Object[]) return toAMFObject((Object[])cf); 098 099 return cf; 100 } 101 102 protected Object toAMFObject(Node node) { 103 return XMLCaster.toRawNode(node); 104 } 105 protected Object toAMFObject(Query query) throws PageException { 106 List result = new ArrayList(); 107 int len=query.getRecordcount(); 108 Collection.Key[] columns=query.keys(); 109 ASObject row; 110 for(int r=1;r<=len;r++) { 111 result.add(row = new ASObject()); 112 for(int c=0;c<columns.length;c++) { 113 row.put(toString(columns[c],forceQueryLower), toAMFObject(query.getAt(columns[c],r)) ); 114 } 115 } 116 return result; 117 } 118 119 protected Object toAMFObject(Image img) throws PageException { 120 try{ 121 return img.getImageBytes(null); 122 } 123 catch(Throwable t){ 124 return img.getImageBytes("png"); 125 } 126 } 127 128 protected ASObject toAMFObject(Component cfc) throws PageException { 129 ASObject aso = new ASObject(); 130 aso.setType(cfc.getCallName()); 131 132 133 Component c=cfc; 134 if(cfc instanceof ComponentAccess)c=ComponentWrap.toComponentWrap(methodAccessLevel,cfc); 135 136 137 Property[] prop = ComponentUtil.getProperties(cfc,false); 138 Object v; UDF udf; 139 if(prop!=null)for(int i=0;i<prop.length;i++) { 140 boolean remotingFetch = Caster.toBooleanValue(prop[i].getDynamicAttributes().get(REMOTING_FETCH,Boolean.TRUE),true); 141 if(!remotingFetch) continue; 142 143 v=cfc.get(prop[i].getName(),null); 144 if(v==null){ 145 v=c.get("get"+prop[i].getName(),null); 146 if(v instanceof UDF){ 147 udf=(UDF) v; 148 if(udf.getReturnType()==CFTypes.TYPE_VOID) continue; 149 if(udf.getFunctionArguments().length>0) continue; 150 151 try { 152 v=c.call(ThreadLocalPageContext.get(), udf.getFunctionName(), ArrayUtil.OBJECT_EMPTY); 153 } catch (PageException e) { 154 continue; 155 } 156 } 157 } 158 159 aso.put(toString(prop[i].getName(),forceCFCLower), toAMFObject(v)); 160 } 161 return aso; 162 } 163 164 protected Object toAMFObject(Map map) throws PageException { 165 if(forceStructLower && map instanceof Struct) toAMFObject((Struct)map); 166 167 map=(Map) Duplicator.duplicate(map,false); 168 Iterator it = map.entrySet().iterator(); 169 Map.Entry entry; 170 while(it.hasNext()) { 171 entry=(Entry) it.next(); 172 entry.setValue(toAMFObject(entry.getValue())); 173 } 174 return MapAsStruct.toStruct(map, false); 175 } 176 177 protected Object toAMFObject(Struct src) throws PageException { 178 Struct trg=new StructImpl(); 179 Key[] keys = src.keys(); 180 181 for(int i=0;i<keys.length;i++) { 182 trg.set(KeyImpl.init(toString(keys[i],forceStructLower)), toAMFObject(src.get(keys[i]))); 183 } 184 return trg; 185 } 186 187 188 189 protected Object toAMFObject(List list) throws PageException { 190 Object[] trg=new Object[list.size()]; 191 ListIterator it = list.listIterator(); 192 193 while(it.hasNext()) { 194 trg[it.nextIndex()]=toAMFObject(it.next()); 195 } 196 return trg; 197 } 198 199 protected Object toAMFObject(Object[] src) throws PageException { 200 Object[] trg=new Object[src.length]; 201 for(int i=0;i<src.length;i++){ 202 trg[i]=toAMFObject(src[i]); 203 } 204 return trg; 205 } 206 207 208 /** 209 * @see railo.runtime.net.amf.AMFCaster#toCFMLObject(java.lang.Object) 210 */ 211 public Object toCFMLObject(Object amf) throws PageException { 212 if(amf instanceof Node) return toCFMLObject((Node)amf); 213 if(amf instanceof List) return toCFMLObject((List)amf); 214 if(Decision.isNativeArray(amf)) { 215 if(amf instanceof byte[]) return amf; 216 if(amf instanceof char[]) return new String((char[])amf); 217 return toCFMLObject(Caster.toNativeArray(amf)); 218 } 219 if(amf instanceof ASObject) return toCFMLObject((ASObject)amf); 220 if(amf instanceof Map) return toCFMLObject((Map)amf); 221 if(amf instanceof Date) return new DateTimeImpl((Date)amf); 222 if(amf == null) return ""; 223 224 return amf; 225 } 226 227 protected Object toCFMLObject(Node node) { 228 return XMLCaster.toXMLStruct(node, true); 229 } 230 protected Object toCFMLObject(Object[] arr) throws PageException { 231 Array trg=new ArrayImpl(); 232 for(int i=0;i<arr.length;i++){ 233 trg.setEL(i+1, toCFMLObject(arr[i])); 234 } 235 return trg; 236 } 237 238 protected Object toCFMLObject(List list) throws PageException { 239 ListIterator it = list.listIterator(); 240 while(it.hasNext()) { 241 //arr.setE(it.nextIndex()+1, toCFMLObject(it.next())); 242 list.set(it.nextIndex(),toCFMLObject(it.next())); 243 } 244 return ListAsArray.toArray(list); 245 } 246 247 protected Object toCFMLObject(Map map) throws PageException { 248 Iterator it = map.entrySet().iterator(); 249 Map.Entry entry; 250 while(it.hasNext()) { 251 entry=(Entry) it.next(); 252 entry.setValue(toCFMLObject(entry.getValue())); 253 } 254 return MapAsStruct.toStruct(map, false); 255 } 256 257 protected Object toCFMLObject(ASObject aso) throws PageException { 258 if(!StringUtil.isEmpty(aso.getType())){ 259 PageContext pc = ThreadLocalPageContext.get(); 260 ConfigWeb config = pc.getConfig(); 261 if(pc!=null){ 262 String name="/"+aso.getType().replace('.', '/')+".cfc"; 263 PagePlus p = (PagePlus) PageSourceImpl.loadPage(pc, ((PageContextImpl)pc).getPageSources(name), null) ; 264 //PageSourceImpl ps = (PageSourceImpl) pc.getPageSource(name); 265 //Page p=ps.loadPage(pc,config,null); 266 if(p==null)throw new ApplicationException("Could not find a Component with name ["+aso.getType()+"]"); 267 268 Component cfc = ComponentLoader.loadComponent(pc, p, p.getPageSource(), aso.getType(), false); 269 ComponentWrap cw=ComponentWrap.toComponentWrap(config.getComponentDataMemberDefaultAccess(),cfc); 270 271 Iterator it = aso.entrySet().iterator(); 272 Map.Entry entry; 273 while(it.hasNext()){ 274 entry = (Entry) it.next(); 275 cw.set(KeyImpl.toKey(entry.getKey()), toCFMLObject(entry.getValue())); 276 } 277 return cfc; 278 } 279 280 } 281 return toCFMLObject((Map)aso); 282 } 283 284 protected String toString(Object key, boolean forceLower) { 285 if(key instanceof Key) return toString((Key)key, forceLower); 286 return toString(Caster.toString(key,""), forceLower); 287 } 288 289 protected String toString(Key key, boolean forceLower) { 290 if(forceLower) return key.getLowerString(); 291 return key.getString(); 292 } 293 294 protected String toString(String key, boolean forceLower) { 295 if(forceLower) return key.toLowerCase(); 296 return key; 297 } 298 }