001    package railo.runtime.tag;
002    
003    import java.io.IOException;
004    
005    import javax.servlet.jsp.tagext.Tag;
006    
007    import railo.commons.lang.StringUtil;
008    import railo.runtime.db.SQLCaster;
009    import railo.runtime.db.SQLItemImpl;
010    import railo.runtime.exp.ApplicationException;
011    import railo.runtime.exp.DatabaseException;
012    import railo.runtime.exp.PageException;
013    import railo.runtime.ext.tag.TagImpl;
014    import railo.runtime.op.Caster;
015    import railo.runtime.type.Array;
016    import railo.runtime.type.ArrayImpl;
017    import railo.runtime.type.util.ListUtil;
018    
019    /**
020    * Checks the data type of a query parameter. The cfqueryparam tag is nested within a cfquery tag. 
021    *   It is embedded within the query SQL statement. If you specify its optional parameters, cfqueryparam 
022    *   also performs data validation.
023    *
024    *
025    *
026    **/
027    public final class QueryParam extends TagImpl {
028            
029        private SQLItemImpl item=new SQLItemImpl();
030        
031            /** Specifies the character that separates values in the list of parameter values in the value 
032            **      attribute. The default is a comma. If you specify a list of values for the value attribute, you must 
033            **      also specify the list attribute. */
034            private String separator=",";
035            
036            /** Yes or No. Indicates that the parameter value of the value attribute is a list of values, 
037            **      separated by a separator character. The default is No */
038            private boolean list;
039    
040    
041            /** Maximum length of the parameter. The default value is the length of the string specified in 
042            **      the value attribute. */
043            private double maxlength=-1;
044        
045            @Override
046            public void release()   {
047                separator=",";
048                list=false;
049                maxlength=-1;
050                item=new SQLItemImpl();
051            }
052            
053    
054            /** set the value list
055            *  Yes or No. Indicates that the parameter value of the value attribute is a list of values, 
056            *       separated by a separator character. The default is No
057            * @param list value to set
058            **/
059            public void setList(boolean list)       {
060                    this.list=list;
061            }
062    
063            /** set the value null
064            *  Yes or No. Indicates whether the parameter is passed as a null. If Yes, the tag ignores the 
065            *       value attribute. The default is No.
066            * @param nulls value to set
067            **/
068            public void setNull(boolean nulls)      {
069                item.setNulls(nulls);
070            }
071    
072            /** set the value value
073            * @param value value to set
074            **/
075            public void setValue(Object value)      {
076                item.setValue(value);
077            }
078    
079            /** set the value maxlength
080            *  Maximum length of the parameter. The default value is the length of the string specified in 
081            *       the value attribute.
082            * @param maxlength value to set
083            **/
084            public void setMaxlength(double maxlength)      {
085                this.maxlength=maxlength;
086            }
087    
088            /** set the value separator
089            *  Specifies the character that separates values in the list of parameter values in the value 
090            *       attribute. The default is a comma. If you specify a list of values for the value attribute, you must 
091            *       also specify the list attribute.
092            * @param separator value to set
093            **/
094            public void setSeparator(String separator)      {
095                this.separator=separator;
096            }
097    
098            /** set the value scale
099            *  Number of decimal places of the parameter. The default value is zero.
100            * @param scale value to set
101            **/
102            public void setScale(double scale)      {
103                item.setScale((int)scale);
104            }
105    
106            /** set the value cfsqltype
107            *  The SQL type that the parameter (any type) will be bound to.
108            * @param type value to set
109             * @throws DatabaseException
110            **/
111            public void setCfsqltype(String type) throws DatabaseException  {
112                    item.setType(SQLCaster.toIntType(type));
113                    
114            }
115    
116            @Override
117            public int doStartTag() throws PageException    {
118                Tag parent = getParent();
119                    while(parent!=null && !(parent instanceof Query)) {
120                            parent=parent.getParent();
121                    }
122                    if(parent instanceof Query) {
123                        Query query = (Query)parent;
124                        if(!item.isNulls() && !item.isValueSet())
125                            throw new ApplicationException("attribute value from tag queryparam is required if attribute null is false");
126                        if(list) {
127                            String v = Caster.toString(item.getValue());
128                            Array arr=null;
129                            if(StringUtil.isEmpty(v)){
130                                    arr=new ArrayImpl();
131                                    arr.append("");
132                            }
133                            else arr=ListUtil.listToArrayRemoveEmpty(v,separator);
134                                    
135                                    int len=arr.size();
136                                    StringBuffer sb=new StringBuffer();
137                                    for(int i=1;i<=len;i++) {
138                                        query.setParam(item.clone(check(arr.getE(i))));
139                                    if(i>1)sb.append(',');
140                                    sb.append('?');
141                                    }
142                                    write(sb.toString());
143                        }
144                        else {
145                            check(item.getValue());
146                            query.setParam(item);
147                            write("?");
148                        } 
149                    }
150                    else {
151                            throw new ApplicationException("Wrong Context, tag QueryParam must be inside a Query tag");     
152                    }
153                return SKIP_BODY;
154            }
155            
156            private Object check(Object value) throws PageException {
157            if(maxlength!=-1) {
158                String str = Caster.toString(value);
159                if(str.length()>maxlength)
160                    throw new DatabaseException("value ["+value+"] is to large, defined maxlength is ["+Caster.toString(maxlength)+"] but length of value is ["+str.length()+"]",null,null,null);
161            }
162                return value;
163            }
164            
165            private void write(String str) {
166                try {
167                pageContext.write(str);
168            } 
169                catch (IOException e) {}
170            }
171    
172    }