Statistics
| Revision:

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

History | View | Annotate | Download (30.6 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.CreateGeometryException;
56
import org.gvsig.fmap.geom.primitive.GeneralPathX;
57
import org.gvsig.fmap.geom.primitive.Point;
58
import org.gvsig.remoteclient.arcims.exceptions.ArcImsException;
59
import org.gvsig.remoteclient.arcims.utils.ArcImsDownloadUtils;
60
import org.gvsig.remoteclient.arcims.utils.ArcImsFeature;
61
import org.gvsig.remoteclient.arcims.utils.FieldInformation;
62
import org.gvsig.remoteclient.arcims.utils.GetFeaturesTags;
63
import org.gvsig.remoteclient.arcims.utils.ServiceInfoTags;
64
import org.gvsig.remoteclient.arcims.utils.ServiceInformation;
65
import org.gvsig.remoteclient.arcims.utils.ServiceInformationLayerFeatures;
66
import org.gvsig.remoteclient.utils.BoundaryBox;
67
import org.kxml2.io.KXmlParser;
68
import org.slf4j.Logger;
69
import org.slf4j.LoggerFactory;
70
import org.xmlpull.v1.XmlPullParserException;
71

    
72
/**
73
 * @author jsanz
74
 * 
75
 */
76
public class ArcImsProtFeatureHandler extends ArcImsProtocolHandler {
77
        private static boolean hasMore;
78
        private static int featCount;
79
        private static Logger logger = LoggerFactory
80
                        .getLogger(ArcImsProtFeatureHandler.class.getName());
81

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

    
94
                List<List<ArcImsFeature>> array = new ArrayList<List<ArcImsFeature>>();
95

    
96
                try {
97
                        /*
98
                         * Build the request
99
                         */
100
                        URL url = new URL(buildCapabilitiesRequest(status));
101

    
102
                        hasMore = true;
103
                        featCount = 1;
104

    
105
                        while (hasMore) {
106
                                /*
107
                                 * Build the proper ArcXML
108
                                 */
109
                                String request = ArcXMLFeatures.getFeatureLayerRequest(status,
110
                                                featCount);
111

    
112
                                if (status.verbose) {
113
                                        System.err.println(request);
114
                                }
115

    
116
                                /*
117
                                 * Request the reader
118
                                 */
119
                                logger.info("Start features downloading");
120

    
121
                                File f = ArcImsDownloadUtils.doRequestPost(url, request,
122
                                                "getFeatures.xml");
123
                                logger.info("End features downloading");
124

    
125
                                /*
126
                                 * Parse response and add geometries to the general Array
127
                                 */
128
                                String layerId = (String) status.getLayersIdsSelected().get(0);
129

    
130
                                // Deal with UTF-8
131
                                Reader reader = null;
132
                                FileInputStream fis = new FileInputStream(f);
133
                                InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
134
                                BufferedReader br = new BufferedReader(isr);
135
                                reader = br;
136

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

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

    
156
                logger.debug("End getMap");
157

    
158
                return array;
159
        }
160

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

    
183
                // fill features map
184
                FieldInformation fi = null;
185
                ServiceInformationLayerFeatures sil = (ServiceInformationLayerFeatures) si
186
                                .getLayerById(layerId);
187

    
188
                /*
189
                 * Prepare a Value array to store every FEATURE tag information
190
                 */
191
                Vector<FieldInformation> fieldsInfo = sil.getFieldsInfo();
192

    
193
                // If flag == true, throw an Exception (no layerId found)
194
                if (fieldsInfo == null) {
195
                        throw new ArcImsException("arcims_no_features");
196
                }
197

    
198
                // We will store names and types in a hashmap
199
                List<FieldInformation> fieldsInfoA = new ArrayList<FieldInformation>();
200

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

    
215
                                if (fi != null) {
216
                                        fieldsInfoA.add(fi);
217
                                }
218
                        }
219
                }
220

    
221
                /*
222
                 * Get the separators
223
                 */
224
                String delCoords = si.getSeparators().getCs();
225
                String delTuple = si.getSeparators().getTs();
226
                char delDec = si.getSeparators().getDs();
227

    
228
                /*
229
                 * ArrayList with features
230
                 */
231
                List<ArcImsFeature> features = new ArrayList<ArcImsFeature>();
232

    
233
                /*
234
                 * Start parsing
235
                 */
236
                int tag;
237
                KXmlParser kxmlParser = new KXmlParser();
238

    
239
                Geometry geom = null;
240
                //Object[] values = new Object[fieldsInfoA.size()];
241
                // Value[] values = new Value[fieldsInfoA.size()];
242
                int[] position = new int[fieldsInfoA.size()];
243

    
244
                // Initialize position array
245
                for (int i = 0; i < position.length; i++)
246
                        position[i] = -1;
247

    
248
                // long timeFeat = 0;
249
                // long timeGeom = 0;
250
                // long timeTemp = 0;
251
                try {
252
                        kxmlParser.setInput(lector);
253
                        kxmlParser.nextTag();
254

    
255
                        if (kxmlParser.getEventType() != KXmlParser.END_DOCUMENT) {
256
                                kxmlParser.require(KXmlParser.START_TAG, null,
257
                                                ServiceInfoTags.tARCXML);
258
                                tag = kxmlParser.nextTag();
259

    
260
                                while (tag != KXmlParser.END_DOCUMENT) {
261
                                        
262
                                        ArcImsFeature afeat = new ArcImsFeature();
263
                                        
264
                                        switch (tag) {
265
                                        case KXmlParser.START_TAG:
266

    
267
                                                if (kxmlParser.getName().compareTo(
268
                                                                GetFeaturesTags.FEATURE) == 0) {
269
                                                        /*
270
                                                         * parse FEATURES' tag
271
                                                         */
272

    
273
                                                        // FIRST ENVELOPE TAG (We hope that ENVELOPE will
274
                                                        // ALLWAYS be returned at first...)
275
                                                        if (withGeometries == 2) {
276
                                                                // timeTemp = System.currentTimeMillis();
277
                                                                geom = parseEnvelopeFromFeatureTag(kxmlParser,
278
                                                                                delDec);
279
                                                                afeat.putGeometry(geom);
280
                                                        }
281

    
282
                                                        // SECOND FIELDS TAG
283
                                                        // timeTemp = System.currentTimeMillis();
284
                                                        afeat = parseValuesFromFeatureTag(kxmlParser, // the
285
                                                                        // kxml
286
                                                                        // parser
287
                                                                        fieldsInfoA, // Hashmap with names and
288
                                                                        // FieldInformation objects)
289
                                                                        delDec, // the separators
290
                                                                        position, // the relative positions of
291
                                                        // returned values
292
                                                                        afeat
293
                                                        );
294

    
295
                                                        // timeFeat += System.currentTimeMillis() -
296
                                                        // timeTemp;
297

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

    
312
                                                                // timeGeom += System.currentTimeMillis() -
313
                                                                // timeTemp;
314
                                                        }
315

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

    
329
                                                        // Get the feature count
330
                                                        value = kxmlParser.getAttributeValue("",
331
                                                                        GetFeaturesTags.COUNT);
332

    
333
                                                        Integer intFeatCount = new Integer(value);
334
                                                        featCount += intFeatCount.intValue();
335

    
336
                                                        // Get the hasmore boolean
337
                                                        value = kxmlParser.getAttributeValue("",
338
                                                                        GetFeaturesTags.HASMORE);
339

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

    
349
                                                break;
350

    
351
                                        case KXmlParser.END_TAG:
352
                                                break;
353

    
354
                                        case KXmlParser.TEXT:
355
                                                break;
356
                                        }
357
                                        if(afeat != null){
358
                                                features.add(afeat);
359
                                        }
360
                                        tag = kxmlParser.next();
361
                                }
362

    
363
                                kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
364
                        }
365
                }
366

    
367
                catch (XmlPullParserException parser_ex) {
368
                        logger.error(parser_ex.getMessage(), parser_ex);
369
                        throw new ArcImsException("arcims_no_features");
370
                } catch (IOException ioe) {
371
                        logger.error(ioe.getMessage(), ioe);
372
                        throw new ArcImsException("arcims_no_features");
373
                } catch (CreateGeometryException e) {
374
                        logger.error(e.getMessage(), e);
375
                        throw new ArcImsException("arcims_no_features");
376
                }
377

    
378
                return features;
379

    
380
        }
