1 /* 2 * Copyright 2014 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.protobuf.nano; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.protobuf.nano.CodedInputByteBufferNano; 22 import com.google.protobuf.nano.MessageNano; 23 import io.grpc.MethodDescriptor.Marshaller; 24 import io.grpc.Status; 25 import java.io.ByteArrayOutputStream; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.io.OutputStream; 29 30 /** 31 * Utility methods for using nano proto with grpc. 32 */ 33 public final class NanoUtils { 34 NanoUtils()35 private NanoUtils() {} 36 37 /** 38 * Adapt {@code parser} to a {@link Marshaller}. 39 * 40 * @since 1.0.0 41 */ marshaller(MessageNanoFactory<T> factory)42 public static <T extends MessageNano> Marshaller<T> marshaller(MessageNanoFactory<T> factory) { 43 return new MessageMarshaller<T>(factory); 44 } 45 46 private static final class MessageMarshaller<T extends MessageNano> implements Marshaller<T> { 47 private static final int BUF_SIZE = 8192; 48 49 private final MessageNanoFactory<T> factory; 50 MessageMarshaller(MessageNanoFactory<T> factory)51 MessageMarshaller(MessageNanoFactory<T> factory) { 52 this.factory = factory; 53 } 54 55 @Override stream(T value)56 public InputStream stream(T value) { 57 return new NanoProtoInputStream(value); 58 } 59 60 @Override parse(InputStream stream)61 public T parse(InputStream stream) { 62 try { 63 // TODO(simonma): Investigate whether we can do 0-copy here. 64 CodedInputByteBufferNano input = 65 CodedInputByteBufferNano.newInstance(toByteArray(stream)); 66 input.setSizeLimit(Integer.MAX_VALUE); 67 T message = factory.newInstance(); 68 message.mergeFrom(input); 69 return message; 70 } catch (IOException ipbe) { 71 throw Status.INTERNAL.withDescription("Failed parsing nano proto message").withCause(ipbe) 72 .asRuntimeException(); 73 } 74 } 75 76 // Copied from guava com.google.common.io.ByteStreams because its API is unstable (beta) toByteArray(InputStream in)77 private static byte[] toByteArray(InputStream in) throws IOException { 78 ByteArrayOutputStream out = new ByteArrayOutputStream(); 79 copy(in, out); 80 return out.toByteArray(); 81 } 82 83 // Copied from guava com.google.common.io.ByteStreams because its API is unstable (beta) copy(InputStream from, OutputStream to)84 private static long copy(InputStream from, OutputStream to) throws IOException { 85 checkNotNull(from); 86 checkNotNull(to); 87 byte[] buf = new byte[BUF_SIZE]; 88 long total = 0; 89 while (true) { 90 int r = from.read(buf); 91 if (r == -1) { 92 break; 93 } 94 to.write(buf, 0, r); 95 total += r; 96 } 97 return total; 98 } 99 } 100 } 101