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
069: .getLogger(SelectManager.class);
070:
071: private MappedFeatureType[] fts;
072:
073: private Map<MappedPropertyType, Collection<PropertyPath>>[] allFetchProps;
074:
075: private List<List<SimpleContent>>[] allFetchContents;
076:
077: private Map<SimpleContent, Integer>[] allResultPosMaps;
078:
079: private int fetchContentsCount;
080:
081: // requested properties, must contain exactly one list for each targeted feature type
082: private List<PropertyPath>[] selectedProps;
083:
084: private String[] ftAliases;
085:
086: // TODO remove this
087: private FeatureFetcher fetcher;
088:
089: @SuppressWarnings("unchecked")
090: SelectManager(Query query, MappedFeatureType[] rootFts,
091: FeatureFetcher fetcher) throws DatastoreException {
092:
093: this .fts = rootFts;
094: this .ftAliases = query.getAliases();
095: this .selectedProps = PropertyPathResolver
096: .normalizePropertyPaths(this .fts, this .ftAliases, query
097: .getPropertyNames());
098:
099: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
100: LOG.logDebug("Selected properties (normalized): ");
101: for (int i = 0; i < fts.length; i++) {
102: List<PropertyPath> props = this .selectedProps[i];
103: LOG
104: .logDebug("Selected properties (normalized) for feature type '"
105: + fts[i].getName() + "'.");
106: for (PropertyPath path : props) {
107: LOG.logDebug(" - " + path);
108: }
109: }
110: }
111:
112: this .allFetchProps = new Map[this .fts.length];
113: this .allFetchContents = new List[this .fts.length];
114: this .allResultPosMaps = new Map[this .fts.length];
115: this .fetcher = fetcher;
116:
117: determineInitialFetchProperties();
118: determineFetchContents();
119: buildResultPosMaps();
120: }
121:
122: private void determineInitialFetchProperties()
123: throws PropertyPathResolvingException {
124:
125: LOG
126: .logDebug("Determining fetch properties for all requested feature types.");
127:
128: for (int i = 0; i < this .fts.length; i++) {
129: MappedFeatureType rootFt = this .fts[i];
130: LOG
131: .logDebug("Feature type: "
132: + rootFt.getName()
133: + " (alias: "
134: + (this .ftAliases != null ? this .ftAliases[i]
135: : "-") + ")");
136: PropertyPath[] requestedProps = this .selectedProps[i]
137: .toArray(new PropertyPath[this .selectedProps[i]
138: .size()]);
139: for (PropertyPath path : requestedProps) {
140: LOG.logDebug("Requested property: " + path);
141: }
142: Map<MappedPropertyType, Collection<PropertyPath>> ftRequestedProps = PropertyPathResolver
143: .determineFetchProperties(rootFt,
144: this .ftAliases != null ? this .ftAliases[i]
145: : null, requestedProps);
146: LOG.logDebug("All properties needed for feature type: "
147: + rootFt.getName());
148: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
149: for (MappedPropertyType pt : ftRequestedProps.keySet()) {
150: LOG.logDebug("-" + pt.getName());
151: }
152: }
153: this .allFetchProps[i] = ftRequestedProps;
154: }
155: }
156:
157: private void determineFetchContents() throws DatastoreException {
158: LOG
159: .logDebug("Determining initial fetch contents for all requested feature types...");
160:
161: for (int i = 0; i < this .fts.length; i++) {
162: MappedFeatureType rootFt = this .fts[i];
163: MappedPropertyType[] requestedProps = new MappedPropertyType[this .allFetchProps[i]
164: .size()];
165: requestedProps = this .allFetchProps[i].keySet().toArray(
166: requestedProps);
167: List<List<SimpleContent>> ftFetchContents = null;
168: if (requestedProps.length > 0) {
169: ftFetchContents = fetcher.determineFetchContents(
170: rootFt, requestedProps);
171: } else {
172: ftFetchContents = new ArrayList<List<SimpleContent>>();
173: }
174: this .allFetchContents[i] = ftFetchContents;
175:
176: LOG
177: .logDebug("Will fetch the following columns initially (for feature type "
178: + rootFt.getName() + "):");
179: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
180: for (List<SimpleContent> list : ftFetchContents) {
181: SimpleContent representer = list.get(0);
182: LOG.logDebug("-" + representer);
183: }
184: }
185: this .fetchContentsCount += ftFetchContents.size();
186: }
187: }
188:
189: private void buildResultPosMaps() {
190:
191: int currentRSPos = 0;
192: for (int i = 0; i < this .allFetchContents.length; i++) {
193: List<List<SimpleContent>> ftFetchContents = this .allFetchContents[i];
194: Map<SimpleContent, Integer> ftResultPosMap = new HashMap<SimpleContent, Integer>();
195: for (int j = 0; j < ftFetchContents.size(); j++) {
196: for (SimpleContent content : ftFetchContents.get(j)) {
197: ftResultPosMap.put(content, j + currentRSPos);
198: }
199: }
200: this .allResultPosMaps[i] = ftResultPosMap;
201: currentRSPos += ftFetchContents.size();
202: }
203: }
204:
205: List<List<SimpleContent>>[] getAllFetchContents() {
206: return this .allFetchContents;
207: }
208:
209: Map<SimpleContent, Integer>[] getResultPosMaps() {
210: return this .allResultPosMaps;
211: }
212:
213: Map<MappedPropertyType, Collection<PropertyPath>>[] getAllFetchProps() {
214: return this .allFetchProps;
215: }
216:
217: int getFetchContentCount() {
218: return this .fetchContentsCount;
219: }
220:
221: private int getActualFeatureTupleLength() {
222: int i = 0;
223: for (List<List<SimpleContent>> ftFetchContents : this .allFetchContents) {
224: if (ftFetchContents.size() > 0) {
225: i++;
226: }
227: }
228: return i;
229: }
230:
231: int[] getIncludedFtIdx() {
232: int[] includedFtIdx = new int[getActualFeatureTupleLength()];
233: int i = 0;
234: int idx = 0;
235: for (List<List<SimpleContent>> ftFetchContents : this .allFetchContents) {
236: if (ftFetchContents.size() > 0) {
237: includedFtIdx[idx] = i;
238: idx++;
239: }
240: i++;
241: }
242: return includedFtIdx;
243: }
244:
245: @Override
246: public String toString() {
247: StringBuffer sb = new StringBuffer();
248: int rsOffset = 0;
249:
250: for (int i = 0; i < this .fts.length; i++) {
251: sb.append("Properties needed for feature type '"
252: + this .fts[i].getName() + "':\n");
253: Map<MappedPropertyType, Collection<PropertyPath>> ftFetchProps = this .allFetchProps[i];
254: for (MappedPropertyType pt : ftFetchProps.keySet()) {
255: sb.append(" - ");
256: sb.append(pt.getName().getLocalName());
257: sb.append(", requesting PropertyNames: ");
258: Collection<PropertyPath> requestingPaths = ftFetchProps
259: .get(pt);
260: for (PropertyPath path : requestingPaths) {
261: sb.append(path);
262: sb.append(" ");
263: }
264: sb.append('\n');
265: }
266:
267: sb.append("Fields to be fetched for feature type '"
268: + this .fts[i].getName() + "':\n");
269: List<List<SimpleContent>> ftFetchContents = this .allFetchContents[i];
270: for (int j = 0; j < ftFetchContents.size(); j++) {
271: List<SimpleContent> sameField = ftFetchContents.get(j);
272: sb.append(" - ResultSet[");
273: sb.append(j + rsOffset);
274: sb.append("], SimpleContent: ");
275: sb.append('\'');
276: sb.append(sameField.get(0));
277: sb.append('\'');
278: sb.append('\n');
279: }
280: rsOffset += ftFetchContents.size();
281: }
282: return sb.toString();
283: }
284: }
|