Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_dal / src / org / gvsig / fmap / dal / feature / impl / DefaultFeatureIndex.java @ 36207

History | View | Annotate | Download (12.3 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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 2
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
 */
22

    
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2008 {{Company}}   {{Task}}
26
 */
27

    
28
package org.gvsig.fmap.dal.feature.impl;
29

    
30
import java.io.File;
31
import java.util.ArrayList;
32
import java.util.List;
33

    
34
import org.slf4j.Logger;
35
import org.slf4j.LoggerFactory;
36

    
37
import org.gvsig.fmap.dal.DataTypes;
38
import org.gvsig.fmap.dal.exception.DataException;
39
import org.gvsig.fmap.dal.exception.InitializeException;
40
import org.gvsig.fmap.dal.feature.Feature;
41
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
42
import org.gvsig.fmap.dal.feature.FeatureSet;
43
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
44
import org.gvsig.fmap.dal.feature.FeatureType;
45
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
46
import org.gvsig.fmap.dal.feature.exception.InvalidFeatureIndexException;
47
import org.gvsig.fmap.dal.feature.spi.DefaultLongList;
48
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
49
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
50
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProvider;
51
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProviderServices;
52
import org.gvsig.tools.ToolsLocator;
53
import org.gvsig.tools.dispose.DisposableIterator;
54
import org.gvsig.tools.dispose.DisposeUtils;
55
import org.gvsig.tools.observer.impl.BaseWeakReferencingObservable;
56
import org.gvsig.tools.task.SimpleTaskStatus;
57
import org.gvsig.tools.task.TaskStatusManager;
58

    
59
/**
60
 * Default feature index provider services.
61
 * 
62
 * @author jyarza
63
 * 
64
 */
65
public class DefaultFeatureIndex extends BaseWeakReferencingObservable
66
    implements FeatureIndexProviderServices {
67

    
68
    private static final Logger LOG = LoggerFactory
69
        .getLogger(DefaultFeatureIndex.class);
70

    
71
    private final FeatureStoreProviderServices featureStore;
72
    private final FeatureType featureType;
73
    private final String attributeName;
74
    private final String indexName;
75
    private final int dataType;
76
    private final FeatureIndexProvider indexProvider;
77
    private List attributeNames;
78

    
79
    private boolean filling = false;
80

    
81
    private boolean valid = true;
82

    
83
    public DefaultFeatureIndex(FeatureStoreProviderServices featureStore,
84
        FeatureType featureType, FeatureIndexProvider indexProvider,
85
        String attributeName, String indexName) {
86
        if (featureStore == null) {
87
            throw new IllegalArgumentException("featureStore cannot be null.");
88
        }
89
        if (featureType == null) {
90
            throw new IllegalArgumentException("featureType cannot be null.");
91
        }
92
        if (attributeName == null) {
93
            throw new IllegalArgumentException("attributeName cannot be null.");
94
        }
95
        if (indexName == null) {
96
            throw new IllegalArgumentException("indexName cannot be null.");
97
        }
98

    
99
        // FIXME Esto debe ir al provider
100
        if (featureStore.getProvider().getOIDType() != DataTypes.INT
101
            && featureStore.getProvider().getOIDType() != DataTypes.LONG) {
102
            throw new IllegalArgumentException();
103
        }
104

    
105
        FeatureAttributeDescriptor attr =
106
            featureType.getAttributeDescriptor(attributeName);
107
        if (attr == null) {
108
            throw new IllegalArgumentException("Attribute " + attributeName
109
                + " not found in FeatureType " + featureType.toString());
110
        }
111

    
112
        this.featureStore = featureStore;
113
        this.featureType = featureType;
114
        this.attributeName = attributeName;
115
        this.indexName = indexName;
116
        this.dataType = attr.getType();
117
        this.indexProvider = indexProvider;
118

    
119
        attributeNames = new ArrayList();
120
        attributeNames.add(attributeName);
121
    }
122

    
123
    public final FeatureAttributeDescriptor getFeatureAttributeDescriptor() {
124
        return featureType.getAttributeDescriptor(attributeName);
125
    }
126

    
127
    public final FeatureStoreProviderServices getFeatureStoreProviderServices() {
128
        return featureStore;
129
    }
130

    
131
    public final FeatureType getFeatureType() {
132
        return featureType;
133
    }
134

    
135
    public final String getName() {
136
        return indexName;
137
    }
138

    
139
    public final String getAttributeName() {
140
        return attributeName;
141
    }
142

    
143
    public final int getDataType() {
144
        return dataType;
145
    }
146

    
147
    public synchronized final void fill() throws FeatureIndexException {
148
        fill(false);
149
    }
150

    
151
    public void fill(boolean background) throws FeatureIndexException {
152
        if (!isValid()) {
153
            throw new InvalidFeatureIndexException();
154
        }
155
        if (background) {
156
            filling = true;
157

    
158
            Runnable task = new Runnable() {
159

    
160
                public void run() {
161
                    try {
162
                        clearAndFill();
163
                    } catch (DataException e) {
164
                        LOG.error("Error filling index: " + this, e);
165
                    }
166
                }
167
            };
168

    
169
            Thread thread = new Thread(task, "Fill index data");
170
            thread.start();
171
        } else {
172
            try {
173
                clearAndFill();
174
            } catch (DataException e) {
175
                throw new FeatureIndexException(e);
176
            }
177
        }
178
    }
179

    
180
    /**
181
     * @throws DataException
182
     */
183
    private void clearAndFill() throws DataException {
184
        FeatureSet set = null;
185
        try {
186
            filling = true;
187
            set =
188
                getFeatureStoreProviderServices().getFeatureStore()
189
                    .getFeatureSet();
190
            clear();
191
            doInsert(set);
192
            filling = false;
193
            notify(this, new DefaultFeatureStoreNotification(
194
                getFeatureStoreProviderServices().getFeatureStore(),
195
                FeatureStoreNotification.INDEX_FILLED_SUCCESSFULLY, this));
196
        } catch (DataException e) {
197
            filling = false;
198
            setValid(false);
199
            notify(this, new DefaultFeatureStoreNotification(
200
                getFeatureStoreProviderServices().getFeatureStore(),
201
                FeatureStoreNotification.INDEX_FILLING_ERROR, e));
202
            throw new FeatureIndexException(e);
203
        } finally {
204
            DisposeUtils.dispose(set);
205
        }
206
    }
207

    
208
    public synchronized final void insert(FeatureSet data) throws DataException {
209
        if (!isValid()) {
210
            throw new InvalidFeatureIndexException();
211
        }
212
        try {
213
            filling = true;
214
            doInsert(data);
215
        } finally {
216
            filling = false;
217
        }
218
    }
219

    
220
    private void doInsert(FeatureSet data) throws DataException {
221
        DisposableIterator it = null;
222
        TaskStatusManager statusManager = ToolsLocator.getTaskStatusManager();
223
        SimpleTaskStatus status =
224
            statusManager.createDefaultSimpleTaskStatus("Filling index");
225
        status.setCancellable(false);
226
        // status.setRangeOfValues(0, data.getSize());
227
        status.add();
228
        long counter = 0;
229
        try {
230
            it = data.fastIterator();
231
            while (it.hasNext()) {
232
                Feature feat = (Feature) it.next();
233
                doInsert(feat);
234
                status.setCurValue(counter++);
235
            }
236
        } catch (RuntimeException e) {
237
            status.abort();
238
            throw e;
239
        } finally {
240
            DisposeUtils.dispose(it);
241
            status.remove();
242
        }
243
    }
244

    
245
    public synchronized final void insert(Feature feat) {
246
        if (!isValid()) {
247
            throw new RuntimeException(new InvalidFeatureIndexException());
248
        }
249
        try {
250
            filling = true;
251
            doInsert(feat);
252
        } finally {
253
            filling = false;
254
        }
255
    }
256

    
257
    private void doInsert(Feature feat) {
258
        try {
259
            indexProvider.insert(feat.get(attributeName),
260
                (FeatureReferenceProviderServices) feat.getReference());
261
        } catch (NullPointerException e) {
262
            throw new IllegalArgumentException(
263
                "Feature does not contain a column with name " + attributeName);
264
        } catch (ClassCastException e) {
265
            throw new IllegalArgumentException(
266
                "Attribute data type is not valid.");
267
        }
268
    }
269

    
270
    public FeatureSet getMatchFeatureSet(Object value)
271
        throws FeatureIndexException {
272
        if (!isValid()) {
273
            throw new InvalidFeatureIndexException();
274
        }
275
        return new IndexFeatureSet(this, new DefaultLongList(
276
            indexProvider.match(value)));
277
    }
278

    
279
    public FeatureSet getRangeFeatureSet(Object value1, Object value2)
280
        throws FeatureIndexException {
281
        if (!isValid()) {
282
            throw new InvalidFeatureIndexException();
283
        }
284
        return new IndexFeatureSet(this, new DefaultLongList(
285
            indexProvider.range(value1, value2)));
286
    }
287

    
288
    public FeatureSet getNearestFeatureSet(int count, Object value)
289
        throws FeatureIndexException {
290
        if (!isValid()) {
291
            throw new InvalidFeatureIndexException();
292
        }
293
        return new IndexFeatureSet(this, new DefaultLongList(
294
            indexProvider.nearest(count, value)));
295
    }
296

    
297
    public FeatureSet getNearestFeatureSet(int count, Object value,
298
        Object tolerance) throws FeatureIndexException {
299
        if (!isValid()) {
300
            throw new InvalidFeatureIndexException();
301
        }
302
        return new IndexFeatureSet(this, new DefaultLongList(
303
            indexProvider.nearest(count, value, tolerance)));
304
    }
305

    
306
    public void initialize() throws InitializeException {
307
        indexProvider.setFeatureIndexProviderServices(this);
308
        indexProvider.initialize();
309
    }
310

    
311
    public synchronized final void delete(Feature feat) {
312
        if (!isValid()) {
313
            throw new RuntimeException(new InvalidFeatureIndexException());
314
        }
315
        try {
316
            filling = true;
317
            doDelete(feat);
318
        } finally {
319
            filling = false;
320
        }
321
    }
322

    
323
    private void doDelete(Feature feat) {
324
        indexProvider.delete(feat.get(this.attributeName),
325
            (FeatureReferenceProviderServices) feat.getReference());
326
    }
327

    
328
    public synchronized final void delete(FeatureSet data)
329
        throws FeatureIndexException {
330
        if (!isValid()) {
331
            throw new InvalidFeatureIndexException();
332
        }
333
        DisposableIterator it = null;
334
        try {
335
            filling = true;
336
            it = data.fastIterator();
337
            while (it.hasNext()) {
338
                Feature feat = (Feature) it.next();
339
                doDelete(feat);
340
            }
341
        } catch (DataException e) {
342
            throw new FeatureIndexException(e);
343
        } finally {
344
            filling = false;
345
            DisposeUtils.dispose(it);
346
        }
347
    }
348

    
349
    private void clear() throws DataException {
350
        indexProvider.clear();
351
    }
352

    
353
    public List getAttributeNames() {
354
        return attributeNames;
355
    }
356

    
357
    public String getNewFileName(String prefix, String sufix) {
358
        int n = 0;
359
        File file = new File(prefix + getName(), sufix);
360
        while (file.exists()) {
361
            n++;
362
            file = new File(prefix + getName() + n, sufix);
363
        }
364
        return file.getAbsolutePath();
365
    }
366

    
367
    public String getFileName() {
368
        // TODO Auto-generated method stub
369
        return null;
370
    }
371

    
372
    public String getTemporaryFileName() {
373
        // TODO Auto-generated method stub
374
        return null;
375
    }
376

    
377
    public FeatureIndexProvider getFeatureIndexProvider() {
378
        return this.indexProvider;
379
    }
380

    
381
    public boolean isFilling() {
382
        return filling;
383
    }
384

    
385
    public boolean isValid() {
386
        return !isFilling() && valid;
387
    }
388

    
389
    public void setValid(boolean valid) {
390
        this.valid = valid;
391
    }
392
}