/** * * Copyright 2015-2017 Ishan Khanna, Fernando Ramirez, 2019-2020 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.smackx.geoloc.packet; import java.io.Serializable; import java.net.URI; import java.util.Date; import javax.xml.namespace.QName; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.util.EqualsUtil; import org.jivesoftware.smack.util.HashCode; import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smackx.xdata.FormField; import org.jivesoftware.smackx.xdata.FormFieldChildElement; /** * A GeoLocation Extension packet, which is used by the XMPP clients to exchange their respective geographic locations. * * @see XEP-0080 * @author Ishan Khanna */ public final class GeoLocation implements Serializable, ExtensionElement, FormFieldChildElement { private static final long serialVersionUID = 1L; public static final String NAMESPACE = "http://jabber.org/protocol/geoloc"; public static final String ELEMENT = "geoloc"; public static final QName QNAME = new QName(NAMESPACE, ELEMENT); public static final GeoLocation EMPTY_GEO_LOCATION = GeoLocation.builder().build(); private final Double accuracy; private final Double alt; private final Double altAccuracy; private final String area; private final Double bearing; private final String building; private final String country; private final String countryCode; private final String datum; private final String description; private final Double error; private final String floor; private final Double lat; private final String locality; private final Double lon; private final String postalcode; private final String region; private final String room; private final Double speed; private final String street; private final String text; private final Date timestamp; private final String tzo; private final URI uri; private GeoLocation(Builder builder) { accuracy = builder.accuracy; alt = builder.alt; altAccuracy = builder.altAccuracy; area = builder.area; bearing = builder.bearing; building = builder.building; country = builder.country; countryCode = builder.countryCode; datum = builder.datum; description = builder.description; error = builder.error; floor = builder.floor; lat = builder.lat; locality = builder.locality; lon = builder.lon; postalcode = builder.postalcode; region = builder.region; room = builder.room; speed = builder.speed; street = builder.street; text = builder.text; timestamp = builder.timestamp; tzo = builder.tzo; uri = builder.uri; } public Double getAccuracy() { return accuracy; } public Double getAlt() { return alt; } public Double getAltAccuracy() { return altAccuracy; } public String getArea() { return area; } public Double getBearing() { return bearing; } public String getBuilding() { return building; } public String getCountry() { return country; } public String getCountryCode() { return countryCode; } public String getDatum() { return datum; } public String getDescription() { return description; } /** * Get the error. * * @return the error. * @deprecated use {@link #getAccuracy()} instead. */ @Deprecated public Double getError() { return error; } public String getFloor() { return floor; } public Double getLat() { return lat; } public String getLocality() { return locality; } public Double getLon() { return lon; } public String getPostalcode() { return postalcode; } public String getRegion() { return region; } public String getRoom() { return room; } public Double getSpeed() { return speed; } public String getStreet() { return street; } public String getText() { return text; } public Date getTimestamp() { return timestamp; } public String getTzo() { return tzo; } public URI getUri() { return uri; } @Override public QName getQName() { return QNAME; } @Override public String getElementName() { return ELEMENT; } @Override public CharSequence toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) { XmlStringBuilder xml = new XmlStringBuilder(this); xml.rightAngleBracket(); xml.optElement("accuracy", accuracy); xml.optElement("alt", alt); xml.optElement("altaccuracy", altAccuracy); xml.optElement("area", area); xml.optElement("bearing", bearing); xml.optElement("building", building); xml.optElement("country", country); xml.optElement("countrycode", countryCode); xml.optElement("datum", datum); xml.optElement("description", description); xml.optElement("error", error); xml.optElement("floor", floor); xml.optElement("lat", lat); xml.optElement("locality", locality); xml.optElement("lon", lon); xml.optElement("postalcode", postalcode); xml.optElement("region", region); xml.optElement("room", room); xml.optElement("speed", speed); xml.optElement("street", street); xml.optElement("text", text); xml.optElement("timestamp", timestamp); xml.optElement("tzo", tzo); xml.optElement("uri", uri); xml.closeElement(this); return xml; } @Override public String getNamespace() { return NAMESPACE; } private final HashCode.Cache hashCodeCache = new HashCode.Cache(); @Override public int hashCode() { return hashCodeCache.getHashCode(c -> c .append(accuracy) .append(alt) .append(altAccuracy) .append(area) .append(bearing) .append(building) .append(country) .append(countryCode) .append(datum) .append(description) .append(error) .append(floor) .append(lat) .append(locality) .append(lon) .append(postalcode) .append(region) .append(room) .append(speed) .append(street) .append(text) .append(timestamp) .append(tzo) .append(uri) ); } @Override public boolean equals(Object obj) { return EqualsUtil.equals(this, obj, (e, o) -> { e .append(accuracy, o.accuracy) .append(altAccuracy, o.altAccuracy) .append(area, o.area) .append(bearing, o.bearing) .append(building, o.building) .append(country, o.country) .append(countryCode, o.countryCode) .append(datum, o.datum) .append(description, o.description) .append(error, o.error) .append(floor, o.floor) .append(lat, o.lat) .append(locality, o.locality) .append(lon, o.lon) .append(postalcode, o.postalcode) .append(region, o.region) .append(room, o.room) .append(speed, o.speed) .append(street, o.street) .append(text, o.text) .append(timestamp, o.timestamp) .append(tzo, o.tzo) .append(uri, o.uri) ; }); } /** * Returns a new instance of {@link Builder}. * @return Builder */ public static Builder builder() { return new GeoLocation.Builder(); } @Override public boolean isExclusiveElement() { return true; } /** * Returns the first GeoLocation, or null if it doesn't exist in {@link Message}. *
* @param message The Message stanza containing GeoLocation * @return GeoLocation */ public static GeoLocation from(Message message) { return message.getExtension(GeoLocation.class); } /** * Returns the first GeoLocation, or null if it doesn't exist in {@link FormField}. *
* @param formField the Formfield containing GeoLocation * @return GeoLocation */ public static GeoLocation from(FormField formField) { return (GeoLocation) formField.getFormFieldChildElement(QNAME); } /** * This class defines a builder class for {@link GeoLocation}. *
* {@link GeoLocation} instance can be obtained using {@link #build()} method as follows.

* GeoLocation.Builder builder = GeoLocation.builder();
* GeoLocation geoLocation = builder.build();
*

* To set GeoLocation parameters, use their respective setters. */ public static final class Builder { private Double accuracy; private Double alt; private Double altAccuracy; private String area; private Double bearing; private String building; private String country; private String countryCode; // If datum is not included, receiver MUST assume WGS84; receivers MUST implement WGS84; senders MAY use another // datum, but it is not recommended. private String datum = "WGS84"; private String description; private Double error; private String floor; private Double lat; private String locality; private Double lon; private String postalcode; private String region; private String room; private Double speed; private String street; private String text; private Date timestamp; private String tzo; private URI uri; /** * Deprecated, do not use. * @deprecated use {@link GeoLocation#builder()} instead. */ @Deprecated // TODO Make constructor private in Smack 4.6. public Builder() { } /** * Sets accuracy of horizontal GPS error in meters. * * @param accuracy accuracy in meters * @return Builder */ public Builder setAccuracy(Double accuracy) { this.accuracy = accuracy; return this; } /** * Sets Altitude in meters above or below sea level. * * @param alt altitude in meters * @return Builder */ public Builder setAlt(Double alt) { this.alt = alt; return this; } /** * Sets Vertical GPS error in meters. * * @param altAccuracy altAccuracy in meters * @return Builder */ public Builder setAltAccuracy(Double altAccuracy) { this.altAccuracy = altAccuracy; return this; } /** * Sets a named area such as a campus or neighborhood. * * @param area the named area * @return Builder */ public Builder setArea(String area) { this.area = area; return this; } /** * Sets GPS bearing (direction in which the entity is heading
* to reach its next waypoint), measured in decimal degrees,
* relative to true north. * * @param bearing bearing in decimal degrees * @return Builder */ public Builder setBearing(Double bearing) { this.bearing = bearing; return this; } /** * Sets a specific building on a street or in an area. * * @param building name of the building * @return Builder */ public Builder setBuilding(String building) { this.building = building; return this; } /** * Sets the nation where the user is located. * * @param country user's country of location * @return Builder */ public Builder setCountry(String country) { this.country = country; return this; } /** * Sets The ISO 3166 two-letter country code. * * @param countryCode two-letter country code * @return Builder */ public Builder setCountryCode(String countryCode) { this.countryCode = countryCode; return this; } /** * Sets GPS Datum. * * @param datum GPS datum * @return Builder */ public Builder setDatum(String datum) { this.datum = datum; return this; } /** * Sets A natural-language name for or description of the location. * * @param description description of the location * @return Builder */ public Builder setDescription(String description) { this.description = description; return this; } /** * Sets Horizontal GPS error in arc minutes;
* this element is deprecated in favor of accuracy. * * @param error error in arc minutes * @return Builder * @deprecated use {@link #setAccuracy(Double)} instead. */ @Deprecated public Builder setError(Double error) { this.error = error; return this; } /** * Sets a particular floor in a building. * * @param floor floor in a building * @return Builder */ public Builder setFloor(String floor) { this.floor = floor; return this; } /** * Sets Latitude in decimal degrees North. * * @param lat latitude in decimal degrees * @return Builder */ public Builder setLat(Double lat) { this.lat = lat; return this; } /** * Sets Locality within the administrative region,
* such as a town or city. * * @param locality locality in a region * @return Builder */ public Builder setLocality(String locality) { this.locality = locality; return this; } /** * Sets Longitude in decimal degrees East. * * @param lon longitude in decimal degrees * @return Builder */ public Builder setLon(Double lon) { this.lon = lon; return this; } /** * Sets PostalCode used for postal delivery. * * @param postalcode code for postal delivery * @return Builder */ public Builder setPostalcode(String postalcode) { this.postalcode = postalcode; return this; } /** * Sets an administrative region of the nation,
* such as a state or province. * * @param region an administrative region * @return Builder */ public Builder setRegion(String region) { this.region = region; return this; } /** * Sets a particular room in a building. * * @param room room inside a building * @return Builder */ public Builder setRoom(String room) { this.room = room; return this; } /** * Sets Speed at which the entity is moving, in meters per second. * * @param speed speed in meters per second * @return Builder */ public Builder setSpeed(Double speed) { this.speed = speed; return this; } /** * Sets a thoroughfare within the locality, or a crossing of two thoroughfares. * * @param street name of the street * @return Builder */ public Builder setStreet(String street) { this.street = street; return this; } /** * Sets a catch-all element that captures any other information about the location. * * @param text distinctive feature about the location * @return Builder */ public Builder setText(String text) { this.text = text; return this; } /** * Sets UTC timestamp specifying the moment when the reading was taken. * * @param timestamp timestamp of the reading * @return Builder */ public Builder setTimestamp(Date timestamp) { this.timestamp = timestamp; return this; } /** * Sets the time zone offset from UTC for the current location. * * @param tzo time zone offset * @return Builder */ public Builder setTzo(String tzo) { this.tzo = tzo; return this; } /** * Sets URI or URL pointing to information about the location. * * @param uri uri to the location * @return Builder */ public Builder setUri(URI uri) { this.uri = uri; return this; } /** * This method is called to build {@link GeoLocation} from the Builder. * * @return GeoLocation */ public GeoLocation build() { return new GeoLocation(this); } } }