Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.file / org.gvsig.fmap.dal.file.gml / src / main / java / org / gvsig / fmap / dal / store / gml / virtualrows / XMLFileAsList.java @ 47679

History | View | Annotate | Download (35.6 KB)

1
/*
2
 * To change this license header, choose License Headers in Project Properties.
3
 * To change this template file, choose Tools | Templates
4
 * and open the template in the editor.
5
 */
6
package org.gvsig.fmap.dal.store.gml.virtualrows;
7

    
8
import java.io.BufferedReader;
9
import java.io.Closeable;
10
import java.io.File;
11
import java.io.IOException;
12
import java.io.Reader;
13
import java.nio.ByteBuffer;
14
import java.nio.CharBuffer;
15
import java.nio.charset.Charset;
16
import java.nio.charset.StandardCharsets;
17
import java.util.AbstractList;
18
import java.util.ArrayList;
19
import java.util.Arrays;
20
import java.util.HashMap;
21
import java.util.List;
22
import java.util.Map;
23
import java.util.Objects;
24
import javax.xml.parsers.SAXParser;
25
import javax.xml.parsers.SAXParserFactory;
26
import org.apache.commons.collections4.CollectionUtils;
27
import org.apache.commons.io.FilenameUtils;
28
import org.apache.commons.io.IOUtils;
29
import org.apache.commons.io.input.CloseShieldReader;
30
import org.apache.commons.lang3.StringUtils;
31
import static org.gvsig.fmap.dal.store.simplereader.SimpleReaderUtils.isFileNewer;
32
import org.gvsig.fmap.dal.store.simplereader.virtualrows.LimitedReader;
33
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RandomAccessFileReader;
34
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFile;
35
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFile.Record;
36
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFile.RecordType;
37
import static org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFile.RecordTypeBuilder.recordTypeBuilder;
38
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFileImpl;
39
import org.gvsig.fmap.geom.Geometry;
40
import org.gvsig.fmap.geom.GeometryLocator;
41
import org.gvsig.tools.ToolsLocator;
42
import org.gvsig.tools.i18n.I18nManager;
43
import org.gvsig.tools.library.impl.DefaultLibrariesInitializer;
44
import org.gvsig.tools.task.SimpleTaskStatus;
45
import org.gvsig.tools.task.UserCancelTaskException;
46
import org.gvsig.tools.util.GetItemWithSize64;
47
import org.slf4j.Logger;
48
import org.slf4j.LoggerFactory;
49
import org.xml.sax.Attributes;
50
import org.xml.sax.InputSource;
51
import org.xml.sax.Locator;
52
import org.xml.sax.SAXException;
53
import org.xml.sax.helpers.DefaultHandler;
54

    
55
/**
56
 *
57
 * @author jjdelcerro
58
 */
59
@SuppressWarnings("UseSpecificCatch")
60
public class XMLFileAsList
61
        extends AbstractList<List<String>>
