001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/io/datastore/schema/content/SQLFunctionCall.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstraße 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041     
042     ---------------------------------------------------------------------------*/
043    package org.deegree.io.datastore.schema.content;
044    
045    import java.util.HashSet;
046    import java.util.List;
047    import java.util.Set;
048    
049    import org.deegree.io.datastore.schema.MappedSimplePropertyType;
050    
051    /**
052     * Content class for {@link MappedSimplePropertyType}s that describes a call to a function provided
053     * by an SQL database.
054     * 
055     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider</a>
056     * @author last edited by: $Author: apoth $
057     * 
058     * @version $Revision: 9342 $, $Date: 2007-12-27 13:32:57 +0100 (Do, 27 Dez 2007) $
059     */
060    public class SQLFunctionCall extends FunctionCall {
061    
062        private String callString;
063    
064        private int typeCode;
065    
066        private int[] usedVarNumbers;
067    
068        /**
069         * Initializes a newly created <code>SQLFunctionCall</code> with the given call string and
070         * {@link FunctionParam}s.
071         * 
072         * @param callString
073         *            call string with placeholders ($1,$2,...,$n)
074         * @param typeCode
075         *            SQL type code of the return value
076         * @param params
077         *            parameters to be used for the placeholders
078         */
079        public SQLFunctionCall( String callString, int typeCode, List<FunctionParam> params ) {
080            super( params );
081            this.callString = callString;
082            this.typeCode = typeCode;
083            this.usedVarNumbers = extractUsedVars( callString );
084        }
085    
086        /**
087         * Initializes a newly created <code>SQLFunctionCall</code> with the given call string and
088         * {@link FunctionParam}s.
089         * 
090         * @param callString
091         *            call string with placeholders ($1,$2,...,$n)
092         * @param typeCode
093         *            SQL type code of the return value
094         * @param params
095         *            parameters to be used for the placeholders
096         */
097        public SQLFunctionCall( String callString, int typeCode, FunctionParam... params ) {
098            super( params );
099            this.callString = callString;
100            this.typeCode = typeCode;
101            this.usedVarNumbers = extractUsedVars( callString );
102        }
103    
104        /**
105         * Extracts all variable numbers ('$i') used in the given call string.
106         * 
107         * @param callString
108         * @return all variable numbers used in the given call string
109         */
110        private int[] extractUsedVars( String callString ) {
111    
112            Set<Integer> usedVars = new HashSet<Integer>();
113    
114            int foundAt = callString.indexOf( '$' );
115            while ( foundAt != -1 ) {
116                foundAt++;
117                String varNumberString = "";
118                while ( foundAt < callString.length() ) {
119                    char numberChar = callString.charAt( foundAt++ );
120                    if ( numberChar >= '0' && numberChar <= '9' ) {
121                        varNumberString += numberChar;
122                    } else {
123                        break;
124                    }
125                }
126    
127                assert varNumberString.length() != 0;
128    
129                try {
130                    int varNo = Integer.parseInt( varNumberString );
131                    assert varNo != 0;
132                    usedVars.add( varNo );
133                } catch ( NumberFormatException e ) {
134                    assert false;
135                }
136    
137                // find next '$' symbol
138                foundAt = callString.indexOf( '$', foundAt );
139            }
140    
141            int[] usedVarInts = new int[usedVars.size()];
142            int i = 0;
143            for ( Integer pos : usedVars ) {
144                usedVarInts[i++] = pos;
145            }
146    
147            return usedVarInts;
148        }
149    
150        /**
151         * Returns true, because the result of an SQL function call is (in general) suitable as a sort
152         * criterion.
153         * 
154         * @return true, because the result of an SQL function call is (in general) suitable as a sort
155         *         criterion
156         */
157        public boolean isSortable() {
158            return true;
159        }
160    
161        /**
162         * Returns the call string with placeholders ($1,$2,...,$n) for the {@link FunctionParam}s.
163         * 
164         * @return the call string with placeholders ($1,$2,...,$n)
165         */
166        public String getCall() {
167            return this.callString;
168        }
169    
170        /**
171         * Returns the SQL type code of the function call's return value.
172         * 
173         * @return the SQL type code of the function call's return value.
174         */
175        public int getTypeCode() {
176            return this.typeCode;
177        }
178    
179        /**
180         * Returns all variable numbers used in the call string.
181         * 
182         * @return all variable numbers used in the call string
183         */
184        public int[] getUsedVars() {
185            return this.usedVarNumbers;
186        }
187    
188        @Override
189        public String toString() {
190            String s = this.callString;
191            int[] usedVars = this.getUsedVars();
192            List<FunctionParam> params = this.getParams();
193            for ( int j = 0; j < usedVars.length; j++ ) {
194                int varNo = usedVars[j];
195                String varString = "\\$" + varNo;
196                FunctionParam param = params.get( varNo - 1 );
197                if ( param instanceof FieldContent ) {
198                    String replace = ( (FieldContent) param ).getField().getTable() + "."
199                                     + ( (FieldContent) param ).getField().getField();
200                    s = s.replaceAll( varString, replace );
201                } else if ( param instanceof ConstantContent ) {
202                    String replace = ( (ConstantContent) param ).getValue();
203                    s = s.replaceAll( varString, replace );
204                } else if ( param instanceof SpecialContent ) {
205    //                appendSpecialContentValue( query, (SpecialContent) param );
206    //                s = s.replaceFirst( varString, "?" );
207                } else {
208                    assert false;
209                }
210            }
211            return s;
212        }
213    }