de.uniluebeck.itm.jaxb4osm.elements.OsmElement.java Source code

Java tutorial

Introduction

Here is the source code for de.uniluebeck.itm.jaxb4osm.elements.OsmElement.java

Source

/**
 * Copyright (c) 2014, Oliver Kleine, Institute of Telematics, University of Luebeck
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 *
 *  - Redistributions of source messageCode must retain the above copyright notice, this list of conditions and the following
 *    disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *    following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 *  - Neither the name of the University of Luebeck nor the names of its contributors may be used to endorse or promote
 *    products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package de.uniluebeck.itm.jaxb4osm.elements;

import com.google.common.collect.*;
import de.uniluebeck.itm.jaxb4osm.tools.WayElementFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.util.*;

/**
 * JAXB compliant class for the osm (root) element in OSM files (Open Street Map)
 *
 * @author Oliver Kleine
 */

public class OsmElement extends AbstractOsmElement {

    private static Logger log = LoggerFactory.getLogger(OsmElement.class.getName());

    private Map<Long, NodeElement> nodeElements;

    private Map<Long, WayElement> wayElements;
    private Multimap<Long, Long> nodeReferences;

    /**
     * Creates a new empty instance of {@link de.uniluebeck.itm.jaxb4osm.elements.OsmElement}
     */
    public OsmElement() {
        initialze();
    }

    private OsmElement(PlainOsmElement plainOsmElement, WayElementFilter filter) {
        super(plainOsmElement);
        initialze();

        //Add <node> elements
        this.addNodeElements(plainOsmElement.getNodeElements());

        //Add <way> elements that match the given filter criteria
        for (WayElement wayElement : plainOsmElement.getWayElements()) {
            if (filter.matchesCriteria(wayElement)) {
                this.addWayElement(wayElement);
            }
        }
    }

    private void initialze() {
        this.nodeElements = new HashMap<>();
        this.nodeReferences = HashMultimap.create();
        this.wayElements = new HashMap<>();
    }

    public void addNodeElements(Collection<NodeElement> nodeElements) {
        for (NodeElement nodeElement : nodeElements) {
            addNodeElement(nodeElement);
        }
    }

    public void addNodeElement(NodeElement nodeElement) {
        this.nodeElements.put(nodeElement.getID(), nodeElement);
    }

    public boolean removeNodeElement(long nodeID) {
        return this.nodeElements.remove(nodeID) != null;
    }

    /**
     * Returns a {@link java.util.Map} with the values of the nodes ID attributes as keys and the
     * {@link de.uniluebeck.itm.jaxb4osm.elements.NodeElement}s as values
     *
     * @return a {@link java.util.Map} with the values of the nodes ID attributes as keys and the
     * {@link de.uniluebeck.itm.jaxb4osm.elements.NodeElement}s as values
     */
    public ImmutableList<NodeElement> getNodeElements() {
        return new ImmutableList.Builder<NodeElement>().addAll(this.nodeElements.values()).build();
    }

    /**
     * Returns the {@link de.uniluebeck.itm.jaxb4osm.elements.NodeElement} that has the given ID or
     * <code>null</code> if no such node was found.
     *
     * @param nodeID the ID to lookup the corresponding node for
     *
     * @return the {@link de.uniluebeck.itm.jaxb4osm.elements.NodeElement} that has the given ID or
     * <code>null</code> if no such node was found.
     */
    public NodeElement getNodeElement(long nodeID) {
        return this.nodeElements.get(nodeID);
    }

    /**
     * Adds the given {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement}s and updates the references returned
     * by {@link #getReferencingWayIDs(long)} properly.
     *
     * @param wayElements the {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement}s to be added
     *
     * @return the number of added {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement}s.
     *
     * <b>Note:</b> Elements with {@link WayElement#getID()} returning an ID that is already contained will not be
     * added, i.e. already contained ways are not overwritten! That's why the returned number may vary from the size
     * of the given {@link java.util.Collection}.
     */
    public int addWayElements(Collection<WayElement> wayElements) {
        int counter = 0;

        for (WayElement wayElement : wayElements) {
            if (this.addWayElement(wayElement)) {
                counter++;
            }
        }

        return counter;
    }

    /**
     * Adds the given {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement} and updates the references returned
     * by {@link #getReferencingWayIDs(long)} properly.
     *
     * @param wayElement the {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement} to be added
     *
     * @return <code>true</code> if the element was successfully added or <code>false</code> otherwise
     *
     * <b>Note:</b> Elements with {@link WayElement#getID()} returning an ID that is already contained will not be
     * added, i.e. already contained ways are not overwritten!
     */
    public boolean addWayElement(WayElement wayElement) {

        if (this.wayElements.containsKey(wayElement.getID()))
            return false;

        this.wayElements.put(wayElement.getID(), wayElement);

        for (NdElement ndElement : wayElement.getNdElements()) {
            this.nodeReferences.put(ndElement.getReference(), wayElement.getID());
        }

        return true;
    }

