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.Iterator;
023import java.util.List;
024import java.util.ListIterator;
025import java.util.Map;
026import java.util.Map.Entry;
027
028import lucee.commons.lang.CFTypes;
029import lucee.commons.lang.StringUtil;
030import lucee.runtime.Component;
031import lucee.runtime.ComponentSpecificAccess;
032import lucee.runtime.engine.ThreadLocalPageContext;
033import lucee.runtime.exp.PageException;
034import lucee.runtime.op.Caster;
035import lucee.runtime.op.Duplicator;
036import lucee.runtime.type.Array;
037import lucee.runtime.type.Collection;
038import lucee.runtime.type.KeyImpl;
039import lucee.runtime.type.Query;
040import lucee.runtime.type.UDF;
041import lucee.runtime.type.util.ArrayUtil;
042import lucee.runtime.type.wrap.ArrayAsList;
043import flex.messaging.io.amf.ASObject;
044
045
046/**
047 * Cast a CFML object to AMF Objects and the other way
048 */
049public final class ModernAMFCaster extends ClassicAMFCaster {
050
051        private boolean doProperties=true;
052        private boolean doGetters=true;
053        private boolean doRemoteValues=true;
054        
055        @Override
056        public void init(Map arguments){
057                super.init(arguments);
058                
059                String strValues = Caster.toString(arguments.get("component-values"),null);
060                if(!StringUtil.isEmpty(strValues)){
061                        doProperties = lucee.runtime.type.util.ListUtil.listFindNoCase(strValues, "properties", ",")!=-1;
062                        doGetters=lucee.runtime.type.util.ListUtil.listFindNoCase(strValues, "getters", ",")!=-1;
063                        doRemoteValues=lucee.runtime.type.util.ListUtil.listFindNoCase(strValues, "remote-values", ",")!=-1;
064                }
065        }
066
067        public Object toAMFObject(Object cf) throws PageException {
068                if(cf instanceof List) return toAMFObject((List)cf);
069                if(cf instanceof Array) return toAMFObject(ArrayAsList.toList((Array)cf));
070                if(cf instanceof Component)     return toAMFObject((Component)cf);
071                if(cf instanceof Query) return super.toAMFObject((Query)cf);
072                if(cf instanceof Map) return super.toAMFObject((Map)cf);
073                if(cf instanceof Object[]) return toAMFObject((Object[])cf);
074                
075                return cf;
076        }
077        
078
079        protected ASObject toAMFObject(Component cfc) throws PageException {
080                // add properties
081                ASObject aso = doProperties?super.toAMFObject(cfc):new ASObject();
082                ComponentSpecificAccess cw=ComponentSpecificAccess.toComponentSpecificAccess(Component.ACCESS_REMOTE,cfc);
083                
084                Iterator it = cfc.entrySet().iterator();
085        Map.Entry entry;
086        Object v;
087        Collection.Key k;
088        UDF udf;
089        String name;
090        while(it.hasNext()) {
091            entry=(Entry) it.next();
092            k=KeyImpl.toKey(entry.getKey());
093            v=entry.getValue();
094            
095            // add getters
096            if(v instanceof UDF){
097                if(!doGetters) continue;
098                udf=(UDF) v;
099                name=udf.getFunctionName();
100                if(!StringUtil.startsWithIgnoreCase(name, "get"))continue;
101                if(udf.getReturnType()==CFTypes.TYPE_VOID) continue;
102                if(udf.getFunctionArguments().length>0) continue;
103                
104                try {
105                                        v=cfc.call(ThreadLocalPageContext.get(), name, ArrayUtil.OBJECT_EMPTY);
106                                } catch (PageException e) {
107                                        continue;
108                                }
109                name=name.substring(3);
110                
111                aso.put(toString(name,forceCFCLower), toAMFObject(v));
112            }
113            
114            // add remote data members
115            if(cw!=null && doRemoteValues){
116                v=cw.get(k,null);
117                if(v!=null)aso.put(toString(k,forceCFCLower), toAMFObject(v));
118            }
119        }
120        return aso;
121        }
122    
123        protected Object toAMFObject(List list) throws PageException {
124                list = Duplicator.duplicateList(list, false);
125        ListIterator it = list.listIterator();
126        while(it.hasNext()) {
127                list.set(it.nextIndex(),toAMFObject(it.next()));
128        }
129        return list;
130    }
131        
132        protected Object toAMFObject(Object[] src) throws PageException {
133                ArrayList list=new ArrayList();
134                for(int i=0;i<src.length;i++){
135                        list.add(toAMFObject(src[i]));
136                }
137                return list;
138    }
139}