package hip.ch3.seqfile.protobuf; import com.google.protobuf.MessageLite; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang3.reflect.MethodUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.io.serializer.Deserializer; import org.apache.hadoop.io.serializer.Serialization; import org.apache.hadoop.io.serializer.Serializer; import org.apache.hadoop.io.serializer.WritableSerialization; import org.apache.hadoop.io.serializer.avro.AvroReflectSerialization; import org.apache.hadoop.io.serializer.avro.AvroSpecificSerialization; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; /** * A {@link org.apache.hadoop.io.serializer.Serialization} for {@link com.google.protobuf.MessageLite}s. */ public class ProtobufSerialization extends Configured implements Serialization<MessageLite> { static class ProtobufDeserializer extends Configured implements Deserializer<MessageLite> { private Class<? extends MessageLite> protobufClass; private InputStream in; public ProtobufDeserializer(Configuration conf, Class<? extends MessageLite> c) { setConf(conf); this.protobufClass = c; } @Override public void open(InputStream in) { this.in = in; } @Override public MessageLite deserialize(MessageLite w) throws IOException { MessageLite.Builder builder; if (w == null) { builder = newBuilder(); } else { builder = w.newBuilderForType(); } if (builder.mergeDelimitedFrom(in)) { return builder.build(); } return null; } public MessageLite.Builder newBuilder() throws IOException { try { return (MessageLite.Builder) MethodUtils.invokeExactStaticMethod(protobufClass, "newBuilder"); } catch (NoSuchMethodException e) { throw new IOException(e); } catch (IllegalAccessException e) { throw new IOException(e); } catch (InvocationTargetException e) { throw new IOException(e); } } @Override public void close() throws IOException { IOUtils.closeStream(in); } } static class ProtobufSerializer extends Configured implements Serializer<MessageLite> { private OutputStream out; @Override public void open(OutputStream out) { this.out = out; } @Override public void serialize(MessageLite w) throws IOException { w.writeDelimitedTo(out); } @Override public void close() throws IOException { IOUtils.closeStream(out); } } @Override public boolean accept(Class<?> c) { return MessageLite.class.isAssignableFrom(c); } @Override public Serializer<MessageLite> getSerializer(Class<MessageLite> c) { return new ProtobufSerializer(); } @Override public Deserializer<MessageLite> getDeserializer(Class<MessageLite> c) { return new ProtobufDeserializer(getConf(), c); } public static void register(Configuration conf) { String[] serializations = conf.getStrings("io.serializations"); if (ArrayUtils.isEmpty(serializations)) { serializations = new String[]{WritableSerialization.class.getName(), AvroSpecificSerialization.class.getName(), AvroReflectSerialization.class.getName()}; } serializations = (String[]) ArrayUtils.add(serializations, ProtobufSerialization.class.getName()); conf.setStrings("io.serializations", serializations); } }