001 //$HeadURL: svn+ssh://mschneider@svn.wald.intevation.org/deegree/base/trunk/resources/eclipse/svn_classfile_header_template.xml $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 This file is part of deegree. 004 Copyright (C) 2001-2008 by: 005 Department of Geography, University of Bonn 006 http://www.giub.uni-bonn.de/deegree/ 007 lat/lon GmbH 008 http://www.lat-lon.de 009 010 This library is free software; you can redistribute it and/or 011 modify it under the terms of the GNU Lesser General Public 012 License as published by the Free Software Foundation; either 013 version 2.1 of the License, or (at your option) any later version. 014 This library is distributed in the hope that it will be useful, 015 but WITHOUT ANY WARRANTY; without even the implied warranty of 016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 017 Lesser General Public License for more details. 018 You should have received a copy of the GNU Lesser General Public 019 License along with this library; if not, write to the Free Software 020 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 021 Contact: 022 023 Andreas Poth 024 lat/lon GmbH 025 Aennchenstr. 19 026 53177 Bonn 027 Germany 028 E-Mail: poth@lat-lon.de 029 030 Prof. Dr. Klaus Greve 031 Department of Geography 032 University of Bonn 033 Meckenheimer Allee 166 034 53115 Bonn 035 Germany 036 E-Mail: greve@giub.uni-bonn.de 037 ---------------------------------------------------------------------------*/ 038 039 package org.deegree.io.datastore.sql; 040 041 import java.util.ArrayList; 042 import java.util.Collection; 043 import java.util.HashMap; 044 import java.util.List; 045 import java.util.Map; 046 047 import org.deegree.framework.log.ILogger; 048 import org.deegree.framework.log.LoggerFactory; 049 import org.deegree.io.datastore.DatastoreException; 050 import org.deegree.io.datastore.PropertyPathResolver; 051 import org.deegree.io.datastore.PropertyPathResolvingException; 052 import org.deegree.io.datastore.schema.MappedFeatureType; 053 import org.deegree.io.datastore.schema.MappedPropertyType; 054 import org.deegree.io.datastore.schema.content.SimpleContent; 055 import org.deegree.ogcbase.PropertyPath; 056 import org.deegree.ogcwebservices.wfs.operation.Query; 057 058 /** 059 * Responsible for managing the mapping of properties to table columns SQL and their position in the SQL result set. 060 * 061 * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider </a> 062 * @author last edited by: $Author:$ 063 * 064 * @version $Revision:$, $Date:$ 065 */ 066 class SelectManager { 067 068 private static final ILogger LOG = LoggerFactory.getLogger( SelectManager.class ); 069 070 private MappedFeatureType[] fts; 071 072 private Map<MappedPropertyType, Collection<PropertyPath>>[] allFetchProps; 073 074 private List<List<SimpleContent>>[] allFetchContents; 075 076 private Map<SimpleContent, Integer>[] allResultPosMaps; 077 078 private int fetchContentsCount; 079 080 // requested properties, must contain exactly one list for each targeted feature type 081 private List<PropertyPath>[] selectedProps; 082 083 private String[] ftAliases; 084 085 // TODO remove this 086 private FeatureFetcher fetcher; 087 088 @SuppressWarnings("unchecked") 089 SelectManager( Query query, MappedFeatureType[] rootFts, FeatureFetcher fetcher ) throws DatastoreException { 090 091 this.fts = rootFts; 092 this.ftAliases = query.getAliases(); 093 this.selectedProps = PropertyPathResolver.normalizePropertyPaths( this.fts, this.ftAliases, 094 query.getPropertyNames() ); 095 096 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 097 LOG.logDebug( "Selected properties (normalized): " ); 098 for ( int i = 0; i < fts.length; i++ ) { 099 List<PropertyPath> props = this.selectedProps[i]; 100 LOG.logDebug( "Selected properties (normalized) for feature type '" + fts[i].getName() + "'." ); 101 for ( PropertyPath path : props ) { 102 LOG.logDebug( " - " + path ); 103 } 104 } 105 } 106 107 this.allFetchProps = new Map[this.fts.length]; 108 this.allFetchContents = new List[this.fts.length]; 109 this.allResultPosMaps = new Map[this.fts.length]; 110 this.fetcher = fetcher; 111 112 determineInitialFetchProperties(); 113 determineFetchContents(); 114 buildResultPosMaps(); 115 } 116 117 private void determineInitialFetchProperties() 118 throws PropertyPathResolvingException { 119 120 LOG.logDebug( "Determining fetch properties for all requested feature types." ); 121 122 for ( int i = 0; i < this.fts.length; i++ ) { 123 MappedFeatureType rootFt = this.fts[i]; 124 LOG.logDebug( "Feature type: " + rootFt.getName() + " (alias: " 125 + ( this.ftAliases != null ? this.ftAliases[i] : "-" ) + ")" ); 126 PropertyPath[] requestedProps = this.selectedProps[i].toArray( new PropertyPath[this.selectedProps[i].size()] ); 127 for ( PropertyPath path : requestedProps ) { 128 LOG.logDebug( "Requested property: " + path ); 129 } 130 Map<MappedPropertyType, Collection<PropertyPath>> ftRequestedProps = PropertyPathResolver.determineFetchProperties( 131 rootFt, 132 this.ftAliases != null ? this.ftAliases[i] 133 : null, 134 requestedProps ); 135 LOG.logDebug( "All properties needed for feature type: " + rootFt.getName() ); 136 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 137 for ( MappedPropertyType pt : ftRequestedProps.keySet() ) { 138 LOG.logDebug( "-" + pt.getName() ); 139 } 140 } 141 this.allFetchProps[i] = ftRequestedProps; 142 } 143 } 144 145 private void determineFetchContents() 146 throws DatastoreException { 147 LOG.logDebug( "Determining initial fetch contents for all requested feature types..." ); 148 149 for ( int i = 0; i < this.fts.length; i++ ) { 150 MappedFeatureType rootFt = this.fts[i]; 151 MappedPropertyType[] requestedProps = new MappedPropertyType[this.allFetchProps[i].size()]; 152 requestedProps = this.allFetchProps[i].keySet().toArray( requestedProps ); 153 List<List<SimpleContent>> ftFetchContents = null; 154 if (requestedProps.length > 0) { 155 ftFetchContents = fetcher.determineFetchContents( rootFt, requestedProps ); 156 } else { 157 ftFetchContents = new ArrayList<List<SimpleContent>> (); 158 } 159 this.allFetchContents[i] = ftFetchContents; 160 161 LOG.logDebug( "Will fetch the following columns initially (for feature type " + rootFt.getName() + "):" ); 162 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) { 163 for ( List<SimpleContent> list : ftFetchContents ) { 164 SimpleContent representer = list.get( 0 ); 165 LOG.logDebug( "-" + representer ); 166 } 167 } 168 this.fetchContentsCount += ftFetchContents.size(); 169 } 170 } 171 172 private void buildResultPosMaps() { 173 174 int currentRSPos = 0; 175 for ( int i = 0; i < this.allFetchContents.length; i++ ) { 176 List<List<SimpleContent>> ftFetchContents = this.allFetchContents[i]; 177 Map<SimpleContent, Integer> ftResultPosMap = new HashMap<SimpleContent, Integer>(); 178 for ( int j = 0; j < ftFetchContents.size(); j++ ) { 179 for ( SimpleContent content : ftFetchContents.get( j ) ) { 180 ftResultPosMap.put( content, j + currentRSPos ); 181 } 182 } 183 this.allResultPosMaps[i] = ftResultPosMap; 184 currentRSPos += ftFetchContents.size(); 185 } 186 } 187 188 List<List<SimpleContent>>[] getAllFetchContents() { 189 return this.allFetchContents; 190 } 191 192 Map<SimpleContent, Integer>[] getResultPosMaps() { 193 return this.allResultPosMaps; 194 } 195 196 Map<MappedPropertyType, Collection<PropertyPath>>[] getAllFetchProps() { 197 return this.allFetchProps; 198 } 199 200 int getFetchContentCount() { 201 return this.fetchContentsCount; 202 } 203 204 private int getActualFeatureTupleLength () { 205 int i = 0; 206 for (List<List<SimpleContent>> ftFetchContents: this.allFetchContents) { 207 if (ftFetchContents.size() > 0) { 208 i++; 209 } 210 } 211 return i; 212 } 213 214 int [] getIncludedFtIdx () { 215 int [] includedFtIdx = new int [getActualFeatureTupleLength()]; 216 int i = 0; 217 int idx = 0; 218 for (List<List<SimpleContent>> ftFetchContents: this.allFetchContents) { 219 if (ftFetchContents.size() > 0) { 220 includedFtIdx [idx] = i; 221 idx++; 222 } 223 i++; 224 } 225 return includedFtIdx; 226 } 227 228 @Override 229 public String toString() { 230 StringBuffer sb = new StringBuffer(); 231 int rsOffset = 0; 232 233 for ( int i = 0; i < this.fts.length; i++ ) { 234 sb.append( "Properties needed for feature type '" + this.fts[i].getName() + "':\n" ); 235 Map<MappedPropertyType, Collection<PropertyPath>> ftFetchProps = this.allFetchProps[i]; 236 for ( MappedPropertyType pt : ftFetchProps.keySet() ) { 237 sb.append( " - " ); 238 sb.append( pt.getName().getLocalName() ); 239 sb.append( ", requesting PropertyNames: " ); 240 Collection<PropertyPath> requestingPaths = ftFetchProps.get( pt ); 241 for ( PropertyPath path : requestingPaths ) { 242 sb.append( path ); 243 sb.append( " " ); 244 } 245 sb.append( '\n' ); 246 } 247 248 sb.append( "Fields to be fetched for feature type '" + this.fts[i].getName() + "':\n" ); 249 List<List<SimpleContent>> ftFetchContents = this.allFetchContents[i]; 250 for ( int j = 0; j < ftFetchContents.size(); j++ ) { 251 List<SimpleContent> sameField = ftFetchContents.get( j ); 252 sb.append( " - ResultSet[" ); 253 sb.append( j + rsOffset ); 254 sb.append( "], SimpleContent: " ); 255 sb.append( '\'' ); 256 sb.append( sameField.get( 0 ) ); 257 sb.append( '\'' ); 258 sb.append( '\n' ); 259 } 260 rsOffset += ftFetchContents.size(); 261 } 262 return sb.toString(); 263 } 264 }