    /**
     * Removes the {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement} with the given ID and updates the references
     * returned by {@link #getReferencingWayIDs(long)} properly.
     *
     * @param wayID the ID of the {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement} to be removed
     *
     * @return <code>true</code> if the element was successfully removed or <code>false</code> otherwise, i.e. there
     * was no way with the given ID
     */
    public boolean removeWayElement(long wayID) {
        WayElement wayElement = this.wayElements.remove(wayID);

        if (wayElement == null)
            return false;

        for (NdElement ndElement : wayElement.getNdElements()) {
            this.nodeReferences.remove(ndElement.getReference(), wayElement.getID());
        }

        return true;
    }

    /**
     * Returns an {@link com.google.common.collect.ImmutableList} containing the already added
     * {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement}s
     *
     * <b>Note:</b> The reason for making the result immutable is to keep the references returned by
     * {@link #getReferencingWayIDs(long)} properly
     *
     * @return an {@link com.google.common.collect.ImmutableList} containing the already added
     * {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement}s
     */
    public ImmutableList<WayElement> getWayElements() {
        return new ImmutableList.Builder<WayElement>().addAll(this.wayElements.values()).build();
    }

    /**
     * Returns the {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement} that has the given ID or
     * <code>null</code> if no such way was found.
     *
     * @return the {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement} that has the given ID or
     * <code>null</code> if no such way was found.
     */
    public WayElement getWayElement(long wayID) {
        return this.wayElements.get(wayID);
    }

    /**
     * Returns an {@link com.google.common.collect.ImmutableSet} containing the IDs of the
     * {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement}s that were already added and refer to the given
     * nodeID.
     *
     * <b>Note:</b> The reason for making the result immutable is to keep the references returned by
     * {@link #getReferencingWayIDs(long)} properly
     *
     * @return an {@link com.google.common.collect.ImmutableSet} containing the IDs of the
     * {@link de.uniluebeck.itm.jaxb4osm.elements.WayElement}s that were already added and refer to the given
     * nodeID.
     */
    public ImmutableSet<Long> getReferencingWayIDs(long nodeID) {
        if (!this.nodeReferences.containsKey(nodeID))
            return new ImmutableSet.Builder<Long>().build();

        return new ImmutableSet.Builder<Long>().addAll(this.nodeReferences.get(nodeID)).build();
    }

    /**
     * This class is for internal use only and is public due to the restrictions (or bug?) of the
     * {@link javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter} not to be applicable on XML root elements.
     */
    @XmlRootElement(name = "osm")
    @XmlType(propOrder = { PROP_VERSION, PROP_GENERATOR, PROP_COPYRIGHT, PROP_ATTRIBUTION, PROP_LICENSE,
            PROP_BOUNDS, PROP_NODE, PROP_WAY })
    @XmlSeeAlso(AbstractOsmElement.class)
    public static class PlainOsmElement extends AbstractOsmElement {

        @XmlElement(name = ELEM_NODE)
        private List<NodeElement> nodeElements;

        @XmlElement(name = ELEM_WAY)
        private List<WayElement> wayElements;

        private PlainOsmElement() {
            this.initialize();
        }

        private PlainOsmElement(OsmElement osmElement) {
            super(osmElement);
            this.initialize();
            this.addNodeElements(osmElement.getNodeElements());
            this.addWayElements(osmElement.getWayElements());
        }

        private void initialize() {
            this.nodeElements = new ArrayList<>();
            this.wayElements = new ArrayList<>();
        }

        private void addNodeElements(Collection<NodeElement> nodeElements) {
            this.nodeElements.addAll(nodeElements);
        }

        private List<NodeElement> getNodeElements() {
            return this.nodeElements;
        }

        private void addWayElements(Collection<WayElement> wayElements) {
            this.wayElements.addAll(wayElements);
        }

        private List<WayElement> getWayElements() {
            return this.wayElements;
        }
    }

    public static class OsmElementAdapter extends XmlAdapter<PlainOsmElement, OsmElement> {

        public OsmElement unmarshal(PlainOsmElement plainOsmElement, WayElementFilter wayElementFilter) {
            return new OsmElement(plainOsmElement, wayElementFilter);
        }

        @Override
        public OsmElement unmarshal(PlainOsmElement plainOsmElement) throws Exception {
            return unmarshal(plainOsmElement, WayElementFilter.ANY_WAY);
        }

        @Override
        public PlainOsmElement marshal(OsmElement osmElement) throws Exception {
            return new PlainOsmElement(osmElement);
        }
    }

}