62
        implements Closeable, GetItemWithSize64<List<String>> {
63
    
64
    private static final Logger LOGGER = LoggerFactory.getLogger(XMLFileAsList.class);
65
    
66
    public static final int COMBINE_NONE = 0;
67
    public static final int COMBINE_FIRST_NOT_NULL = 1;
68

    
69
    private static final int IDXFIELD_BEGINLINE = 0; //INTEGER
70
    private static final int IDXFIELD_BEGINCOLUMN = 1; //INTEGER
71
    private static final int IDXFIELD_BEGINRECORDPOS = 2; //LONG
72
    private static final int IDXFIELD_ENDLINE = 3; //INTEGER
73
    private static final int IDXFIELD_ENDCOLUMN = 4; //INTEGER
74
    
75
    private static final int IDXFIELD_BEGINGEOMLINE = 5; //INTEGER
76
    private static final int IDXFIELD_BEGINGEOMCOLUMN = 6; //INTEGER
77
    private static final int IDXFIELD_BEGINGEOMPOS = 7; //LONG
78
    private static final int IDXFIELD_ENDGEOMLINE = 8; //INTEGER
79
    private static final int IDXFIELD_ENDGEOMCOLUMN = 9; //INTEGER
80
    private static final int IDXFIELD_ENDGEOMPOS = 10; //LONG
81

    
82
            
83
    private final RandomAccessFileReader reader;
84
    private final String recordPath;
85
    private RecordsFile index;
86
    private List<String> fieldPaths;
87
    private final List<String> geomPaths;
88
    private int combineMode;
89
    private long lastModified;
90

    
91
    
92
    public XMLFileAsList(File text, Charset charset, String recordPath, List<String> geomPath, List<String> fieldPaths) throws IOException {
93
        this.reader = new RandomAccessFileReader(text, charset);
94
        this.index = null;
95
        this.recordPath = recordPath;
96
        this.geomPaths = geomPath;
97
        this.fieldPaths = fieldPaths;
98
        this.lastModified = text.lastModified();
99
    }
100

    
101
    public XMLFileAsList(RandomAccessFileReader reader, RecordsFile index, String recordPath, List<String> geomPath, List<String> fieldPaths) throws IOException {
102
        this.reader = reader;
103
        this.index = index;
104
        this.recordPath = recordPath;
105
        this.geomPaths = geomPath;
106
        this.fieldPaths = fieldPaths;
107
        this.lastModified = -1;
108
    }
109

    
110
    @Override
111
    public void close() {
112
        IOUtils.closeQuietly(this.reader);
113
        IOUtils.closeQuietly(this.index);
114
    }
115

    
116
    private synchronized List<String> getRecord(long position, List<String> fieldPaths) {
117
        class StopParserSAXException extends SAXException {
118
        }
119

    
120
        class ParseRecordsHandler extends DefaultHandler {
121

    
122
            Locator locator;
123
            List<String> path = new ArrayList<>();
124
            Map<String, String> record = new HashMap<>();
125
            StringBuilder value = new StringBuilder();
126
            List<String> values = new ArrayList<>();
127
            private int endLineNumber;
128
            private int endColumnNumber;
129

    
130
            @Override
131
            public void setDocumentLocator(Locator locator) {
132
                this.locator = locator;
133
            }
134

    
135
            @Override
136
            public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
137
                localName = removeNamespace(qName);
138
                path.add(localName);
139
                String path_s = StringUtils.join(path, "/");
140
//                System.out.println("start path_s "+path_s);
141
                if (StringUtils.equalsIgnoreCase(path_s, recordPath)) {
142
                    return;
143
                }
144
                this.value.setLength(0);
145
                for (int i = 0; i < attributes.getLength(); i++) {
146
                    String attrPath = path_s+"/"+removeNamespace(attributes.getQName(i));
147
                    for (String fieldPath : fieldPaths) {
148
                        if (StringUtils.equalsIgnoreCase(attrPath, fieldPath)) {
149
                            record.put(fieldPath, attributes.getValue(i));
150
                            // No break to handle repeated columns
151
                        }
152
                    }
153
                }
154
            }
155

    
156
            @Override
157
            public void characters(char[] ch, int start, int length) throws SAXException {
158
                value.append(new String(ch, start, length));
159
            }
160

    
161
            private String removeNamespace(String s){
162
                if(s.indexOf(':') < 0){
163
                    return s;
164
                }
165
                String[] ss = s.split(":");
166
                return ss[1];
167
            }
168
            
169
            @Override
170
            public void endElement(String uri, String localName, String qName) throws SAXException {
171
                localName = removeNamespace(qName);
172
                String path_s = StringUtils.join(path, "/");
173

    
174
//                System.out.println("end   path_s "+path_s);
175
                for (String fieldPath : fieldPaths) {
176
                    if (StringUtils.equalsIgnoreCase(path_s, fieldPath)) {
177
                        record.put(fieldPath, this.value.toString());
178
                        // No break to handle repeated columns
179
                    }
180
                }
181

    
182
                if (this.locator.getLineNumber() >= this.endLineNumber
183
                        && this.locator.getColumnNumber() >= this.endColumnNumber) {
184
                    for (String fieldPath : fieldPaths) {
185
                        values.add(record.get(fieldPath));
186
                    }
187
                    throw new StopParserSAXException();
188
                }
189

    
190
                path.remove(path.size() - 1);
191
            }
192
        }
193

    
194
//        System.out.println("RECORD "+position);
195
        ParseRecordsHandler handler = null;
196
        Record record = this.index.get64(position);
197
        int recordLine = record.getInt(IDXFIELD_BEGINLINE);
198
        int recordColumn = record.getInt(IDXFIELD_BEGINCOLUMN);
199
        long recordPosition = record.getLong(IDXFIELD_BEGINRECORDPOS);
200
        try {
201
            this.reader.seek(recordPosition);
202
            // TODO: guardarse el tama?o del registro en el indice y en funcion de eso usar un buffersize mas peque?o aqui si procede
203
            int bufferSize = 1024*8; 
204
            BufferedReader breader = new BufferedReader(this.reader, bufferSize);
205

    
206
            InputSource is = new InputSource(CloseShieldReader.wrap(breader));
207
            SAXParserFactory spf = SAXParserFactory.newInstance();
208
            spf.setNamespaceAware(false);
209
            SAXParser saxParser = spf.newSAXParser();
210
            handler = new ParseRecordsHandler();
211
            handler.endLineNumber=(int) (record.getInt(IDXFIELD_ENDLINE)-record.getInt(IDXFIELD_BEGINLINE)+1);
212
            handler.endColumnNumber=(int) record.getInt(IDXFIELD_ENDCOLUMN);
213

    
214
            saxParser.parse(is, handler);
215
        } catch (StopParserSAXException ex) {
216
            //Do nothing
217
        } catch (Exception ex) {
218
            throw new RuntimeException("Can't parse record " + position +" recordPosition "+recordPosition+ " line "+recordLine+ " column "+recordColumn, ex);
219
        }
220
        if (handler == null) {
221
            return null;
222
        }
223
        
224
        try {
225
            Geometry geom = null;
226
            if(CollectionUtils.isNotEmpty(this.geomPaths)) {
227
                for (int i = 0; i < this.geomPaths.size(); i++) {
228
                    Reader limitedReader = null;
229
                    BufferedReader breader = null;
230

    
231
                    try {
232
                        geom = null;
233
                        long geomPosition = record.getLong(IDXFIELD_BEGINGEOMPOS+i*6);
234
                        long endGeomPosition = record.getLong(IDXFIELD_ENDGEOMPOS+i*6);
235
                        if(geomPosition == 0 || endGeomPosition == 0){
236
                            if(this.combineMode != COMBINE_FIRST_NOT_NULL){
237
                                handler.values.add(null);
238
                            }
239
                            continue;
240
                        }
241
                        this.reader.seek(geomPosition);
242
                        if(position == 0){
243
                            char[] cbuff = new char[(int)(endGeomPosition-geomPosition)];
244
                            this.reader.read(cbuff);
245
    //                        System.out.println("["+new String(cbuff)+"]");
246
                            this.reader.seek(geomPosition);
247
                        }
248
                        limitedReader = new LimitedReader(reader, (int)(endGeomPosition-geomPosition));
249
                        // TODO: calcular el buffersize como el min(8k,endGeomPosition-geomPosition+1)
250
                        int bufferSize = 1024*8; 
251
                        breader = new BufferedReader(limitedReader, bufferSize);
252
                        geom = GeometryLocator.getGeometryManager().createFrom(breader, null);
253
                    } catch (Throwable t) {
254
                        //Do nothing
255
                        LOGGER.debug("Can't load geometry", t);
256
                    }
257
                    if(this.combineMode == COMBINE_FIRST_NOT_NULL){
258
                        if(geom != null){
259
                            handler.values.add(geom.convertToHexWKB());
260
                            break;
261
                        }
262
                    } else {
263
                        handler.values.add(geom==null?null:geom.convertToHexWKB());
264
                    }
265
                }
266
                if(this.combineMode == COMBINE_FIRST_NOT_NULL && geom == null){
267
                    handler.values.add(null);
268
                }
269
            }
270
            
271
        } catch (Exception ex) {
272
            throw new RuntimeException("Can't parse record " + position, ex);
273
        }
274
        return handler.values;
275
    }
