Java из-за нехватки памяти при разборе файла GPX (xml) - PullRequest
0 голосов
/ 14 сентября 2018

Итак, я создал приложение, которое читает некоторые файлы gpx (файлы xml с координатами широты и долготы) и сохраняет эти точки в базе данных. Это веб-приложение, работающее на wildfly 10.1.0. Я загружаю файл и отправляю его в очередь, потому что процесс очень тяжелый. Когда я делал тест на моей машине, у меня не было проблем. У меня больше оперативной памяти (16 ГБ), чем на моем сервере (8 ГБ), и на моем сервере запущено несколько приложений. У меня есть файл с 17 МБ, который, кажется, должен быть в состоянии справиться с этим, это не должно быть так сложно, но это приводит к тому, что моя бабочка падает на моем сервере. В моем ноутбуке он обрабатывает его меньше минуты.

Я не знаю, что я могу сделать лучше или что я могу сделать неправильно.

Это мой обработчик, он основан на этом https://mappingdev.wordpress.com/2011/09/22/parsing-gpxxml-files-with-sax/

public class SAXFileHandler extends DefaultHandler {
    private final static String NODE_WAYPOINT = "wpt"; //$NON-NLS-1$
    private final static String NODE_TRACK = "trk"; //$NON-NLS-1$
    private final static String NODE_TRACK_SEGMENT = "trkseg"; //$NON-NLS-1$
    private final static String NODE_TRACK_POINT = "trkpt"; //$NON-NLS-1$
    private final static String NODE_ROUTE = "rte"; //$NON-NLS-1$
    private final static String NODE_ROUTE_POINT = "rtept"; //$NON-NLS-1$
    private final static String NODE_NAME = "name"; //$NON-NLS-1$
    private final static String NODE_TIME = "time"; //$NON-NLS-1$
    private final static String NODE_ELEVATION = "ele"; //$NON-NLS-1$
    private final static String NODE_SPEED = "speed"; //$NON-NLS-1$
    private final static String NODE_DESCRIPTION = "desc"; //$NON-NLS-1$
    private final static String ATTR_LONGITUDE = "lon"; //$NON-NLS-1$
    private final static String ATTR_LATITUDE = "lat"; //$NON-NLS-1$

    private List<GPXTrack> tracks;
    private List<GPXPunto> wayPoints = new ArrayList<GPXPunto>();
    // private List<GPXPunto> currentTrackPoints;
    private GPXTrack currentTrack;
    private GPXPunto currentTrackPoint;
    private GPXPunto currentWayPoint;
    private ZonedDateTime fechaExtraido;
    private ZonedDateTime fechaIni;
    private ZonedDateTime fechaFin;
    private DateTimeFormatter parser = DateTimeFormatter
            .ofPattern("[yyyy-MM-dd'T'HH:mm:ss.SSS'Z']" + "[yyyy-MM-dd'T'HH:mm:ss'Z']");

    final StringBuilder mStringAccumulator = new StringBuilder();

    public SAXFileHandler() {
        super();
    }

    boolean mSuccess = true;

