| /* |
| * Copyright 2017-present Open Networking Laboratory |
| * |
| * 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.onosproject.lisp.msg.types.lcaf; |
| |
| import io.netty.buffer.ByteBuf; |
| import org.onlab.util.ByteOperator; |
| import org.onosproject.lisp.msg.exceptions.LispParseError; |
| import org.onosproject.lisp.msg.exceptions.LispReaderException; |
| import org.onosproject.lisp.msg.exceptions.LispWriterException; |
| import org.onosproject.lisp.msg.types.LispAddressReader; |
| import org.onosproject.lisp.msg.types.LispAddressWriter; |
| import org.onosproject.lisp.msg.types.LispAfiAddress; |
| |
| import java.util.Objects; |
| |
| import static com.google.common.base.MoreObjects.toStringHelper; |
| import static com.google.common.base.Preconditions.checkNotNull; |
| |
| /** |
| * Geo Coordinate type LCAF address class. |
| * <p> |
| * Geo Coordinate type is defined in draft-ietf-lisp-lcaf-22 |
| * https://tools.ietf.org/html/draft-ietf-lisp-lcaf-22#page-11 |
| * |
| * <pre> |
| * {@literal |
| * 0 1 2 3 |
| * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | AFI = 16387 | Rsvd1 | Flags | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | Type = 5 | Rsvd2 | Length | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * |N| Latitude Degrees | Minutes | Seconds | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * |E| Longitude Degrees | Minutes | Seconds | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | Altitude | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * | AFI = x | Address ... | |
| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| * }</pre> |
| */ |
| public final class LispGeoCoordinateLcafAddress extends LispLcafAddress { |
| |
| private final boolean north; |
| private final short latitudeDegree; |
| private final byte latitudeMinute; |
| private final byte latitudeSecond; |
| private final boolean east; |
| private final short longitudeDegree; |
| private final byte longitudeMinute; |
| private final byte longitudeSecond; |
| private final int altitude; |
| private final LispAfiAddress address; |
| |
| /** |
| * Initializes geo coordinate type LCAF address. |
| * |
| * @param north north flag |
| * @param latitudeDegree latitude degree |
| * @param latitudeMinute latitude minute |
| * @param latitudeSecond latitude second |
| * @param east east flag |
| * @param longitudeDegree longitude degree |
| * @param longitudeMinute longitude minute |
| * @param longitudeSecond longitude second |
| * @param altitude altitude |
| * @param address AFI address |
| */ |
| private LispGeoCoordinateLcafAddress(boolean north, short latitudeDegree, |
| byte latitudeMinute, byte latitudeSecond, |
| boolean east, short longitudeDegree, |
| byte longitudeMinute, byte longitudeSecond, |
| int altitude, LispAfiAddress address) { |
| super(LispCanonicalAddressFormatEnum.GEO_COORDINATE); |
| this.north = north; |
| this.latitudeDegree = latitudeDegree; |
| this.latitudeMinute = latitudeMinute; |
| this.latitudeSecond = latitudeSecond; |
| this.east = east; |
| this.longitudeDegree = longitudeDegree; |
| this.longitudeMinute = longitudeMinute; |
| this.longitudeSecond = longitudeSecond; |
| this.altitude = altitude; |
| this.address = address; |
| } |
| |
| /** |
| * Obtains north flag value. |
| * |
| * @return north flag value |
| */ |
| public boolean isNorth() { |
| return north; |
| } |
| |
| /** |
| * Obtains latitude degree. |
| * |
| * @return latitude degree |
| */ |
| public short getLatitudeDegree() { |
| return latitudeDegree; |
| } |
| |
| /** |
| * Obtains latitude minute. |
| * |
| * @return latitude minute |
| */ |
| public byte getLatitudeMinute() { |
| return latitudeMinute; |
| } |
| |
| /** |
| * Obtains latitude second. |
| * |
| * @return latitude second |
| */ |
| public byte getLatitudeSecond() { |
| return latitudeSecond; |
| } |
| |
| /** |
| * Obtains east flag value. |
| * |
| * @return east flag vlaue |
| */ |
| public boolean isEast() { |
| return east; |
| } |
| |
| /** |
| * Obtains longitude degree. |
| * |
| * @return longitude degree |
| */ |
| public short getLongitudeDegree() { |
| return longitudeDegree; |
| } |
| |
| /** |
| * Obtains longitude minute. |
| * |
| * @return longitude minute |
| */ |
| public byte getLongitudeMinute() { |
| return longitudeMinute; |
| } |
| |
| /** |
| * Obtains longitude second. |
| * |
| * @return longitude second |
| */ |
| public byte getLongitudeSecond() { |
| return longitudeSecond; |
| } |
| |
| /** |
| * Obtains altitude. |
| * |
| * @return altitude |
| */ |
| public int getAltitude() { |
| return altitude; |
| } |
| |
| /** |
| * Obtains AFI address. |
| * |
| * @return AFI address |
| */ |
| public LispAfiAddress getAddress() { |
| return address; |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(north, latitudeDegree, latitudeMinute, latitudeSecond, |
| east, longitudeDegree, longitudeMinute, longitudeSecond, |
| altitude, address); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| |
| if (obj instanceof LispGeoCoordinateLcafAddress) { |
| final LispGeoCoordinateLcafAddress other = |
| (LispGeoCoordinateLcafAddress) obj; |
| return Objects.equals(this.north, other.north) && |
| Objects.equals(this.latitudeDegree, other.latitudeDegree) && |
| Objects.equals(this.latitudeMinute, other.latitudeMinute) && |
| Objects.equals(this.latitudeSecond, other.latitudeSecond) && |
| Objects.equals(this.east, other.east) && |
| Objects.equals(this.longitudeDegree, other.longitudeDegree) && |
| Objects.equals(this.longitudeMinute, other.longitudeMinute) && |
| Objects.equals(this.longitudeSecond, other.longitudeSecond) && |
| Objects.equals(this.altitude, other.altitude) && |
| Objects.equals(this.address, other.address); |
| } |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| return toStringHelper(this) |
| .add("north", north) |
| .add("latitude degree", latitudeDegree) |
| .add("latitude minute", latitudeMinute) |
| .add("latitude second", latitudeSecond) |
| .add("east", east) |
| .add("longitude degree", longitudeDegree) |
| .add("longitude minute", longitudeMinute) |
| .add("longitude second", longitudeSecond) |
| .add("altitude", altitude) |
| .add("address", address) |
| .toString(); |
| } |
| |
| public static final class GeoCoordinateAddressBuilder |
| extends LcafAddressBuilder<GeoCoordinateAddressBuilder> { |
| private boolean north; |
| private short latitudeDegree; |
| private byte latitudeMinute; |
| private byte latitudeSecond; |
| private boolean east; |
| private short longitudeDegree; |
| private byte longitudeMinute; |
| private byte longitudeSecond; |
| private int altitude; |
| private LispAfiAddress address; |
| |
| /** |
| * Sets north flag value. |
| * |
| * @param north north flag value |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withIsNorth(boolean north) { |
| this.north = north; |
| return this; |
| } |
| |
| /** |
| * Sets latitude degree. |
| * |
| * @param latitudeDegree latitude degree |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withLatitudeDegree(short latitudeDegree) { |
| this.latitudeDegree = latitudeDegree; |
| return this; |
| } |
| |
| /** |
| * Sets latitude minute. |
| * |
| * @param latitudeMinute latitude minute |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withLatitudeMinute(byte latitudeMinute) { |
| this.latitudeMinute = latitudeMinute; |
| return this; |
| } |
| |
| /** |
| * Sets latitude second. |
| * |
| * @param latitudeSecond latitude second |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withLatitudeSecond(byte latitudeSecond) { |
| this.latitudeSecond = latitudeSecond; |
| return this; |
| } |
| |
| /** |
| * Sets east flag value. |
| * |
| * @param east east flag |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withIsEast(boolean east) { |
| this.east = east; |
| return this; |
| } |
| |
| /** |
| * Sets longitude degree. |
| * |
| * @param longitudeDegree longitude degree |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withLongitudeDegree(short longitudeDegree) { |
| this.longitudeDegree = longitudeDegree; |
| return this; |
| } |
| |
| /** |
| * Sets longitude minute. |
| * |
| * @param longitudeMinute longitude minute |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withLongitudeMinute(byte longitudeMinute) { |
| this.longitudeMinute = longitudeMinute; |
| return this; |
| } |
| |
| /** |
| * Sets longitude second. |
| * |
| * @param longitudeSecond longitude second |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withLongitudeSecond(byte longitudeSecond) { |
| this.longitudeSecond = longitudeSecond; |
| return this; |
| } |
| |
| /** |
| * Sets altitude. |
| * |
| * @param altitude altitude |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withAltitude(int altitude) { |
| this.altitude = altitude; |
| return this; |
| } |
| |
| /** |
| * Sets AFI address. |
| * |
| * @param address AFI address |
| * @return GeoCoordinateAddressBuilder object |
| */ |
| public GeoCoordinateAddressBuilder withAddress(LispAfiAddress address) { |
| this.address = address; |
| return this; |
| } |
| |
| /** |
| * Builds LispGeoCoordinateLcafAddress instance. |
| * |
| * @return LispGeoCoordinateLcafAddress instance |
| */ |
| @Override |
| public LispGeoCoordinateLcafAddress build() { |
| |
| checkNotNull(address, "Must specify an AFI address"); |
| |
| return new LispGeoCoordinateLcafAddress(north, latitudeDegree, |
| latitudeMinute, latitudeSecond, east, longitudeDegree, |
| longitudeMinute, longitudeSecond, altitude, address); |
| } |
| } |
| |
| /** |
| * GeoCoordinate LCAF address reader class. |
| */ |
| public static class GeoCoordinateLcafAddressReader |
| implements LispAddressReader<LispGeoCoordinateLcafAddress> { |
| |
| private static final int NORTH_INDEX = 7; |
| private static final int EAST_INDEX = 7; |
| private static final int FLAG_SHIFT = 8; |
| |
| @Override |
| public LispGeoCoordinateLcafAddress readFrom(ByteBuf byteBuf) |
| throws LispParseError, LispReaderException { |
| |
| LispLcafAddress.deserializeCommon(byteBuf); |
| |
| // north flag -> 1 bit |
| byte flagWithLatitude = byteBuf.readByte(); |
| |
| boolean north = ByteOperator.getBit(flagWithLatitude, NORTH_INDEX); |
| |
| // latitude degree -> 15 bits |
| short latitudeFirst = flagWithLatitude; |
| if (north) { |
| latitudeFirst = (short) (flagWithLatitude & 0x7F); |
| } |
| short latitude = (short) ((latitudeFirst << FLAG_SHIFT) + byteBuf.readByte()); |
| |
| // latitude minute -> 8 bits |
| byte latitudeMinute = byteBuf.readByte(); |
| |
| // latitude second -> 8 bits |
| byte latitudeSecond = byteBuf.readByte(); |
| |
| // east flag -> 1 bit |
| byte flagWithLongitude = byteBuf.readByte(); |
| |
| boolean east = ByteOperator.getBit(flagWithLongitude, EAST_INDEX); |
| |
| // longitude degree -> 15 bits |
| short longitudeFirst = flagWithLongitude; |
| if (east) { |
| longitudeFirst = (short) (flagWithLongitude & 0x7F); |
| } |
| short longitude = (short) ((longitudeFirst << FLAG_SHIFT) + byteBuf.readByte()); |
| |
| // longitude minute -> 8 bits |
| byte longitudeMinute = byteBuf.readByte(); |
| |
| // longitude second -> 8 bits |
| byte longitudeSecond = byteBuf.readByte(); |
| |
| // altitude -> 32 bits |
| int altitude = byteBuf.readInt(); |
| |
| LispAfiAddress address = new AfiAddressReader().readFrom(byteBuf); |
| |
| return new GeoCoordinateAddressBuilder() |
| .withIsNorth(north) |
| .withLatitudeDegree(latitude) |
| .withLatitudeMinute(latitudeMinute) |
| .withLatitudeSecond(latitudeSecond) |
| .withIsEast(east) |
| .withLongitudeDegree(longitude) |
| .withLongitudeMinute(longitudeMinute) |
| .withLongitudeSecond(longitudeSecond) |
| .withAltitude(altitude) |
| .withAddress(address) |
| .build(); |
| } |
| } |
| |
| /** |
| * GeoCoordinate LCAF address writer class. |
| */ |
| public static class GeoCoordinateLcafAddressWriter |
| implements LispAddressWriter<LispGeoCoordinateLcafAddress> { |
| |
| private static final int NORTH_SHIFT_BIT = 15; |
| private static final int EAST_SHIFT_BIT = 15; |
| |
| private static final int ENABLE_BIT = 1; |
| private static final int DISABLE_BIT = 0; |
| |
| @Override |
| public void writeTo(ByteBuf byteBuf, LispGeoCoordinateLcafAddress address) |
| throws LispWriterException { |
| |
| int lcafIndex = byteBuf.writerIndex(); |
| LispLcafAddress.serializeCommon(byteBuf, address); |
| |
| // north flag + latitude degree |
| short north = DISABLE_BIT; |
| if (address.isNorth()) { |
| north = (short) (ENABLE_BIT << NORTH_SHIFT_BIT); |
| } |
| |
| byteBuf.writeShort(north + address.latitudeDegree); |
| |
| // latitude minute |
| byteBuf.writeByte(address.latitudeMinute); |
| |
| // latitude second |
| byteBuf.writeByte(address.latitudeSecond); |
| |
| // east flag + longitude degree |
| short east = DISABLE_BIT; |
| if (address.isEast()) { |
| east = (short) (ENABLE_BIT << EAST_SHIFT_BIT); |
| } |
| |
| byteBuf.writeShort(east + address.longitudeDegree); |
| |
| // longitude minute |
| byteBuf.writeByte(address.longitudeMinute); |
| |
| // longitude second |
| byteBuf.writeByte(address.longitudeSecond); |
| |
| // altitude |
| byteBuf.writeInt(address.altitude); |
| |
| // address |
| AfiAddressWriter writer = new AfiAddressWriter(); |
| writer.writeTo(byteBuf, address.getAddress()); |
| |
| LispLcafAddress.updateLength(lcafIndex, byteBuf); |
| } |
| } |
| } |