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