/** * 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"); } } }