276

    
277
    @Override
278
    public List<String> get(int index) {
279
        return this.getRecord(index, fieldPaths);
280
    }
281

    
282
    @Override
283
    public List<String> get64(long position) {
284
        return this.getRecord(position, fieldPaths);
285
    }
286

    
287
    @Override
288
    public int size() {
289
        return this.index.size();
290
    }
291

    
292
    @Override
293
    public long size64() {
294
        return this.index.size64();
295
    }
296

    
297
    public int getCombineMode() {
298
        return combineMode;
299
    }
300
    
301
    public void setCombineMode(int combineMode) {
302
        this.combineMode = combineMode;
303
    }
304
    
305
    public boolean loadIndex(File fileIndex, SimpleTaskStatus status) throws IOException{
306
        if (!fileIndex.exists()) {
307
            return false;
308
        }
309
        if(this.lastModified > 0 && isFileNewer(fileIndex, this.lastModified)){
310
            this.index = new RecordsFileImpl(fileIndex);
311
            return true;
312
        }
313
        return false;
314
    }
315
    
316
    final public synchronized void createIndex(File indexFile, SimpleTaskStatus status) throws IOException {
317
        try {
318
            // 1. Creamos el indice vacio
319
            RecordsFile.RecordTypeBuilder builder = recordTypeBuilder()
320
                    .addInteger()
321
                    .addInteger()
322
                    .addLong()
323
                    .addInteger()
324
                    .addInteger();
325

    
326
            if (CollectionUtils.isNotEmpty(geomPaths)) {
327
                for (int i = 0; i < geomPaths.size(); i++) {
328
                    builder.addInteger()
329
                            .addInteger()
330
                            .addLong()
331
                            .addInteger()
332
                            .addInteger()
333
                            .addLong();
334
                }
335
            }
336
            RecordType recordType = builder.build();
337
            Record record = recordType.createRecord();
338
            final RecordsFile theIndex = new RecordsFileImpl();
339
            theIndex.create(indexFile, recordType);
340

    
341
            // 2. Rellenamos los campos numero de linea y columna de cada registro 
342
            //    en el indice.
343
            // Para ello nos recorremos el XML y vamos escribiendo en el indice.
344
            this.reader.rewind();
345
            InputSource is = new InputSource(CloseShieldReader.wrap(reader));
346
            SAXParserFactory spf = SAXParserFactory.newInstance();
347
            spf.setNamespaceAware(true);
348
            SAXParser saxParser = spf.newSAXParser();
349
            
350
            if (status != null) {
351
                I18nManager i18n = ToolsLocator.getI18nManager();
352
                status.push();
353
                status.message(i18n.getTranslation("_Creating_record_index"));
354
                status.setIndeterminate();
355
            }
356

    
357
            List<String> path = new ArrayList<>();
358
            // TODO: Aqui habria que quedarse con la primera aparicion de
359
            // los campos solicitados que no pertenezcan al registro principal.
360
            // Probablemente habria que guardar esos valores en disco junto al
361
            // fichero de indice.
362
            saxParser.parse(is, new DefaultHandler() {
363
                Locator locator;
364
                private int beginLineNumber;
365
                private int beginColumnNumber;
366
                private int lastTagLineNumber;
367
                private int lastTagColumnNumber;
368

    
369
                @Override
370
                public void setDocumentLocator(Locator locator) {
371
                    this.locator = locator;
372
                }
373

    
374
                @Override
375
                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
376
                    path.add(localName);
377
                    String path_s = StringUtils.join(path, "/");
378

    
379
                    if (StringUtils.equalsIgnoreCase(path_s, recordPath)) {
380
                        record.setInt(IDXFIELD_BEGINLINE, locator.getLineNumber());
381
                        record.setInt(IDXFIELD_BEGINCOLUMN, locator.getColumnNumber());
382
                        record.setInt(IDXFIELD_ENDLINE, 0);
383
                        record.setInt(IDXFIELD_ENDCOLUMN, 0);
384
                        if (CollectionUtils.isNotEmpty(geomPaths)) {
385
                            for (int i = 0; i < geomPaths.size(); i++) {
386
                                record.setInt(IDXFIELD_BEGINGEOMLINE + 6 * i, 0);
387
                                record.setInt(IDXFIELD_BEGINGEOMCOLUMN + 6 * i, 0);
388
                                record.setLong(IDXFIELD_BEGINGEOMPOS + 6 * i, 0);
389
                                record.setInt(IDXFIELD_ENDGEOMLINE + 6 * i, 0);
390
                                record.setInt(IDXFIELD_ENDGEOMCOLUMN + 6 * i, 0);
391
                                record.setLong(IDXFIELD_ENDGEOMPOS + 6 * i, 0);
392
                            }
393
                        }
394
                        this.beginLineNumber = locator.getLineNumber();
395
                        this.beginColumnNumber = locator.getColumnNumber();
396
                    }
397
                    if (CollectionUtils.isNotEmpty(geomPaths)) {
398
                        for (int i = 0; i < geomPaths.size(); i++) {
399
                            String geomPath = geomPaths.get(i);
400
                            if (StringUtils.equalsIgnoreCase(path_s, recordPath + "/" + geomPath)) {
401
                                record.setInt(IDXFIELD_BEGINGEOMLINE + 6 * i, locator.getLineNumber());
402
                                record.setInt(IDXFIELD_BEGINGEOMCOLUMN + 6 * i, locator.getColumnNumber());
403
                                record.setLong(IDXFIELD_BEGINGEOMPOS + 6 * i, 0);
404
                                break;
405
                            }
406
                        }
407
                    }
408
                    if (status != null) {
409
                        if (status.isCancellationRequested()) {
410
                            throw new UserCancelTaskException();
411
                        }
412
                    }
413
                }
414

    
415
                @Override
416
                public void endElement(String uri, String localName, String qName) throws SAXException {
417
                    String path_s = StringUtils.join(path, "/");
418

    
419
                    if (StringUtils.equalsIgnoreCase(path_s, recordPath)) {
420
                        int line = lastTagLineNumber;//-this.beginLineNumber;
421
                        int column = this.lastTagColumnNumber;
422
                        if (line == 0) {
423
                            column = column - this.beginColumnNumber;
424
                        }
425
                        record.setInt(IDXFIELD_ENDLINE, line);
426
                        record.setInt(IDXFIELD_ENDCOLUMN, column);
427
                        theIndex.add(record);
428
                    }
429
                    if (CollectionUtils.isNotEmpty(geomPaths)) {
430
                        for (int i = 0; i < geomPaths.size(); i++) {
431
                            String geomPath = geomPaths.get(i);
432
                            if (StringUtils.equalsIgnoreCase(path_s, recordPath + "/" + geomPath)) {
433
                                record.setInt(IDXFIELD_ENDGEOMLINE + 6 * i, this.lastTagLineNumber);
434
                                record.setInt(IDXFIELD_ENDGEOMCOLUMN + 6 * i, this.lastTagColumnNumber);
435
                                break;
436
                            }
437
                        }
438
                    }
439
                    this.lastTagLineNumber = locator.getLineNumber();
440
                    this.lastTagColumnNumber = locator.getColumnNumber();
441
                    path.remove(path.size() - 1);
442

    
443
                    if (status != null) {
444
                        if (status.isCancellationRequested()) {
445
                            throw new UserCancelTaskException();
446
                        }
447
                    }
448

    
449
                }
450
            });
451
            if (status != null) {
452
                status.setRangeOfValues(0, theIndex.size64());
453
                status.setCurValue(0);
454
            }
455

    
456
            // 3. Nos recorremos el indice y calculamos la posicion de la linea
457
            //    para cada registro.
458
            this.reader.rewind();
459
            PositionCalculator positionCalculator = new PositionCalculator(reader);
460

    
461
            for (int j = 0; j < theIndex.size(); j++) {
462
                Record r = theIndex.get(j);
463
//                if(i==0){
464
//                    System.out.println("RECO BEGIN: "+r.getLong(IDXFIELD_BEGINLINE) + " " + r.getLong(IDXFIELD_BEGINCOLUMN));
465
//                    if(CollectionUtils.isNotEmpty(geomPaths)) {
466
//                        for (int i = 0; i < geomPaths.size(); i++) {
467
//                            System.out.println("GEOM"+i+"BEGIN: "+r.getLong(IDXFIELD_BEGINGEOMLINE+i*6) + " " + r.getLong(IDXFIELD_BEGINGEOMCOLUMN+i*6));
468
//                            System.out.println("GEOM"+i+"END  : "+r.getLong(IDXFIELD_ENDGEOMLINE+i*6) + " " +  r.getLong(IDXFIELD_ENDGEOMCOLUMN+i*6));
469
//                        }
470
//                    }
471
//                    System.out.println("RECO END  : "+r.getLong(IDXFIELD_ENDLINE) + " " +  r.getLong(IDXFIELD_ENDCOLUMN));
472
//                }
473
                positionCalculator.next(r.getInt(IDXFIELD_BEGINLINE), r.getInt(IDXFIELD_BEGINCOLUMN));
474
                r.setLong(IDXFIELD_BEGINRECORDPOS, positionCalculator.getColumnPosition());
475
//                System.out.println("RPOS      : " + r.getLong(IDXFIELD_BEGINRECORDPOS));
476
                //Todo esto es porque los campos de geometrias pueden tener distinta ordenacion en cada uno de los registros del XML
477
                if(CollectionUtils.isNotEmpty(geomPaths)) {
478
                    class Element implements Comparable<Element> {
479

    
480
                        final int index;
481
                        final long beginGeomLine;
482
                        final long endGeomLine;
483
                        final long beginGeomColumn;
484
                        final long endGeomColumn;
485
                        long beginGeomPos;
486
                        long endGeomPos;
487
                        
488
                        Element(int index, long beginGeomLine, long endGeomLine, long beginGeomColumn, long endGeomColumn){
489
                            this.index = index;
490
                            this.beginGeomLine = beginGeomLine;
491
                            this.endGeomLine = endGeomLine;
492
                            this.beginGeomColumn = beginGeomColumn;
493
                            this.endGeomColumn = endGeomColumn;
494
                        }
495

    
496
                        @Override
497
                        public int compareTo(Element o) {
498
                            return Long.compare(beginGeomLine, o.beginGeomLine);
499
                        }
500
                        
501
                    }
502
                    Element[] elements = new Element[geomPaths.size()];
503
                    for (int i = 0; i < elements.length; i++) {
504
                        long beginGeomLine = r.getInt(IDXFIELD_BEGINGEOMLINE + i * 6);
505
                        long endGeomLine = r.getInt(IDXFIELD_ENDGEOMLINE + i * 6);
506
                        elements[i] = new Element(
507
                            i, 
508
                            beginGeomLine, 
509
                            endGeomLine,
510
                            r.getInt(IDXFIELD_BEGINGEOMCOLUMN + i * 6),
511
                            r.getInt(IDXFIELD_ENDGEOMCOLUMN + i * 6)
512
                        );
513
                    }
514
                    
515
                    Arrays.sort(elements);
516
                    for (int i = 0; i < elements.length; i++) {
517
                        Element e = elements[i];
518
                        if (e.beginGeomLine == 0 || e.endGeomLine == 0) {
519
                            continue;
520
                        }
521
                        positionCalculator.next(e.beginGeomLine, e.beginGeomColumn);
522
                        e.beginGeomPos = positionCalculator.getColumnPosition();
523
                        positionCalculator.next(e.endGeomLine, e.endGeomColumn);
524
                        e.endGeomPos = positionCalculator.getColumnPosition();
525
                    }
526

    
527
                    for (int i = 0; i < elements.length; i++) {
528
                        Element e = elements[i];
529
                        r.setLong(IDXFIELD_BEGINGEOMPOS + e.index * 6, e.beginGeomPos);
530
                        r.setLong(IDXFIELD_ENDGEOMPOS + e.index * 6, e.endGeomPos);
531
                    }
532

    
533
//                    for (int i = 0; i < geomPaths.size(); i++) {
534
//                        long beginGeomLine = r.getInt(IDXFIELD_BEGINGEOMLINE + i * 6);
535
//                        long endGeomLine = r.getInt(IDXFIELD_ENDGEOMLINE + i * 6);
536
//                        if (beginGeomLine == 0 || endGeomLine == 0) {
537
//                            continue;
538
//                        }
539
//                        positionCalculator.next(beginGeomLine, r.getInt(IDXFIELD_BEGINGEOMCOLUMN + i * 6));
540
//                        r.setLong(IDXFIELD_BEGINGEOMPOS + i * 6, positionCalculator.getColumnPosition());
541
//                        positionCalculator.next(endGeomLine, r.getInt(IDXFIELD_ENDGEOMCOLUMN + i * 6));
542
//                        r.setLong(IDXFIELD_ENDGEOMPOS + i * 6, positionCalculator.getColumnPosition());
543
////                        System.out.println("GPOS" + i + "     : " + r.getLong(IDXFIELD_BEGINGEOMPOS + i * 6) + " " + r.getLong(IDXFIELD_ENDGEOMPOS + i * 6));
544
//                    }
545
                }
546
                theIndex.set(j, r);
547
                if (status != null) {
548
                    if (status.isCancellationRequested()) {
549
                        status.cancel();
550
                        removeIndex(indexFile);
551
                        return;
552
                    }
553
                    status.incrementCurrentValue();
554
                }
555

    
556
            }
557
            this.index = new RecordsFileImpl(indexFile);
558
            if (status != null) {
559
                status.terminate();
560
            }
561
        } catch (UserCancelTaskException ex) {
562
            if (status != null) {
563
                if (status.isCancellationRequested()) {
564
                    status.cancel();
565
                }
566
            }
567
            removeIndex(indexFile);
568
            throw ex;
569
        } catch (Exception ex) {
570
            if (status != null) {
571
                status.abort();
572
            }
573
            removeIndex(indexFile);
574
            throw new IOException("Can't create index " + Objects.toString(indexFile), ex);
575
        } finally {
576
            if (status != null) {
577
                status.pop();
578
            }
579
        }
