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.List;
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            /**
046            * @see javax.servlet.jsp.tagext.Tag#release()
047            */
048            public void release()   {
049                separator=",";
050                list=false;
051                maxlength=-1;
052                item=new SQLItemImpl();
053            }
054            
055    
056            /** set the value list
057            *  Yes or No. Indicates that the parameter value of the value attribute is a list of values, 
058            *       separated by a separator character. The default is No
059            * @param list value to set
060            **/
061            public void setList(boolean list)       {
062                    this.list=list;
063            }
064    
065            /** set the value null
066            *  Yes or No. Indicates whether the parameter is passed as a null. If Yes, the tag ignores the 
067            *       value attribute. The default is No.
068            * @param nulls value to set
069            **/
070            public void setNull(boolean nulls)      {
071                item.setNulls(nulls);
072            }
073    
074            /** set the value value
075            * @param value value to set
076            **/
077            public void setValue(Object value)      {
078                item.setValue(value);
079            }
080    
081            /** set the value maxlength
082            *  Maximum length of the parameter. The default value is the length of the string specified in 
083            *       the value attribute.
084            * @param maxlength value to set
085            **/
086            public void setMaxlength(double maxlength)      {
087                this.maxlength=maxlength;
088            }
089    
090            /** set the value separator
091            *  Specifies the character that separates values in the list of parameter values in the value 
092            *       attribute. The default is a comma. If you specify a list of values for the value attribute, you must 
093            *       also specify the list attribute.
094            * @param separator value to set
095            **/
096            public void setSeparator(String separator)      {
097                this.separator=separator;
098            }
099    
100            /** set the value scale
101            *  Number of decimal places of the parameter. The default value is zero.
102            * @param scale value to set
103            **/
104            public void setScale(double scale)      {
105                item.setScale((int)scale);
106            }
107    
108            /** set the value cfsqltype
109            *  The SQL type that the parameter (any type) will be bound to.
110            * @param type value to set
111             * @throws DatabaseException
112            **/
113            public void setCfsqltype(String type) throws DatabaseException  {
114                    item.setType(SQLCaster.toIntType(type));
115                    
116            }
117    
118            /**
119            * @see javax.servlet.jsp.tagext.Tag#doStartTag()
120            */
121            public int doStartTag() throws PageException    {
122                Tag parent = getParent();
123                    while(parent!=null && !(parent instanceof Query)) {
124                            parent=parent.getParent();
125                    }
126                    if(parent instanceof Query) {
127                        Query query = (Query)parent;
128                        if(!item.isNulls() && !item.isValueSet())
129                            throw new ApplicationException("attribute value from tag queryparam is required if attribute null is false");
130                        if(list) {
131                            String v = Caster.toString(item.getValue());
132                            Array arr=null;
133                            if(StringUtil.isEmpty(v)){
134                                    arr=new ArrayImpl();
135                                    arr.append("");
136                            }
137                            else arr=List.listToArrayRemoveEmpty(v,separator);
138                                    
139                                    int len=arr.size();
140                                    StringBuffer sb=new StringBuffer();
141                                    for(int i=1;i<=len;i++) {
142                                        query.setParam(item.clone(check(arr.getE(i))));
143                                    if(i>1)sb.append(',');
144                                    sb.append('?');
145                                    }
146                                    write(sb.toString());
147                        }
148                        else {
149                            check(item.getValue());
150                            query.setParam(item);
151                            write("?");
152                        } 
153                    }
154                    else {
155                            throw new ApplicationException("Wrong Context, tag QueryParam must be inside a Query tag");     
156                    }
157                return SKIP_BODY;
158            }
159            
160            private Object check(Object value) throws PageException {
161            if(maxlength!=-1) {
162                String str = Caster.toString(value);
163                if(str.length()>maxlength)
164                    throw new DatabaseException("value ["+value+"] is to large, defined maxlength is ["+Caster.toString(maxlength)+"] but length of value is ["+str.length()+"]",null,null,null);
165            }
166                return value;
167            }
168            
169            private void write(String str) {
170                try {
171                pageContext.write(str);
172            } 
173                catch (IOException e) {}
174            }
175    
176    }