| /* |
| * 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.accumulo.core.data; |
| |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| import static java.util.Objects.requireNonNull; |
| import static org.apache.accumulo.core.util.ByteBufferUtil.toBytes; |
| |
| import java.io.DataInput; |
| import java.io.DataOutput; |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| |
| import org.apache.hadoop.io.BytesWritable; |
| import org.apache.hadoop.io.Text; |
| import org.apache.hadoop.io.WritableComparable; |
| import org.apache.hadoop.io.WritableComparator; |
| |
| /** |
| * A byte sequence that is usable as a key or value. Based on |
| * {@link org.apache.hadoop.io.BytesWritable} only this class is NOT resizable and DOES NOT |
| * distinguish between the size of the sequence and the current capacity as |
| * {@link org.apache.hadoop.io.BytesWritable} does. Hence it is comparatively 'immutable'. |
| */ |
| public class Value implements WritableComparable<Object> { |
| private static final byte[] EMPTY = new byte[0]; |
| protected byte[] value; |
| |
| /** |
| * Creates a zero-size sequence. |
| */ |
| public Value() { |
| this(EMPTY, false); |
| } |
| |
| /** |
| * Creates a value using the UTF-8 encoding of the CharSequence |
| * |
| * @param cs |
| * may not be null |
| * |
| * @since 1.8.0 |
| */ |
| public Value(CharSequence cs) { |
| this(cs.toString().getBytes(UTF_8)); |
| } |
| |
| /** |
| * Creates a Value using the bytes of the Text. Makes a copy, does not use the byte array from the |
| * Text. |
| * |
| * @param text |
| * may not be null |
| * |
| * @since 1.8.0 |
| */ |
| public Value(Text text) { |
| this(text.getBytes(), 0, text.getLength()); |
| } |
| |
| /** |
| * Creates a Value using a byte array as the initial value. The given byte array is used directly |
| * as the backing array, so later changes made to the array reflect into the new Value. |
| * |
| * @param bytes |
| * May not be null |
| */ |
| public Value(byte[] bytes) { |
| this(bytes, false); |
| } |
| |
| /** |
| * Creates a Value using the bytes in a buffer as the initial value. Makes a defensive copy. |
| * |
| * @param bytes |
| * May not be null |
| */ |
| public Value(ByteBuffer bytes) { |
| /* TODO ACCUMULO-2509 right now this uses the entire backing array, which must be accessible. */ |
| this(toBytes(bytes), false); |
| } |
| |
| /** |
| * Creates a Value using a byte array as the initial value. |
| * |
| * @param bytes |
| * may not be null |
| * @param copy |
| * false to use the given byte array directly as the backing array, true to force a copy |
| */ |
| public Value(byte[] bytes, boolean copy) { |
| requireNonNull(bytes); |
| if (copy) { |
| this.value = new byte[bytes.length]; |
| System.arraycopy(bytes, 0, this.value, 0, bytes.length); |
| } else { |
| this.value = bytes; |
| } |
| |
| } |
| |
| /** |
| * Creates a new Value based on another. |
| * |
| * @param ibw |
| * may not be null. |
| */ |
| public Value(final Value ibw) { |
| this(ibw.get(), 0, ibw.getSize()); |
| } |
| |
| /** |
| * Creates a Value based on a range in a byte array. A copy of the bytes is always made. |
| * |
| * @param newData |
| * source of copy, may not be null |
| * @param offset |
| * the offset in newData to start with for value bytes |
| * @param length |
| * the number of bytes in the value |
| * @throws IndexOutOfBoundsException |
| * if offset or length are invalid |
| */ |
| public Value(final byte[] newData, final int offset, final int length) { |
| requireNonNull(newData); |
| this.value = new byte[length]; |
| System.arraycopy(newData, offset, this.value, 0, length); |
| } |
| |
| /** |
| * Gets the byte data of this value. |
| * |
| * @return the underlying byte array directly. |
| */ |
| public byte[] get() { |
| assert (value != null); |
| return this.value; |
| } |
| |
| /** |
| * Sets the byte data of this value. The given byte array is used directly as the backing array, |
| * so later changes made to the array reflect into this Value. |
| * |
| * @param b |
| * may not be null |
| */ |
| public void set(final byte[] b) { |
| requireNonNull(b); |
| this.value = b; |
| } |
| |
| /** |
| * Sets the byte data of this value. The given byte array is copied. |
| * |
| * @param b |
| * may not be null |
| */ |
| public void copy(byte[] b) { |
| requireNonNull(b); |
| this.value = new byte[b.length]; |
| System.arraycopy(b, 0, this.value, 0, b.length); |
| } |
| |
| /** |
| * Gets the size of this value. |
| * |
| * @return size in bytes |
| */ |
| public int getSize() { |
| assert (value != null); |
| return this.value.length; |
| } |
| |
| @Override |
| public void readFields(final DataInput in) throws IOException { |
| this.value = new byte[in.readInt()]; |
| in.readFully(this.value, 0, this.value.length); |
| } |
| |
| @Override |
| public void write(final DataOutput out) throws IOException { |
| out.writeInt(this.value.length); |
| out.write(this.value, 0, this.value.length); |
| } |
| |
| // Below methods copied from BytesWritable |
| |
| @Override |
| public int hashCode() { |
| return WritableComparator.hashBytes(value, this.value.length); |
| } |
| |
| /** |
| * Define the sort order of the BytesWritable. |
| * |
| * @param right_obj |
| * The other bytes writable |
| * @return Positive if left is bigger than right, 0 if they are equal, and negative if left is |
| * smaller than right. |
| */ |
| @Override |
| public int compareTo(Object right_obj) { |
| return compareTo(((Value) right_obj).get()); |
| } |
| |
| /** |
| * Compares the bytes in this object to the specified byte array |
| * |
| * @return Positive if left is bigger than right, 0 if they are equal, and negative if left is |
| * smaller than right. |
| */ |
| public int compareTo(final byte[] that) { |
| int diff = this.value.length - that.length; |
| return (diff != 0) ? diff |
| : WritableComparator.compareBytes(this.value, 0, this.value.length, that, 0, that.length); |
| } |
| |
| @Override |
| public boolean equals(Object right_obj) { |
| if (right_obj instanceof Value) { |
| return compareTo(right_obj) == 0; |
| } |
| return false; |
| } |
| |
| /** |
| * Compares the bytes in this object to the specified byte array |
| * |
| * @return true if the contents of this Value is equivalent to the supplied byte array |
| * @since 2.0.0 |
| */ |
| public boolean contentEquals(byte[] right_obj) { |
| return compareTo(right_obj) == 0; |
| } |
| |
| @Override |
| public String toString() { |
| return new String(get(), UTF_8); |
| } |
| |
| /** |
| * A Comparator optimized for Value. |
| */ |
| public static class Comparator extends WritableComparator { |
| private BytesWritable.Comparator comparator = new BytesWritable.Comparator(); |
| |
| /** constructor */ |
| public Comparator() { |
| super(Value.class); |
| } |
| |
| @Override |
| public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { |
| return comparator.compare(b1, s1, l1, b2, s2, l2); |
| } |
| } |
| |
| static { // register this comparator |
| WritableComparator.define(Value.class, new Comparator()); |
| } |
| |
| } |