Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / org.gvsig.arcims / src / org / gvsig / remoteclient / arcims / ArcImsProtFeatureHandler.java @ 32668

History | View | Annotate | Download (32.8 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
 * 2010 Prodevelop S.L. main development
26
 * http://www.prodevelop.es
27
 */
28
package org.gvsig.remoteclient.arcims;
29

    
30
import java.awt.geom.Rectangle2D;
31
import java.io.BufferedReader;
32
import java.io.File;
33
import java.io.FileInputStream;
34
import java.io.FileNotFoundException;
35
import java.io.FileReader;
36
import java.io.IOException;
37
import java.io.InputStream;
38
import java.io.InputStreamReader;
39
import java.io.Reader;
40
import java.io.UnsupportedEncodingException;
41
import java.net.MalformedURLException;
42
import java.net.URL;
43
import java.util.ArrayList;
44
import java.util.Date;
45
import java.util.Iterator;
46
import java.util.List;
47
import java.util.StringTokenizer;
48
import java.util.Vector;
49

    
50
import org.exolab.castor.xml.dtd.parser.ParseException;
51
import org.gvsig.fmap.geom.Geometry;
52
import org.gvsig.fmap.geom.GeometryLocator;
53
import org.gvsig.fmap.geom.GeometryManager;
54
import org.gvsig.fmap.geom.aggregate.impl.MultiPoint2D;
55
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
56
import org.gvsig.fmap.geom.exception.CreateGeometryException;
57
import org.gvsig.fmap.geom.primitive.Envelope;
58
import org.gvsig.fmap.geom.primitive.GeneralPathX;
59
import org.gvsig.fmap.geom.primitive.Point;
60
import org.gvsig.fmap.geom.primitive.impl.Point2D;
61
import org.gvsig.remoteclient.arcims.exceptions.ArcImsException;
62
import org.gvsig.remoteclient.arcims.utils.ArcImsDownloadUtils;
63
import org.gvsig.remoteclient.arcims.utils.ArcImsFeature;
64
import org.gvsig.remoteclient.arcims.utils.FieldInformation;
65
import org.gvsig.remoteclient.arcims.utils.GetFeaturesTags;
66
import org.gvsig.remoteclient.arcims.utils.ServiceInfoTags;
67
import org.gvsig.remoteclient.arcims.utils.ServiceInformation;
68
import org.gvsig.remoteclient.arcims.utils.ServiceInformationLayerFeatures;
69
import org.gvsig.remoteclient.utils.BoundaryBox;
70
import org.kxml2.io.KXmlParser;
71
import org.slf4j.Logger;
72
import org.slf4j.LoggerFactory;
73
import org.xmlpull.v1.XmlPullParserException;
74

    
75
/**
76
 * @author jsanz
77
 * @author vsanjaime version 2.0
78
 * 
79
 */
80
public class ArcImsProtFeatureHandler extends ArcImsProtocolHandler {
81
        private static boolean hasMore;
82
        private static int featCount;
83
        private static Logger logger = LoggerFactory
84
                        .getLogger(ArcImsProtFeatureHandler.class.getName());
85

    
86
        /**
87
         * Method to retrieve an ArrayList of features from an ArcIMS FeatureService
88
         * 
89
         * @param status
90
         * @return ArrayList of IFeatures with geometries and Id's to attribute
91
         *         table
92
         * @throws ArcImsException
93
         */
94
        public List<List<ArcImsFeature>> getMap(ArcImsVectStatus status)
95
                        throws ArcImsException {
96
                logger.info("Start getMap");
97

    
98
                List<List<ArcImsFeature>> array = new ArrayList<List<ArcImsFeature>>();
99

    
100
                try {
101
                        /*
102
                         * Build the request
103
                         */
104
                        URL url = new URL(buildCapabilitiesRequest(status));
105

    
106
                        hasMore = true;
107
                        featCount = 1;
108

    
109
                        while (hasMore) {
110
                                /*
111
                                 * Build the proper ArcXML
112
                                 */
113
                                String request = ArcXMLFeatures.getFeatureLayerRequest(status,
114
                                                featCount);
115

    
116
                                if (status.verbose) {
117
                                        System.err.println(request);
118
                                }
119

    
120
                                /*
121
                                 * Request the reader
122
                                 */
123
                                logger.info("Start features downloading");
124

    
125
                                File f = ArcImsDownloadUtils.doRequestPost(url, request,
126
                                                "getFeatures.xml");
127
                                logger.info("End features downloading");
128

    
129
                                /*
130
                                 * Parse response and add geometries to the general Array
131
                                 */
132
                                String layerId = (String) status.getLayersIdsSelected().get(0);
133

    
134
                                // Deal with UTF-8
135
                                Reader reader = null;
136
                                FileInputStream fis = new FileInputStream(f);
137
                                InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
138
                                BufferedReader br = new BufferedReader(isr);
139
                                reader = br;
140

    
141
                                logger.debug("Start features with attributes parsing");
142
                                List<ArcImsFeature> feats = this.getFeatures(reader, status
143
                                                .getServiceInfo(), layerId, status.getSubfields(), 1);
144
                                array.add(feats);
145
                                logger.debug("End features with attributes parsing");
146
                        }
147

    
148
                        hasMore = true;
149
                        featCount = 1;
150
                } catch (MalformedURLException e) {
151
                        logger.error(e.getMessage(), e);
152
                        throw new ArcImsException("arcims_server_error");
153
                } catch (FileNotFoundException e) {
154
                        logger.error(e.getMessage(), e);
155
                        throw new ArcImsException("arcims_server_error");
156
                } catch (UnsupportedEncodingException e) {
157
                        logger.error(e.getMessage(), e);
158
                }
159

    
160
                logger.debug("End getMap");
161

    
162
                return array;
163
        }
164

    
165
        /**
166
         * Parse the XML data retrieved from ArcIMS GET_FEATURES request to get a
167
         * set of Features if withGeometries is true or an ArrayList of Value[] if
168
         * this boolean is false
169
         * 
170
         * @param Reader
171
         *            Stream to parse
172
         * @param si
173
         *            ServiceInformation with metadata
174
         * @param layerId
175
         *            Layer retrieved
176
         * @param subfields
177
         *            Subfields retrieved
178
         * @param withGeometries
179
         *            Will geometries be parsed?: 0=no 1=yes 2=evelopes
180
         * @return ArrayList of IFeatures or Value[]
181
         * @throws ArcImsException
182
         */
183
        private List<ArcImsFeature> getFeatures(Reader lector,
184
                        ServiceInformation si, String layerId, String[] subfields,
185
                        int withGeometries) throws ArcImsException {
186

    
187
                // fill features map
188
                FieldInformation fi = null;
189

    
190
                ServiceInformationLayerFeatures sil = (ServiceInformationLayerFeatures) si
191
                                .getLayerById(layerId);
192

    
193
                /*
194
                 * Prepare a Value array to store every FEATURE tag information
195
                 */
196
                Vector<FieldInformation> fieldsInfo = sil.getFieldsInfo();
197

    
198
                // If flag == true, throw an Exception (no layerId found)
199
                if (fieldsInfo == null) {
200
                        throw new ArcImsException("arcims_no_features");
201
                }
202

    
203
                // We will store names and types in a hashmap
204
                List<FieldInformation> fieldsInfoA = new ArrayList<FieldInformation>();
205

    
206
                /*
207
                 * If subfields[0] is equal to #ALL we add the entire vector into the
208
                 * Hasmap
209
                 */
210
                if (subfields[0].equals("#ALL#")) {
211
                        for (int i = 0; i < fieldsInfo.size(); i++) {
212
                                fi = fieldsInfo.get(i);
213
                                fieldsInfoA.add(fi);
214
                        }
215
                } else {
216
                        for (int i = 0; i < subfields.length; i++) {
217
                                fi = null;
218
                                fi = sil.getFieldInformation(subfields[i]);
219

    
220
                                if (fi != null) {
221
                                        fieldsInfoA.add(fi);
222
                                }
223
                        }
224
                }
225

    
226
                /*
227
                 * Get the separators
228
                 */
229
                String delCoords = si.getSeparators().getCs();
230
                String delTuple = si.getSeparators().getTs();
231
                char delDec = si.getSeparators().getDs();
232

    
233
                /*
234
                 * ArrayList with features
235
                 */
236
                List<ArcImsFeature> features = new ArrayList<ArcImsFeature>();
237

    
238
                /*
239
                 * Start parsing
240
                 */
241
                int tag;
242
                KXmlParser kxmlParser = new KXmlParser();
243

    
244
                Geometry geom = null;
245
                Envelope envelope = null;
246
                // Object[] values = new Object[fieldsInfoA.size()];
247
                // Value[] values = new Value[fieldsInfoA.size()];
248
                int[] position = new int[fieldsInfoA.size()];
249

    
250
                // Initialize position array
251
                for (int i = 0; i < position.length; i++)
252
                        position[i] = -1;
253

    
254
                // long timeFeat = 0;
255
                // long timeGeom = 0;
256
                // long timeTemp = 0;
257
                try {
258
                        kxmlParser.setInput(lector);
259
                        kxmlParser.nextTag();
260

    
261
                        if (kxmlParser.getEventType() != KXmlParser.END_DOCUMENT) {
262
                                kxmlParser.require(KXmlParser.START_TAG, null,
263
                                                ServiceInfoTags.tARCXML);
264
                                tag = kxmlParser.nextTag();
265

    
266
                                while (tag != KXmlParser.END_DOCUMENT) {
267

    
268
                                        ArcImsFeature afeat = new ArcImsFeature();
269

    
270
                                        switch (tag) {
271
                                        case KXmlParser.START_TAG:
272

    
273
                                                if (kxmlParser.getName().compareTo(
274
                                                                GetFeaturesTags.FEATURE) == 0) {
275
                                                        /*
276
                                                         * parse FEATURES' tag
277
                                                         */
278

    
279
                                                        // FIRST ENVELOPE TAG (We hope that ENVELOPE will
280
                                                        // ALLWAYS be returned at first...)
281
                                                        if (withGeometries == 2) {
282
                                                                // timeTemp = System.currentTimeMillis();
283
                                                                envelope = parseEnvelopeFromFeatureTag(
284
                                                                                kxmlParser, delDec);
285

    
286
                                                        }
287

    
288
                                                        // SECOND FIELDS TAG
289
                                                        // timeTemp = System.currentTimeMillis();
290
                                                        afeat = parseValuesFromFeatureTag(kxmlParser, // the
291
                                                                        // kxml
292
                                                                        // parser
293
                                                                        fieldsInfoA, // Hashmap with names and
294
                                                                        // FieldInformation objects)
295
                                                                        delDec, // the separators
296
                                                                        position, // the relative positions of
297
                                                                        // returned values
298
                                                                        afeat);
299

    
300
                                                        // timeFeat += System.currentTimeMillis() -
301
                                                        // timeTemp;
302

    
303
                                                        // If geometries are neede we add to the ArrayList
304
                                                        // the Ifeature
305
                                                        if (withGeometries == 1) {
306
                                                                // THIRD GEOMETRIES
307
                                                                // timeTemp = System.currentTimeMillis();
308
                                                                geom = parseGeomFromFeatureTag(kxmlParser, // the
309
                                                                                // kxml
310
                                                                                // parser
311
                                                                                delTuple, delCoords, delDec // the
312
                                                                // separators
313

    
314
                                                                );
315
                                                                afeat.putGeometry(geom, envelope);
316

    
317
                                                                // timeGeom += System.currentTimeMillis() -
318
                                                                // timeTemp;
319
                                                        }
320

    
321
                                                        // // If some geometry is created, we add a IFeature
322
                                                        // // into features ArrayList
323
                                                        // if (withGeometries > 0) {
324
                                                        // features.add(new ArcImsFeature(geom, values));
325
                                                        // }
326
                                                        // // Else we only need the Value[] array
327
                                                        // else {
328
                                                        // features.add(new ArcImsFeature(values));
329
                                                        // }
330
                                                } else if (kxmlParser.getName().compareTo(
331
                                                                GetFeaturesTags.FEATURECOUNT) == 0) {
332
                                                        String value = new String();
333

    
334
                                                        // Get the feature count
335
                                                        value = kxmlParser.getAttributeValue("",
336
                                                                        GetFeaturesTags.COUNT);
337

    
338
                                                        Integer intFeatCount = new Integer(value);
339
                                                        featCount += intFeatCount.intValue();
340

    
341
                                                        // Get the hasmore boolean
342
                                                        value = kxmlParser.getAttributeValue("",
343
                                                                        GetFeaturesTags.HASMORE);
344

    
345
                                                        Boolean boHasMore = new Boolean(value);
346
                                                        hasMore = boHasMore.booleanValue();
347
                                                } else if (kxmlParser.getName().compareTo(
348
                                                                ServiceInfoTags.tERROR) == 0) {
349
                                                        logger.error("Error parsing GET_FEATURES:\r\n"
350
                                                                        + kxmlParser.nextText());
351
                                                        throw new ArcImsException("arcims_server_error");
352
                                                }
353

    
354
                                                break;
355

    
356
                                        case KXmlParser.END_TAG:
357
                                                break;
358

    
359
                                        case KXmlParser.TEXT:
360
                                                break;
361
                                        }
362
                                        if (afeat != null) {
363
                                                features.add(afeat);
364
                                        }
365
                                        tag = kxmlParser.next();
366
                                }
367

    
368
                                kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
369
                        }
370
                }
371

    
372
                catch (XmlPullParserException parser_ex) {
373
                        logger.error(parser_ex.getMessage(), parser_ex);
374
                        throw new ArcImsException("arcims_no_features");
375
                } catch (IOException ioe) {
376
                        logger.error(ioe.getMessage(), ioe);
377
                        throw new ArcImsException("arcims_no_features");
378
                } catch (CreateGeometryException e) {
379
                        logger.error(e.getMessage(), e);
380
                        throw new ArcImsException("arcims_no_features");
381
                }
382

    
383
                return features;
384

    
385
        }
386

    
387
        /**
388
         * Returns an IGeometry with a line between corners of an ENVELOPE
389
         * 
390
         * @param parser
391
         * @param delDec
392
         * @return
393
         * @throws XmlPullParserException
394
         * @throws IOException
395
         */
396
        private Envelope parseEnvelopeFromFeatureTag(KXmlParser parser, char delDec)
397
                        throws XmlPullParserException, IOException {
398
                int currentTag;
399
                boolean end = false;
400

    
401
                BoundaryBox bb = null;
402

    
403
                // parser.require(KXmlParser.START_TAG,null,GetFeaturesTags.FIELDS);
404
                currentTag = parser.next();
405

    
406
                while (!end) {
407
                        switch (currentTag) {
408
                        case KXmlParser.START_TAG:
409

    
410
                                if (parser.getName().equals(ServiceInfoTags.tENVELOPE)) {
411
                                        bb = super.parseEnvelope(parser, delDec);
412
                                        end = true;
413
                                }
414

    
415
                                break;
416

    
417
                        case KXmlParser.END_TAG:
418

    
419
                                if (parser.getName().equals(GetFeaturesTags.FIELDS)) {
420
                                        end = true;
421
                                }
422

    
423
                                break;
424

    
425
                        case KXmlParser.TEXT:
426
                                break;
427
                        }
428

    
429
                        if (!end) {
430
                                currentTag = parser.next();
431
                        }
432
                }
433

    
434
                // If BoundaryBox object has been created, we can convert it to Envelope
435

    
436
                if (bb != null) {
437
                        GeneralPathX polyline = new GeneralPathX(GeneralPathX.WIND_EVEN_ODD);
438

    
439
                        polyline.moveTo(bb.getXmin(), bb.getYmin());
440
                        polyline.lineTo(bb.getXmax(), bb.getYmax());
441

    
442
                        GeometryManager geomManager = GeometryLocator.getGeometryManager();
443
                        Envelope envelo = null;
444
                        try {
445
                                envelo = geomManager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
446
                                envelo.setLowerCorner(new Point2D(bb.getXmin(), bb.getYmin()));
447
                                envelo.setUpperCorner(new Point2D(bb.getXmax(), bb.getYmax()));
448
                        } catch (CreateEnvelopeException e) {
449
                                logger.error("Error creating curve", e);
450
                                return null;
451
                        }
452
                        return envelo;
453
                } else {
454
                        return null;
455
                }
456

    
457
        }
458

    
459
        /**
460
         * @param kxmlParser
461
         * @param fieldsInfoH
462
         * @param delDec
463
         * @param position
464
         * @return
465
         * @throws IOException
466
         * @throws XmlPullParserException
467
         * @throws IOException
468
         * @throws XmlPullParserException
469
         * @throws ArcImsException
470
         * @throws ArcImsException
471
         * @throws ParseException
472
         */
473
        private ArcImsFeature parseValuesFromFeatureTag(KXmlParser parser,
474
                        List<FieldInformation> fieldsInfoA, char delDec, int[] position,
475
                        ArcImsFeature afeat) throws XmlPullParserException, IOException,
476
                        ArcImsException {
477

    
478
                int currentTag;
479
                boolean end = false;
480
                int f = 0;
481
                String att;
482
                String text;
483
                int type;
484

    
485
                // Object[] values = new Object[fieldsInfoA.size()];
486

    
487
                currentTag = parser.next();
488

    
489
                while (!end) {
490
                        switch (currentTag) {
491
                        case KXmlParser.START_TAG:
492

    
493
                                if (parser.getName().equals(GetFeaturesTags.FIELD)) {
494
                                        att = parser.getAttributeValue("", GetFeaturesTags.NAME);
495
                                        text = parser.getAttributeValue("", GetFeaturesTags.VALUE);
496

    
497
                                        /*
498
                                         * As NAME is known, we need to get the position of that
499
                                         * attribute into the ArrayList of fieldInformation objects
500
                                         */
501
                                        if (position[f] == -1) {
502
                                                position[f] = getPosition(fieldsInfoA.iterator(), att);
503
                                        }
504

    
505
                                        if (position[f] == -1) {
506
                                                logger.error("Attribute not found at Metadata");
507
                                                throw new ArcImsException(
508
                                                                "Attribute not found at Metadata");
509
                                        }
510

    
511
                                        // This way we can create a NullValue
512
                                        if (text.equals("")) {
513
                                                text = null;
514
                                        }
515

    
516
                                        /*
517
                                         * At this point we know wat FieldInfo of the ArrayList we
518
                                         * have to retrieve
519
                                         */
520
                                        type = ((FieldInformation) fieldsInfoA.get(position[f]))
521
                                                        .getType();
522

    
523
                                        // Add the Value into the correct position
524
                                        if (text == null) {
525
                                                String fieldName = fieldsInfoA.get(position[f])
526
                                                                .getName();
527
                                                afeat.put(fieldName, null);
528
                                        } else {
529
                                                String fieldName = fieldsInfoA.get(position[f])
530
                                                                .getName();
531
                                                switch (type) {
532
                                                case FieldInformation.BOOLEAN:
533
                                                        afeat.put(fieldName, new Boolean(text));
534
                                                        f++;
535
                                                        break;
536
                                                case FieldInformation.SHAPE:
537
                                                case FieldInformation.STRING:
538
                                                        afeat.put(fieldName, new String(text));
539
                                                        f++;
540
                                                        break;
541
                                                case FieldInformation.DATE:
542
                                                        afeat
543
                                                                        .put(fieldName, new Date(Long
544
                                                                                        .parseLong(text)));
545
                                                        f++;
546
                                                        break;
547
                                                case FieldInformation.FLOAT:
548
                                                        String textfloat = text.replace(delDec, '.');
549
                                                        afeat.put(fieldName, new Float(textfloat));
550
                                                        f++;
551
                                                        break;
552
                                                case FieldInformation.DOUBLE:
553
                                                        String textdouble = text.replace(delDec, '.');
554
                                                        afeat.put(fieldName, new Double(textdouble));
555
                                                        f++;
556
                                                        break;
557
                                                case FieldInformation.SMALLINT:
558
                                                        afeat.put(fieldName, new Short(text));
559
                                                        f++;
560
                                                        break;
561
                                                case FieldInformation.BIGINT:
562
                                                        afeat.put(fieldName, new Long(text));
563
                                                        f++;
564
                                                        break;
565
                                                case FieldInformation.ID:
566
                                                        afeat.put(fieldName, new String(text));
567
                                                        afeat.setFieldPK(fieldName);
568
                                                        f++;
569
                                                        break;
570
                                                case FieldInformation.INTEGER:
571
                                                        afeat.put(fieldName, new Integer(text));
572
                                                        f++;
573
                                                        break;
574
                                                default:
575
                                                        afeat.put(fieldName, new String(text));
576
                                                        f++;
577
                                                }
578
                                        }
579
                                }
580

    
581
                                break;
582

    
583
                        case KXmlParser.END_TAG:
584

    
585
                                if (parser.getName().equals(GetFeaturesTags.FIELDS)) {
586
                                        end = true;
587
                                }
588

    
589
                                break;
590

    
591
                        case KXmlParser.TEXT:
592
                                break;
593
                        }
594

    
595
                        if (!end) {
596
                                currentTag = parser.next();
597
                        }
598
                }
599

    
600
                return afeat;
601

    
602
        }
603

    
604
        /**
605
         * Method to get the position of an attribute into the subfields array
606
         * 
607
         * @param fieldsInfoA
608
         * @param att
609
         * @return
610
         */
611
        private int getPosition(Iterator<FieldInformation> it, String att) {
612
                int res = 0;
613
                FieldInformation fi;
614

    
615
                while (it.hasNext()) {
616
                        fi = it.next();
617

    
618
                        if (fi.getName().equals(att)) {
619
                                return res;
620
                        }
621

    
622
                        res++;
623
                }
624

    
625
                // If no integer has returned at this point we return a -1
626
                return -1;
627
        }
628

    
629
        /**
630
         * Parses the Feature Tag to get a IFeature
631
         * 
632
         * @param KxmlParser
633
         *            with the FEATURE tag
634
         * @param Value
635
         *            array with the correct subtypes to store FIELDS data
636
         * @param String
637
         *            array with the correct fields names to retrieve
638
         * @param String
639
         *            with the tuple separator
640
         * @param String
641
         *            with the coordinates separator
642
         * @param Char
643
         *            with the decimal separator
644
         * @return @see com.hardcode.gdbms.engine.values.Value.IFeature
645
         * @throws IOException
646
         * @throws XmlPullParserException
647
         * @throws IOException
648
         * @throws XmlPullParserException
649
         * @throws CreateGeometryException
650
         * @throws ArcImsException
651
         * @throws CreateGeometryException
652
         * @throws ArcImsException
653
         */
654
        private Geometry parseGeomFromFeatureTag(KXmlParser parser,
655
                        String delTuple, String delCoords, char delDec)
656
                        throws XmlPullParserException, IOException,
657
                        CreateGeometryException, ArcImsException {
658

    
659
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
660
                int currentTag;
661
                boolean end = false;
662
                Geometry geom = null;
663
                currentTag = parser.next();
664

    
665
                while (!end) {
666
                        String featType = parser.getName();
667

    
668
                        switch (currentTag) {
669
                        case KXmlParser.START_TAG:
670
                                // //////////////////////////
671
                                // geometry type MULTIPOINT
672
                                // //////////////////////////
673
                                if (featType.equals(GetFeaturesTags.MULTIPOINT)) {
674
                                        // Go to COORDS tag
675
                                        parser.nextTag();
676

    
677
                                        if (parser.getName().equals(GetFeaturesTags.COORDS)) {
678
                                                // Create a tokenizer with the tuples
679
                                                String strPoints = parser.nextText();
680

    
681
                                                // Get the points from COORDS string
682
                                                List<Point> points = parseCoords(strPoints, delTuple,
683
                                                                delCoords, delDec);
684

    
685
                                                geom = geomManager.create(Geometry.TYPES.MULTIPOINT,
686
                                                                Geometry.SUBTYPES.GEOM2D);
687
                                                MultiPoint2D mpoint = (MultiPoint2D) geom;
688
                                                for (Point point : points) {
689
                                                        mpoint.addPoint(point);
690
                                                }
691
                                        } else {
692
                                                logger.error("Error parsing MULTIPOINT tag");
693
                                                throw new ArcImsException("arcims_features_error");
694
                                        }
695
                                }
696
                                // ////////////////////////////////////////////
697
                                // POLYLINE or POLYGON
698
                                // ////////////////////////////////////////////
699
                                else if (featType.equals(GetFeaturesTags.POLYLINE)
700
                                                || featType.equals(GetFeaturesTags.POLYGON)) {
701
                                        // Parse while parser doesn't found </FEATURES> tag
702
                                        // The GeneralPath to store the different paths
703
                                        GeneralPathX polyline = new GeneralPathX(
704
                                                        GeneralPathX.WIND_EVEN_ODD);
705
                                        boolean endpol = false;
706

    
707
                                        while (!endpol) {
708
                                                switch (currentTag) {
709
                                                case KXmlParser.START_TAG:
710

    
711
                                                        if (parser.getName().equals(GetFeaturesTags.COORDS)) {
712
                                                                // Create a tokenizer with the tuples
713
                                                                String strPoints = parser.nextText();
714

    
715
                                                                // Get the points (Point2D) from COORDS string
716
                                                                List<Point> points = parseCoords(strPoints,
717
                                                                                delTuple, delCoords, delDec);
718

    
719
                                                                Iterator<Point> it = points.iterator();
720
                                                                // First we MOVE to the first point of the path
721
                                                                Point point = it.next();
722
                                                                polyline.moveTo(point.getX(), point.getY());
723

    
724
                                                                // And now we can LINE to the rest of the points
725
                                                                // of the path
726
                                                                while (it.hasNext()) {
727
                                                                        Point pto = it.next();
728
                                                                        polyline.lineTo(pto.getX(), pto.getY());
729
                                                                }
730
                                                        }
731

    
732
                                                        break;
733

    
734
                                                case KXmlParser.END_TAG:
735

    
736
                                                        if (parser.getName().equals(featType)) {
737
                                                                endpol = true;
738
                                                        }
739

    
740
                                                        break;
741

    
742
                                                case KXmlParser.TEXT:
743
                                                        break;
744
                                                }
745

    
746
                                                if (!endpol) {
747
                                                        currentTag = parser.next();
748
                                                }
749
                                        }
750

    
751
                                        if (featType.equals(GetFeaturesTags.POLYLINE)) {
752
                                                geom = geomManager.createMultiCurve(polyline,
753
                                                                Geometry.SUBTYPES.GEOM2D);
754

    
755
                                        } else if (featType.equals(GetFeaturesTags.POLYGON)) {
756
                                                geom = geomManager.createMultiSurface(polyline,
757
                                                                Geometry.SUBTYPES.GEOM2D);
758
                                        }
759
                                }
760

    
761
                                break;
762

    
763
                        case KXmlParser.END_TAG:
764

    
765
                                if (parser.getName().compareTo(GetFeaturesTags.FEATURE) == 0) {
766
                                        end = true;
767
                                }
768

    
769
                                break;
770

    
771
                        case KXmlParser.TEXT:
772
                                break;
773
                        }
774

    
775
                        if (!end) {
776
                                currentTag = parser.next();
777
                        }
778
                }
779

    
780
                return geom;
781
        }
782

    
783
        /**
784
         * Private method that parses a COORDS tag to return an ArrayList of
785
         * Point2D.Double objects
786
         * 
787
         * @param strCoords
788
         * @param delTuple
789
         * @param delCoords
790
         * @param delDec
791
         * @return
792
         * @throws CreateGeometryException
793
         */
794
        private List<Point> parseCoords(String strCoords, String delTuple,
795
                        String delCoords, char delDec) throws CreateGeometryException {
796

    
797
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
798
                List<Point> points = new ArrayList<Point>();
799
                String tupla = new String();
800
                String[] tuplaPart;
801
                Double x;
802
                Double y;
803

    
804
                /*
805
                 * Replaces Decimal Separator to convert coords to suitable doubles.
806
                 * 
807
                 * Maybe it will have a better performance if we insert this replace
808
                 * into the while
809
                 */
810
                if (delDec != '.') {
811
                        strCoords = strCoords.replace(delDec, '.');
812
                }
813

    
814
                // Creates a tokenizer to run over the string
815
                StringTokenizer tuplas = new StringTokenizer(strCoords, delTuple, false);
816

    
817
                // Get ArrayLists collections with X's and Y's
818
                while (tuplas.hasMoreTokens()) {
819
                        // tupla = tuplas.nextToken().replace(delDec,'.');
820
                        tupla = tuplas.nextToken();
821
                        tuplaPart = tupla.split(delCoords);
822
                        x = new Double(tuplaPart[0]);
823
                        y = new Double(tuplaPart[1]);
824

    
825
                        Point pto = geomManager.createPoint(x.doubleValue(), y
826
                                        .doubleValue(), Geometry.SUBTYPES.GEOM2D);
827
                        points.add(pto);
828
                }
829

    
830
                // Return a list of Points
831
                return points;
832
        }
833

    
834
        /**
835
         * @param status
836
         * @return
837
         * @throws ArcImsException
838
         */
839
        public Rectangle2D getLayerExtent(ArcImsVectStatus status)
840
                        throws ArcImsException {
841
                Rectangle2D envelope = null;
842
                String layerId = (String) status.getLayersIdsSelected().get(0);
843

    
844
                // logger.info("Getting Vectorial Layer Extent (" + status.getl)
845
                ServiceInformation si = status.getServiceInfo();
846
                String ini_srs = ServiceInfoTags.vINI_SRS;
847

    
848
                String srsView = status.getSrs().substring(ini_srs.length()).trim();
849
                String srsServ = si.getFeaturecoordsys();
850
                boolean srsAssumed = si.isSrsAssumed();
851

    
852
                if (srsAssumed || (srsView.equals(srsServ))) {
853
                        BoundaryBox bb = si.getLayerById(layerId).getEnvelope();
854

    
855
                        /*
856
                         * At the end, we convert the BoundaryBox to a Rectangle2D
857
                         */
858
                        envelope = new Rectangle2D.Double();
859

    
860
                        envelope.setFrameFromDiagonal(bb.getXmin(), bb.getYmin(), bb
861
                                        .getXmax(), bb.getYmax());
862

    
863
                        return envelope;
864
                }
865

    
866
                /*
867
                 * If SRS of View and Service are different, we do a custom request to
868
                 * retrieve the global envelope of the layer
869
                 */
870
                try {
871
                        /*
872
                         * Build the request
873
                         */
874
                        URL url;
875
                        url = new URL(buildCapabilitiesRequest(status));
876

    
877
                        /*
878
                         * Build the proper ArcXML
879
                         */
880
                        String request = ArcXMLFeatures.getLayerExtentRequest(status);
881

    
882
                        if (status.verbose) {
883
                                System.err.println(request);
884
                        }
885

    
886
                        /*
887
                         * Request the envelope
888
                         */
889
                        File response;
890
                        response = ArcImsDownloadUtils.doRequestPost(url, request,
891
                                        "getLayerExtent.xml");
892

    
893
                        /*
894
                         * Parse response and return a Rectangle2D
895
                         */
896
                        char ds = si.getSeparators().getDs();
897
                        envelope = parseEnvelopeTag(new FileReader(response), ds);
898
                } catch (MalformedURLException e) {
899
                        logger.error(e.getMessage(), e);
900
                        throw new ArcImsException("arcims_server_error");
901
                } catch (FileNotFoundException e) {
902
                        logger.error(e.getMessage(), e);
903
                        throw new ArcImsException("arcims_server_error");
904
                }
905

    
906
                return envelope;
907
        }
908

    
909
        /**
910
         * Retrieves an ArrayList of Value arrays. The query can be filtered by a
911
         * WHERE clause or an envelope. Only subfields passed will be retrieved
912
         * 
913
         * @param status
914
         * @param subfields
915
         * @param where
916
         * @param envelope
917
         * @return
918
         * @throws ArcImsException
919
         */
920
        public List<List<ArcImsFeature>> getAttributes(ArcImsVectStatus status,
921
                        String[] subfields, String where, Rectangle2D envelope)
922
                        throws ArcImsException {
923

    
924
                logger.info("Start getAttributes");
925

    
926
                List<List<ArcImsFeature>> features = new ArrayList<List<ArcImsFeature>>();
927

    
928
                // Clone the status and set temporal subfields and where clause
929
                ArcImsVectStatus statusCloned = status;
930

    
931
                String[] subTemp = status.getSubfields();
932
                String whereTemp = status.getWhere();
933
                Rectangle2D rectTemp = status.getEnvelopeRect();
934

    
935
                statusCloned.setSubfields(subfields);
936
                statusCloned.setWhere(where);
937
                statusCloned.setEnvelope(envelope);
938

    
939
                try {
940
                        /*
941
                         * Build the request
942
                         */
943
                        URL url;
944
                        url = new URL(buildCapabilitiesRequest(statusCloned));
945

    
946
                        hasMore = true;
947
                        featCount = 0;
948

    
949
                        while (hasMore) {
950
                                /*
951
                                 * Build the proper ArcXML
952
                                 */
953
                                String request = ArcXMLFeatures.getAttributesRequest(
954
                                                statusCloned, featCount);
955

    
956
                                if (status.verbose) {
957
                                        System.err.println(request);
958
                                }
959

    
960
                                // The attributes come from ArcIMS in ASCII/cp1252 encoding
961
                                boolean withUTF = false;
962

    
963
                                // Don't download the file, pass the data directly from the
964
                                // connection
965
                                boolean withFile = false;
966

    
967
                                /*
968
                                 * Get an InputStream from File or directly from the connection
969
                                 */
970
                                InputStream is = null;
971

    
972
                                if (withFile) {
973
                                        File f = ArcImsDownloadUtils.doRequestPost(url, request,
974
                                                        "getAttributes.xml");
975

    
976
                                        try {
977
                                                is = new FileInputStream(f);
978
                                        } catch (FileNotFoundException e) {
979
                                                logger.error(e.getMessage(), e);
980
                                        }
981
                                } else {
982
                                        is = ArcImsDownloadUtils.getRemoteIS(url, request);
983
                                }
984

    
985
                                InputStreamReader isr = null;
986

    
987
                                if (withUTF) {
988
                                        // Deal with UTF-8
989
                                        try {
990
                                                isr = new InputStreamReader(is, "UTF-8");
991
                                        } catch (UnsupportedEncodingException e) {
992
                                                logger.error(e.getMessage(), e);
993
                                        }
994
                                } else {
995
                                        // No deal with UTF-8
996
                                        isr = new InputStreamReader(is);
997
                                }
998

    
999
                                /*
1000
                                 * Finally, we can create a BufferedReader from the
1001
                                 * InputStreamReader
1002
                                 */
1003
                                BufferedReader br = new BufferedReader(isr);
1004

    
1005
                                /*
1006
                                 * Parse response and return a Rectangle2D
1007
                                 */
1008
                                String layerId = (String) statusCloned.getLayersIdsSelected()
1009
                                                .get(0);
1010
                                logger.debug("Start attributes downloading and parsing ("
1011
                                                + featCount + ") ids retrieved");
1012
                                features.add(getFeatures(br, statusCloned.getServiceInfo(),
1013
                                                layerId, statusCloned.getSubfields(), 0));
1014
                                logger.debug("End attributes downloading and parsing");
1015
                        }
1016

    
1017
                        hasMore = true;
1018
                        featCount = 0;
1019
                } catch (MalformedURLException e) {
1020
                        logger.error(e.getMessage(), e);
1021
                        throw new ArcImsException("arcims_server_error");
1022
                } catch (ArcImsException e) {
1023
                        logger.error(e.getMessage(), e);
1024
                        throw new ArcImsException("arcims_server_error");
1025
                } finally {
1026
                        status.setSubfields(subTemp);
1027
                        status.setWhere(whereTemp);
1028
                        status.setEnvelope(rectTemp);
1029
                }
1030

    
1031
                logger.debug("End attributes retrieving");
1032

    
1033
                return features;
1034
        }
1035

    
1036
        /**
1037
         * Retrieves an ArrayList of I by some IDs. The geometry returned is the
1038
         * envelope of the feature requested. The query can be filtered by a WHERE
1039
         * clause or an envelope. Only subfields passed will be retrieved
1040
         * 
1041
         * @param status
1042
         * @param subfields
1043
         * @param where
1044
         * @param envelope
1045
         * @return
1046
         * @throws ArcImsException
1047
         */
1048
        public List<List<ArcImsFeature>> getAttributesWithEnvelope(
1049
                        ArcImsVectStatus status, String[] subfields, String where,
1050
                        Rectangle2D envelope) throws ArcImsException {
1051

    
1052
                logger.info("Start getAttributesWihtEnvelope");
1053

    
1054
                List<List<ArcImsFeature>> features = new ArrayList<List<ArcImsFeature>>();
1055

    
1056
                // Clone the status and set temporal subfields and where clause
1057
                ArcImsVectStatus statusCloned = status;
1058

    
1059
                String[] subTemp = status.getSubfields();
1060
                String whereTemp = status.getWhere();
1061
                Rectangle2D rectTemp = status.getEnvelopeRect();
1062

    
1063
                statusCloned.setSubfields(subfields);
1064
                statusCloned.setWhere(where);
1065
                statusCloned.setEnvelope(envelope);
1066

    
1067
                try {
1068
                        /*
1069
                         * Build the request
1070
                         */
1071
                        URL url;
1072
                        url = new URL(buildCapabilitiesRequest(statusCloned));
1073

    
1074
                        hasMore = true;
1075
                        featCount = 0;
1076

    
1077
                        while (hasMore) {
1078
                                /*
1079
                                 * Build the proper ArcXML
1080
                                 */
1081
                                String request = ArcXMLFeatures.getAttributesRequest(
1082
                                                statusCloned, featCount);
1083

    
1084
                                if (status.verbose) {
1085
                                        System.err.println(request);
1086
                                }
1087

    
1088
                                // The attributes come from ArcIMS in ASCII/cp1252 encoding
1089
                                boolean withUTF = false;
1090

    
1091
                                // Don't download the file, pass the data directly from the
1092
                                // connection
1093
                                boolean withFile = false;
1094

    
1095
                                /*
1096
                                 * Get an InputStream from File or directly from the connection
1097
                                 */
1098
                                InputStream is = null;
1099

    
1100
                                if (withFile) {
1101
                                        File f = ArcImsDownloadUtils.doRequestPost(url, request,
1102
                                                        "getAttributes.xml");
1103

    
1104
                                        try {
1105
                                                is = new FileInputStream(f);
1106
                                        } catch (FileNotFoundException e) {
1107
                                                logger.error(e.getMessage(), e);
1108
                                        }
1109
                                } else {
1110
                                        is = ArcImsDownloadUtils.getRemoteIS(url, request);
1111
                                }
1112

    
1113
                                InputStreamReader isr = null;
1114

    
1115
                                if (withUTF) {
1116
                                        // Deal with UTF-8
1117
                                        try {
1118
                                                isr = new InputStreamReader(is, "UTF-8");
1119
                                        } catch (UnsupportedEncodingException e) {
1120
                                                logger.error(e.getMessage(), e);
1121
                                        }
1122
                                } else {
1123
                                        // No deal with UTF-8
1124
                                        isr = new InputStreamReader(is);
1125
                                }
1126

    
1127
                                /*
1128
                                 * Finally, we can create a BufferedReader from the
1129
                                 * InputStreamReader
1130
                                 */
1131
                                BufferedReader br = new BufferedReader(isr);
1132

    
1133
                                /*
1134
                                 * Parse response and return a Rectangle2D
1135
                                 */
1136
                                String layerId = (String) statusCloned.getLayersIdsSelected()
1137
                                                .get(0);
1138
                                logger.debug("Start attributes downloading and parsing ("
1139
                                                + featCount + ") ids retrieved");
1140
                                features.add(getFeatures(br, statusCloned.getServiceInfo(),
1141
                                                layerId, statusCloned.getSubfields(), 2)); // Here we
1142
                                // request
1143
                                // envelopes instead
1144
                                // of geometries
1145
                                logger.debug("End attributes downloading and parsing");
1146
                        }
1147

    
1148
                        hasMore = true;
1149
                        featCount = 0;
1150
                } catch (MalformedURLException e) {
1151
                        logger.error(e.getMessage(), e);
1152
                        throw new ArcImsException("arcims_server_error");
1153
                } catch (ArcImsException e) {
1154
                        logger.error(e.getMessage(), e);
1155
                        throw new ArcImsException("arcims_server_error");
1156
                } finally {
1157
                        status.setSubfields(subTemp);
1158
                        status.setWhere(whereTemp);
1159
                        status.setEnvelope(rectTemp);
1160
                }
1161

    
1162
                logger.debug("End attributes retrieving");
1163

    
1164
                return features;
1165
        }
1166

    
1167
        /*
1168
         * (non-Javadoc)
1169
         * 
1170
         * @see
1171
         * org.gvsig.remoteClient.arcims.ArcImsProtocolHandler#getElementInfo(org
1172
         * .gvsig.remoteClient.arcims.ArcImsStatus, int, int, int)
1173
         */
1174
        public String getElementInfo(ArcImsStatus status, int x, int y,
1175
                        int featureCount) throws ArcImsException {
1176
                throw new ClassCastException(
1177
                                "Invalid request, this method is only valid for Image Services");
1178
        }
1179
        
1180
        
1181
        
1182
        /**
1183
         * Method to retrieve an ArrayList of features from an ArcIMS FeatureService
1184
         * 
1185
         * @param status
1186
         * @return ArrayList of IFeatures with geometries and Id's to attribute
1187
         *         table
1188
         * @throws ArcImsException
1189
         */
1190
        public List<ArcImsFeature> getFeaturesByEnvelope(ArcImsVectStatus status, String layerId)
1191
                        throws ArcImsException {
1192
                logger.info("Start getMap");
1193

    
1194
                List<ArcImsFeature> feats = new ArrayList<ArcImsFeature>();
1195

    
1196
                try {
1197
                        /*
1198
                         * Build the request
1199
                         */
1200
                        URL url = new URL(buildCapabilitiesRequest(status));
1201

    
1202
                        hasMore = true;
1203
                        featCount = 1;
1204

    
1205
                        while (hasMore) {
1206
                                /*
1207
                                 * Build the proper ArcXML
1208
                                 */
1209
                                String request = ArcXMLFeatures.getFeaturesExtentRequest(status, featCount, layerId);
1210

    
1211
                                if (status.verbose) {
1212
                                        System.err.println(request);
1213
                                }
1214

    
1215
                                /*
1216
                                 * Request the reader
1217
                                 */
1218
                                logger.info("Start features downloading");
1219

    
1220
                                File f = ArcImsDownloadUtils.doRequestPost(url, request,
1221
                                                "getFeaturesEnvelope.xml");
1222
                                logger.info("End features downloading by envelope");                        
1223
                                
1224

    
1225
                                // Deal with UTF-8
1226
                                Reader reader = null;
1227
                                FileInputStream fis = new FileInputStream(f);
1228
                                InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
1229
                                BufferedReader br = new BufferedReader(isr);
1230
                                reader = br;
1231

    
1232
                                logger.debug("Start features with attributes parsing");
1233
                                feats = this.getFeatures(reader, status
1234
                                                .getServiceInfo(), layerId, status.getSubfields(), 1);
1235
                                
1236
                                logger.debug("End features with attributes parsing");
1237
                        }
1238

    
1239
                        hasMore = true;
1240
                        featCount = 1;
1241
                } catch (MalformedURLException e) {
1242
                        logger.error(e.getMessage(), e);
1243
                        throw new ArcImsException("arcims_server_error");
1244
                } catch (FileNotFoundException e) {
1245
                        logger.error(e.getMessage(), e);
1246
                        throw new ArcImsException("arcims_server_error");
1247
                } catch (UnsupportedEncodingException e) {
1248
                        logger.error(e.getMessage(), e);
1249
                }
1250

    
1251
                logger.debug("End getMap");
1252

    
1253
                return feats;
1254
        }
1255
}