381

    
382
        /**
383
         * Returns an IGeometry with a line between corners of an ENVELOPE
384
         * 
385
         * @param parser
386
         * @param delDec
387
         * @return
388
         * @throws XmlPullParserException
389
         * @throws IOException
390
         */
391
        private Geometry parseEnvelopeFromFeatureTag(KXmlParser parser, char delDec)
392
                        throws XmlPullParserException, IOException {
393
                int currentTag;
394
                boolean end = false;
395

    
396
                BoundaryBox bb = null;
397

    
398
                // parser.require(KXmlParser.START_TAG,null,GetFeaturesTags.FIELDS);
399
                currentTag = parser.next();
400

    
401
                while (!end) {
402
                        switch (currentTag) {
403
                        case KXmlParser.START_TAG:
404

    
405
                                if (parser.getName().equals(ServiceInfoTags.tENVELOPE)) {
406
                                        bb = super.parseEnvelope(parser, delDec);
407
                                        end = true;
408
                                }
409

    
410
                                break;
411

    
412
                        case KXmlParser.END_TAG:
413

    
414
                                if (parser.getName().equals(GetFeaturesTags.FIELDS)) {
415
                                        end = true;
416
                                }
417

    
418
                                break;
419

    
420
                        case KXmlParser.TEXT:
421
                                break;
422
                        }
423

    
424
                        if (!end) {
425
                                currentTag = parser.next();
426
                        }
427
                }
428

    
429
                // If BoundaryBox object has been created, we can convert it into a
430
                // IGeometry (polyline).
431
                if (bb != null) {
432
                        GeneralPathX polyline = new GeneralPathX(GeneralPathX.WIND_EVEN_ODD);
433

    
434
                        polyline.moveTo(bb.getXmin(), bb.getYmin());
435
                        polyline.lineTo(bb.getXmax(), bb.getYmax());
436

    
437
                        GeometryManager geomManager = GeometryLocator.getGeometryManager();
438
                        Geometry curve = null;
439
                        try {
440
                                curve = geomManager.createCurve(polyline,
441
                                                Geometry.SUBTYPES.GEOM2D);
442
                        } catch (CreateGeometryException e) {
443
                                logger.error("Error creating curve", e);
444
                                return null;
445
                        }
446
                        return curve;
447
                } else {
448
                        return null;
449
                }
450

    
451
        }