580
    }
581
    
582
    private void removeIndex(File indexFile) {
583
        indexFile.delete();
584
    }
585

    
586
    private static class CharacterSize {
587

    
588
        private final Charset charset;
589
        private final CharBuffer charBuffer;
590

    
591
        public CharacterSize(Charset charset) {
592
            this.charset = charset;
593
            this.charBuffer = CharBuffer.allocate(1);
594
        }
595

    
596
        public int size(char ch) {
597
            this.charBuffer.put(0, ch);
598
            this.charBuffer.position(0);
599
            ByteBuffer buffer = this.charset.encode(this.charBuffer);
600
            return buffer.limit();
601
        }
602

    
603
        public int size(char[] cbuf, int off, int len) {
604
            CharBuffer cb = CharBuffer.wrap(cbuf, off, len);
605
            ByteBuffer byteBuffer = this.charset.encode(cb);
606
            return byteBuffer.limit();
607
        }
608

    
609
        public int size(char[] cbuf) {
610
            CharBuffer cb = CharBuffer.wrap(cbuf, 0, cbuf.length);
611
            ByteBuffer byteBuffer = this.charset.encode(cb);
612
            return byteBuffer.limit();
613
        }
614

    
615
        public int size(String s) {
616
            CharBuffer cb = CharBuffer.wrap(s);
617
            ByteBuffer byteBuffer = this.charset.encode(cb);
618
            return byteBuffer.limit();
619
        }
620
    }
