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 **/
019 package lucee.runtime.type;
020
021import lucee.commons.lang.CFTypes;
022import lucee.commons.lang.StringUtil;
023import lucee.runtime.ComponentImpl;
024import lucee.runtime.PageContext;
025import lucee.runtime.component.Property;
026import lucee.runtime.exp.ExpressionException;
027import lucee.runtime.exp.PageException;
028import lucee.runtime.listener.ApplicationContextPro;
029import lucee.runtime.op.Caster;
030import lucee.runtime.op.Decision;
031import lucee.runtime.orm.ORMUtil;
032import lucee.runtime.type.Collection.Key;
033import lucee.runtime.type.util.CollectionUtil;
034import lucee.runtime.type.util.KeyConstants;
035import lucee.runtime.type.util.UDFUtil;
036
037public final class UDFSetterProperty extends UDFGSProperty {
038
039        private static final Collection.Key VALIDATE_PARAMS = KeyImpl.intern("validateParams");
040        private final Property prop;
041        private final Key propName;
042        private String validate;
043        private Struct validateParams;
044
045        public UDFSetterProperty(ComponentImpl component,Property prop) throws PageException {
046                super(component,"set"+StringUtil.ucFirst(prop.getName()),new FunctionArgument[]{
047                        new FunctionArgumentImpl(
048                                        KeyImpl.init(prop.getName()),
049                                        prop.getType(),
050                                        CFTypes.toShortStrict(prop.getType(),CFTypes.TYPE_UNKNOW),
051                                        true)
052                },CFTypes.TYPE_ANY,"wddx");
053
054                this.prop=prop; 
055                this.propName=KeyImpl.getInstance(prop.getName());
056                
057                this.validate=Caster.toString(prop.getDynamicAttributes().get(KeyConstants._validate,null),null);
058                if(!StringUtil.isEmpty(validate,true)) {
059                        validate=validate.trim().toLowerCase();
060                        Object o = prop.getDynamicAttributes().get(VALIDATE_PARAMS,null);
061                        if(o!=null){
062                                if(Decision.isStruct(o))validateParams=Caster.toStruct(o);
063                                else {
064                                        String str=Caster.toString(o);
065                                        if(!StringUtil.isEmpty(str,true)) {
066                                                validateParams=ORMUtil.convertToSimpleMap(str);
067                                                if(validateParams==null)
068                                                        throw new ExpressionException("cannot parse string ["+str+"] as struct");
069                                        }
070                                }
071                        }
072                }
073        } 
074
075        @Override
076        public UDF duplicate() {
077                try {
078                        return new UDFSetterProperty(component,prop);
079                } catch (PageException e) {
080                        return null;
081                }
082        }
083        
084        @Override
085        public Object call(PageContext pageContext, Object[] args,boolean doIncludePath) throws PageException {
086                if(args.length<1)
087                        throw new ExpressionException("The parameter "+prop.getName()+" to function "+getFunctionName()+" is required but was not passed in.");
088                validate(validate,validateParams,args[0]);
089                component.getComponentScope().set(propName, cast(pageContext,this.arguments[0],args[0],1));
090
091
092                // make sure it is recognized that set is called by hibernate (if ORM is enabled)
093                ApplicationContextPro appContext = (ApplicationContextPro) pageContext.getApplicationContext();
094                if(appContext.isORMEnabled() && component.isPersistent())ORMUtil.getSession(pageContext);
095                
096                return component;
097        }
098
099        @Override
100        public Object callWithNamedValues(PageContext pageContext, Struct values,boolean doIncludePath) throws PageException {
101                UDFUtil.argumentCollection(values,getFunctionArguments());
102                Object value = values.get(propName,null);
103                
104                if(value==null){
105                        Key[] keys = CollectionUtil.keys(values);
106                        if(keys.length==1) {
107                                value=values.get(keys[0]);
108                        }
109                        else throw new ExpressionException("The parameter "+prop.getName()+" to function "+getFunctionName()+" is required but was not passed in.");
110                }
111                component.getComponentScope().set(propName, cast(pageContext,arguments[0],value,1));
112
113                // make sure it is recognized that set is called by hibernate (if ORM is enabled)
114                ApplicationContextPro appContext = (ApplicationContextPro) pageContext.getApplicationContext();
115                if(appContext.isORMEnabled() && component.isPersistent())ORMUtil.getSession(pageContext);
116                
117                return component;
118        }
119
120        @Override
121        public Object getDefaultValue(PageContext pc, int index) throws PageException {
122                return prop.getDefault();
123        }
124        
125        @Override
126        public Object getDefaultValue(PageContext pc, int index, Object defaultValue) throws PageException {
127                return prop.getDefault();
128        }
129
130        @Override
131        public String getReturnTypeAsString() {
132                return "any";
133        }
134
135        @Override
136        public Object implementation(PageContext pageContext) throws Throwable {
137                return null;
138        }
139
140}