net.tourbook.device.gpx.GPX_SAX_Handler.java Source code

Java tutorial

Introduction

Here is the source code for net.tourbook.device.gpx.GPX_SAX_Handler.java

Source

/*******************************************************************************
 * Copyright (C) 2005, 2010 Wolfgang Schramm and Contributors
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation version 2 of the License.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 *******************************************************************************/
package net.tourbook.device.gpx;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.TimeZone;

import net.tourbook.chart.ChartLabel;
import net.tourbook.data.TimeData;
import net.tourbook.data.TourData;
import net.tourbook.data.TourMarker;
import net.tourbook.data.TourWayPoint;
import net.tourbook.device.DeviceReaderTools;
import net.tourbook.importdata.DeviceData;
import net.tourbook.importdata.TourbookDevice;
import net.tourbook.ui.UI;
import net.tourbook.util.Util;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class GPX_SAX_Handler extends DefaultHandler {

    private static final String NAME_SPACE_GPX_1_0 = "http://www.topografix.com/GPX/1/0"; //$NON-NLS-1$
    private static final String NAME_SPACE_GPX_1_1 = "http://www.topografix.com/GPX/1/1"; //$NON-NLS-1$

    // namespace for extensions used by Garmin
    //   private static final String            NAME_SPACE_TPEXT      = "http://www.garmin.com/xmlschemas/TrackPointExtension/v1";   //$NON-NLS-1$

    private static final int GPX_VERSION_1_0 = 10;
    private static final int GPX_VERSION_1_1 = 11;

    /*
     * gpx tags, attributes
     */
    private static final String TAG_GPX = "gpx"; //$NON-NLS-1$

    private static final String TAG_TRK = "trk"; //$NON-NLS-1$
    private static final String TAG_TRK_NAME = "name"; //$NON-NLS-1$
    private static final String TAG_TRKPT = "trkpt"; //$NON-NLS-1$

    private static final String TAG_TIME = "time"; //$NON-NLS-1$
    private static final String TAG_ELE = "ele"; //$NON-NLS-1$

    // Extension element for temperature, heart rate, cadence
    private static final String TAG_EXT_CAD = "gpxtpx:cad"; //$NON-NLS-1$
    private static final String TAG_EXT_HR = "gpxtpx:hr"; //$NON-NLS-1$
    private static final String TAG_EXT_TEMP = "gpxtpx:atemp"; //$NON-NLS-1$

    private static final String ATTR_LATITUDE = "lat"; //$NON-NLS-1$
    private static final String ATTR_LONGITUDE = "lon"; //$NON-NLS-1$

    private static final String TAG_WPT = "wpt"; //$NON-NLS-1$
    private static final Object TAG_WPT_ELE = "ele"; //$NON-NLS-1$
    private static final Object TAG_WPT_TIME = "time"; //$NON-NLS-1$
    private static final Object TAG_WPT_NAME = "name"; //$NON-NLS-1$
    private static final Object TAG_WPT_CMT = "cmt"; //$NON-NLS-1$
    private static final Object TAG_WPT_DESC = "desc"; //$NON-NLS-1$
    private static final Object TAG_WPT_SYM = "sym"; //$NON-NLS-1$
    private static final Object TAG_WPT_TYPE = "type"; //$NON-NLS-1$
    ////////////////////////

    //   private static final Calendar         _calendar            = GregorianCalendar.getInstance();

    private static final DateTimeFormatter _dtIsoParser = ISODateTimeFormat.dateTimeParser();
    private static final DateTimeFormatter _dtFormatterShort = DateTimeFormat.mediumDateTime();

    private static final SimpleDateFormat GPX_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); //$NON-NLS-1$
    private static final SimpleDateFormat GPX_TIME_FORMAT_SSSZ = new SimpleDateFormat(
            "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); //$NON-NLS-1$
    private static final SimpleDateFormat GPX_TIME_FORMAT_RFC822 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); //$NON-NLS-1$

    private int _gpxVersion = -1;

    private boolean _isInTrk = false;
    private boolean _isInTrkName = false;
    private boolean _isInTrkPt = false;

    private boolean _isInTime = false;
    private boolean _isInEle = false;
    private final boolean _isInName = false;

    // gpx extensions
    private boolean _isInCadence = false;
    private boolean _isInHr = false;
    private boolean _isInTemp = false;

    /*
     * wap points
     */
    private boolean _isInWpt = false;
    private boolean _isInWptEle = false;
    private boolean _isInWptTime = false;
    private boolean _isInWptName = false;
    private boolean _isInWptCmt = false;
    private boolean _isInWptDesc = false;
    private boolean _isInWptSym = false;
    private boolean _isInWptType = false;

    private final ArrayList<TimeData> _timeDataList = new ArrayList<TimeData>();
    private TimeData _timeSlice;
    private TimeData _prevTimeSlice;
    private String _trkName;

    private final TourbookDevice _deviceDataReader;
    private final String _importFilePath;
    private final HashMap<Long, TourData> _tourDataMap;
    private int _trackCounter;

    private final ArrayList<TourWayPoint> _wptList = new ArrayList<TourWayPoint>();
    private TourWayPoint _wpt;

    private boolean _isSetTrackMarker = false;

    private float _absoluteDistance;

    private boolean _isImported;
    private boolean _isError = false;

    private final StringBuilder _characters = new StringBuilder();

    {
        GPX_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); //$NON-NLS-1$
        GPX_TIME_FORMAT_SSSZ.setTimeZone(TimeZone.getTimeZone("UTC")); //$NON-NLS-1$
        GPX_TIME_FORMAT_RFC822.setTimeZone(TimeZone.getTimeZone("UTC")); //$NON-NLS-1$
    }

    public GPX_SAX_Handler(final TourbookDevice deviceDataReader, final String importFileName,
            final DeviceData deviceData, final HashMap<Long, TourData> tourDataMap) {

        _deviceDataReader = deviceDataReader;
        _importFilePath = importFileName;
        _tourDataMap = tourDataMap;
    }

    @Override
    public void characters(final char[] chars, final int startIndex, final int length) throws SAXException {

        if (_isInTrkName //
                || _isInTime || _isInEle || _isInName || _isInCadence || _isInHr || _isInTemp
                //
                || _isInWptCmt || _isInWptDesc || _isInWptEle || _isInWptName || _isInWptSym || _isInWptTime
                || _isInWptType) {

            _characters.append(chars, startIndex, length);
        }
    }

    private void displayError(final ParseException e) {
        Display.getDefault().syncExec(new Runnable() {
            public void run() {
                final String message = e.getMessage();
                MessageDialog.openError(Display.getCurrent().getActiveShell(), "Error", message); //$NON-NLS-1$
                System.err.println(message + " in " + _importFilePath); //$NON-NLS-1$
            }
        });
    }

    @Override
    public void endElement(final String uri, final String localName, final String name) throws SAXException {

        //      System.out.println("</" + name + ">");

        if (_isError) {
            return;
        }

        try {

            if (_isInTrk) {

                if (_isInTrkPt) {

                    final String charData = _characters.toString();

                    if (name.equals(TAG_ELE)) {

                        // </ele>

                        _isInEle = false;

                        _timeSlice.absoluteAltitude = getFloatValue(charData);

                    } else if (name.equals(TAG_TIME)) {

                        // </time>

                        _isInTime = false;

                        try {
                            _timeSlice.absoluteTime = _dtIsoParser.parseDateTime(charData).getMillis();
                        } catch (final Exception e0) {
                            try {
                                _timeSlice.absoluteTime = GPX_TIME_FORMAT.parse(charData).getTime();
                            } catch (final ParseException e1) {
                                try {
                                    _timeSlice.absoluteTime = GPX_TIME_FORMAT_SSSZ.parse(charData).getTime();
                                } catch (final ParseException e2) {
                                    try {
                                        _timeSlice.absoluteTime = GPX_TIME_FORMAT_RFC822.parse(charData).getTime();
                                    } catch (final ParseException e3) {

                                        _isError = true;

                                        displayError(e3);
                                    }
                                }
                            }
                        }

                    } else if (name.equals(TAG_EXT_CAD)) {

                        // </gpxtpx:cad>

                        _isInCadence = false;
                        _timeSlice.cadence = getIntValue(charData);

                    } else if (name.equals(TAG_EXT_HR)) {

                        // </gpxtpx:hr>

                        _isInHr = false;
                        _timeSlice.pulse = getIntValue(charData);

                    } else if (name.equals(TAG_EXT_TEMP)) {

                        // </gpxtpx:atemp>

                        _isInTemp = false;
                        _timeSlice.temperature = Math
                                .round(getFloatValue(charData) * TourbookDevice.TEMPERATURE_SCALE);
                    }

                } else if (name.equals(TAG_TRK_NAME)) {

                    // </name> track name

                    _isInTrkName = false;
                    _trkName = _characters.toString();
                }

            } else if (_isInWpt) {

                // in <wpt>

                final String charData = _characters.toString();

                if (name.equals(TAG_WPT_ELE)) {

                    // </ele> elevation

                    _isInWptEle = false;

                    _wpt.setAltitude(getFloatValue(charData));

                } else if (name.equals(TAG_WPT_TIME)) {

                    // </time>

                    _isInWptTime = false;

                    try {
                        _wpt.setTime(_dtIsoParser.parseDateTime(charData).getMillis());
                    } catch (final Exception e0) {
                        try {
                            _wpt.setTime(GPX_TIME_FORMAT.parse(charData).getTime());
                        } catch (final ParseException e1) {
                            try {
                                _wpt.setTime(GPX_TIME_FORMAT_SSSZ.parse(charData).getTime());
                            } catch (final ParseException e2) {
                                try {
                                    _wpt.setTime(GPX_TIME_FORMAT_RFC822.parse(charData).getTime());
                                } catch (final ParseException e3) {

                                    _isError = true;

                                    displayError(e3);
                                }
                            }
                        }
                    }

                } else if (name.equals(TAG_WPT_NAME)) {

                    // </name> name

                    _isInWptName = false;
                    _wpt.setName(charData);

                } else if (name.equals(TAG_WPT_CMT)) {

                    // </cmt> comment

                    _isInWptCmt = false;
                    _wpt.setComment(charData);

                } else if (name.equals(TAG_WPT_DESC)) {

                    // </desc> description

                    _isInWptDesc = false;
                    _wpt.setDescription(charData);

                } else if (name.equals(TAG_WPT_SYM)) {

                    // </sym> symbol

                    _isInWptSym = false;
                    _wpt.setSymbol(charData);

                } else if (name.equals(TAG_WPT_TYPE)) {

                    // </type> type/category

                    _isInWptType = true;
                    _wpt.setCategory(charData);
                }
            }

            if (name.equals(TAG_TRKPT)) {

                /*
                 * trackpoint ends
                 */

                _isInTrkPt = false;

                finalizeTrackpoint();

            } else if (name.equals(TAG_TRK)) {

                /*
                 * track ends
                 */

                _isInTrk = false;

                if (_deviceDataReader.isMergeTracks == false) {
                    finalizeTour();
                }

            } else if (name.equals(TAG_WPT)) {

                /*
                 * way point ends
                 */

                _isInWpt = false;

                finalizeWayPoint();

            } else if (name.equals(TAG_GPX)) {

                /*
                 * file end
                 */

                if (_deviceDataReader.isMergeTracks) {
                    finalizeTour();
                }
            }

        } catch (final NumberFormatException e) {
            net.tourbook.util.StatusUtil.showStatus(e);
        }

    }

    private void finalizeTour() {

        if (_timeDataList.size() == 0) {
            // there is not data
            return;
        }

        final TimeData firstTimeData = _timeDataList.get(0);

        // create data object for each tour
        final TourData tourData = new TourData();

        tourData.setTourTitle(_trkName);

        /*
         * set tour start date/time
         */
        final DateTime dtTourStart = new DateTime(firstTimeData.absoluteTime);

        tourData.setStartYear((short) dtTourStart.getYear());
        tourData.setStartMonth((short) dtTourStart.getMonthOfYear());
        tourData.setStartDay((short) dtTourStart.getDayOfMonth());

        tourData.setStartHour((short) dtTourStart.getHourOfDay());
        tourData.setStartMinute((short) dtTourStart.getMinuteOfHour());
        tourData.setStartSecond((short) dtTourStart.getSecondOfMinute());

        tourData.setWeek(tourData.getStartYear(), tourData.getStartMonth(), tourData.getStartDay());

        tourData.setDeviceTimeInterval((short) -1);
        tourData.setTemperatureScale(TourbookDevice.TEMPERATURE_SCALE);

        tourData.importRawDataFile = _importFilePath;
        tourData.setTourImportFilePath(_importFilePath);

        tourData.createTimeSeries(_timeDataList, true);
        tourData.computeAltitudeUpDown();

        tourData.setWayPoints(_wptList);

        /*
         * adjust default marker which are created in tourData.createTimeSeries()
         */
        for (final TourMarker tourMarker : tourData.getTourMarkers()) {

            tourMarker.setVisualPosition(ChartLabel.VISUAL_VERTICAL_BOTTOM_CHART);

            // disable time/distance
            tourMarker.setTime(-1);
            tourMarker.setDistance(-1);
        }

        // after all data are added, the tour id can be created
        final int[] distanceSerie = tourData.getMetricDistanceSerie();
        String uniqueKey;

        if (_deviceDataReader.isCreateTourIdWithRecordingTime) {

            /*
             * 23.3.2009: added recording time to the tour distance for the unique key because tour
             * export and import found a wrong tour when exporting was done with camouflage speed ->
             * this will result in a NEW tour
             */
            final int tourRecordingTime = tourData.getTourRecordingTime();

            if (distanceSerie == null) {
                uniqueKey = Integer.toString(tourRecordingTime);
            } else {

                final long tourDistance = distanceSerie[(distanceSerie.length - 1)];

                uniqueKey = Long.toString(tourDistance + tourRecordingTime);
            }

        } else {

            /*
             * original version to create tour id
             */
            if (distanceSerie == null) {
                uniqueKey = Util.UNIQUE_ID_SUFFIX_GPX;
            } else {
                uniqueKey = Integer.toString(distanceSerie[distanceSerie.length - 1]);
            }
        }

        final Long tourId = tourData.createTourId(uniqueKey);

        // check if the tour is already imported
        if (_tourDataMap.containsKey(tourId) == false) {

            tourData.computeTourDrivingTime();
            tourData.computeComputedValues();

            tourData.setDeviceId(_deviceDataReader.deviceId);
            tourData.setDeviceName(_deviceDataReader.visibleName);

            // add new tour to other tours
            _tourDataMap.put(tourId, tourData);
        }

        _isImported = true;
    }

    private void finalizeTrackpoint() {

        if (_timeSlice == null) {
            return;
        }

        _timeDataList.add(_timeSlice);

        // calculate distance
        if (_prevTimeSlice == null) {
            // first time data
            _timeSlice.absoluteDistance = 0;
        } else {
            if (_timeSlice.absoluteDistance == Float.MIN_VALUE) {
                _timeSlice.absoluteDistance = _absoluteDistance += DeviceReaderTools.computeDistance(
                        _prevTimeSlice.latitude, _prevTimeSlice.longitude, _timeSlice.latitude,
                        _timeSlice.longitude);
            }
        }

        final long originalTime = _timeSlice.absoluteTime;

        // set virtual time if time is not available
        if (_timeSlice.absoluteTime == Long.MIN_VALUE) {
            _timeSlice.absoluteTime = new DateTime(2000, 1, 1, 0, 0, 0, 0).getMillis();
        }

        if (_isSetTrackMarker) {

            _isSetTrackMarker = false;

            final String markerLabel = NLS.bind(Messages.Marker_Label_Track, Integer.toString(_trackCounter) + //
                    (originalTime == Long.MIN_VALUE //
                            ? UI.EMPTY_STRING
                            : UI.DASH_WITH_SPACE + _dtFormatterShort.print(_timeSlice.absoluteTime)));

            _timeSlice.marker = 1;
            _timeSlice.markerLabel = markerLabel;
        }

        _prevTimeSlice = _timeSlice;
    }

    private void finalizeWayPoint() {

        if (_wpt == null) {
            return;
        }

        // lat/lon are required fields
        if ((_wpt.getLatitude() == Double.MIN_VALUE) || (_wpt.getLongitude() == Double.MIN_VALUE)) {
            _wpt = null;
            return;
        }

        _wptList.add(_wpt);

        _wpt = null;
    }

    private double getDoubleValue(final String textValue) {

        try {
            if (textValue != null) {
                return Double.parseDouble(textValue);
            } else {
                return Double.MIN_VALUE;
            }

        } catch (final NumberFormatException e) {
            return Double.MIN_VALUE;
        }
    }

    private float getFloatValue(final String textValue) {

        try {
            if (textValue != null) {
                return Float.parseFloat(textValue);
            } else {
                return Float.MIN_VALUE;
            }

        } catch (final NumberFormatException e) {
            return Float.MIN_VALUE;
        }
    }

    //   private short getShortValue(String textValue) {
    //
    //      try {
    //         if (textValue != null) {
    //            return Short.parseShort(textValue);
    //         } else {
    //            return Short.MIN_VALUE;
    //         }
    //      } catch (NumberFormatException e) {
    //         return Short.MIN_VALUE;
    //      }
    //   }

    private int getIntValue(final String textValue) {
        try {
            if (textValue != null) {
                return Integer.parseInt(textValue);
            } else {
                return Integer.MIN_VALUE;
            }

        } catch (final NumberFormatException e) {
            return Integer.MIN_VALUE;
        }
    }

    private void initNewTrack() {
        _timeDataList.clear();
        _absoluteDistance = 0;
        _prevTimeSlice = null;
        _trkName = null;
    }

    /**
     * @return Returns <code>true</code> when a tour was imported
     */
    public boolean isImported() {

        if (_isError) {
            return false;
        }

        return _isImported;
    }

    @Override
    public void startElement(final String uri, final String localName, final String name,
            final Attributes attributes) throws SAXException {

        //      System.out.print("<" + name + ">");

        if (_isError) {
            return;
        }

        if (_gpxVersion < 0) {

            // gpx version is not set

            if (name.equals(TAG_GPX)) {

                /*
                 * get version of the xml file
                 */
                for (int attrIndex = 0; attrIndex < attributes.getLength(); attrIndex++) {

                    final String value = attributes.getValue(attrIndex);

                    if (value.contains(NAME_SPACE_GPX_1_0)) {

                        _gpxVersion = GPX_VERSION_1_0;

                        if (_deviceDataReader.isMergeTracks) {
                            initNewTrack();
                        }

                        break;

                    } else if (value.contains(NAME_SPACE_GPX_1_1)) {

                        _gpxVersion = GPX_VERSION_1_1;

                        if (_deviceDataReader.isMergeTracks) {
                            initNewTrack();
                        }

                        break;
                    }
                }
            }

        } else if ((_gpxVersion == GPX_VERSION_1_0) || (_gpxVersion == GPX_VERSION_1_1)) {

            // name space: http://www.topografix.com/GPX/1/0/gpx.xsd

            if (_isInTrk) {

                if (_isInTrkPt) {

                    if (name.equals(TAG_ELE)) {

                        _isInEle = true;
                        _characters.delete(0, _characters.length());

                    } else if (name.equals(TAG_TIME)) {

                        _isInTime = true;
                        _characters.delete(0, _characters.length());

                    } else if (name.equals(TAG_EXT_CAD)) {

                        _isInCadence = true;
                        _characters.delete(0, _characters.length());

                    } else if (name.equals(TAG_EXT_HR)) {

                        _isInHr = true;
                        _characters.delete(0, _characters.length());

                    } else if (name.equals(TAG_EXT_TEMP)) {

                        _isInTemp = true;
                        _characters.delete(0, _characters.length());
                    }

                } else if (name.equals(TAG_TRKPT) /* || name.equals(TAG_RTEPT) */) {

                    /*
                     * new trackpoing
                     */
                    _isInTrkPt = true;

                    // create new time item
                    _timeSlice = new TimeData();

                    // get attributes
                    _timeSlice.latitude = getDoubleValue(attributes.getValue(ATTR_LATITUDE));
                    _timeSlice.longitude = getDoubleValue(attributes.getValue(ATTR_LONGITUDE));

                } else if (name.equals(TAG_TRK_NAME)) {

                    _isInTrkName = true;
                    _characters.delete(0, _characters.length());

                }

            } else if (_isInWpt) {

                if (name.equals(TAG_WPT_ELE)) {

                    _isInWptEle = true;
                    _characters.delete(0, _characters.length());

                } else if (name.equals(TAG_WPT_TIME)) {

                    _isInWptTime = true;
                    _characters.delete(0, _characters.length());

                } else if (name.equals(TAG_WPT_NAME)) {

                    _isInWptName = true;
                    _characters.delete(0, _characters.length());

                } else if (name.equals(TAG_WPT_CMT)) {

                    _isInWptCmt = true;
                    _characters.delete(0, _characters.length());

                } else if (name.equals(TAG_WPT_DESC)) {

                    _isInWptDesc = true;
                    _characters.delete(0, _characters.length());

                } else if (name.equals(TAG_WPT_SYM)) {

                    _isInWptSym = true;
                    _characters.delete(0, _characters.length());

                } else if (name.equals(TAG_WPT_TYPE)) {

                    _isInWptType = true;
                    _characters.delete(0, _characters.length());

                }

            } else if (name.equals(TAG_TRK)) {

                /*
                 * new track starts
                 */

                _isInTrk = true;

                if (_deviceDataReader.isMergeTracks) {

                    _trackCounter++;

                    _isSetTrackMarker = true;

                } else {

                    initNewTrack();
                }

            } else if (name.equals(TAG_WPT)) {

                /*
                 * new way point starts
                 */

                _isInWpt = true;

                _wpt = new TourWayPoint();

                // get attributes
                _wpt.setLatitude(getDoubleValue(attributes.getValue(ATTR_LATITUDE)));
                _wpt.setLongitude(getDoubleValue(attributes.getValue(ATTR_LONGITUDE)));
            }
        }
    }
}