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.java;
020
021import java.lang.reflect.Field;
022import java.lang.reflect.InvocationTargetException;
023import java.lang.reflect.Modifier;
024import java.util.ArrayList;
025import java.util.Date;
026import java.util.Iterator;
027import java.util.List;
028
029import lucee.runtime.PageContext;
030import lucee.runtime.dump.DumpData;
031import lucee.runtime.dump.DumpProperties;
032import lucee.runtime.dump.DumpUtil;
033import lucee.runtime.exp.ExpressionException;
034import lucee.runtime.exp.PageException;
035import lucee.runtime.op.Caster;
036import lucee.runtime.op.Operator;
037import lucee.runtime.op.date.DateCaster;
038import lucee.runtime.reflection.Reflector;
039import lucee.runtime.reflection.pairs.MethodInstance;
040import lucee.runtime.type.Collection;
041import lucee.runtime.type.ObjectWrap;
042import lucee.runtime.type.Objects;
043import lucee.runtime.type.Struct;
044import lucee.runtime.type.dt.DateTime;
045import lucee.runtime.type.util.ArrayUtil;
046import lucee.runtime.util.VariableUtil;
047import lucee.runtime.util.VariableUtilImpl;
048
049
050/**
051 * class to handle initialising and call native object from lucee
052 */
053public class JavaObject implements Objects,ObjectWrap {
054        
055        private Class clazz;
056        private boolean isInit=false;
057        private Object object;
058    private VariableUtil variableUtil;
059    
060        /**
061         * constructor with className to load
062         * @param variableUtil
063         * @param clazz
064         * @throws ExpressionException
065         */
066        public JavaObject(VariableUtil variableUtil,Class clazz) {
067            this.variableUtil=variableUtil;
068                this.clazz=clazz;
069        }
070
071
072        public JavaObject(VariableUtil variableUtil,Object object) {
073            this.variableUtil=variableUtil;
074                this.clazz=object.getClass();
075                this.object=object;
076                isInit=true;
077        }
078
079        public Object get(PageContext pc, String propertyName) throws PageException {
080        if(isInit) {
081            return variableUtil.get(pc,object,propertyName);
082        }
083            
084        // Check Field
085            Field[] fields = Reflector.getFieldsIgnoreCase(clazz,propertyName,null);
086            if(!ArrayUtil.isEmpty(fields) && Modifier.isStatic(fields[0].getModifiers())) {
087                        try {
088                    return fields[0].get(null);
089                } 
090                catch (Exception e) {
091                    throw Caster.toPageException(e);
092                }
093                }
094        // Getter
095            MethodInstance mi = Reflector.getGetterEL(clazz,propertyName);
096            if(mi!=null) {
097                if(Modifier.isStatic(mi.getMethod().getModifiers())) {
098                    try {
099                        return mi.invoke(null);
100                    } 
101                    catch (IllegalAccessException e) {
102                        throw Caster.toPageException(e);
103                    } 
104                    catch (InvocationTargetException e) {
105                        throw Caster.toPageException(e.getTargetException());
106                    }    
107                }
108            }
109        // male Instance
110        return variableUtil.get(pc,init(),propertyName);  
111        }
112
113        @Override
114        public Object get(PageContext pc, Collection.Key key) throws PageException {
115                return get(pc, key.getString());
116        }
117
118    public Object get(PageContext pc, String propertyName, Object defaultValue) {
119        if(isInit) {
120            return variableUtil.get(pc,object,propertyName,defaultValue);  
121        }
122        // Field
123        Field[] fields = Reflector.getFieldsIgnoreCase(clazz,propertyName,null);
124        if(!ArrayUtil.isEmpty(fields) && Modifier.isStatic(fields[0].getModifiers())) {
125                        try {
126                return fields[0].get(null);
127            } catch (Exception e) {}
128                }
129        // Getter
130        MethodInstance mi = Reflector.getGetterEL(clazz,propertyName);
131        if(mi!=null) {
132            if(Modifier.isStatic(mi.getMethod().getModifiers())) {
133                try {
134                    return mi.invoke(null);
135                } 
136                catch (Exception e) {}    
137            }
138        }
139        try {
140            return variableUtil.get(pc,init(),propertyName,defaultValue);  
141        } catch (PageException e1) {
142            return defaultValue;
143        }         
144    }
145
146        @Override
147        public Object get(PageContext pc, Collection.Key key, Object defaultValue) {
148                return get(pc, key.getString(), defaultValue);
149        }
150
151        @Override
152        public Object set(PageContext pc, Collection.Key propertyName, Object value) throws PageException  {
153                if(isInit) {
154                    return ((VariableUtilImpl)variableUtil).set(pc,object,propertyName,value);
155                }
156            // Field
157                Field[] fields=Reflector.getFieldsIgnoreCase(clazz,propertyName.getString(),null);
158                if(!ArrayUtil.isEmpty(fields) && Modifier.isStatic(fields[0].getModifiers())) {
159                        try {
160                fields[0].set(null,value);
161                return value;
162            } catch (Exception e) {
163                Caster.toPageException(e);
164            }
165                }
166        // Getter
167        MethodInstance mi = Reflector.getSetter(clazz,propertyName.getString(),value,null);
168        if(mi!=null) {
169            if(Modifier.isStatic(mi.getMethod().getModifiers())) {
170                try {
171                    return mi.invoke(null);
172                } 
173                catch (IllegalAccessException e) {
174                    throw Caster.toPageException(e);
175                } 
176                catch (InvocationTargetException e) {
177                    throw Caster.toPageException(e.getTargetException());
178                }    
179            }
180        }
181        
182
183            return ((VariableUtilImpl)variableUtil).set(pc,init(),propertyName,value);
184        }
185
186    @Override
187    public Object setEL(PageContext pc, Collection.Key propertyName, Object value) {
188                if(isInit) {
189                    return variableUtil.setEL(pc,object,propertyName,value);
190                }
191            // Field
192                Field[] fields=Reflector.getFieldsIgnoreCase(clazz,propertyName.getString(),null);
193                if(!ArrayUtil.isEmpty(fields) && Modifier.isStatic(fields[0].getModifiers())) {
194                        try {
195                fields[0].set(null,value);
196            } catch (Exception e) {}
197                        return value;
198                }
199        // Getter
200        MethodInstance mi = Reflector.getSetter(clazz,propertyName.getString(),value,null);
201        if(mi!=null) {
202            if(Modifier.isStatic(mi.getMethod().getModifiers())) {
203                try {
204                    return mi.invoke(null);
205                } 
206                catch (Exception e) {}    
207            }
208        }
209           
210        try {
211            return variableUtil.setEL(pc,init(),propertyName,value);
212        } catch (PageException e1) {
213            return value;
214        }
215    }
216
217        public Object call(PageContext pc, String methodName, Object[] arguments) throws PageException {
218        if(arguments==null)arguments=new Object[0];
219        
220        // edge cases
221        if(methodName.equalsIgnoreCase("init")) {
222            return init(arguments);
223        }
224        else if(methodName.equalsIgnoreCase("getClass")) {
225            return clazz;
226        }
227        else if(isInit) {
228                    return Reflector.callMethod(object,methodName,arguments);
229                }
230        
231        
232            try {
233                    // get method
234                    MethodInstance mi = Reflector.getMethodInstance(this,clazz,methodName,arguments);
235                        // call static method if exist
236                    if(Modifier.isStatic(mi.getMethod().getModifiers())) {
237                                return mi.invoke(null);
238                        }
239                    
240                    if(arguments.length==0 && methodName.equalsIgnoreCase("getClass")){
241                        return clazz;
242                    }
243                    
244                    // invoke constructor and call instance method
245                        return mi.invoke(init());
246                }
247                catch(InvocationTargetException e) {
248                        Throwable target = e.getTargetException();
249                        if(target instanceof PageException) throw (PageException)target;
250                        throw Caster.toPageException(e.getTargetException());
251                }
252                catch(Exception e) {
253                        throw Caster.toPageException(e);
254                }
255        }
256
257        @Override
258        public Object call(PageContext pc, Collection.Key methodName, Object[] arguments) throws PageException {
259                return call(pc, methodName.getString(), arguments);
260        }
261
262    public Object callWithNamedValues(PageContext pc, String methodName, Struct args) throws PageException {
263        Iterator<Object> it = args.valueIterator();
264        List<Object> values=new ArrayList<Object>();
265        while(it.hasNext()) {
266            values.add(it.next());
267        }   
268        return call(pc,methodName,values.toArray(new Object[values.size()]));
269    }
270
271        public Object callWithNamedValues(PageContext pc, Collection.Key methodName, Struct args) throws PageException {
272                return callWithNamedValues(pc, methodName.getString(), args);
273        }
274
275        /**
276         * initialize method (default no object)
277         * @return initialize object
278         * @throws PageException
279         */
280        private Object init() throws PageException {
281                return init(new Object[0]);
282        }
283        
284        private Object init(Object defaultValue) {
285                return init(new Object[0],defaultValue);
286        }
287        
288        /**
289         * initialize method
290         * @param arguments
291         * @return Initalised Object
292         * @throws PageException
293         */
294        private Object init(Object[] arguments) throws PageException {
295                object=Reflector.callConstructor(clazz,arguments);
296                isInit=true;
297                return object;
298        }
299        private Object init(Object[] arguments, Object defaultValue) {
300                object=Reflector.callConstructor(clazz,arguments,defaultValue);
301                isInit=object!=defaultValue;
302                return object;
303        }
304
305
306        @Override
307        public Object getEmbededObject() throws PageException {
308                if(object==null)init();
309                return object;
310        }
311
312        @Override
313        public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties props) {
314                try {
315                        return DumpUtil.toDumpData(getEmbededObject(), pageContext,maxlevel,props);
316                } catch (PageException e) {
317                        return DumpUtil.toDumpData(clazz, pageContext,maxlevel,props);
318                }
319        }
320        
321        /**
322         * @return the containing Class
323         */
324        public Class getClazz() {return clazz;}
325
326    public boolean isInitalized() {
327        return isInit;
328    }
329
330    @Override
331    public String castToString() throws PageException {
332        return Caster.toString(getEmbededObject());
333    }
334    
335
336
337    @Override
338    public String castToString(String defaultValue) {
339        try {
340                        return Caster.toString(getEmbededObject(),defaultValue);
341                } catch (PageException e) {
342                        return defaultValue;
343                }
344    }
345    
346
347    @Override
348    public boolean castToBooleanValue() throws PageException {
349        return Caster.toBooleanValue(getEmbededObject());
350    }
351    
352    @Override
353    public Boolean castToBoolean(Boolean defaultValue) {
354        try {
355                        return Caster.toBoolean(getEmbededObject(),defaultValue);
356                } catch (PageException e) {
357                        return defaultValue;
358                }
359    }
360
361    @Override
362    public double castToDoubleValue() throws PageException {
363        return Caster.toDoubleValue(getEmbededObject());
364    }
365    
366    @Override
367    public double castToDoubleValue(double defaultValue) {
368        try {
369                        return Caster.toDoubleValue(getEmbededObject(),true,defaultValue);
370                } catch (PageException e) {
371                        return defaultValue;
372                }
373    }
374
375    @Override
376    public DateTime castToDateTime() throws PageException {
377        return Caster.toDatetime(getEmbededObject(),null);
378    }
379    
380    @Override
381    public DateTime castToDateTime(DateTime defaultValue) {
382        try {
383                        return DateCaster.toDateAdvanced(getEmbededObject(),DateCaster.CONVERTING_TYPE_OFFSET,null,defaultValue);
384                } catch (PageException e) {
385                        return defaultValue;
386                }
387    }
388
389    @Override
390    public Object getEmbededObject(Object def) {
391        if(object==null)init(def);
392                return object;
393    }
394
395        /**
396         * @return the object
397         */
398        public Object getObject() {
399                return object;
400        }
401
402        @Override
403        public int compareTo(boolean b) throws PageException {
404                return Operator.compare(castToBooleanValue(), b);
405        }
406
407        @Override
408        public int compareTo(DateTime dt) throws PageException {
409                return Operator.compare((Date)castToDateTime(), (Date)dt);
410        }
411
412        @Override
413        public int compareTo(double d) throws PageException {
414                return Operator.compare(castToDoubleValue(), d);
415        }
416
417        @Override
418        public int compareTo(String str) throws PageException {
419                return Operator.compare(castToString(), str);
420        }
421
422}