001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/io/datastore/sql/VirtualContentProvider.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2006 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.sql;
044    
045    import java.sql.Connection;
046    import java.util.List;
047    
048    import org.deegree.datatypes.Types;
049    import org.deegree.i18n.Messages;
050    import org.deegree.io.datastore.schema.content.ConstantContent;
051    import org.deegree.io.datastore.schema.content.FieldContent;
052    import org.deegree.io.datastore.schema.content.FunctionParam;
053    import org.deegree.io.datastore.schema.content.SQLFunctionCall;
054    import org.deegree.io.datastore.schema.content.SpecialContent;
055    import org.deegree.io.datastore.schema.content.SpecialContent.VARIABLE;
056    import org.deegree.model.filterencoding.ComplexFilter;
057    import org.deegree.model.filterencoding.Filter;
058    import org.deegree.model.filterencoding.FilterTools;
059    import org.deegree.model.spatialschema.Envelope;
060    import org.deegree.model.spatialschema.Geometry;
061    import org.deegree.model.spatialschema.GeometryFactory;
062    
063    /**
064     * Responsible for determining the value of properties that are mapped to {@link SQLFunctionCall}s.
065     * <p>
066     * This involves the lookup of the values of variables ({@link SpecialContent} instances).
067     * 
068     * <table border="1">
069     * <tr>
070     * <th>Variable name</th>
071     * <th>Description</th>
072     * </tr>
073     * <tr>
074     * <td>$QUERY.BBOX</td>
075     * <td>Bounding box of the query (null if it is not present).</td>
076     * </tr>
077     * </table>
078     * </p>
079     * 
080     * @see SQLFunctionCall
081     * @see SpecialContent
082     * 
083     * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider</a>
084     * @author last edited by: $Author: mschneider $
085     * 
086     * @version $Revision: 7781 $, $Date: 2007-07-17 17:56:59 +0200 (Di, 17 Jul 2007) $
087     */
088    public class VirtualContentProvider {
089    
090        // used in case that no BBOX is available
091        private static final Envelope DEFAULT_BBOX = GeometryFactory.createEnvelope( 0.0, 0.0, 0.0, 0.0, null );
092    
093        private Filter filter;
094    
095        private AbstractSQLDatastore ds;
096    
097        private Connection conn;
098    
099        /**
100         * Creates a new instance of {@link VirtualContentProvider}.
101         * 
102         * @param filter
103         * @param ds
104         * @param conn
105         */
106        VirtualContentProvider( Filter filter, AbstractSQLDatastore ds, Connection conn ) {
107            this.filter = filter;
108            this.ds = ds;
109            this.conn = conn;
110        }
111    
112        /**
113         * Appends a {@link SQLFunctionCall} to the given {@link StatementBuffer}.
114         * <p>
115         * This includes the correct qualification of all columns that are used as {@link FunctionParam}s.
116         * 
117         * @param query
118         * @param tableAlias
119         * @param call
120         */
121        public void appendSQLFunctionCall( StatementBuffer query, String tableAlias, SQLFunctionCall call ) {
122    
123            String callString = call.getCall();
124            int[] usedVars = call.getUsedVars();
125            List<FunctionParam> params = call.getParams();
126            for ( int j = 0; j < usedVars.length; j++ ) {
127                int varNo = usedVars[j];
128                String varString = "\\$" + varNo;
129                FunctionParam param = params.get( varNo - 1 );
130                if ( param instanceof FieldContent ) {
131                    String replace = tableAlias + "." + ( (FieldContent) param ).getField().getField();
132                    callString = callString.replaceAll( varString, replace );
133                } else if ( param instanceof ConstantContent ) {
134                    String replace = ( (ConstantContent) param ).getValue();
135                    callString = callString.replaceAll( varString, replace );
136                } else if ( param instanceof SpecialContent ) {
137                    appendSpecialContentValue( query, (SpecialContent) param );
138                    callString = callString.replaceFirst( varString, "?" );
139                } else {
140                    assert false;
141                }
142            }
143            query.append( callString );
144        }
145    
146        /**
147         * Appends the variable from a {@link SpecialContent} property to the given
148         * {@link StatementBuffer}.
149         * 
150         * @param query
151         * @param param
152         */
153        public void appendSpecialContentValue( StatementBuffer query, SpecialContent param ) {
154    
155            VARIABLE var = param.getVariable();
156    
157            switch ( var ) {
158            case QUERY_BBOX: {
159    
160                Object bboxDBGeometry = null;
161    
162                try {
163                    Envelope requestBBOX = DEFAULT_BBOX;
164    
165                    if ( this.filter instanceof ComplexFilter ) {
166                        Object[] objects = FilterTools.extractFirstBBOX( (ComplexFilter) filter );
167                        if ( objects[0] != null ) {
168                            requestBBOX = (Envelope) objects[0];
169                        }
170                    }
171                    Geometry geometry = GeometryFactory.createSurface( requestBBOX, null );
172                    bboxDBGeometry = this.ds.convertDeegreeToDBGeometry( geometry, param.getSRS(), this.conn );
173                } catch ( Exception e ) {
174                    String msg = Messages.getMessage( "DATASTORE_EXTRACTBBOX" );
175                    throw new RuntimeException( msg, e );
176                }
177    
178                // TODO: remove quick hack to make this work on Oracle
179                if (this.ds.getClass().getName().equals( "org.deegree.io.datastore.sql.oracle.OracleDatastore" )) {
180                    query.addArgument( bboxDBGeometry, Types.STRUCT );                
181                } else {
182                    query.addArgument( bboxDBGeometry, Types.OTHER );
183                }
184                
185    
186                break;
187            }
188            default: {
189                assert false;
190            }
191            }
192        }
193    }