Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.spi / src / main / java / org / gvsig / fmap / dal / feature / spi / AbstractFeatureSetProvider.java @ 47665

History | View | Annotate | Download (12 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.spi;
25

    
26
import java.util.Iterator;
27
import java.util.Objects;
28
import org.apache.commons.lang3.builder.ToStringBuilder;
29
import org.apache.commons.lang3.mutable.MutableObject;
30
import org.gvsig.expressionevaluator.Code;
31
import org.gvsig.expressionevaluator.Expression;
32
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
33
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
34
import org.gvsig.expressionevaluator.Interpreter;
35
import org.gvsig.expressionevaluator.MutableSymbolTable;
36
import org.gvsig.expressionevaluator.SymbolTable;
37
import org.gvsig.fmap.dal.exception.DataException;
38
import org.gvsig.fmap.dal.feature.FeatureQuery;
39
import org.gvsig.fmap.dal.feature.FeatureType;
40
import org.gvsig.fmap.geom.Geometry;
41
import org.gvsig.fmap.geom.SpatialIndex;
42
import org.gvsig.fmap.geom.primitive.Envelope;
43
import org.gvsig.tools.dispose.DisposableIterator;
44
import org.gvsig.tools.dispose.impl.AbstractDisposable;
45
import org.gvsig.tools.exception.BaseException;
46
import org.gvsig.tools.visitor.VisitCanceledException;
47
import org.gvsig.tools.visitor.Visitor;
48
import org.slf4j.Logger;
49
import org.slf4j.LoggerFactory;
50

    
51
/**
52
 * Base implementation for {@link FeatureSetProvider}s, adding some utility
53
 * methods.
54
 * 
55
 * @author 2009- <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
56
 */
57
public abstract class AbstractFeatureSetProvider extends AbstractDisposable
58
                implements FeatureSetProvider {
59

    
60
        protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractFeatureSetProvider.class);
61
                
62
        private final AbstractFeatureStoreProvider store;
63
        private final FeatureQuery query;
64
        private final FeatureType providerFeatureType;
65
        private final FeatureType storeFeatureType;
66

    
67
        /**
68
         * Creates a new {@link FeatureSetProvider}.
69
         * 
70
         * @param store
71
         *            the underlying {@link FeatureStoreProvider} to get the data
72
         *            from
73
         * @param query
74
         *            used to create the {@link FeatureSetProvider}
75
         * @param providerFeatureType
76
         *            the type of feature to get
77
         */
78
        public AbstractFeatureSetProvider(AbstractFeatureStoreProvider store,
79
                        FeatureQuery query, FeatureType providerFeatureType, FeatureType storeFeatureType) {
80
                this.store = store;
81
                this.query = query;
82
                this.providerFeatureType = providerFeatureType;
83
                this.storeFeatureType = storeFeatureType;
84
        }
85
        public AbstractFeatureSetProvider(AbstractFeatureStoreProvider store,
86
                        FeatureQuery query, FeatureType providerFeatureType) {
87
            this(store, query, providerFeatureType, null);
88
        }
89
        /**
90
         * Return the {@link AbstractFeatureStoreProvider}.
91
         * 
92
         * @return the store
93
         */
94
        protected AbstractFeatureStoreProvider getStore() {
95
                return store;
96
        }
97

    
98
        /**
99
         * Returns the {@link FeatureQuery} used to create this set.
100
         * 
101
         * @return the query
102
         */
103
        protected FeatureQuery getQuery() {
104
                return query;
105
        }
106
    
107
        /**
108
         * Returns the type of features from provider to load.
109
         * 
110
         * @return the providerFeatureType
111
         */
112
        protected FeatureType getProviderFeatureType() {
113
                return providerFeatureType;
114
        }
115
    
116
        /**
117
         * Returns the type of features from store to load.
118
         * 
119
         * @return the storeFeatureType
120
         */
121
        protected FeatureType getStoreFeatureType() {
122
                return storeFeatureType;
123
        }
124

    
125
        /**
126
         * Returns the type of features from provider to load.
127
         * 
128
         * @return the providerFeatureType
129
         * @deprecated use getProviderFeatureType
130
         */        
131
        protected FeatureType getFeatureType() {
132
                return providerFeatureType;
133
        }
134
    
135
        @Override
136
        public final DisposableIterator fastIterator() throws DataException {
137
                return fastIterator(0);
138
        }
139

    
140
        public final DisposableIterator fastIterator(long index)
141
                        throws DataException {
142
                return createFastIterator(index);
143
        }
144

    
145
    @Override
146
    public final DisposableIterator fastIterator(long index, long elements) throws DataException {
147
                return createFastIterator(index, elements);
148
        }
149

    
150
    @Override
151
        public final DisposableIterator iterator() throws DataException {
152
                return iterator(0);
153
        }
154

    
155
        public final DisposableIterator iterator(long index) throws DataException {
156
                return createIterator(index);
157
        }
158

    
159
    @Override
160
        public final DisposableIterator iterator(long index, long elements) throws DataException {
161
                return createIterator(index, elements);
162
        }
163

    
164
        /**
165
         * Creates a new {@link Iterator}, begginning at the specified data index.
166
         * 
167
         * @param index
168
         *            the first element position to be returned by the
169
         *            {@link Iterator}
170
         * @return a new {@link Iterator}
171
         * @throws DataException
172
         *             if there is an error creating the {@link Iterator}
173
         */
174
        protected abstract AbstractFeatureProviderIterator createIterator(long index)
175
                        throws DataException;
176

    
177
        protected AbstractFeatureProviderIterator createIterator(long index, long elements)
178
                        throws DataException {
179
            return createIterator(index);
180
    }
181

    
182
    /**
183
         * Creates a new fast {@link Iterator}, begginning at the specified data
184
         * index. By fast this means the object instances of data (
185
         * {@link FeatureProvider}) may be reused between the
186
         * {@link Iterator#next()} method invocations.
187
         * 
188
         * @param index
189
         *            the first element position to be returned by the
190
         *            {@link Iterator}
191
         * @return a new {@link Iterator}
192
         * @throws DataException
193
         *             if there is an error creating the {@link Iterator}
194
         */
195
        protected abstract AbstractFeatureProviderIterator createFastIterator(
196
                        long index) throws DataException;
197
        
198
        protected AbstractFeatureProviderIterator createFastIterator(
199
                        long index, long elements) throws DataException {
200
            return createFastIterator(index);
201
        }
202

    
203
    @Override
204
    public String toString() {
205
        try {
206
            ToStringBuilder builder = new ToStringBuilder(this);
207
            builder.append("store", this.store, true);
208
            builder.append("query", this.query, true);
209
            return builder.toString();
210
        } catch (Exception e) {
211
            return super.toString();
212
        }
213
    }
214

    
215
    protected SpatialIndex getSpatialIndex(String name) {
216
        return null;
217
    }
218
    
219
    @SuppressWarnings("Convert2Lambda")
220
    protected Iterator createSpatialIterator(FeatureType featureType, FeatureQuery query) {
221
        if( featureType==null || query == null || query.getFilter()==null) {
222
            return null;
223
        }
224
        ExpressionEvaluatorManager expmanager = ExpressionEvaluatorLocator.getExpressionEvaluatorManager();
225
        Code filterCode = null;
226
        try {
227
            SymbolTable filterSymbolTable = null;
228
            Expression filterExp = query.getExpressionFilter();               
229
            if( filterExp == null ) {
230
                String sql = query.getFilter().getSQL();
231
                if( sql == null ) {
232
                    return null;
233
                }
234
                filterCode = expmanager.compile(sql);
235
            } else {
236
                filterCode = filterExp.getCode();
237
                filterSymbolTable = filterExp.getSymbolTable();
238
            }
239
            MutableObject<Code> spatialQuery = new MutableObject<>();
240
            MutableObject<SpatialIndex> spatialIndex = new MutableObject<>();
241
            try {
242
                filterCode.accept(new Visitor() {
243
                    @Override
244
                    public void visit(Object obj) throws VisitCanceledException, BaseException {
245
                        SpatialIndex spaIndex = null;
246
                        if (Code.isFunction((Code) obj, "NOT") && spatialIndex.getValue() == null) {
247
                            Code isCode = ((Code.Callable)obj).parameters().get(0);
248
                            if (Code.isFunction(isCode, "IS")) {
249
                                Code p1 = ((Code.Callable)isCode).parameters().get(0);
250
                                Code p2 = ((Code.Callable)isCode).parameters().get(1);
251
                                if (p1.code() == Code.IDENTIFIER && p2.code()==Code.CONSTANT && ((Code.Constant)p2).value()==null) {
252
                                    spaIndex = getSpatialIndex(((Code.Identifier) p1).name());
253
                                    if(spaIndex != null) {
254
                                        spatialIndex.setValue(spaIndex);
255
                                    }
256
                                }
257
                            }
258
                        } else if (Code.isFunction((Code) obj, "ST_INTERSECTS")
259
                            || Code.isFunction((Code) obj, "ST_CONTAINS")
260
                            || Code.isFunction((Code) obj, "&&")) {
261
                            Code.Callable intersects = (Code.Callable) obj;
262
                            Code p1 = intersects.parameters().get(0);
263
                            Code p2 = intersects.parameters().get(1);
264
                            Code sq = null;
265
                            if (p1.code() == Code.IDENTIFIER) {
266
                                spaIndex = getSpatialIndex(((Code.Identifier) p1).name());
267
                                if(spaIndex != null) {
268
                                    sq = p2;
269
                                }
270
                            } else if (p2.code() == Code.IDENTIFIER) {
271
                                spaIndex = getSpatialIndex(((Code.Identifier) p2).name());
272
                                if(spaIndex != null) {
273
                                    sq = p1;
274
                                }
275
                            }
276
                            if (sq != null) {
277
                                spatialIndex.setValue(spaIndex);
278
                                spatialQuery.setValue(sq);
279
                                throw new VisitCanceledException();
280
                            }
281
                        }
282
                    }
283
                });
284
            } catch(VisitCanceledException ex) {
285

    
286
            }
287
            if( spatialIndex.getValue() != null && spatialQuery.getValue()!=null ) {
288
                Interpreter interpreter = expmanager.createInterpreter();
289
                MutableSymbolTable symbolTable;
290
                if( filterSymbolTable instanceof MutableSymbolTable ) {
291
                    interpreter.setSymbolTable(filterSymbolTable);
292
                } else {
293
                    symbolTable = expmanager.createSymbolTable();
294
                    if( filterSymbolTable != null ) {
295
                        symbolTable.addSymbolTable(filterSymbolTable);
296
                    }
297
                    interpreter.setSymbolTable(symbolTable);
298
                }
299
                Envelope envelope = null;
300
                Object value = interpreter.runCode(spatialQuery.getValue());
301
                if( value instanceof Geometry ) {
302
                    envelope = ((Geometry)value).getEnvelope();
303
                } else if( value instanceof Envelope ) {
304
                    envelope = (Envelope) value;
305
                }
306
                if( envelope!=null ) {
307
                    return spatialIndex.getValue().query(envelope, Long.MAX_VALUE);
308
                }
309
            } else if( spatialIndex.getValue() != null) {
310
                return spatialIndex.getValue().queryAll();
311
            }
312

    
313
        } catch (Exception ex) {
314
            LOGGER.warn("Can't use spatial index for query '"+Objects.toString(filterCode)+"'.",ex);
315
        }
316
        return null;
317
    }
318

    
319
}