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.rpc;
020
021import java.io.IOException;
022import java.math.BigDecimal;
023import java.net.MalformedURLException;
024import java.util.ArrayList;
025import java.util.Calendar;
026import java.util.Date;
027import java.util.HashMap;
028import java.util.HashSet;
029import java.util.Iterator;
030import java.util.List;
031import java.util.Map;
032import java.util.Map.Entry;
033import java.util.Set;
034import java.util.TimeZone;
035import java.util.Vector;
036
037import javax.xml.namespace.QName;
038import javax.xml.rpc.encoding.TypeMapping;
039
040import lucee.commons.lang.ClassException;
041import lucee.commons.lang.ClassUtil;
042import lucee.commons.lang.ExceptionUtil;
043import lucee.commons.lang.Pair;
044import lucee.commons.lang.PhysicalClassLoader;
045import lucee.commons.lang.StringUtil;
046import lucee.runtime.Component;
047import lucee.runtime.ComponentScope;
048import lucee.runtime.ComponentSpecificAccess;
049import lucee.runtime.PageContext;
050import lucee.runtime.component.Property;
051import lucee.runtime.component.PropertyImpl;
052import lucee.runtime.engine.ThreadLocalPageContext;
053import lucee.runtime.exp.ApplicationException;
054import lucee.runtime.exp.ExpressionException;
055import lucee.runtime.exp.PageException;
056import lucee.runtime.interpreter.CFMLExpressionInterpreter;
057import lucee.runtime.net.http.ReqRspUtil;
058import lucee.runtime.op.Caster;
059import lucee.runtime.op.Decision;
060import lucee.runtime.op.date.DateCaster;
061import lucee.runtime.reflection.Reflector;
062import lucee.runtime.type.Array;
063import lucee.runtime.type.Collection;
064import lucee.runtime.type.Collection.Key;
065import lucee.runtime.type.KeyImpl;
066import lucee.runtime.type.ObjectWrap;
067import lucee.runtime.type.Query;
068import lucee.runtime.type.QueryColumn;
069import lucee.runtime.type.QueryImpl;
070import lucee.runtime.type.Struct;
071import lucee.runtime.type.StructImpl;
072import lucee.runtime.type.dt.DateTime;
073import lucee.runtime.type.dt.TimeSpan;
074import lucee.runtime.type.scope.Argument;
075import lucee.runtime.type.util.ArrayUtil;
076import lucee.runtime.type.util.ComponentProUtil;
077import lucee.runtime.type.util.ComponentUtil;
078
079import org.apache.axis.Constants;
080import org.apache.axis.types.Day;
081import org.apache.axis.types.Duration;
082import org.apache.axis.types.Entities;
083import org.apache.axis.types.Entity;
084import org.apache.axis.types.Language;
085import org.apache.axis.types.Month;
086import org.apache.axis.types.MonthDay;
087import org.apache.axis.types.NCName;
088import org.apache.axis.types.NMToken;
089import org.apache.axis.types.NMTokens;
090import org.apache.axis.types.Name;
091import org.apache.axis.types.Token;
092import org.apache.axis.types.URI;
093import org.apache.axis.types.URI.MalformedURIException;
094import org.apache.axis.types.Year;
095import org.apache.axis.types.YearMonth;
096import org.apache.axis.wsdl.symbolTable.TypeEntry;
097
098import coldfusion.xml.rpc.QueryBean;
099
100/**
101 * Axis Type Caster
102 */
103public final class AxisCaster {
104
105        /**
106     * cast a value to a Axis Compatible Type
107     * @param type
108     * @param value
109     * @return Axis Compatible Type
110     * @throws PageException
111     */
112    public static Object toAxisType(TypeMapping tm,TimeZone tz,TypeEntry typeEntry,QName type, Object value) throws PageException {
113        return _toAxisType(tm, tz, typeEntry,type,null, value,new HashSet<Object>());
114        }
115
116    public static Object toAxisType(TypeMapping tm,Object value, Class targetClass) throws PageException {
117        return _toAxisType(tm,null,null,null,targetClass, value, new HashSet<Object>());
118    }
119        
120    /**
121     * cast a value to a Axis Compatible Type
122     * @param type
123     * @param value
124     * @return Axis Compatible Type
125     * @throws PageException
126     */
127    private static Object _toAxisType(TypeMapping tm,TimeZone tz,TypeEntry typeEntry,QName type, Class targetClass, Object value,Set<Object> done) throws PageException {
128        
129        // first make sure we have no wrapper
130        if(value instanceof ObjectWrap) {
131                value=((ObjectWrap)value).getEmbededObject();
132        }
133        
134        
135        if(done.contains(value)){
136                        return null;// TODO not sure what in this case is the best solution.
137                }
138        
139        done.add(value);
140        try{
141                if(type!=null) {
142
143                        // Array Of
144                        if(type.getLocalPart().startsWith("ArrayOf")) {
145                                return toArray(tm,typeEntry,type,value,done);
146                }
147                        
148                        
149                        // XSD
150                        for(int i=0;i<Constants.URIS_SCHEMA_XSD.length;i++) {
151                                if(Constants.URIS_SCHEMA_XSD[i].equals(type.getNamespaceURI())) {
152                                return toAxisTypeXSD(tm,tz,type.getLocalPart(), value,done);
153                            }
154                        }
155                        if(StringUtil.startsWithIgnoreCase(type.getLocalPart(),"xsd_")) {
156                                return toAxisTypeXSD(tm,tz,type.getLocalPart().substring(4), value,done);
157                        }
158
159                        //SOAP
160                        if(type.getNamespaceURI().indexOf("soap")!=-1) {
161                            return toAxisTypeSoap(tm,type.getLocalPart(), value,done);
162                        }
163                        if(StringUtil.startsWithIgnoreCase(type.getLocalPart(),"soap_")) {
164                                return toAxisTypeSoap(tm,type.getLocalPart().substring(5), value,done);
165                        }
166                }
167                return _toDefinedType(tm,typeEntry,type,targetClass,value,done);
168        
169        }
170        finally{
171                done.remove(value);
172        }
173    }
174    
175    private static Object toArray(TypeMapping tm, TypeEntry typeEntry,QName type, Object value, Set<Object> done) throws PageException {
176        if(type==null || !type.getLocalPart().startsWith("ArrayOf"))
177                throw new ApplicationException("invalid call of the functionn toArray");
178        
179        // get component Type
180                String tmp = type.getLocalPart().substring(7);
181                QName componentType=null;
182                
183                // no arrayOf embeded anymore
184                if(tmp.indexOf("ArrayOf")==-1 && typeEntry!=null) {
185                        TypeEntry ref = typeEntry.getRefType();
186                        componentType=ref.getQName();
187                }
188                if(componentType==null) {
189                        if(tmp.startsWith("_tns1_"))tmp=tmp.substring(6);
190                        componentType=new QName(type.getNamespaceURI(), tmp);
191                }
192        Object[] objs = Caster.toNativeArray(value);
193        Object[] rtns;
194        List<Object> list=new ArrayList<Object>();
195        
196        
197        Class componentClass=null;
198        Object v;
199        for(int i=0;i<objs.length;i++) {
200                v=_toAxisType(tm,null,typeEntry,componentType,null,objs[i],done);
201                list.add(v);
202                if(i==0) {
203                        if(v!=null) componentClass=v.getClass();
204                }
205                else {
206                        if(v==null || v.getClass()!=componentClass) componentClass=null;
207                }
208                
209            }
210
211        if(componentClass!=null) {
212                componentClass=toAxisTypeClass(componentClass);
213                rtns = (Object[]) java.lang.reflect.Array.newInstance(componentClass, objs.length);
214        }
215        else 
216                rtns = new Object[objs.length];
217        
218        
219        
220        return list.toArray(rtns);
221    }
222
223    
224    
225
226        private static Object toAxisTypeSoap(TypeMapping tm,String local, Object value, Set<Object> done) throws PageException {
227        if(local.equals(Constants.SOAP_ARRAY.getLocalPart())) return toArrayList(tm,value,done);
228        if(local.equals(Constants.SOAP_ARRAY12.getLocalPart())) return toArrayList(tm,value,done);
229        if(local.equals(Constants.SOAP_ARRAY_ATTRS11.getLocalPart())) return toArrayList(tm,value,done);
230        if(local.equals(Constants.SOAP_ARRAY_ATTRS12.getLocalPart())) return toArrayList(tm,value,done);
231        if(local.equals(Constants.SOAP_BASE64.getLocalPart())) return Caster.toBinary(value);
232        if(local.equals(Constants.SOAP_BASE64BINARY.getLocalPart())) return Caster.toBinary(value);
233        if(local.equals(Constants.SOAP_BOOLEAN.getLocalPart())) return Caster.toBoolean(value);
234        if(local.equals(Constants.SOAP_BYTE.getLocalPart())) return Caster.toByte(value);
235        if(local.equals(Constants.SOAP_DECIMAL.getLocalPart())) return new BigDecimal(Caster.toDoubleValue(value));
236        if(local.equals(Constants.SOAP_DOUBLE.getLocalPart())) return Caster.toDouble(value);
237        if(local.equals(Constants.SOAP_FLOAT.getLocalPart())) return new Float(Caster.toDoubleValue(value));
238        if(local.equals(Constants.SOAP_INT.getLocalPart())) return Caster.toInteger(value);
239        if(local.equals(Constants.SOAP_INTEGER.getLocalPart())) return Caster.toInteger(value);
240        if(local.equals(Constants.SOAP_LONG.getLocalPart())) return Caster.toLong(value);
241        if(local.equals(Constants.SOAP_MAP.getLocalPart())) return toMap(tm,value,done);
242        if(local.equals(Constants.SOAP_SHORT.getLocalPart())) return Caster.toShort(value);
243        if(local.equals(Constants.SOAP_STRING.getLocalPart())) return Caster.toString(value);
244        if(local.equals(Constants.SOAP_VECTOR.getLocalPart())) return toVector(tm,value,done);
245        
246        return _toDefinedType(tm,null,null,null,value,done);
247        
248        
249    }
250
251    private static Object toAxisTypeXSD(TypeMapping tm,TimeZone tz,String local, Object value, Set<Object> done) throws PageException {
252        //if(local.equals(Constants.XSD_ANY.getLocalPart())) return value;
253        if(local.equalsIgnoreCase(Constants.XSD_ANYSIMPLETYPE.getLocalPart())) return Caster.toString(value);
254        if(local.equalsIgnoreCase(Constants.XSD_ANYURI.getLocalPart())) return toURI(value);
255        if(local.equalsIgnoreCase(Constants.XSD_STRING.getLocalPart())) return Caster.toString(value);
256        if(local.equalsIgnoreCase(Constants.XSD_BASE64.getLocalPart())) return Caster.toBinary(value);
257        if(local.equalsIgnoreCase(Constants.XSD_BOOLEAN.getLocalPart())) return Caster.toBoolean(value);
258        if(local.equalsIgnoreCase(Constants.XSD_BYTE.getLocalPart())) return Caster.toByte(value);
259        if(local.equalsIgnoreCase(Constants.XSD_DATE.getLocalPart())) return Caster.toDate(value,null);
260        if(local.equalsIgnoreCase(Constants.XSD_DATETIME.getLocalPart())) return Caster.toDate(value,null);
261        if(local.equalsIgnoreCase(Constants.XSD_DAY.getLocalPart())) return toDay(value);
262        if(local.equalsIgnoreCase(Constants.XSD_DECIMAL.getLocalPart())) return new BigDecimal(Caster.toDoubleValue(value));
263        if(local.equalsIgnoreCase(Constants.XSD_DOUBLE.getLocalPart())) return Caster.toDouble(value);
264        if(local.equalsIgnoreCase(Constants.XSD_DURATION.getLocalPart())) return toDuration(value);
265        if(local.equalsIgnoreCase(Constants.XSD_ENTITIES.getLocalPart())) return toEntities(value);
266        if(local.equalsIgnoreCase(Constants.XSD_ENTITY.getLocalPart())) return toEntity(value);
267        if(local.equalsIgnoreCase(Constants.XSD_FLOAT.getLocalPart())) return new Float(Caster.toDoubleValue(value));
268        if(local.equalsIgnoreCase(Constants.XSD_HEXBIN.getLocalPart())) return Caster.toBinary(value);
269        if(local.equalsIgnoreCase(Constants.XSD_ID.getLocalPart())) return Caster.toString(value);
270        if(local.equalsIgnoreCase(Constants.XSD_IDREF.getLocalPart())) return Caster.toString(value);
271        if(local.equalsIgnoreCase(Constants.XSD_IDREFS.getLocalPart())) return Caster.toString(value);
272        if(local.equalsIgnoreCase(Constants.XSD_INT.getLocalPart())) return Caster.toInteger(value);
273        if(local.equalsIgnoreCase(Constants.XSD_INTEGER.getLocalPart())) return Caster.toInteger(value);
274        if(local.equalsIgnoreCase(Constants.XSD_LANGUAGE.getLocalPart())) return toLanguage(value);
275        if(local.equalsIgnoreCase(Constants.XSD_LONG.getLocalPart())) return Caster.toLong(value);
276        if(local.equalsIgnoreCase(Constants.XSD_MONTH.getLocalPart())) return toMonth(value);
277        if(local.equalsIgnoreCase(Constants.XSD_MONTHDAY.getLocalPart())) return toMonthDay(value);
278        if(local.equalsIgnoreCase(Constants.XSD_NAME.getLocalPart())) return toName(value);
279        if(local.equalsIgnoreCase(Constants.XSD_NCNAME.getLocalPart())) return toNCName(value);
280        if(local.equalsIgnoreCase(Constants.XSD_NEGATIVEINTEGER.getLocalPart())) return Caster.toInteger(value);
281        if(local.equalsIgnoreCase(Constants.XSD_NMTOKEN.getLocalPart())) return toNMToken(value);
282        if(local.equalsIgnoreCase(Constants.XSD_NMTOKENS.getLocalPart())) return toNMTokens(value);
283        if(local.equalsIgnoreCase(Constants.XSD_NONNEGATIVEINTEGER.getLocalPart())) return Caster.toInteger(value);
284        if(local.equalsIgnoreCase(Constants.XSD_NONPOSITIVEINTEGER.getLocalPart())) return Caster.toInteger(value);
285        if(local.equalsIgnoreCase(Constants.XSD_NORMALIZEDSTRING.getLocalPart())) return Caster.toString(value);
286        if(local.equalsIgnoreCase(Constants.XSD_POSITIVEINTEGER.getLocalPart())) return Caster.toInteger(value);
287        if(local.equalsIgnoreCase(Constants.XSD_QNAME.getLocalPart())) return toQName(value);
288        if(local.equalsIgnoreCase(Constants.XSD_SCHEMA.getLocalPart())) return toQName(value);
289        if(local.equalsIgnoreCase(Constants.XSD_SHORT.getLocalPart())) return Caster.toShort(value);
290        if(local.equalsIgnoreCase(Constants.XSD_TIME.getLocalPart())) return DateCaster.toTime(tz,value);
291        if(local.equalsIgnoreCase(Constants.XSD_TIMEINSTANT1999.getLocalPart())) return DateCaster.toTime(tz,value);
292        if(local.equalsIgnoreCase(Constants.XSD_TIMEINSTANT2000.getLocalPart())) return DateCaster.toTime(tz,value);
293        if(local.equalsIgnoreCase(Constants.XSD_TOKEN.getLocalPart())) return toToken(value);
294        if(local.equalsIgnoreCase(Constants.XSD_UNSIGNEDBYTE.getLocalPart())) return Caster.toByte(value);
295        if(local.equalsIgnoreCase(Constants.XSD_UNSIGNEDINT.getLocalPart())) return Caster.toInteger(value);
296        if(local.equalsIgnoreCase(Constants.XSD_UNSIGNEDLONG.getLocalPart())) return Caster.toLong(value);
297        if(local.equalsIgnoreCase(Constants.XSD_UNSIGNEDSHORT.getLocalPart())) return Caster.toShort(value);
298        if(local.equalsIgnoreCase(Constants.XSD_YEAR.getLocalPart())) return toYear(value);
299        if(local.equalsIgnoreCase(Constants.XSD_YEARMONTH.getLocalPart())) return toYearMonth(value);
300        return _toDefinedType(tm, null,null,null, value, done);
301    }
302
303    private static ArrayList<Object> toArrayList(TypeMapping tm,Object value, Set<Object> done) throws PageException {
304        Array arr = Caster.toArray(value);
305        ArrayList<Object> al=new ArrayList<Object>();
306        int len=arr.size();
307        Object o;
308        for(int i=0;i<len;i++) {
309            o=arr.get(i+1,null);
310            al.add(i,_toAxisType(tm,null,null,null,null,o,done));
311        }
312        return al;
313    }
314    
315    private static Object[] toNativeArray(TypeMapping tm,Class targetClass,Object value, Set<Object> done) throws PageException {
316                Object[] objs = Caster.toNativeArray(value);
317                Object[] rtns;
318
319                Class<?> componentClass = null;
320                if(targetClass!=null) {
321                componentClass = targetClass.getComponentType();
322            }
323                
324            if(componentClass!=null) {
325                componentClass=toAxisTypeClass(componentClass);
326                rtns = (Object[]) java.lang.reflect.Array.newInstance(componentClass, objs.length);
327            }
328            else 
329                rtns = new Object[objs.length];
330            
331                try{
332                for(int i=0;i<objs.length;i++) {
333                        rtns[i]=_toAxisType(tm,null,null,null,componentClass,objs[i],done);
334                }
335                }
336                // just in case something goes wrong with typed array
337                catch(ArrayStoreException ase){
338                        rtns = new Object[objs.length];
339                        for(int i=0;i<objs.length;i++) {
340                        rtns[i]=_toAxisType(tm,null,null,null,componentClass,objs[i],done);
341                }
342                }
343                
344                return rtns;
345        }
346
347    private static Vector<Object> toVector(TypeMapping tm,Object value, Set<Object> done) throws PageException {
348        Array arr = Caster.toArray(value);
349        Vector<Object> v=new Vector<Object>();
350        int len=arr.size();
351        Object o;
352        for(int i=0;i<len;i++) {
353            o=arr.get(i+1,null);
354            v.set(i,_toAxisType(tm,null,null,null,null,o,done));
355        }
356        return v;
357        }
358
359        public static Component toComponent(PageContext pc, Pojo pojo, String compPath , Component defaultValue) {
360                try {
361                        Component cfc = pc.loadComponent(compPath);
362                        Property[] props = ComponentProUtil.getProperties(cfc, false, true, false, false);
363                        PojoIterator it=new PojoIterator(pojo);
364                        // only when the same amount of properties
365                        if(props.length==it.size()) {
366                                Map<Collection.Key, Property> propMap = toMap(props);
367                                Property p;
368                                Pair<Collection.Key,Object> pair;
369                                ComponentScope scope = cfc.getComponentScope();
370                                while(it.hasNext()){
371                                        pair=it.next();
372                                        p=propMap.get(pair.getName());
373                                        if(p==null) return defaultValue;
374                                        Object val = null;
375                                        try {
376                                                val = Caster.castTo(pc, p.getType(), pair.getValue(), false);
377                                        } catch (PageException e) {     }
378                                        
379                                        // store in variables and this scope
380                                        scope.setEL(pair.getName(), val);
381                                        cfc.setEL(pair.getName(), val);
382                                }
383                                return cfc;
384                        }
385                }
386                catch (PageException e) {}
387                return defaultValue;
388        }
389
390    private static Map<Collection.Key,Property> toMap(Property[] props) {
391        Map<Collection.Key,Property> map=new HashMap<Collection.Key, Property>();
392                for(int i=0;i<props.length;i++){
393                        map.put(KeyImpl.init(props[i].getName()), props[i]);
394                }
395                return map;
396        }
397
398        public static Pojo toPojo(Pojo pojo, TypeMapping tm,TypeEntry typeEntry,QName type,Component comp, Set<Object> done) throws PageException {
399        PageContext pc = ThreadLocalPageContext.get(); 
400            try {
401                return _toPojo(pc,pojo, tm,typeEntry,type, comp,done);
402                }
403                catch (Exception e) {
404                        throw Caster.toPageException(e);
405                }
406        }
407        
408        private static Pojo _toPojo(PageContext pc, Pojo pojo, TypeMapping tm,TypeEntry typeEntry,QName type,Component comp, Set<Object> done) throws PageException {//print.ds();System.exit(0);
409        comp=ComponentSpecificAccess.toComponentSpecificAccess(Component.ACCESS_PRIVATE,comp);
410                ComponentScope scope = comp.getComponentScope();
411        
412                // create Pojo
413                if(pojo==null) {
414                try {
415                                pojo = (Pojo) ClassUtil.loadInstance(ComponentUtil.getComponentPropertiesClass(pc,comp));
416                        } catch (ClassException e) {
417                                throw Caster.toPageException(e);
418                        }
419                }
420        
421        // initialize Pojo
422                Property[] props=ComponentProUtil.getProperties(comp, false, true, false, false);
423                _initPojo(pc,typeEntry,type,pojo,props,scope,comp,tm,done);
424
425        return pojo;
426    }
427        
428        public static Pojo toPojo(Pojo pojo, TypeMapping tm,TypeEntry typeEntry,QName type,Struct sct, Set<Object> done) throws PageException {
429        PageContext pc = ThreadLocalPageContext.get(); 
430            try {
431                return _toPojo(pc,pojo, tm,typeEntry,type, sct,done);
432                }
433                catch (Exception e) {
434                        throw Caster.toPageException(e);
435                }
436        }
437
438        private static Pojo _toPojo(PageContext pc, Pojo pojo, TypeMapping tm,TypeEntry typeEntry,QName type,Struct sct, Set<Object> done) throws PageException {//print.ds();System.exit(0);
439                if(pojo==null) {
440                        try {
441                                PhysicalClassLoader cl=(PhysicalClassLoader) pc.getConfig().getRPCClassLoader(false);
442                        pojo = (Pojo) ClassUtil.loadInstance(ComponentUtil.getStructPropertiesClass(pc,sct,cl));
443                        }
444                        catch (ClassException e) {
445                                throw Caster.toPageException(e);
446                        }
447                        catch (IOException e) {
448                                throw Caster.toPageException(e);
449                        }
450                }
451        
452        // initialize
453                List<Property> props=new ArrayList<Property>();
454                Iterator<Entry<Key, Object>> it = sct.entryIterator();
455                Entry<Key, Object> e;
456                PropertyImpl p;
457                while(it.hasNext()){
458                        e = it.next();
459                        p=new PropertyImpl();
460                        p.setAccess(Component.ACCESS_PUBLIC);
461                        p.setName(e.getKey().getString());
462                        p.setType(e.getValue()==null?"any":Caster.toTypeName(e.getValue())); 
463                        props.add(p);
464                }
465                
466                _initPojo(pc,typeEntry,type,pojo,props.toArray(new Property[props.size()]),sct,null,tm,done);
467
468        return pojo;
469    }
470    
471    private static void _initPojo(PageContext pc, TypeEntry typeEntry, QName type, Pojo pojo, Property[] props, Struct sct, Component comp, TypeMapping tm, Set<Object> done) throws PageException {
472        Property p;
473        Object v;
474        Collection.Key k;
475                CFMLExpressionInterpreter interpreter = new CFMLExpressionInterpreter(false);
476                
477                
478                
479        for(int i=0;i<props.length;i++){
480                p=props[i];
481                k=Caster.toKey(p.getName());
482        // value
483                v=sct.get(k,null);
484                if(v==null && comp!=null)v=comp.get(k, null);
485                
486        // default
487                
488                if(v!=null)v=Caster.castTo(pc, p.getType(), v, false);
489                else{
490                        if(!StringUtil.isEmpty(p.getDefault())){
491                                try {
492                                        v=Caster.castTo(pc, p.getType(), p.getDefault(), false);
493                                        
494                                }
495                                catch(PageException pe) {
496                                        try {
497                                                v=interpreter.interpret(pc, p.getDefault());
498                                                v=Caster.castTo(pc, p.getType(), v, false);
499                                        }
500                                catch(PageException pe2) {
501                                                throw new ExpressionException("can not use default value ["+p.getDefault()+"] for property ["+p.getName()+"] with type ["+p.getType()+"]");
502                                }
503                                }
504                        }
505                }
506                
507        // set or throw
508                if(v==null) {
509                        if(p.isRequired())throw new ExpressionException("required property ["+p.getName()+"] is not defined");
510                }
511                else {
512                        TypeEntry childTE=null;
513                        QName childT=null;
514                        if(typeEntry!=null) {
515                                childTE = AxisUtil.getContainedElement(typeEntry,p.getName(),null);
516                                if(childTE!=null) childT=childTE.getQName();
517                                
518                        }
519                        Reflector.callSetter(pojo, p.getName().toLowerCase(), _toAxisType(tm,null,childTE,childT,null,v,done)); 
520                }
521        }
522        }
523
524        private static QueryBean toQueryBean(TypeMapping tm,Object value, Set<Object> done) throws PageException {
525        Query query = Caster.toQuery(value);
526                int recordcount=query.getRecordcount();
527        String[] columnList = query.getColumns();
528        QueryColumn[] columns=new QueryColumn[columnList.length];
529        Object[][] data = new Object[recordcount][columnList.length];
530        
531        for(int i=0;i<columnList.length;i++) {
532                columns[i]=query.getColumn(columnList[i]);
533        }
534        
535        int row;
536        for(row=1;row<=recordcount;row++) {
537            for(int i=0;i<columns.length;i++) {
538                data[row-1][i]=_toAxisType(tm,null,null,null,null,columns[i].get(row,null),done);
539            }
540        }
541        
542        QueryBean qb = new QueryBean();
543        qb.setColumnList(columnList);
544        qb.setData(data);
545        return qb;
546        
547    }
548    
549
550    
551    private static Map<String,Object> toMap(TypeMapping tm,Object value, Set<Object> done) throws PageException {
552        Struct src = Caster.toStruct(value);
553        
554        HashMap<String,Object> trg=new HashMap<String,Object>();
555        Iterator<Entry<Key, Object>> it = src.entryIterator();
556        Entry<Key, Object> e;
557        while(it.hasNext()) {
558                e = it.next();
559            trg.put(e.getKey().getString(),_toAxisType(tm,null,null,null,null,e.getValue(),done));
560
561        }
562        return trg;
563        
564    }
565
566    private static Object _toDefinedType(TypeMapping tm,TypeEntry typeEntry,QName type,Class targetClass,Object value,Set<Object> done) throws PageException {
567        
568        // Date
569        if(value instanceof Date) {// not set to Decision.isDate(value)
570                return new Date(((Date)value).getTime());
571        }
572        
573        
574        
575        
576        Class clazz=type==null?null:((org.apache.axis.encoding.TypeMapping)tm).getClassForQName(type);
577        // Pojo
578        if(clazz!=null && Reflector.isInstaneOf(clazz,Pojo.class)) {
579                Pojo pojo;
580                try{
581                        pojo=(Pojo) ClassUtil.loadInstance(clazz);
582                }
583                catch(Throwable t){
584                        ExceptionUtil.rethrowIfNecessary(t);
585                        throw Caster.toPageException(t);
586                }
587                // Struct
588            if(Decision.isStruct(value)) {
589                
590                if(value instanceof Component) 
591                        return toPojo(pojo,tm,typeEntry,type,(Component)value,done);
592                return toPojo(pojo,tm,typeEntry,type,Caster.toStruct(value),done);
593            }
594        }
595
596        // No Mapping found
597        
598        
599        // Array
600        if(Decision.isArray(value) && !(value instanceof Argument)) {
601                if(value instanceof byte[]) return value;
602                return toNativeArray(tm,targetClass,value,done);
603        }
604        // Struct
605        if(Decision.isStruct(value)) {
606                if(value instanceof Component) {
607                        Object pojo= toPojo(null,tm,null,null,(Component)value,done);
608                        try     {
609                                if(type==null || type.getLocalPart().equals("anyType")) {
610                                        type= new QName(getRequestDefaultNameSpace(),pojo.getClass().getName());
611                                        //type= new QName(getRequestNameSpace(),pojo.getClass().getName());
612                                        //print.ds("missing type for "+pojo.getClass().getName());
613                                }
614                                TypeMappingUtil.registerBeanTypeMapping(tm, pojo.getClass(), type);
615                                
616                        }
617                        catch(Throwable fault){
618                        ExceptionUtil.rethrowIfNecessary(fault);
619                                throw Caster.toPageException(fault);
620                        }
621                        return pojo;
622                }
623                /*if(type!=null && !type.getLocalPart().equals("anyType")) {
624                        Object pojo= toPojo(null,tm,Caster.toStruct(value),targetClass,done);
625                        
626                        //Map<String, Object> map = toMap(tm,value,targetClass,done);
627                        //TypeMappingUtil.registerMapTypeMapping(tm, map.getClass(), type);
628                        TypeMappingUtil.registerBeanTypeMapping(tm, pojo.getClass(), type);
629                        return pojo;
630                }*/
631                return toMap(tm,value,done);
632                
633                
634        }
635        // Query
636        if(Decision.isQuery(value)) return toQueryBean(tm,value,done);
637        // Other
638        return value;
639    }
640    
641    public static Class toAxisTypeClass(Class clazz) {
642        if(clazz.isArray()) {
643                return ClassUtil.toArrayClass(toAxisTypeClass(clazz.getComponentType()));
644        }
645        
646        if(Query.class==clazz) return QueryBean.class;
647        if(Array.class==clazz) return Object[].class;
648        if(Struct.class==clazz) return Map.class;
649        //if(Struct[].class==clazz) return Map[].class;
650        //if(Query[].class==clazz) return QueryBean[].class;
651        
652        return clazz;
653    }
654    
655    private static Object toURI(Object value) throws PageException {
656        if(value instanceof URI) return value;
657        if(value instanceof java.net.URI) return value;
658        try {
659            return new URI(Caster.toString(value));
660        } catch (MalformedURIException e) {
661            throw Caster.toPageException(e);
662        }
663    }
664
665    private static Token toToken(Object value) throws PageException {
666        if(value instanceof Token) return (Token) value;
667        return new Token(Caster.toString(value));
668    }
669    
670    private static QName toQName(Object value) throws PageException {
671        if(value instanceof QName) return (QName) value;
672        return new QName(Caster.toString(value));
673    }
674
675    private static NMTokens toNMTokens(Object value) throws PageException {
676        if(value instanceof NMTokens) return (NMTokens) value;
677        return new NMTokens(Caster.toString(value));
678    }
679    
680    private static NMToken toNMToken(Object value) throws PageException {
681        if(value instanceof NMToken) return (NMToken) value;
682        return new NMToken(Caster.toString(value));
683    }
684    private static NCName toNCName(Object value) throws PageException {
685        if(value instanceof NCName) return (NCName) value;
686        return new NCName(Caster.toString(value));
687    }
688
689    private static Name toName(Object value) throws PageException {
690        if(value instanceof Name) return (Name) value;
691        return new Name(Caster.toString(value));
692    }
693
694    private static Language toLanguage(Object value) throws PageException {
695        if(value instanceof Language) return (Language) value;
696        return new Language(Caster.toString(value));
697    }
698
699    private static Entities toEntities(Object value) throws PageException {
700        if(value instanceof Entities) return (Entities) value;
701        return new Entities(Caster.toString(value));
702    }
703    
704    private static Entity toEntity(Object value) throws PageException {
705        if(value instanceof Entity) return (Entity) value;
706        return new Entity(Caster.toString(value));
707    }
708
709    private static Day toDay(Object value) throws PageException {
710        if(value instanceof Day) return (Day) value;
711        if(Decision.isDateSimple(value,false)) {
712            return new Day(Caster.toDate(value,null).getDate());
713        }
714        
715        try {
716            return new Day(Caster.toIntValue(value));
717        } 
718        catch (Exception e) {
719            try {
720                return new Day(Caster.toString(value));
721            } catch (NumberFormatException nfe) {
722                throw Caster.toPageException(nfe);
723            } 
724            catch (ExpressionException ee) {
725                throw ee;
726            }
727        }
728    }
729
730    private static Year toYear(Object value) throws PageException {
731        if(value instanceof Year) return (Year) value;
732        if(Decision.isDateSimple(value,false)) {
733            return new Year(Caster.toDate(value,null).getYear());
734        }
735        try {
736            return new Year(Caster.toIntValue(value));
737        } 
738        catch (Exception e) {
739            try {
740                return new Year(Caster.toString(value));
741            } catch (NumberFormatException nfe) {
742                throw Caster.toPageException(nfe);
743            } 
744            catch (ExpressionException ee) {
745                throw ee;
746            }
747        }
748    }
749
750    private static Month toMonth(Object value) throws PageException {
751        if(value instanceof Month) return (Month) value;
752        if(Decision.isDateSimple(value,false)) {
753            return new Month(Caster.toDate(value,null).getMonth());
754        }
755        try {
756            return new Month(Caster.toIntValue(value));
757        } 
758        catch (Exception e) {
759            try {
760                return new Month(Caster.toString(value));
761            } catch (NumberFormatException nfe) {
762                throw Caster.toPageException(nfe);
763            } 
764            catch (ExpressionException ee) {
765                throw ee;
766            }
767        }
768    }
769
770    private static YearMonth toYearMonth(Object value) throws PageException {
771        if(value instanceof YearMonth) return (YearMonth) value;
772        if(Decision.isDateSimple(value,false)) {
773            DateTime dt = Caster.toDate(value,null);
774            return new YearMonth(dt.getYear(),dt.getMonth());
775        }
776        
777        try {
778            return new YearMonth(Caster.toString(value));
779        } catch (NumberFormatException nfe) {
780            throw Caster.toPageException(nfe);
781        } 
782        catch (ExpressionException ee) {
783            throw ee;
784        }
785    }
786
787    private static MonthDay toMonthDay(Object value) throws PageException {
788        if(value instanceof MonthDay) return (MonthDay) value;
789        if(Decision.isDateSimple(value,false)) {
790            DateTime dt = Caster.toDate(value,null);
791            return new MonthDay(dt.getMonth(),dt.getDate());
792        }
793        
794        try {
795            return new MonthDay(Caster.toString(value));
796        } catch (NumberFormatException nfe) {
797            throw Caster.toPageException(nfe);
798        } 
799        catch (ExpressionException ee) {
800            throw ee;
801        }
802    }
803
804    private static Duration toDuration(Object value) throws PageException, IllegalArgumentException {
805        if(value instanceof Duration) return (Duration) value;
806        try {
807            TimeSpan ts = Caster.toTimespan(value);
808            return new Duration(true, 0, 0, ts.getDay(), ts.getHour(), ts.getMinute(), ts.getSecond());
809        } catch (PageException e) {
810            return new Duration(Caster.toString(value));
811        }
812    }
813    
814
815    public static Object toLuceeType(PageContext pc, Object value) throws PageException {
816        return toLuceeType(pc, null, value);
817    }
818    
819
820    public static Object toLuceeType(PageContext pc, String customType, Object value) throws PageException {
821        pc=ThreadLocalPageContext.get(pc);
822        if(pc!=null && value instanceof Pojo) {
823                if(!StringUtil.isEmpty(customType)){
824                        Component cfc = toComponent(pc, (Pojo)value,customType, null);
825                        if(cfc!=null) return cfc;
826                }
827                /*
828                // try package/class name as component name
829                String compPath=value.getClass().getName();
830                Component cfc = toComponent(pc, (Pojo)value, compPath, null);
831                if(cfc!=null) return cfc;
832                
833                // try class name as component name
834                compPath=ListUtil.last(compPath, '.');
835                cfc = toComponent(pc, (Pojo)value, compPath, null);
836                if(cfc!=null) return cfc;
837                */
838        }
839        if(value instanceof Date || value instanceof Calendar) {// do not change to caster.isDate
840                return Caster.toDate(value,null);
841        }
842        if(value instanceof Object[]) {
843                Object[] arr=(Object[]) value;
844                if(!ArrayUtil.isEmpty(arr)){
845                        boolean allTheSame=true;
846                        // byte
847                        if(arr[0] instanceof Byte){
848                                for(int i=1;i<arr.length;i++){
849                                        if(!(arr[i] instanceof Byte)){
850                                                allTheSame=false;
851                                                break;
852                                        }
853                                }
854                                if(allTheSame){
855                                        byte[] bytes=new byte[arr.length];
856                                        for(int i=0;i<arr.length;i++){
857                                        bytes[i]=Caster.toByteValue(arr[i]);
858                                }
859                                        return bytes;
860                                }
861                        }
862                }
863        }
864        if(value instanceof Byte[]) {
865                Byte[] arr=(Byte[]) value;
866                if(!ArrayUtil.isEmpty(arr)){
867                                byte[] bytes=new byte[arr.length];
868                                for(int i=0;i<arr.length;i++){
869                                bytes[i]=arr[i].byteValue();
870                        }
871                                return bytes;
872                }
873        }
874        if(value instanceof byte[]) {
875                return value;
876        }
877        if(Decision.isArray(value)) {
878                
879            Array a = Caster.toArray(value);
880            int len=a.size();
881            Object o;
882            String ct;
883            for(int i=1;i<=len;i++) {
884                o=a.get(i,null);
885                if(o!=null) {
886                        ct=customType!=null && customType.endsWith("[]")?customType.substring(0,customType.length()-2):null;
887                        a.setEL(i,toLuceeType(pc,ct,o));
888                }
889            }
890            return a;
891        }
892        if(value instanceof Map) {
893                Struct sct = new StructImpl();
894            Iterator it=((Map)value).entrySet().iterator();
895            Map.Entry entry;
896            while(it.hasNext()) {
897                entry=(Entry) it.next();
898                sct.setEL(Caster.toString(entry.getKey()),toLuceeType(pc,null,entry.getValue()));
899            }
900            return sct;
901                
902                
903                //return StructUtil.copyToStruct((Map)value);
904        }
905        if(isQueryBean(value)) {
906                QueryBean qb = (QueryBean) value;
907            String[] strColumns = qb.getColumnList();
908            Object[][] data = qb.getData();
909            int recorcount=data.length;
910            Query qry=new QueryImpl(strColumns,recorcount,"QueryBean");
911            QueryColumn[] columns=new QueryColumn[strColumns.length];
912            for(int i=0;i<columns.length;i++) {
913                columns[i]=qry.getColumn(strColumns[i]);
914            }
915            
916            int row;
917            for(row=1;row<=recorcount;row++) {
918                for(int i=0;i<columns.length;i++) {
919                        columns[i].set(row,toLuceeType(pc,null,data[row-1][i]));
920                }
921            }
922            return qry;
923        }
924        if(Decision.isQuery(value)) {
925            Query q = Caster.toQuery(value);
926            int recorcount=q.getRecordcount();
927            String[] strColumns = q.getColumns();
928            
929            QueryColumn col;
930            int row;
931            for(int i=0;i<strColumns.length;i++) {
932                col=q.getColumn(strColumns[i]);
933                for(row=1;row<=recorcount;row++) {
934                    col.set(row,toLuceeType(pc,null,col.get(row,null)));
935                }
936            }
937            return q;
938        }
939        return value;
940    }
941
942        private static boolean isQueryBean(Object value) {
943                return (value instanceof QueryBean);
944        }
945
946        public static QName toComponentType(QName qName, QName defaultValue) {
947                String lp = qName.getLocalPart();
948                String uri = qName.getNamespaceURI();
949                if(lp.startsWith("ArrayOf"))
950                        return new QName(uri, lp.substring(7));
951                return defaultValue;
952        }
953
954        public static String getRequestNameSpace() {
955                String rawURL = ReqRspUtil.getRequestURL(ThreadLocalPageContext.get().getHttpServletRequest(),false);
956                String urlPath ="";
957                try {
958                        urlPath = new java.net.URL(rawURL).getPath();
959                }
960                catch (MalformedURLException e) {}
961                String pathWithoutContext = urlPath.replaceFirst("/[^/]*", "");
962                        
963                
964                return "http://rpc.xml.coldfusion" + pathWithoutContext.toLowerCase();
965        }
966        public static String getRequestDefaultNameSpace() {
967                return "http://rpc.xml.coldfusion";
968        }
969        
970}