621

    
622
    private static class PositionCalculator {
623

    
624
        private final RandomAccessFileReader reader;
625
        private final BufferedReader breader;
626
        private long currentPosition;
627
        private long currentColumn;
628
        private long currentLine;
629
        private long currentColumnPosition;
630
        private long currentLinePosition;
631

    
632
        private final char[] ch;
633
        private final CharacterSize characterSize;
634

    
635
        public PositionCalculator(RandomAccessFileReader reader) {
636
            this.reader = reader;
637
            this.breader = new BufferedReader(this.reader, 1024 * 8);
638
            this.currentPosition = this.reader.getCurrentPosition();
639
            this.currentLine = 1;
640
            this.currentColumn = 1;
641
            this.ch = new char[1];
642
            this.characterSize = new CharacterSize(this.reader.getCharset());
643
        }
644

    
645
        public boolean next(long line, long column) throws IOException {
646
//            System.out.println();
647
//            System.out.println("----"+line+" "+column);
648
            if(this.currentLine>line){
649
                throw new IOException("Illegal column number " + column + " ("+this.currentColumn+") for line " + line+ " ("+this.currentLine+")");
650
            }
651
            if(this.currentLine==line && this.currentColumn > column){
652
                throw new IOException("Illegal column number " + column + " ("+this.currentColumn+") for line " + line);
653
            }
654
//            System.out.print(this.currentLine+":");
655
            while (this.currentLine < line) {
656
                if (breader.read(this.ch, 0, 1) < 1) {
657
                    return false;
658
                }
659
                char c = ch[0];
660
//                System.out.print(String.valueOf(c));
661
                this.currentPosition += characterSize.size(c);
662
                if (c == '\n') {
663
                    this.currentLine++;
664
                    this.currentColumn = 1;
665
//                    System.out.print(this.currentLine+":");
666
                }
667
            }
668
            this.currentLinePosition = this.currentPosition;
669
            while (true) {
670
                if (breader.read(this.ch, 0, 1) < 1) {
671
                    return false;
672
                }
673
                char c = ch[0];
674
//                System.out.print(String.valueOf(c));
675
                this.currentColumn++;
676
                this.currentPosition += characterSize.size(c);
677
                if(this.currentColumn >= column){
678
                    break;
679
                }
680
                if (c == '\n') {
681
                    throw new IOException("Illegal column number " + column + " ("+this.currentColumn+") for line " + line+ " ("+this.currentLine+")");
682
                }
683
            }
684
            this.currentColumnPosition = this.currentPosition;
685
//            System.out.println();
686
            return true;
687
        }
688

    
689
        public long getLinePosition() {
690
            return this.currentLinePosition;
691
        }
692

    
693
        public long getColumnPosition() {
694
            return this.currentColumnPosition;
695
        }
696

    
697
    }