    @Override
    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
        try {
            if (name.equals(NODE_TRACK_POINT)) {
                if (currentTrack != null) {
                    currentTrack.getPuntos().add(currentTrackPoint = new GPXPunto());
                    currentTrackPoint.setType(TipoPuntoEnum.TRKPT.toString());
                    handleLocation(currentTrackPoint, attributes);
                }
            } else if (name.equals(NODE_WAYPOINT)) {
                currentWayPoint = new GPXPunto();
                currentWayPoint.setType(TipoPuntoEnum.WPT.toString());
                wayPoints.add(currentWayPoint);
                handleLocation(currentWayPoint, attributes);
            } else if (name.equals(NODE_TRACK)) {
                currentTrack = new GPXTrack();
                currentTrack.setPuntos(new ArrayList<GPXPunto>());
                if (tracks == null)
                    tracks = new ArrayList<GPXTrack>();
                tracks.add(currentTrack);
            } else if (name.equals(NODE_TRACK_SEGMENT)) {
            } else if (name.equals(NODE_ROUTE)) {
                /* Agregar ruta algun rato */
            } else if (name.equals(NODE_ROUTE_POINT)) {
                /* Agregar punto para ruta algun rato */
            }
        } finally {
            mStringAccumulator.setLength(0);
        }
    }

    /**
     * Processes new characters for the node content. The characters are simply
     * stored, and will be processed when
     * {@link #endElement(String, String, String)} is called.
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        mStringAccumulator.append(ch, start, length);
    }

    @Override
    public void endElement(String uri, String localName, String name) throws SAXException {
        if (NODE_TRACK_POINT.equals(name)) {
            currentTrackPoint = null;
        } else if (NODE_NAME.equals(name)) {
            if (currentTrackPoint != null) {
                currentTrackPoint.setPunto(mStringAccumulator.toString());
            }else if (currentWayPoint != null) {
                currentWayPoint.setPunto(mStringAccumulator.toString());
            }else if (currentTrack != null && currentWayPoint == null && currentTrackPoint == null) {
                currentTrack.setName(mStringAccumulator.toString());
            }
        } else if (NODE_TIME.equals(name)) {
            if (currentTrackPoint != null) {
                try {
                    /*
                     * Revisar acá si la fecha esta mal al importar
                     */

                    LocalDateTime ldt = LocalDateTime.parse(mStringAccumulator.toString(), parser);
                    ZoneId zoneId = ZoneId.of( "UTC" ); // Or "America/Montreal" etc.
                    ZonedDateTime zdt = ldt.atZone( zoneId ); 

                    currentTrackPoint.setFecha(zdt);
                    /// ZonedDateTime.parse(mStringAccumulator.toString(), parser);
                    fechaFin = currentTrackPoint.getFecha();
                    if (fechaIni == null)
                        fechaIni = currentTrackPoint.getFecha();
                } catch (Exception e) {
                    System.out.println("Error " + e.getMessage());
                }
            } else if (currentWayPoint != null) {
                LocalDateTime ldt = LocalDateTime.parse(mStringAccumulator.toString(), parser);
                ZoneId zoneId = ZoneId.of( "UTC" ); // Or "America/Montreal" etc.
                ZonedDateTime zdt = ldt.atZone( zoneId ); 

                currentWayPoint.setFecha(zdt);
            } else if (tracks == null || tracks.size() == 0) {
                LocalDateTime ldt = LocalDateTime.parse(mStringAccumulator.toString(), parser);
                ZoneId zoneId = ZoneId.of( "UTC" ); // Or "America/Montreal" etc.
                ZonedDateTime zdt = ldt.atZone( zoneId ); 

                fechaExtraido = zdt;
            }
        } else if (NODE_ELEVATION.equals(name)) {
            if (currentTrackPoint != null) {
                currentTrackPoint.setEle(Double.parseDouble(mStringAccumulator.toString()));
            } else if (currentWayPoint != null) {
                currentWayPoint.setEle(Double.parseDouble(mStringAccumulator.toString()));
            }
        } else if (NODE_SPEED.equals(name)) {
            if (currentTrackPoint != null) {
                currentTrackPoint.setDesc(mStringAccumulator.toString());
                try {
                    currentTrackPoint.setVelocidad(Double.parseDouble(mStringAccumulator.toString()));
                } catch (NumberFormatException e) {
                    // wrong data, do nothing.
                }
            }
        } else if (NODE_DESCRIPTION.equals(name)) {
            if (currentWayPoint != null) {
                currentWayPoint.setDesc(mStringAccumulator.toString());
            }
        } else if (NODE_WAYPOINT.equals(name)) {
            currentWayPoint = null;
        } else if (NODE_TRACK.equals(name)) {
            currentTrack = null;
        } else if (NODE_TRACK_SEGMENT.equals(name)) {
        } else if (NODE_ROUTE.equals(name)) {
        } else if (NODE_ROUTE_POINT.equals(name)) {
        }
    }

    @Override
    public void error(SAXParseException e) throws SAXException {
        mSuccess = false;
    }

    @Override
    public void fatalError(SAXParseException e) throws SAXException {
        mSuccess = false;
    }

    /**
     * Handles the location attributes and store them into a
     * {@link LocationPoint}.
     * 
     * @param locationNode
     *            the {@link LocationPoint} to receive the location data.
     * @param attributes
     *            the attributes from the XML node.
     */
    private void handleLocation(GPXPunto gpxPunto, Attributes attributes) {
        try {
            double longitude = Double.parseDouble(attributes.getValue(ATTR_LONGITUDE));
            double latitude = Double.parseDouble(attributes.getValue(ATTR_LATITUDE));

            gpxPunto.setLon(longitude);
            gpxPunto.setLat(latitude);
        } catch (NumberFormatException e) {
            // wrong data, do nothing.
        }
    }

    public List<GPXTrack> getTracks() {
        return tracks;
    }

    public void setTracks(List<GPXTrack> tracks) {
        this.tracks = tracks;
    }

    public List<GPXPunto> getWayPoints() {
        return wayPoints;
    }

    public void setWayPoints(List<GPXPunto> wayPoints) {
        this.wayPoints = wayPoints;
    }

    public GPXTrack getCurrentTrack() {
        return currentTrack;
    }

    public void setCurrentTrack(GPXTrack currentTrack) {
        this.currentTrack = currentTrack;
    }

    public GPXPunto getCurrentTrackPoint() {
        return currentTrackPoint;
    }

    public void setCurrentTrackPoint(GPXPunto currentTrackPoint) {
        this.currentTrackPoint = currentTrackPoint;
    }

    public GPXPunto getCurrentWayPoint() {
        return currentWayPoint;
    }

    public void setCurrentWayPoint(GPXPunto currentWayPoint) {
        this.currentWayPoint = currentWayPoint;
    }

    public ZonedDateTime getFechaExtraido() {
        return fechaExtraido;
    }

    public void setFechaExtraido(ZonedDateTime fechaExtraido) {
        this.fechaExtraido = fechaExtraido;
    }

    public ZonedDateTime getFechaIni() {
        return fechaIni;
    }

    public void setFechaIni(ZonedDateTime fechaIni) {
        this.fechaIni = fechaIni;
    }

    public ZonedDateTime getFechaFin() {
        return fechaFin;
    }

    public void setFechaFin(ZonedDateTime fechaFin) {
        this.fechaFin = fechaFin;
    }

    public DateTimeFormatter getParser() {
        return parser;
    }

    public void setParser(DateTimeFormatter parser) {
        this.parser = parser;
    }

    public static String getNodeElevation() {
        return NODE_ELEVATION;
    }

    public static String getNodeDescription() {
        return NODE_DESCRIPTION;
    }

    public static String getAttrLongitude() {
        return ATTR_LONGITUDE;
    }

    public static String getAttrLatitude() {
        return ATTR_LATITUDE;
    }

}
...