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    }