698

    
699
    public static void main(String[] args) throws Exception {
700
        new DefaultLibrariesInitializer().fullInitialize();
701

    
702
//        final String XMLFILE1 = "/home/jjdelcerro/datos/geodata/vector/gml/navarra.gml";
703
//        final String XMLFILE2 = "/home/jjdelcerro/datos/geodata/vector/gml/Municipis/Municipis.gml";
704
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/1075305YJ2717N.gml";
705
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/Recinto.gml";
706
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/FG-GML-543863-AdmBdry-20190101-0001.gml";
707
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/Municipis.gml";
708
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/navarra.gml";
709
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/Falls.gml";
710
        
711
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/AerodromeArea.gml";
712
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/AerodromeType.gml"; //No tiene geometr?as
713
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/BuildingP.gml";
714
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/CablewayLink.gml";
715
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/ConditionOfFacility.gml"; //No tiene geometr?as
716
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/CrossingS.gml";
717
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/CrossingP.gml";
718
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/DamOrWeirL.gml";
719
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/EmbankmentL.gml";
720
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/EmbankmentS.gml";
721
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/FordP.gml";
722
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/FormOfWay.gml";
723
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/FunctionalRoadClass.gml"; //No tiene geometr?as
724
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/INSPIRE_GN.gml";
725
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/INSPIRE_AU.gml"; //Hay 3 geometr?as, LineString, Surface y MultiSurface
726
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RunwayArea.gml";
727
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayStationArea.gml";
728
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/DamOrWeirS.gml";
729
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/NominalTrackGauge.gml"; //No tiene geometr?as
730
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/NumberOfTracks.gml"; //No tiene geometr?as
731
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/Road.gml"; //No tiene geometr?as
732
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadServiceType.gml"; //No tiene geometr?as
733
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayArea.gml";
734
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayElectrification.gml"; //No tiene geometr?as
735
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayType.gml"; //No tiene geometr?as
736
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayLink.gml"; //Added Multicurve Strategy (ojo, en los registros, tras la geometr?a aparece otro atributo a null
737
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayYardArea.gml";
738
        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadArea.gml"; //NO VA
739
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadLink.gml"; //Hay 2 geometr?as, Curve y Multicurve
740
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadServiceArea.gml";
741
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadSurfaceCategory.gml"; //No tiene geometr?as
742
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadWidth.gml"; //No tiene geometr?as
743
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/ShorelineConstructionL.gml";
744
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/StandingWater.gml";
745
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/SurfaceComposition.gml";
746
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/VerticalPosition.gml"; //No tiene geometr?as
747
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/Watercourse.gml"; //Hay 2 geometr?as, Curve y Multicurve
748
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/WatercourseLink.gml";
749
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/WatercourseLinkSequence.gml"; //No tiene geometr?as
750
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/Wetland.gml";
751

    
752
        
753

    
754

    
755

    
756

    
757

    
758
        String gmlfile = XMLFILE1;
759
        File idxFile = new File(FilenameUtils.removeExtension(gmlfile)+".gmlidx");
760
        if(idxFile.exists()){
761
            idxFile.delete();
762
        }
763
        File gfsFile = new File(FilenameUtils.removeExtension(gmlfile)+".gfs");
764
        if(gfsFile.exists()){
765
            gfsFile.delete();
766
        }
767
        GfsFile gfs = new GfsFile();
768
        gfs.fetch(new File(gmlfile));
769
        gfs.save(gfsFile);
770
//        return;
771
        XMLFileAsList gml = new XMLFileAsList(
772
                new File(gmlfile), 
773
//                StandardCharsets.ISO_8859_1, 
774
                StandardCharsets.UTF_8, 
775
                gfs.getBaseElementPath(),
776
                gfs.getGeometryElementPaths(),
777
                gfs.getPropertiesPaths()
778
        );
779
        gml.createIndex(new File(FilenameUtils.removeExtension(gmlfile)+".gmlidx"), SimpleTaskStatus.FAKE_STATUS);
780
        System.out.println("File: "+gmlfile);
781
        for (int i = 0; i < gml.size(); i++) {
782
            List<String> item = gml.get(i);
783
            System.out.println("RECORD "+i+":"+item);
784
        }
785
        System.out.println(StringUtils.join(gfs.getPropertiesPaths(), "\n"));
786
        System.out.println("Geometries:\n"+StringUtils.join(gfs.getGeometryElementPaths(), "\n"));
787
    }
788
}