001    package railo.runtime.type;
002    
003    import java.util.HashMap;
004    import java.util.Map;
005    
006    import railo.commons.lang.CFTypes;
007    import railo.commons.lang.StringUtil;
008    import railo.runtime.ComponentImpl;
009    import railo.runtime.PageContext;
010    import railo.runtime.component.Property;
011    import railo.runtime.exp.ExpressionException;
012    import railo.runtime.exp.PageException;
013    import railo.runtime.type.Collection.Key;
014    import railo.runtime.type.util.CollectionUtil;
015    import railo.runtime.type.util.KeyConstants;
016    import railo.runtime.type.util.PropertyFactory;
017    
018    public final class UDFAddProperty extends UDFGSProperty {
019    
020            private final Property prop;
021            //private ComponentScope scope;
022            
023            private final Key propName;
024            
025            private static final Object NULL=new Object();
026    
027            public UDFAddProperty(ComponentImpl component,Property prop)  {
028                    super(component,"add"+StringUtil.ucFirst(PropertyFactory.getSingularName(prop)),getFunctionArgument(prop),CFTypes.TYPE_ANY,"wddx");
029                    this.prop=prop;
030                    this.propName=KeyImpl.getInstance(prop.getName());
031            } 
032    
033            private static FunctionArgument[] getFunctionArgument(Property prop) {
034                    String t = PropertyFactory.getType(prop);
035                    FunctionArgument value = new FunctionArgumentImpl(KeyImpl.init(PropertyFactory.getSingularName(prop)),"any",CFTypes.TYPE_ANY,true);
036                    if("struct".equalsIgnoreCase(t)){
037                            FunctionArgument key = new FunctionArgumentImpl(KeyConstants._key,"string",CFTypes.TYPE_STRING,true);
038                            return new FunctionArgument[]{key,value};
039                    }
040                    return new FunctionArgument[]{value};
041            }
042    
043            @Override
044            public UDF duplicate(ComponentImpl c) {
045                    return new UDFAddProperty(c,prop);
046            }
047            
048     
049            public UDF duplicate() {
050                    return duplicate(component);
051            }
052            
053            @Override
054            public Object call(PageContext pageContext, Object[] args,boolean doIncludePath) throws PageException {
055                    // struct
056                    if(this.arguments.length==2) {
057                            if(args.length<2)
058                                    throw new ExpressionException("The function "+getFunctionName()+" need 2 arguments, only "+args.length+" argment"+(args.length==1?" is":"s are")+" passed in.");
059                            return _call(pageContext, args[0], args[1]);
060                    }
061                    // array
062                    else if(this.arguments.length==1) {
063                            if(args.length<1)
064                                    throw new ExpressionException("The parameter "+this.arguments[0].getName()+" to function "+getFunctionName()+" is required but was not passed in.");
065                            return _call(pageContext, null, args[0]);
066                    }
067                    
068                    // never reached
069                    return component;
070                    
071            }
072    
073            @Override
074            public Object callWithNamedValues(PageContext pageContext, Struct values,boolean doIncludePath) throws PageException {
075                    UDFImpl.argumentCollection(values,getFunctionArguments());
076                    
077                    
078                    // struct
079                    if(this.arguments.length==2) {
080                            Key keyName = arguments[0].getName();
081                            Key valueName = arguments[1].getName();
082                            Object key = values.get(keyName,null);
083                            Object value = values.get(valueName,null);
084                            if(key==null)
085                                    throw new ExpressionException("The parameter "+keyName+" to function "+getFunctionName()+" is required but was not passed in.");
086                            if(value==null)
087                                    throw new ExpressionException("The parameter "+valueName+" to function "+getFunctionName()+" is required but was not passed in.");
088                            
089                            return _call(pageContext, key, value);
090                    }
091                    // array
092                    else if(this.arguments.length==1) {
093                            Key valueName = arguments[0].getName();
094                            Object value = values.get(valueName,null);
095                            if(value==null){
096                                    Key[] keys = CollectionUtil.keys(values);
097                                    if(keys.length==1) {
098                                            value=values.get(keys[0]);
099                                    }
100                                    else throw new ExpressionException("The parameter "+valueName+" to function "+getFunctionName()+" is required but was not passed in.");
101                            }
102                            return _call(pageContext, null, value);
103                    }
104    
105                    // never reached
106                    return component;
107            }
108            
109            
110            private Object _call(PageContext pageContext, Object key, Object value) throws PageException {
111                    
112                    
113                    Object propValue = component.getComponentScope().get(propName,null);
114                    
115                    // struct
116                    if(this.arguments.length==2) {
117                            key=cast(arguments[0],key,1);
118                            value=cast(arguments[1],value,2);
119                            if(propValue==null){
120                                    HashMap map=new HashMap();
121                                    component.getComponentScope().setEL(propName,map);
122                                    propValue=map;
123                            }       
124                            if(propValue instanceof Struct) {
125                                    ((Struct)propValue).set(KeyImpl.toKey(key), value);
126                            }
127                            else if(propValue instanceof Map) {
128                                    ((Map)propValue).put(key, value);
129                            }
130                    }
131                    else {
132                            value=cast(arguments[0],value,1);
133                            if(propValue==null){
134                                    /* jira2049
135                                    PageContext pc = ThreadLocalPageContext.get();
136                                    ORMSession sess = ORMUtil.getSession(pc);
137                                    SessionImpl s=(SessionImpl) sess.getRawSession();
138                                    propValue=new PersistentList(s);
139                                    component.getComponentScope().setEL(propName,propValue);*/
140                                    Array arr=new ArrayImpl();
141                                    component.getComponentScope().setEL(propName,arr);
142                                    propValue=arr;
143                            }       
144                            if(propValue instanceof Array) {
145                                    ((Array)propValue).appendEL(value);
146                            }
147                            else if(propValue instanceof java.util.List) {
148                                    ((java.util.List)propValue).add(value);
149                            }
150                    }
151                    return component;
152            }
153    
154            @Override
155            public Object implementation(PageContext pageContext) throws Throwable {
156                    return null;
157            }
158            
159            @Override
160            public Object getDefaultValue(PageContext pc, int index) throws PageException {
161                    return prop.getDefault();
162            }
163            
164            @Override
165            public Object getDefaultValue(PageContext pc, int index, Object defaultValue) throws PageException {
166                    return prop.getDefault();
167            }
168    
169            @Override
170            public String getReturnTypeAsString() {
171                    return "any";
172            }
173    }