blob: db5b5c68143b4bb06c30318e066b719673ed53ef [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You 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.apache.geode.internal.serialization;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
public class VersioningIO {
private VersioningIO() {}
/**
* Reads ordinal as written by {@link VersioningIO#writeOrdinal(DataOutput,short,boolean)} from
* given {@link DataInput}.
*/
public static short readOrdinal(DataInput in) throws IOException {
final byte ordinal = in.readByte();
if (ordinal != KnownVersion.TOKEN_ORDINAL) {
return ordinal;
} else {
return in.readShort();
}
}
/**
* Write the given ordinal (result of {@link Version#ordinal()}) to given
* {@link DataOutput}. This keeps
* the serialization of ordinal compatible with previous versions writing a single byte to
* DataOutput when possible, and a token with 2 bytes if it is large.
*
* @param out the {@link DataOutput} to write the ordinal write to
* @param ordinal the version to be written
* @param compressed if true, then use single byte for ordinal < 128, and three bytes for beyond
* that, else always use three bytes where the first byte is
* {@link KnownVersion#TOKEN_ORDINAL};
* former
* mode is useful for interoperatibility with previous versions while latter to use fixed
* size for writing version; typically former will be used for P2P/client-server
* communications while latter for persisting to disk; we use the token to ensure that
* {@link #readOrdinal(DataInput)} can deal with both compressed/uncompressed cases
* seemlessly
*/
public static void writeOrdinal(DataOutput out, short ordinal, boolean compressed)
throws IOException {
if (compressed && ordinal <= Byte.MAX_VALUE) {
out.writeByte(ordinal);
} else {
out.writeByte(KnownVersion.TOKEN_ORDINAL);
out.writeShort(ordinal);
}
}
/**
* Reads ordinal as written by {@link VersioningIO#writeOrdinal(ByteBuffer,short,boolean)} from
* given {@link InputStream}. Returns -1 on
* end of stream.
*/
public static short readOrdinalFromInputStream(InputStream is) throws IOException {
final int ordinal = is.read();
if (ordinal != -1) {
if (ordinal != KnownVersion.TOKEN_ORDINAL_INT) {
return (short) ordinal;
} else {
// two byte ordinal
final int ordinalPart1 = is.read();
final int ordinalPart2 = is.read();
if ((ordinalPart1 | ordinalPart2) >= 0) {
return (short) ((ordinalPart1 << 8) | ordinalPart2);
} else {
return -1;
}
}
} else {
return -1;
}
}
/**
* Write the given ordinal (result of {@link Version#ordinal()}) to given
* {@link ByteBuffer}. This keeps
* the serialization of ordinal compatible with previous versions writing a single byte to
* DataOutput when possible, and a token with 2 bytes if it is large.
*
* @param buffer the {@link ByteBuffer} to write the ordinal write to
* @param ordinal the version to be written
* @param compressed if true, then use single byte for ordinal < 128, and three bytes for beyond
* that, else always use three bytes where the first byte is
* {@link KnownVersion#TOKEN_ORDINAL}
*/
public static void writeOrdinal(ByteBuffer buffer, short ordinal, boolean compressed) {
if (compressed && ordinal <= Byte.MAX_VALUE) {
buffer.put((byte) ordinal);
} else {
buffer.put(KnownVersion.TOKEN_ORDINAL);
buffer.putShort(ordinal);
}
}
}