/**
* Copyright 2012 Willet Inc.
*
* 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 com.willetinc.hadoop.mapreduce.dynamodb;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.codec.binary.Base64;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableUtils;
import com.amazonaws.services.dynamodb.model.AttributeValue;
public class AttributeValueIOUtils {
public static AttributeValue read(Types type, DataInput in)
throws IOException {
AttributeValue value = new AttributeValue();
switch (type) {
case STRING:
value.withS(Text.readString(in));
break;
case NUMBER:
value.withN(Text.readString(in));
break;
case BINARY:
byte[] bytes = WritableUtils.readCompressedByteArray(in);
ByteBuffer buf = ByteBuffer.wrap(bytes);
value.withB(buf);
case STRING_SET:
case NUMBER_SET:
case BINARY_SET: {
// handle sets
int size = in.readInt();
List<AttributeValue> values = new ArrayList<AttributeValue>(size);
for (int i = 0; i < size; i++) {
switch (type) {
case STRING_SET:
values.add(read(Types.STRING, in));
break;
case NUMBER_SET:
values.add(read(Types.NUMBER, in));
break;
case BINARY_SET:
values.add(read(Types.BINARY, in));
break;
default:
throw new IOException(
"Nested sets of sets are not permitted");
}
}
break;
}
}
return value;
}
public static void write(Types type, AttributeValue value, DataOutput out)
throws IOException {
switch (type) {
case STRING:
Text.writeString(out, value.getS());
break;
case NUMBER:
Text.writeString(out, value.getN());
break;
case BINARY: {
WritableUtils.writeCompressedByteArray(out, value.getB().array());
break;
}
case STRING_SET: {
List<String> values = value.getSS();
out.writeInt(values.size());
for (String s : values) {
Text.writeString(out, s);
}
break;
}
case NUMBER_SET: {
List<String> values = value.getNS();
out.writeInt(values.size());
for (String s : values) {
Text.writeString(out, s);
}
break;
}
case BINARY_SET: {
List<ByteBuffer> values = value.getBS();
out.writeInt(values.size());
for (ByteBuffer buf : values) {
WritableUtils.writeCompressedByteArray(out, buf.array());
}
}
}
}
public static Collection<AttributeValue> readCollection(Types type,
DataInput in) throws IOException {
int size = in.readInt();
List<AttributeValue> list = new ArrayList<AttributeValue>(size);
for (int i = 0; i < size; i++) {
list.add(read(type, in));
}
return list;
}
public static void writeCollection(Types type,
Collection<AttributeValue> values, DataOutput out)
throws IOException {
int size = values.size();
out.writeInt(size);
for (AttributeValue value : values) {
write(type, value, out);
}
}
/**
* <p>
* Creates a string representation of the specified AttributeValue.
* </p>
*
* <p>
* Supported AttributeValue types are Number, String, and Binary. Throws an
* IllegalArgumentException if any other types are specified.
* </p>
*
* @param type
* AttributeValue type
* @param value
* value to serialize.
* @return String representation of value.
*/
public static String toString(Types type, AttributeValue value) {
if(null == value) return null;
switch (type) {
case STRING:
return value.getS();
case NUMBER:
return value.getN();
case BINARY:
ByteBuffer buf = value.getB();
return Base64.encodeBase64String(buf.array());
default:
throw new IllegalArgumentException(
"Only String, Number and Binary types are supported");
}
}
/**
* <p>
* Parses the specified string and returns and AttributeValue.
* </p>
*
* <p>
* Supported AttributeValue types are Number, String, and Binary. Throws an
* IllegalArgumentException if any other types are specified.
* </p>
*
* @param type
* AttributeValue type
* @param value
* String generated by the AttributeValueIOUtils.toString()
* method.
* @return Deserialized AttributeValue.
*/
public static AttributeValue valueOf(Types type, String value) {
if(null == value) return null;
switch (type) {
case STRING:
return new AttributeValue().withS(value);
case NUMBER:
return new AttributeValue().withN(value);
case BINARY:
byte[] bytes = Base64.decodeBase64(value);
return new AttributeValue().withB(ByteBuffer.wrap(bytes));
default:
throw new IllegalArgumentException(
"Only String, Number and Binary types are supported");
}
}
}