452

    
453
        /**
454
         * @param kxmlParser
455
         * @param fieldsInfoH
456
         * @param delDec
457
         * @param position
458
         * @return
459
         * @throws IOException
460
         * @throws XmlPullParserException
461
         * @throws IOException
462
         * @throws XmlPullParserException
463
         * @throws ArcImsException
464
         * @throws ArcImsException
465
         * @throws ParseException
466
         */
467
        private ArcImsFeature parseValuesFromFeatureTag(KXmlParser parser,
468
                        List<FieldInformation> fieldsInfoA, char delDec, int[] position, ArcImsFeature afeat )
469
                        throws XmlPullParserException, IOException, ArcImsException {
470

    
471
                int currentTag;
472
                boolean end = false;
473
                int f = 0;
474
                String att;
475
                String text;
476
                int type;
477

    
478
                //Object[] values = new Object[fieldsInfoA.size()];
479

    
480
                currentTag = parser.next();
481

    
482
                while (!end) {
483
                        switch (currentTag) {
484
                        case KXmlParser.START_TAG:
485

    
486
                                if (parser.getName().equals(GetFeaturesTags.FIELD)) {
487
                                        att = parser.getAttributeValue("", GetFeaturesTags.NAME);
488
                                        text = parser.getAttributeValue("", GetFeaturesTags.VALUE);
489

    
490
                                        /*
491
                                         * As NAME is known, we need to get the position of that
492
                                         * attribute into the ArrayList of fieldInformation objects
493
                                         */
494
                                        if (position[f] == -1) {
495
                                                position[f] = getPosition(fieldsInfoA.iterator(), att);                                                
496
                                        }
497

    
498
                                        if (position[f] == -1) {
499
                                                logger.error("Attribute not found at Metadata");
500
                                                throw new ArcImsException(
501
                                                                "Attribute not found at Metadata");
502
                                        }
503

    
504
                                        // This way we can create a NullValue
505
                                        if (text.equals("")) {
506
                                                text = null;
507
                                        }
508

    
509
                                        /*
510
                                         * At this point we know wat FieldInfo of the ArrayList we
511
                                         * have to retrieve
512
                                         */
513
                                        type = ((FieldInformation) fieldsInfoA.get(position[f]))
514
                                                        .getType();
515

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

    
570
                                break;
571

    
572
                        case KXmlParser.END_TAG:
573

    
574
                                if (parser.getName().equals(GetFeaturesTags.FIELDS)) {
575
                                        end = true;
576
                                }
577

    
578
                                break;
579

    
580
                        case KXmlParser.TEXT:
581
                                break;
582
                        }
583

    
584
                        if (!end) {
585
                                currentTag = parser.next();
586
                        }
587
                }
588

    
589
                return afeat;
590

    
591
        }
592

    
593
        /**
594
         * Method to get the position of an attribute into the subfields array
595
         * 
596
         * @param fieldsInfoA
597
         * @param att
598
         * @return
599
         */
600
        private int getPosition(Iterator it, String att) {
601
                int res = 0;
602
                FieldInformation fi;
603

    
604
                while (it.hasNext()) {
605
                        fi = (FieldInformation) it.next();
606

    
607
                        if (fi.getName().equals(att)) {
608
                                return res;
609
                        }
610

    
611
                        res++;
612
                }
613

    
614
                // If no integer has returned at this point we return a -1
615
                return -1;
616
        }
617

    
618
        /**
619
         * Parses the Feature Tag to get a IFeature
620
         * 
621
         * @param KxmlParser
622
         *            with the FEATURE tag
623
         * @param Value
624
         *            array with the correct subtypes to store FIELDS data
625
         * @param String
626
         *            array with the correct fields names to retrieve
627
         * @param String
628
         *            with the tuple separator
629
         * @param String
630
         *            with the coordinates separator
631
         * @param Char
632
         *            with the decimal separator
633
         * @return @see com.hardcode.gdbms.engine.values.Value.IFeature
634
         * @throws IOException
635
         * @throws XmlPullParserException
636
         * @throws IOException
637
         * @throws XmlPullParserException
638
         * @throws CreateGeometryException
639
         * @throws ArcImsException
640
         * @throws CreateGeometryException
641
         * @throws ArcImsException
642
         */
643
        private Geometry parseGeomFromFeatureTag(KXmlParser parser,
644
                        String delTuple, String delCoords, char delDec)
645
                        throws XmlPullParserException, IOException,
646
                        CreateGeometryException, ArcImsException {
647

    
648
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
649
                int currentTag;
650
                boolean end = false;
651
                Geometry geom = null;
652
                currentTag = parser.next();
653

    
654
                while (!end) {
655
                        String featType = parser.getName();
656

    
657
                        switch (currentTag) {
658
                        case KXmlParser.START_TAG:
659
                                // //////////////////////////
660
                                // geometry type MULTIPOINT
661
                                // //////////////////////////
662
                                if (featType.equals(GetFeaturesTags.MULTIPOINT)) {
663
                                        // Go to COORDS tag
664
                                        parser.nextTag();
665

    
666
                                        if (parser.getName().equals(GetFeaturesTags.COORDS)) {
667
                                                // Create a tokenizer with the tuples
668
                                                String strPoints = parser.nextText();
669

    
670
                                                // Get the points from COORDS string
671
                                                List<Point> points = parseCoords(strPoints, delTuple,
672
                                                                delCoords, delDec);
673

    
674
                                                geom = geomManager.create(Geometry.TYPES.MULTIPOINT,
675
                                                                Geometry.SUBTYPES.GEOM2D);
676
                                                MultiPoint2D mpoint = (MultiPoint2D) geom;
677
                                                for (Point point : points) {
678
                                                        mpoint.addPoint(point);
679
                                                }
680
                                        } else {
681
                                                logger.error("Error parsing MULTIPOINT tag");
682
                                                throw new ArcImsException("arcims_features_error");
683
                                        }
684
                                }
685
                                // ////////////////////////////////////////////
686
                                // POLYLINE or POLYGON
687
                                // ////////////////////////////////////////////
688
                                else if (featType.equals(GetFeaturesTags.POLYLINE)
689
                                                || featType.equals(GetFeaturesTags.POLYGON)) {
690
                                        // Parse while parser doesn't found </FEATURES> tag
691
                                        // The GeneralPath to store the different paths
692
                                        GeneralPathX polyline = new GeneralPathX(
693
                                                        GeneralPathX.WIND_EVEN_ODD);
694
                                        boolean endpol = false;
695

    
696
                                        while (!endpol) {
697
                                                switch (currentTag) {
698
                                                case KXmlParser.START_TAG:
699

    
700
                                                        if (parser.getName().equals(GetFeaturesTags.COORDS)) {
701
                                                                // Create a tokenizer with the tuples
702
                                                                String strPoints = parser.nextText();
703

    
704
                                                                // Get the points (Point2D) from COORDS string
705
                                                                List<Point> points = parseCoords(strPoints,
706
                                                                                delTuple, delCoords, delDec);
707

    
708
                                                                Iterator<Point> it = points.iterator();
709
                                                                Point point;
710

    
711
                                                                // First we MOVE to the first point of the path
712
                                                                point = (Point) it.next();
713
                                                                polyline.moveTo(point.getX(), point.getY());
714

    
715
                                                                // And now we can LINE to the rest of the points
716
                                                                // of the path
717
                                                                while (it.hasNext()) {
718
                                                                        point = (Point) it.next();
719
                                                                        polyline.lineTo(point.getX(), point.getY());
720
                                                                }
721
                                                        }
722

    
723
                                                        break;
724

    
725
                                                case KXmlParser.END_TAG:
726

    
727
                                                        if (parser.getName().equals(featType)) {
728
                                                                endpol = true;
729
                                                        }
730

    
731
                                                        break;
732

    
733
                                                case KXmlParser.TEXT:
734
                                                        break;
735
                                                }
736

    
737
                                                if (!endpol) {
738
                                                        currentTag = parser.next();
739
                                                }
740
                                        }
741

    
742
                                        if (featType.equals(GetFeaturesTags.POLYLINE)) {
743
                                                geom = geomManager.createMultiCurve(polyline,
744
                                                                Geometry.SUBTYPES.GEOM2D);
745
                                        } else if (featType.equals(GetFeaturesTags.POLYGON)) {
746
                                                geom = geomManager.createMultiSurface(polyline,
747
                                                                Geometry.SUBTYPES.GEOM2D);
748
                                        }
749
                                }
750

    
751
                                break;
752

    
753
                        case KXmlParser.END_TAG:
754

    
755
                                if (parser.getName().compareTo(GetFeaturesTags.FEATURE) == 0) {
756
                                        end = true;
757
                                }
758

    
759
                                break;
760

    
761
                        case KXmlParser.TEXT:
762
                                break;
763
                        }
764

    
765
                        if (!end) {
766
                                currentTag = parser.next();
767
                        }
768
                }
769

    
770
                return geom;
771
        }
772

    
773
        /**
774
         * Private method that parses a COORDS tag to return an ArrayList of
775
         * Point2D.Double objects
776
         * 
777
         * @param strCoords
778
         * @param delTuple
779
         * @param delCoords
780
         * @param delDec
781
         * @return
782
         * @throws CreateGeometryException
783
         */
784
        private List<Point> parseCoords(String strCoords, String delTuple,
785
                        String delCoords, char delDec) throws CreateGeometryException {
786

    
787
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
788
                List<Point> points = new ArrayList<Point>();
789
                String tupla = new String();
790
                String[] tuplaPart;
791
                Double x;
792
                Double y;
793

    
794
                /*
795
                 * Replaces Decimal Separator to convert coords to suitable doubles.
796
                 * 
797
                 * Maybe it will have a better performance if we insert this replace
798
                 * into the while
799
                 */
800
                if (delDec != '.') {
801
                        strCoords = strCoords.replace(delDec, '.');
802
                }
803

    
804
                // Creates a tokenizer to run over the string
805
                StringTokenizer tuplas = new StringTokenizer(strCoords, delTuple, false);
806

    
807
                // Get ArrayLists collections with X's and Y's
808
                while (tuplas.hasMoreTokens()) {
809
                        // tupla = tuplas.nextToken().replace(delDec,'.');
810
                        tupla = tuplas.nextToken();
811
                        tuplaPart = tupla.split(delCoords);
812
                        x = new Double(tuplaPart[0]);
813
                        y = new Double(tuplaPart[1]);
814

    
815
                        Point pto = geomManager.createPoint(x.doubleValue(), y
816
                                        .doubleValue(), Geometry.SUBTYPES.GEOM2D);
817
                        points.add(pto);
818
                }
819

    
820
                // Return an array of Point objects
821
                return points;
822
        }
823

    
824
        /**
825
         * @param status
826
         * @return
827
         * @throws ArcImsException
828
         */
829
        public Rectangle2D getLayerExtent(ArcImsVectStatus status)
830
                        throws ArcImsException {
831
                Rectangle2D envelope = null;
832
                String layerId = (String) status.getLayersIdsSelected().get(0);
833

    
834
                // logger.info("Getting Vectorial Layer Extent (" + status.getl)
835
                ServiceInformation si = status.getServiceInfo();
836
                String ini_srs = ServiceInfoTags.vINI_SRS;
837

    
838
                String srsView = status.getSrs().substring(ini_srs.length()).trim();
839
                String srsServ = si.getFeaturecoordsys();
840
                boolean srsAssumed = si.isSrsAssumed();
841

    
842
                if (srsAssumed || (srsView.equals(srsServ))) {
843
                        BoundaryBox bb = si.getLayerById(layerId).getEnvelope();
844

    
845
                        /*
846
                         * At the end, we convert the BoundaryBox to a Rectangle2D
847
                         */
848
                        envelope = new Rectangle2D.Double();
849

    
850
                        envelope.setFrameFromDiagonal(bb.getXmin(), bb.getYmin(), bb
851
                                        .getXmax(), bb.getYmax());
852

    
853
                        return envelope;
854
                }
855

    
856
                /*
857
                 * If SRS of View and Service are different, we do a custom request to
858
                 * retrieve the global envelope of the layer
859
                 */
860
                try {
861
                        /*
862
                         * Build the request
863
                         */
864
                        URL url;
865
                        url = new URL(buildCapabilitiesRequest(status));
866

    
867
                        /*
868
                         * Build the proper ArcXML
869
                         */
870
                        String request = ArcXMLFeatures.getLayerExtentRequest(status);
871

    
872
                        if (status.verbose) {
873
                                System.err.println(request);
874
                        }
875

    
876
                        /*
877
                         * Request the envelope
878
                         */
879
                        File response;
880
                        response = ArcImsDownloadUtils.doRequestPost(url, request,
881
                                        "getLayerExtent.xml");
882

    
883
                        /*
884
                         * Parse response and return a Rectangle2D
885
                         */
886
                        char ds = si.getSeparators().getDs();
887
                        envelope = parseEnvelopeTag(new FileReader(response), ds);
888
                } catch (MalformedURLException e) {
889
                        logger.error(e.getMessage(), e);
890
                        throw new ArcImsException("arcims_server_error");
891
                } catch (FileNotFoundException e) {
892
                        logger.error(e.getMessage(), e);
893
                        throw new ArcImsException("arcims_server_error");
894
                }
895

    
896
                return envelope;
897
        }
898

    
899
        /**
900
         * Retrieves an ArrayList of Value arrays. The query can be filtered by a
901
         * WHERE clause or an envelope. Only subfields passed will be retrieved
902
         * 
903
         * @param status
904
         * @param subfields
905
         * @param where
906
         * @param envelope
907
         * @return
908
         * @throws ArcImsException
909
         */
910
        public List<List<ArcImsFeature>> getAttributes(ArcImsVectStatus status,
911
                        String[] subfields, String where, Rectangle2D envelope)
912
                        throws ArcImsException {
913

    
914
                logger.info("Start getAttributes");
915

    
916
                List<List<ArcImsFeature>> features = new ArrayList<List<ArcImsFeature>>();
917

    
918
                // Clone the status and set temporal subfields and where clause
919
                ArcImsVectStatus statusCloned = status;
920

    
921
                String[] subTemp = status.getSubfields();
922
                String whereTemp = status.getWhere();
923
                Rectangle2D rectTemp = status.getEnvelopeRect();
924

    
925
                statusCloned.setSubfields(subfields);
926
                statusCloned.setWhere(where);
927
                statusCloned.setEnvelope(envelope);
928

    
929
                try {
930
                        /*
931
                         * Build the request
932
                         */
933
                        URL url;
934
                        url = new URL(buildCapabilitiesRequest(statusCloned));
935

    
936
                        hasMore = true;
937
                        featCount = 0;
938

    
939
                        while (hasMore) {
940
                                /*
941
                                 * Build the proper ArcXML
942
                                 */
943
                                String request = ArcXMLFeatures.getAttributesRequest(
944
                                                statusCloned, featCount);
945

    
946
                                if (status.verbose) {
947
                                        System.err.println(request);
948
                                }
949

    
950
                                // The attributes come from ArcIMS in ASCII/cp1252 encoding
951
                                boolean withUTF = false;
952

    
953
                                // Don't download the file, pass the data directly from the
954
                                // connection
955
                                boolean withFile = false;
956

    
957
                                /*
958
                                 * Get an InputStream from File or directly from the connection
959
                                 */
960
                                InputStream is = null;
961

    
962
                                if (withFile) {
963
                                        File f = ArcImsDownloadUtils.doRequestPost(url, request,
964
                                                        "getAttributes.xml");
965

    
966
                                        try {
967
                                                is = new FileInputStream(f);
968
                                        } catch (FileNotFoundException e) {
969
                                                logger.error(e.getMessage(), e);
970
                                        }
971
                                } else {
972
                                        is = ArcImsDownloadUtils.getRemoteIS(url, request);
973
                                }
974

    
975
                                InputStreamReader isr = null;
976

    
977
                                if (withUTF) {
978
                                        // Deal with UTF-8
979
                                        try {
980
                                                isr = new InputStreamReader(is, "UTF-8");
981
                                        } catch (UnsupportedEncodingException e) {
982
                                                logger.error(e.getMessage(), e);
983
                                        }
984
                                } else {
985
                                        // No deal with UTF-8
986
                                        isr = new InputStreamReader(is);
987
                                }
988

    
989
                                /*
990
                                 * Finally, we can create a BufferedReader from the
991
                                 * InputStreamReader
992
                                 */
993
                                BufferedReader br = new BufferedReader(isr);
994

    
995
                                /*
996
                                 * Parse response and return a Rectangle2D
997
                                 */
998
                                String layerId = (String) statusCloned.getLayersIdsSelected().get(0);
999
                                logger.debug("Start attributes downloading and parsing ("
1000
                                                + featCount + ") ids retrieved");
1001
                                features.add(getFeatures(br, statusCloned.getServiceInfo(),
1002
                                                layerId, statusCloned.getSubfields(), 0));
1003
                                logger.debug("End attributes downloading and parsing");
1004
                        }
1005

    
1006
                        hasMore = true;
1007
                        featCount = 0;
1008
                } catch (MalformedURLException e) {
1009
                        logger.error(e.getMessage(), e);
1010
                        throw new ArcImsException("arcims_server_error");
1011
                } catch (ArcImsException e) {
1012
                        logger.error(e.getMessage(), e);
1013
                        throw new ArcImsException("arcims_server_error");
1014
                } finally {
1015
                        status.setSubfields(subTemp);
1016
                        status.setWhere(whereTemp);
1017
                        status.setEnvelope(rectTemp);
1018
                }
1019

    
1020
                logger.debug("End attributes retrieving");
1021

    
1022
                return features;
1023
        }
1024

    
1025
        /**
1026
         * Retrieves an ArrayList of I by some IDs. The geometry returned is the
1027
         * envelope of the feature requested. The query can be filtered by a WHERE
1028
         * clause or an envelope. Only subfields passed will be retrieved
1029
         * 
1030
         * @param status
1031
         * @param subfields
1032
         * @param where
1033
         * @param envelope
1034
         * @return
1035
         * @throws ArcImsException
1036
         */
1037
        public List<List<ArcImsFeature>> getAttributesWithEnvelope(
1038
                        ArcImsVectStatus status, String[] subfields, String where,
1039
                        Rectangle2D envelope) throws ArcImsException {
1040

    
1041
                logger.info("Start getAttributesWihtEnvelope");
1042

    
1043
                List<List<ArcImsFeature>> features = new ArrayList<List<ArcImsFeature>>();
1044

    
1045
                // Clone the status and set temporal subfields and where clause
1046
                ArcImsVectStatus statusCloned = status;
1047

    
1048
                String[] subTemp = status.getSubfields();
1049
                String whereTemp = status.getWhere();
1050
                Rectangle2D rectTemp = status.getEnvelopeRect();
1051

    
1052
                statusCloned.setSubfields(subfields);
1053
                statusCloned.setWhere(where);
1054
                statusCloned.setEnvelope(envelope);
1055

    
1056
                try {
1057
                        /*
1058
                         * Build the request
1059
                         */
1060
                        URL url;
1061
                        url = new URL(buildCapabilitiesRequest(statusCloned));
1062

    
1063
                        hasMore = true;
1064
                        featCount = 0;
1065

    
1066
                        while (hasMore) {
1067
                                /*
1068
                                 * Build the proper ArcXML
1069
                                 */
1070
                                String request = ArcXMLFeatures.getAttributesRequest(
1071
                                                statusCloned, featCount);
1072

    
1073
                                if (status.verbose) {
1074
                                        System.err.println(request);
1075
                                }
1076

    
1077
                                // The attributes come from ArcIMS in ASCII/cp1252 encoding
1078
                                boolean withUTF = false;
1079

    
1080
                                // Don't download the file, pass the data directly from the
1081
                                // connection
1082
                                boolean withFile = false;
1083

    
1084
                                /*
1085
                                 * Get an InputStream from File or directly from the connection
1086
                                 */
1087
                                InputStream is = null;
1088

    
1089
                                if (withFile) {
1090
                                        File f = ArcImsDownloadUtils.doRequestPost(url, request,
1091
                                                        "getAttributes.xml");
1092

    
1093
                                        try {
1094
                                                is = new FileInputStream(f);
1095
                                        } catch (FileNotFoundException e) {
1096
                                                logger.error(e.getMessage(), e);
1097
                                        }
1098
                                } else {
1099
                                        is = ArcImsDownloadUtils.getRemoteIS(url, request);
1100
                                }
1101

    
1102
                                InputStreamReader isr = null;
1103

    
1104
                                if (withUTF) {
1105
                                        // Deal with UTF-8
1106
                                        try {
1107
                                                isr = new InputStreamReader(is, "UTF-8");
1108
                                        } catch (UnsupportedEncodingException e) {
1109
                                                logger.error(e.getMessage(), e);
1110
                                        }
1111
                                } else {
1112
                                        // No deal with UTF-8
1113
                                        isr = new InputStreamReader(is);
1114
                                }
1115

    
1116
                                /*
1117
                                 * Finally, we can create a BufferedReader from the
1118
                                 * InputStreamReader
1119
                                 */
1120
                                BufferedReader br = new BufferedReader(isr);
1121

    
1122
                                /*
1123
                                 * Parse response and return a Rectangle2D
1124
                                 */
1125
                                String layerId = (String) statusCloned.getLayersIdsSelected().get(0);
1126
                                logger.debug("Start attributes downloading and parsing ("
1127
                                                + featCount + ") ids retrieved");
1128
                                features.add(getFeatures(br, statusCloned.getServiceInfo(),
1129
                                                layerId, statusCloned.getSubfields(), 2)); // Here we
1130
                                // request
1131
                                // envelopes instead
1132
                                // of geometries
1133
                                logger.debug("End attributes downloading and parsing");
1134
                        }
1135

    
1136
                        hasMore = true;
1137
                        featCount = 0;
1138
                } catch (MalformedURLException e) {
1139
                        logger.error(e.getMessage(), e);
1140
                        throw new ArcImsException("arcims_server_error");
1141
                } catch (ArcImsException e) {
1142
                        logger.error(e.getMessage(), e);
1143
                        throw new ArcImsException("arcims_server_error");
1144
                } finally {
1145
                        status.setSubfields(subTemp);
1146
                        status.setWhere(whereTemp);
1147
                        status.setEnvelope(rectTemp);
1148
                }
1149

    
1150
                logger.debug("End attributes retrieving");
1151

    
1152
                return features;
1153
        }
1154

    
1155
        /*
1156
         * (non-Javadoc)
1157
         * 
1158
         * @see
1159
         * org.gvsig.remoteClient.arcims.ArcImsProtocolHandler#getElementInfo(org
1160
         * .gvsig.remoteClient.arcims.ArcImsStatus, int, int, int)
1161
         */
1162
        public String getElementInfo(ArcImsStatus status, int x, int y,
1163
                        int featureCount) throws ArcImsException {
1164
                throw new ClassCastException(
1165
                                "Invalid request, this method is only valid for Image Services");
1166
        }
1167
}