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    }