001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 the ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package org.conqat.lib.commons.collections; 018 019import java.io.IOException; 020import java.io.ObjectInputStream; 021import java.io.ObjectOutputStream; 022import java.io.Serializable; 023import java.util.Arrays; 024 025import org.conqat.lib.commons.string.StringUtils; 026 027/** 028 * A wrapper class around a byte array that supports a clean implementation of 029 * {@link #hashCode()} and {@link #equals(Object)}, so byte arrays can be used, 030 * e.g., in a HashMap. The class is immutable. Custom (de)serialization is 031 * provided to make this efficient to use in storage or RMI scenarios. 032 */ 033public class ByteArrayWrapper implements Serializable, Comparable<ByteArrayWrapper> { 034 035 /** Version used for serialization. */ 036 private static final long serialVersionUID = 1; 037 038 /** The wrapped array. */ 039 protected byte[] array; 040 041 /** Constructor. */ 042 public ByteArrayWrapper(byte[] array) { 043 this.array = array.clone(); 044 } 045 046 /** Returns a copy of the internal byte representation. */ 047 public byte[] getBytes() { 048 return array.clone(); 049 } 050 051 /** {@inheritDoc} */ 052 @Override 053 public int hashCode() { 054 return Arrays.hashCode(array); 055 } 056 057 /** {@inheritDoc} */ 058 @Override 059 public boolean equals(Object obj) { 060 if (obj instanceof ByteArrayWrapper) { 061 return Arrays.equals(array, ((ByteArrayWrapper) obj).array); 062 } 063 if (obj instanceof byte[]) { 064 return Arrays.equals(array, ((byte[]) obj)); 065 } 066 return false; 067 } 068 069 /** {@inheritDoc} */ 070 @Override 071 public String toString() { 072 return StringUtils.encodeAsHex(array); 073 } 074 075 /** {@inheritDoc} */ 076 @Override 077 public int compareTo(ByteArrayWrapper o) { 078 if (o == null) { 079 return -1; 080 } 081 082 int lengthDelta = array.length - o.array.length; 083 if (lengthDelta != 0) { 084 return lengthDelta; 085 } 086 087 for (int i = 0; i < array.length; ++i) { 088 int delta = array[i] - o.array[i]; 089 if (delta != 0) { 090 return delta; 091 } 092 } 093 094 return 0; 095 } 096 097 /** Custom serialization. */ 098 private void writeObject(ObjectOutputStream out) throws IOException { 099 out.writeInt(array.length); 100 out.write(array); 101 } 102 103 /** Custom deserialization. */ 104 private void readObject(ObjectInputStream in) throws IOException { 105 int size = in.readInt(); 106 array = new byte[size]; 107 int pos = 0; 108 while (pos < size) { 109 pos += in.read(array, pos, size - pos); 110 } 111 } 112 113 /** Comparator for {@link ByteArrayWrapper}. */ 114 public static class Comparator implements java.util.Comparator<ByteArrayWrapper>, Serializable { 115 116 /** Serial version ID. */ 117 private static final long serialVersionUID = 1; 118 119 /** {@inheritDoc} */ 120 @Override 121 public int compare(ByteArrayWrapper o1, ByteArrayWrapper o2) { 122 return o1.compareTo(o2); 123 } 124 } 125}