Statistics
| Revision:

root / trunk / libraries / libArcIMS / src / org / gvsig / remoteClient / arcims / ArcImsProtFeatureHandler.java @ 8109

History | View | Annotate | Download (38.2 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2006 Prodevelop and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *   +34 963862235
28
 *   gvsig@gva.es
29
 *   www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   Prodevelop Integraci?n de Tecnolog?as SL
34
 *   Conde Salvatierra de ?lava , 34-10
35
 *   46004 Valencia
36
 *   Spain
37
 *
38
 *   +34 963 510 612
39
 *   +34 963 510 968
40
 *   gis@prodevelop.es
41
 *   http://www.prodevelop.es
42
 */
43

    
44
package org.gvsig.remoteClient.arcims;
45

    
46
import com.hardcode.gdbms.engine.values.Value;
47

    
48
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
49
import com.iver.cit.gvsig.fmap.core.FMultiPoint2D;
50
import com.iver.cit.gvsig.fmap.core.FPoint2D;
51
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
52
import com.iver.cit.gvsig.fmap.core.IGeometry;
53
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
54

    
55
import org.apache.log4j.Logger;
56

    
57
import org.gvsig.remoteClient.arcims.exceptions.ArcImsException;
58
import org.gvsig.remoteClient.arcims.utils.ArcImsDownloadUtils;
59
import org.gvsig.remoteClient.arcims.utils.ArcImsValueFactory;
60
import org.gvsig.remoteClient.arcims.utils.FieldInformation;
61
import org.gvsig.remoteClient.arcims.utils.GetFeaturesTags;
62
import org.gvsig.remoteClient.arcims.utils.GetImageTags;
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

    
68
import org.kxml2.io.KXmlParser;
69

    
70
import org.xmlpull.v1.XmlPullParserException;
71

    
72
import java.awt.geom.Point2D;
73
import java.awt.geom.Rectangle2D;
74

    
75
import java.io.BufferedReader;
76
import java.io.File;
77
import java.io.FileInputStream;
78
import java.io.FileNotFoundException;
79
import java.io.FileReader;
80
import java.io.IOException;
81
import java.io.InputStream;
82
import java.io.InputStreamReader;
83
import java.io.Reader;
84
import java.io.UnsupportedEncodingException;
85

    
86
import java.net.MalformedURLException;
87
import java.net.URL;
88

    
89
import java.text.ParseException;
90

    
91
import java.util.ArrayList;
92
import java.util.Iterator;
93
import java.util.StringTokenizer;
94
import java.util.Vector;
95

    
96

    
97
/**
98
 * @author jsanz
99
 *
100
 */
101
public class ArcImsProtFeatureHandler extends ArcImsProtocolHandler {
102
    private static boolean hasMore;
103
    private static int featCount;
104
    private static Logger logger = Logger.getLogger(ArcImsProtFeatureHandler.class.getName());
105

    
106
    /*
107
    private ArcImsCache aic;
108
    
109
    public ArrayList getCacheMap(ArcImsVectStatus status) throws ArcImsException{
110
            if (aic==null)
111
                    aic = new ArcImsCache(this.getLayerExtent(status),1);
112
    
113
            aic.addStatus(status);
114
    
115
            return aic.getGeometries(status);
116
    }
117
    */
118

    
119
    /**
120
     * Method to retrieve an ArrayList of features from an ArcIMS FeatureService
121
     *
122
     * @param status
123
     * @return ArrayList of IFeatures with geometries and Id's to attribute
124
     *         table
125
     * @throws ArcImsException
126
     */
127
    public ArrayList getMap(ArcImsVectStatus status) throws ArcImsException {
128
        logger.info("Start getMap");
129

    
130
        ArrayList array = new ArrayList();
131

    
132
        try {
133
            /*
134
             * Build the request
135
             */
136
            URL url = new URL(buildCapabilitiesRequest(status));
137

    
138
            hasMore = true;
139
            featCount = 1;
140

    
141
            while (hasMore) {
142
                /*
143
                 * Build the proper ArcXML
144
                 */
145
                String request = ArcXMLFeatures.getFeatureLayerRequest(status,
146
                        featCount);
147

    
148
                if (status.verbose) {
149
                    System.err.println(request);
150
                }
151

    
152
                /*
153
                 * Request the reader
154
                 */
155
                logger.info("Start features downloading");
156

    
157
                File f = ArcImsDownloadUtils.doRequestPost(url, request,
158
                        "getFeatures.xml");
159
                logger.info("End features downloading");
160

    
161
                /*
162
                 * Parse response and add geometries to the general Array
163
                 */
164
                String layerId = (String) status.getLayerIds().get(0);
165

    
166
                //Deal with UTF-8
167
                Reader reader = null;
168
                FileInputStream fis = new FileInputStream(f);
169
                InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
170
                BufferedReader br = new BufferedReader(isr);
171
                reader = br;
172

    
173
                logger.debug("Start features with attributes parsing");
174
                array.addAll(getFeatures(reader, status.getServiceInfo(),
175
                        layerId, status.getSubfields(), 1));
176
                logger.debug("End features with attributes parsing");
177
            }
178

    
179
            hasMore = true;
180
            featCount = 1;
181
        } catch (MalformedURLException e) {
182
            logger.error(e.getMessage(), e);
183
            throw new ArcImsException("arcims_server_error");
184
        } catch (FileNotFoundException e) {
185
            logger.error(e.getMessage(), e);
186
            throw new ArcImsException("arcims_server_error");
187
        } catch (UnsupportedEncodingException e) {
188
            logger.error(e.getMessage(), e);
189
        }
190

    
191
        logger.debug("End getMap");
192

    
193
        return array;
194
    }
195

    
196
    /**
197
     * Parse the XML data retrieved from ArcIMS GET_FEATURES request
198
     * to get a set of Features if withGeometries is true or an ArrayList of
199
     * Value[] if this boolean is false
200
     * @param Reader Stream to parse
201
     * @param si ServiceInformation with metadata
202
     * @param layerId Layer retrieved
203
     * @param subfields Subfields retrieved
204
     * @param withGeometries Will geometries be parsed?: 0=no 1=yes 2=evelopes
205
     * @return ArrayList of IFeatures or Value[]
206
     * @throws ArcImsException
207
     */
208
    private ArrayList getFeatures(Reader lector, ServiceInformation si,
209
        String layerId, String[] subfields, int withGeometries)
210
        throws ArcImsException {
211
        FieldInformation fi = null;
212
        ServiceInformationLayerFeatures sil = (ServiceInformationLayerFeatures) si.getLayerById(layerId);
213

    
214
        /*
215
         * Prepare a Value array to store every FEATURE tag information
216
         */
217
        Vector fieldsInfo = null;
218
        fieldsInfo = sil.getFieldsInfo();
219

    
220
        //If flag == true, throw an Exception (no layerId found)
221
        if (fieldsInfo == null) {
222
            throw new ArcImsException("arcims_no_features");
223
        }
224

    
225
        //We will store names and types in a hashmap
226
        ArrayList fieldsInfoA = new ArrayList();
227

    
228
        /*
229
         * If subfields[0] is equal to #ALL we add the entire vector
230
         * into the Hasmap
231
         */
232
        if (subfields[0].equals("#ALL#")) {
233
            for (int i = 0; i < fieldsInfo.size(); i++) {
234
                fi = ((FieldInformation) fieldsInfo.get(i));
235
                fieldsInfoA.add(fi);
236
            }
237
        } else {
238
            for (int i = 0; i < subfields.length; i++) {
239
                fi = null;
240
                fi = sil.getFieldInformation(subfields[i]);
241

    
242
                if (fi != null) {
243
                    fieldsInfoA.add(fi);
244
                }
245
            }
246
        }
247

    
248
        /*
249
             * Get the separators
250
             */
251
        String delCoords = si.getSeparators().getCs();
252
        String delTuple = si.getSeparators().getTs();
253
        char delDec = si.getSeparators().getDs();
254

    
255
        /*
256
         * ArrayList with features
257
         */
258
        ArrayList features = new ArrayList();
259

    
260
        /*
261
         * Start parsing
262
         */
263
        int tag;
264
        KXmlParser kxmlParser = null;
265
        kxmlParser = new KXmlParser();
266

    
267
        //FileReader fr = null;
268
        IGeometry geom = null;
269
        Value[] values = new Value[fieldsInfoA.size()];
270
        int[] position = new int[fieldsInfoA.size()];
271

    
272
        //Initialize position array
273
        for (int i = 0; i < position.length; i++)
274
            position[i] = -1;
275

    
276
        //                long timeFeat = 0;
277
        //                long timeGeom = 0;
278
        //                long timeTemp = 0;
279
        try {
280
            kxmlParser.setInput(lector);
281
            kxmlParser.nextTag();
282

    
283
            if (kxmlParser.getEventType() != KXmlParser.END_DOCUMENT) {
284
                kxmlParser.require(KXmlParser.START_TAG, null,
285
                    ServiceInfoTags.tARCXML);
286
                tag = kxmlParser.nextTag();
287

    
288
                while (tag != KXmlParser.END_DOCUMENT) {
289
                    switch (tag) {
290
                    case KXmlParser.START_TAG:
291

    
292
                        if (kxmlParser.getName()
293
                                          .compareTo(GetFeaturesTags.FEATURE) == 0) {
294
                            /*
295
                             * parse FEATURES' tag
296
                             */
297

    
298
                            //FIRST ENVELOPE TAG (We hope that ENVELOPE will ALLWAYS be returned at first...)
299
                            if (withGeometries == 2) {
300
                                //timeTemp = System.currentTimeMillis();
301
                                geom = parseEnvelopeFromFeatureTag(kxmlParser,
302
                                        delDec);
303
                            }
304

    
305
                            //SECOND FIELDS TAG
306
                            //timeTemp = System.currentTimeMillis();
307
                            values = parseValuesFromFeatureTag(kxmlParser, //the kxml parser
308
                                    fieldsInfoA, //Hashmap with names and FieldInformation objects)
309
                                    delDec, //the separators
310
                                    position //the relative positions of returned values
311
                                );
312

    
313
                            //timeFeat += System.currentTimeMillis() - timeTemp;
314

    
315
                            //If geometries are neede we add to the ArrayList the Ifeature
316
                            if (withGeometries == 1) {
317
                                //THIRD GEOMETRIES
318
                                //                                                                timeTemp = System.currentTimeMillis();
319
                                geom = parseGeomFromFeatureTag(kxmlParser, //the kxml parser
320
                                        delTuple, delCoords,
321
                                        delDec //the separators
322
                                    );
323

    
324
                                //timeGeom += System.currentTimeMillis() - timeTemp;
325
                            }
326

    
327
                            //If some geometry is created, we add a IFeature into features ArrayList
328
                            if (withGeometries > 0) {
329
                                features.add(new DefaultFeature(geom, values));
330
                            }
331
                            //Else we only need the Value[] array
332
                            else {
333
                                features.add(values);
334
                            }
335
                        } else if (kxmlParser.getName()
336
                                                 .compareTo(GetFeaturesTags.FEATURECOUNT) == 0) {
337
                            String value = new String();
338

    
339
                            //Get the feature count
340
                            value = kxmlParser.getAttributeValue("",
341
                                    GetFeaturesTags.COUNT);
342

    
343
                            Integer intFeatCount = new Integer(value);
344
                            featCount += intFeatCount.intValue();
345

    
346
                            //Get the hasmore boolean
347
                            value = kxmlParser.getAttributeValue("",
348
                                    GetFeaturesTags.HASMORE);
349

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

    
359
                        break;
360

    
361
                    case KXmlParser.END_TAG:
362
                        break;
363

    
364
                    case KXmlParser.TEXT:
365
                        break;
366
                    }
367

    
368
                    tag = kxmlParser.next();
369
                }
370

    
371
                kxmlParser.require(KXmlParser.END_DOCUMENT, null, null);
372
            }
373
        } catch (ParseException pe) {
374
            logger.error(pe.getMessage(), pe);
375
            throw new ArcImsException("arcims_no_features");
376
        } catch (XmlPullParserException parser_ex) {
377
            logger.error(parser_ex.getMessage(), parser_ex);
378
            throw new ArcImsException("arcims_no_features");
379
        } catch (IOException ioe) {
380
            logger.error(ioe.getMessage(), ioe);
381
            throw new ArcImsException("arcims_no_features");
382
        }
383

    
384
        //logger.debug("Time for parsing features " + timeFeat + " msecs");
385
        //logger.debug("Time for parsing geometries " + timeGeom + " msecs");
386
        return features;
387
    }
388

    
389
    /**
390
     * Returns an IGeometry with a line between corners of an ENVELOPE
391
     * @param parser
392
     * @param delDec
393
     * @return
394
     * @throws XmlPullParserException
395
     * @throws IOException
396
     */
397
    private IGeometry parseEnvelopeFromFeatureTag(KXmlParser parser, char delDec)
398
        throws XmlPullParserException, IOException {
399
        int currentTag;
400
        boolean end = false;
401
        int f = 0;
402
        String att;
403
        String val;
404
        int type;
405

    
406
        BoundaryBox bb = null;
407

    
408
        //                parser.require(KXmlParser.START_TAG,null,GetFeaturesTags.FIELDS);
409
        currentTag = parser.next();
410

    
411
        while (!end) {
412
            switch (currentTag) {
413
            case KXmlParser.START_TAG:
414

    
415
                if (parser.getName().equals(ServiceInfoTags.tENVELOPE)) {
416
                    bb = super.parseEnvelope(parser, delDec);
417
                    end = true;
418
                }
419

    
420
                break;
421

    
422
            case KXmlParser.END_TAG:
423

    
424
                if (parser.getName().equals(GetFeaturesTags.FIELDS)) {
425
                    end = true;
426
                }
427

    
428
                break;
429

    
430
            case KXmlParser.TEXT:
431
                break;
432
            }
433

    
434
            if (!end) {
435
                currentTag = parser.next();
436
            }
437
        }
438

    
439
        //If BoundaryBox object has been created, we can convert it into a IGeometry (polyline).
440
        if (bb != null) {
441
            GeneralPathX polyline = new GeneralPathX(GeneralPathX.WIND_EVEN_ODD);
442

    
443
            polyline.moveTo(bb.getXmin(), bb.getYmin());
444
            polyline.lineTo(bb.getXmax(), bb.getYmax());
445

    
446
            return ShapeFactory.createPolyline2D(polyline);
447
        } else {
448
            return null;
449
        }
450
    }
451

    
452
    /**
453
     * @param kxmlParser
454
     * @param fieldsInfoH
455
     * @param delDec
456
     * @param position
457
     * @return
458
     * @throws IOException
459
     * @throws XmlPullParserException
460
     * @throws ArcImsException
461
     * @throws ParseException
462
     */
463
    private Value[] parseValuesFromFeatureTag(KXmlParser parser,
464
        ArrayList fieldsInfoA, char delDec, int[] position)
465
        throws XmlPullParserException, IOException, ArcImsException, 
466
            ParseException {
467
        int currentTag;
468
        boolean end = false;
469
        int f = 0;
470
        String att;
471
        String val;
472
        int type;
473

    
474
        Value[] values = new Value[fieldsInfoA.size()];
475

    
476
        //                parser.require(KXmlParser.START_TAG,null,GetFeaturesTags.FIELDS);
477
        currentTag = parser.next();
478

    
479
        while (!end) {
480
            switch (currentTag) {
481
            case KXmlParser.START_TAG:
482

    
483
                if (parser.getName().equals(GetFeaturesTags.FIELD)) {
484
                    att = parser.getAttributeValue("", GetFeaturesTags.NAME);
485
                    val = parser.getAttributeValue("", GetFeaturesTags.VALUE);
486

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

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

    
501
                    // This way we can create a NullValue
502
                    if (val.equals("")) {
503
                        val = null;
504
                    }
505

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

    
512
                    // Add the Value into the correct position
513
                    values[position[f]] = ArcImsValueFactory.createValueByType(val,
514
                            type, delDec);
515

    
516
                    // logger.info(att + " ("+type+")\t" +
517
                    // values[f].toString());
518
                    f++;
519
                }
520

    
521
                break;
522

    
523
            case KXmlParser.END_TAG:
524

    
525
                if (parser.getName().equals(GetFeaturesTags.FIELDS)) {
526
                    end = true;
527
                }
528

    
529
                break;
530

    
531
            case KXmlParser.TEXT:
532
                break;
533
            }
534

    
535
            if (!end) {
536
                currentTag = parser.next();
537
            }
538
        }
539

    
540
        return values;
541
    }
542

    
543
    /**
544
     * Method to get the position of an attribute into the subfields array
545
     *
546
     * @param fieldsInfoA
547
     * @param att
548
     * @return
549
     */
550
    private int getPosition(Iterator it, String att) {
551
        int res = 0;
552
        FieldInformation fi;
553

    
554
        while (it.hasNext()) {
555
            fi = (FieldInformation) it.next();
556

    
557
            if (fi.getName().equals(att)) {
558
                return res;
559
            }
560

    
561
            res++;
562
        }
563

    
564
        //If no integer has returned at this point we return a -1
565
        return -1;
566
    }
567

    
568
    /**
569
     * Parses the Feature Tag to get a IFeature
570
     * @param KxmlParser with the FEATURE tag
571
     * @param Value array with the correct subtypes to store FIELDS data
572
     * @param String array with the correct fields names to retrieve
573
     * @param String with the tuple separator
574
     * @param String with the coordinates separator
575
     * @param Char with the decimal separator
576
     * @return @see com.hardcode.gdbms.engine.values.Value.IFeature
577
     * @throws IOException
578
     * @throws XmlPullParserException
579
     * @throws ArcImsException
580
     */
581
    private IGeometry parseGeomFromFeatureTag(KXmlParser parser,
582
        String delTuple, String delCoords, char delDec)
583
        throws IOException, XmlPullParserException, ArcImsException {
584
        int currentTag;
585
        boolean end = false;
586

    
587
        IGeometry geom = null;
588

    
589
        currentTag = parser.next();
590

    
591
        while (!end) {
592
            String featType = parser.getName();
593

    
594
            switch (currentTag) {
595
            case KXmlParser.START_TAG:
596

    
597
                if (featType.equals(GetFeaturesTags.MULTIPOINT)) {
598
                    // Go to COORDS tag
599
                    parser.nextTag();
600

    
601
                    if (parser.getName().equals(GetFeaturesTags.COORDS)) {
602
                        // Create a tokenizer with the tuples
603
                        String strPoints = parser.nextText();
604

    
605
                        // Get the points from COORDS string
606
                        ArrayList points = parseCoords(strPoints, delTuple,
607
                                delCoords, delDec);
608

    
609
                        //Convert these collections to array of doubles (primitive type)
610
                        double[] xD = new double[points.size()];
611
                        double[] yD = new double[points.size()];
612

    
613
                        int size = xD.length;
614

    
615
                        for (int i = 0; i < size; i++) {
616
                            xD[0] = ((Point2D) points.get(i)).getX();
617
                            yD[0] = ((Point2D) points.get(i)).getY();
618
                        }
619

    
620
                        //Get the geometry
621

    
622
                        //BUG in 1.0 FMultiPoint2D(double[] x, double[] y)
623
                        //                                                geom = ShapeFactory.createMultipoint2D(xD,yD);
624

    
625
                        //We will use another way to construct the geom object
626
                        FPoint2D[] fpoints = new FPoint2D[size];
627

    
628
                        for (int i = 0; i < size; i++) {
629
                            fpoints[i] = new FPoint2D(xD[i], yD[i]);
630
                        }
631

    
632
                        geom = new FMultiPoint2D(fpoints);
633
                    } else {
634
                        logger.error("Error parsing MULTIPOINT tag");
635
                        throw new ArcImsException("arcims_features_error");
636
                    }
637
                } else if (featType.equals(GetFeaturesTags.POLYLINE) ||
638
                        featType.equals(GetFeaturesTags.POLYGON)) {
639
                    //Parse while parser doesn't found </FEATURES> tag
640
                    //The GeneralPath to store the different paths
641
                    GeneralPathX polyline = new GeneralPathX(GeneralPathX.WIND_EVEN_ODD);
642
                    boolean endpol = false;
643

    
644
                    while (!endpol) {
645
                        switch (currentTag) {
646
                        case KXmlParser.START_TAG:
647

    
648
                            if (parser.getName().equals(GetFeaturesTags.COORDS)) {
649
                                // Create a tokenizer with the tuples
650
                                String strPoints = parser.nextText();
651

    
652
                                // Get the points (Point2D) from COORDS string
653
                                ArrayList points = parseCoords(strPoints,
654
                                        delTuple, delCoords, delDec);
655

    
656
                                Iterator it = points.iterator();
657
                                Point2D point;
658

    
659
                                //First we MOVE to the first point of the path
660
                                point = (Point2D) it.next();
661
                                polyline.moveTo(point.getX(), point.getY());
662

    
663
                                //And now we can LINE to the rest of the points of the path
664
                                while (it.hasNext()) {
665
                                    point = (Point2D) it.next();
666
                                    polyline.lineTo(point.getX(), point.getY());
667
                                }
668
                            }
669

    
670
                            break;
671

    
672
                        case KXmlParser.END_TAG:
673

    
674
                            if (parser.getName().equals(featType)) {
675
                                endpol = true;
676
                            }
677

    
678
                            break;
679

    
680
                        case KXmlParser.TEXT:
681
                            break;
682
                        }
683

    
684
                        if (!endpol) {
685
                            currentTag = parser.next();
686
                        }
687
                    }
688

    
689
                    if (featType.equals(GetFeaturesTags.POLYLINE)) {
690
                        geom = ShapeFactory.createPolyline2D(polyline);
691
                    } else if (featType.equals(GetFeaturesTags.POLYGON)) {
692
                        geom = ShapeFactory.createPolygon2D(polyline);
693
                    }
694
                }
695

    
696
                break;
697

    
698
            case KXmlParser.END_TAG:
699

    
700
                if (parser.getName().compareTo(GetFeaturesTags.FEATURE) == 0) {
701
                    end = true;
702
                }
703

    
704
                break;
705

    
706
            case KXmlParser.TEXT:
707
                break;
708
            }
709

    
710
            if (!end) {
711
                currentTag = parser.next();
712
            }
713
        }
714

    
715
        return geom;
716
    }
717

    
718
    /**
719
     * Private method that parses a COORDS tag to return an ArrayList of Point2D.Double objects
720
     * @param strCoords
721
     * @param delTuple
722
     * @param delCoords
723
     * @param delDec
724
     * @return
725
     */
726
    private ArrayList parseCoords(String strCoords, String delTuple,
727
        String delCoords, char delDec) {
728
        String tupla = new String();
729
        ArrayList points = new ArrayList();
730
        String[] tuplaPart;
731
        Double x;
732
        Double y;
733

    
734
        /*
735
         * Replaces Decimal Separator to convert coords to suitable doubles.
736
         *
737
         * Maybe it will have a better performance if we insert this replace into
738
         * the while
739
         */
740
        if (delDec != '.') {
741
            strCoords = strCoords.replace(delDec, '.');
742
        }
743

    
744
        //Creates a tokenizer to run over the string
745
        StringTokenizer tuplas = new StringTokenizer(strCoords, delTuple, false);
746

    
747
        //Get ArrayLists collections with X's and Y's
748
        while (tuplas.hasMoreTokens()) {
749
            //                        tupla = tuplas.nextToken().replace(delDec,'.');
750
            tupla = tuplas.nextToken();
751
            tuplaPart = tupla.split(delCoords);
752
            x = new Double(tuplaPart[0]);
753
            y = new Double(tuplaPart[1]);
754

    
755
            //Version with in-loop replacing
756
            /*
757
            if (delDec!='.'){
758
            x = new Double(tuplaPart[0].replace(delDec,'.'));
759
            y = new Double(tuplaPart[1].replace(delDec,'.'));
760
            } else{
761
            x = new Double(tuplaPart[0]);
762
            y = new Double(tuplaPart[1]);
763
            }
764
             */
765
            points.add(new Point2D.Double(x.doubleValue(), y.doubleValue()));
766
        }
767

    
768
        //Return an array op Point2D objects
769
        return points;
770
    }
771

    
772
    /**
773
     * @param status
774
     * @return
775
     * @throws ArcImsException
776
     */
777
    public Rectangle2D getLayerExtent(ArcImsVectStatus status)
778
        throws ArcImsException {
779
        Rectangle2D envelope = null;
780
        String layerId = (String) status.getLayerIds().get(0);
781

    
782
        //                logger.info("Getting Vectorial Layer Extent (" + status.getl)
783
        ServiceInformation si = status.getServiceInfo();
784
        String ini_srs = ServiceInfoTags.vINI_SRS;
785

    
786
        String srsView = status.getSrs().substring(ini_srs.length()).trim();
787
        String srsServ = si.getFeaturecoordsys();
788
        boolean srsAssumed = si.isSrsAssumed();
789

    
790
        if (srsAssumed || (srsView.equals(srsServ))) {
791
            BoundaryBox bb = si.getLayerById(layerId).getEnvelope();
792

    
793
            /*
794
             * At the end, we convert the BoundaryBox to a Rectangle2D
795
             */
796
            envelope = new Rectangle2D.Double();
797

    
798
            envelope.setFrameFromDiagonal(bb.getXmin(), bb.getYmin(),
799
                bb.getXmax(), bb.getYmax());
800

    
801
            return envelope;
802
        }
803

    
804
        /*
805
         * If SRS of View and Service are different, we do a custom request to retrieve the
806
         * global envelope of the layer
807
         */
808
        try {
809
            /*
810
             * Build the request
811
             */
812
            URL url;
813
            url = new URL(buildCapabilitiesRequest(status));
814

    
815
            /*
816
             * Build the proper ArcXML
817
             */
818
            String request = ArcXMLFeatures.getLayerExtentRequest(status);
819

    
820
            if (status.verbose) {
821
                System.err.println(request);
822
            }
823

    
824
            /*
825
             * Request the envelope
826
             */
827
            File response;
828
            response = ArcImsDownloadUtils.doRequestPost(url, request,
829
                    "getLayerExtent.xml");
830

    
831
            /*
832
             * Parse response and return a Rectangle2D
833
             */
834
            char ds = si.getSeparators().getDs();
835
            envelope = parseEnvelopeTag(new FileReader(response), ds);
836
        } catch (MalformedURLException e) {
837
            logger.error(e.getMessage(), e);
838
            throw new ArcImsException("arcims_server_error");
839
        } catch (FileNotFoundException e) {
840
            logger.error(e.getMessage(), e);
841
            throw new ArcImsException("arcims_server_error");
842
        }
843

    
844
        return envelope;
845
    }
846

    
847
    /**
848
     * Retrieves an ArrayList of Value arrays. The query can be filtered by a WHERE clause or an
849
     * envelope. Only subfields passed will be retrieved
850
     * @param status
851
     * @param subfields
852
     * @param where
853
     * @param envelope
854
     * @return
855
     * @throws ArcImsException
856
     */
857
    public ArrayList getAttributes(ArcImsVectStatus status, String[] subfields,
858
        String where, Rectangle2D envelope) throws ArcImsException {
859
        //                //TEST
860
        //                try {
861
        //                        boolean flag = true;
862
        //                        IntValue iv;
863
        //                        IdsReader ids = new IdsReader(status, "#ID#");
864
        //                        while (flag) {
865
        //                                iv = ids.readId();
866
        //                                if (iv!=null)
867
        //                                        logger.info("ID = " + iv.intValue());
868
        //                                else
869
        //                                        flag = false;
870
        //                        }
871
        //                } catch (IOException e) {
872
        //                        e.printStackTrace();
873
        //                } catch (ArcImsException e) {
874
        //                        e.printStackTrace();
875
        //                }
876
        logger.info("Start getAttributes");
877

    
878
        ArrayList valuesArray = new ArrayList();
879

    
880
        //Clone the status and set temporal subfields and where clause
881
        ArcImsVectStatus statusCloned = status;
882

    
883
        String[] subTemp = status.getSubfields();
884
        String whereTemp = status.getWhere();
885
        Rectangle2D rectTemp = status.getExtent();
886

    
887
        statusCloned.setSubfields(subfields);
888
        statusCloned.setWhere(where);
889
        statusCloned.setExtent(envelope);
890

    
891
        try {
892
            /*
893
             * Build the request
894
             */
895
            URL url;
896
            url = new URL(buildCapabilitiesRequest(statusCloned));
897

    
898
            hasMore = true;
899
            featCount = 0;
900

    
901
            while (hasMore) {
902
                /*
903
                 * Build the proper ArcXML
904
                 */
905
                String request = ArcXMLFeatures.getAttributesRequest(statusCloned,
906
                        featCount);
907

    
908
                if (status.verbose) {
909
                    System.err.println(request);
910
                }
911

    
912
                //The attributes come from ArcIMS in ASCII/cp1252 encoding
913
                boolean withUTF = false;
914

    
915
                //Don't download the file, pass the data directly from the connection
916
                boolean withFile = false;
917

    
918
                /*
919
                 * Get an InputStream from File or directly from the connection
920
                 */
921
                InputStream is = null;
922

    
923
                if (withFile) {
924
                    File f = ArcImsDownloadUtils.doRequestPost(url, request,
925
                            "getAttributes.xml");
926

    
927
                    try {
928
                        is = new FileInputStream(f);
929
                    } catch (FileNotFoundException e) {
930
                        logger.error(e.getMessage(), e);
931
                    }
932
                } else {
933
                    is = ArcImsDownloadUtils.getRemoteIS(url, request);
934
                }
935

    
936
                InputStreamReader isr = null;
937

    
938
                if (withUTF) {
939
                    //Deal with UTF-8
940
                    try {
941
                        isr = new InputStreamReader(is, "UTF-8");
942
                    } catch (UnsupportedEncodingException e) {
943
                        logger.error(e.getMessage(), e);
944
                    }
945
                } else {
946
                    //No deal with UTF-8
947
                    isr = new InputStreamReader(is);
948
                }
949

    
950
                /*
951
                     * Finally, we can create a BufferedReader from the InputStreamReader
952
                     */
953
                BufferedReader br = new BufferedReader(isr);
954

    
955
                /*
956
                 * Parse response and return a Rectangle2D
957
                 */
958
                String layerId = (String) statusCloned.getLayerIds().get(0);
959
                logger.debug("Start attributes downloading and parsing (" +
960
                    featCount + ") ids retrieved");
961
                valuesArray.addAll(getFeatures(br,
962
                        statusCloned.getServiceInfo(), layerId,
963
                        statusCloned.getSubfields(), 0));
964
                logger.debug("End attributes downloading and parsing");
965
            }
966

    
967
            hasMore = true;
968
            featCount = 0;
969
        } catch (MalformedURLException e) {
970
            logger.error(e.getMessage(), e);
971
            throw new ArcImsException("arcims_server_error");
972
        } catch (ArcImsException e) {
973
            logger.error(e.getMessage(), e);
974
            throw new ArcImsException("arcims_server_error");
975
        }
976
        finally {
977
            status.setSubfields(subTemp);
978
            status.setWhere(whereTemp);
979
            status.setExtent(rectTemp);
980
        }
981

    
982
        logger.debug("End attributes retrieving");
983

    
984
        return valuesArray;
985
    }
986

    
987
    /**
988
     * Retrieves an ArrayList of I by some IDs. The geometry returned is the envelope
989
     * of the feature requested. The query can be filtered by a WHERE clause or an
990
     * envelope. Only subfields passed will be retrieved
991
     * @param status
992
     * @param subfields
993
     * @param where
994
     * @param envelope
995
     * @return
996
     * @throws ArcImsException
997
     */
998
    public ArrayList getAttributesWithEnvelope(ArcImsVectStatus status,
999
        String[] subfields, String where, Rectangle2D envelope)
1000
        throws ArcImsException {
1001
        //                //TEST
1002
        //                try {
1003
        //                        boolean flag = true;
1004
        //                        IntValue iv;
1005
        //                        IdsReader ids = new IdsReader(status, "#ID#");
1006
        //                        while (flag) {
1007
        //                                iv = ids.readId();
1008
        //                                if (iv!=null)
1009
        //                                        logger.info("ID = " + iv.intValue());
1010
        //                                else
1011
        //                                        flag = false;
1012
        //                        }
1013
        //                } catch (IOException e) {
1014
        //                        e.printStackTrace();
1015
        //                } catch (ArcImsException e) {
1016
        //                        e.printStackTrace();
1017
        //                }
1018
        logger.info("Start getAttributesWihtEnvelope");
1019

    
1020
        ArrayList valuesArray = new ArrayList();
1021

    
1022
        //Clone the status and set temporal subfields and where clause
1023
        ArcImsVectStatus statusCloned = status;
1024

    
1025
        String[] subTemp = status.getSubfields();
1026
        String whereTemp = status.getWhere();
1027
        Rectangle2D rectTemp = status.getExtent();
1028

    
1029
        statusCloned.setSubfields(subfields);
1030
        statusCloned.setWhere(where);
1031
        statusCloned.setExtent(envelope);
1032

    
1033
        try {
1034
            /*
1035
             * Build the request
1036
             */
1037
            URL url;
1038
            url = new URL(buildCapabilitiesRequest(statusCloned));
1039

    
1040
            hasMore = true;
1041
            featCount = 0;
1042

    
1043
            while (hasMore) {
1044
                /*
1045
                 * Build the proper ArcXML
1046
                 */
1047
                String request = ArcXMLFeatures.getAttributesRequest(statusCloned,
1048
                        featCount);
1049

    
1050
                if (status.verbose) {
1051
                    System.err.println(request);
1052
                }
1053

    
1054
                //The attributes come from ArcIMS in ASCII/cp1252 encoding
1055
                boolean withUTF = false;
1056

    
1057
                //Don't download the file, pass the data directly from the connection
1058
                boolean withFile = false;
1059

    
1060
                /*
1061
                 * Get an InputStream from File or directly from the connection
1062
                 */
1063
                InputStream is = null;
1064

    
1065
                if (withFile) {
1066
                    File f = ArcImsDownloadUtils.doRequestPost(url, request,
1067
                            "getAttributes.xml");
1068

    
1069
                    try {
1070
                        is = new FileInputStream(f);
1071
                    } catch (FileNotFoundException e) {
1072
                        logger.error(e.getMessage(), e);
1073
                    }
1074
                } else {
1075
                    is = ArcImsDownloadUtils.getRemoteIS(url, request);
1076
                }
1077

    
1078
                InputStreamReader isr = null;
1079

    
1080
                if (withUTF) {
1081
                    //Deal with UTF-8
1082
                    try {
1083
                        isr = new InputStreamReader(is, "UTF-8");
1084
                    } catch (UnsupportedEncodingException e) {
1085
                        logger.error(e.getMessage(), e);
1086
                    }
1087
                } else {
1088
                    //No deal with UTF-8
1089
                    isr = new InputStreamReader(is);
1090
                }
1091

    
1092
                /*
1093
                     * Finally, we can create a BufferedReader from the InputStreamReader
1094
                     */
1095
                BufferedReader br = new BufferedReader(isr);
1096

    
1097
                /*
1098
                 * Parse response and return a Rectangle2D
1099
                 */
1100
                String layerId = (String) statusCloned.getLayerIds().get(0);
1101
                logger.debug("Start attributes downloading and parsing (" +
1102
                    featCount + ") ids retrieved");
1103
                valuesArray.addAll(getFeatures(br,
1104
                        statusCloned.getServiceInfo(), layerId,
1105
                        statusCloned.getSubfields(), 2)); //Here we request envelopes instead of geometries
1106
                logger.debug("End attributes downloading and parsing");
1107
            }
1108

    
1109
            hasMore = true;
1110
            featCount = 0;
1111
        } catch (MalformedURLException e) {
1112
            logger.error(e.getMessage(), e);
1113
            throw new ArcImsException("arcims_server_error");
1114
        } catch (ArcImsException e) {
1115
            logger.error(e.getMessage(), e);
1116
            throw new ArcImsException("arcims_server_error");
1117
        }
1118
        finally {
1119
            status.setSubfields(subTemp);
1120
            status.setWhere(whereTemp);
1121
            status.setExtent(rectTemp);
1122
        }
1123

    
1124
        logger.debug("End attributes retrieving");
1125

    
1126
        return valuesArray;
1127
    }
1128

    
1129
    /* (non-Javadoc)
1130
     * @see org.gvsig.remoteClient.arcims.ArcImsProtocolHandler#getElementInfo(org.gvsig.remoteClient.arcims.ArcImsStatus, int, int, int)
1131
     */
1132
    public String getElementInfo(ArcImsStatus status, int x, int y,
1133
        int featureCount) throws ArcImsException {
1134
        throw new ClassCastException(
1135
            "Invalid request, this method is only valid for Image Services");
1136
    }
1137
}