1 /* 2 * Copyright 2014 Google Inc. All rights reserved. 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 package com.google.flatbuffers.grpc; 17 18 import com.google.flatbuffers.Table; 19 import io.grpc.Drainable; 20 import io.grpc.KnownLength; 21 import io.grpc.MethodDescriptor; 22 23 import javax.annotation.Nullable; 24 import java.io.ByteArrayInputStream; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.io.OutputStream; 28 import java.nio.ByteBuffer; 29 30 public class FlatbuffersUtils { 31 abstract public static class FBExtactor <T extends Table> { extract(InputStream stream)32 T extract (InputStream stream) throws IOException { 33 if (stream instanceof KnownLength) { 34 int size = stream.available(); 35 ByteBuffer buffer = ByteBuffer.allocate(size); 36 stream.read(buffer.array()); 37 return extract(buffer); 38 } else 39 throw new RuntimeException("The class " + stream.getClass().getCanonicalName() + " does not extend from KnownLength "); 40 } 41 extract(ByteBuffer buffer)42 public abstract T extract(ByteBuffer buffer); 43 44 } 45 46 static class FBInputStream extends InputStream implements Drainable, KnownLength { 47 private final ByteBuffer buffer; 48 private final int size; 49 @Nullable private ByteArrayInputStream inputStream; 50 FBInputStream(ByteBuffer buffer)51 FBInputStream(ByteBuffer buffer) { 52 this.buffer = buffer; 53 this.size = buffer.remaining(); 54 } 55 makeStreamIfNotAlready()56 private void makeStreamIfNotAlready() { 57 if (inputStream == null) 58 inputStream = new ByteArrayInputStream(buffer.array(), buffer.position(), size); 59 } 60 61 @Override drainTo(OutputStream target)62 public int drainTo(OutputStream target) throws IOException { 63 target.write(buffer.array(), buffer.position(), size); 64 return size; 65 } 66 67 @Override read()68 public int read() throws IOException { 69 makeStreamIfNotAlready(); 70 return inputStream.read(); 71 } 72 73 @Override read(byte[] b, int off, int len)74 public int read(byte[] b, int off, int len) throws IOException { 75 makeStreamIfNotAlready(); 76 if (inputStream == null) { 77 if (len >= size) { 78 System.arraycopy(buffer.array(), buffer.position(), b, off, size); 79 return size; 80 } else { 81 makeStreamIfNotAlready(); 82 return inputStream.read(b, off, len); 83 } 84 } else 85 return inputStream.read(b, off, len); 86 } 87 88 @Override available()89 public int available() throws IOException { 90 return inputStream == null ? size : inputStream.available(); 91 } 92 93 } 94 marshaller(final Class<T> clazz, final FBExtactor<T> extractor)95 public static <T extends Table> MethodDescriptor.Marshaller<T> marshaller(final Class<T> clazz, final FBExtactor<T> extractor) { 96 return new MethodDescriptor.ReflectableMarshaller<T>() { 97 @Override 98 public Class<T> getMessageClass() { 99 return clazz; 100 } 101 102 @Override 103 public InputStream stream(T value) { 104 return new FBInputStream (value.getByteBuffer()); 105 } 106 107 @Override 108 public T parse(InputStream stream) { 109 try { 110 return extractor.extract(stream); 111 } catch (IOException e) { 112 throw new RuntimeException(e); 113 } 114 } 115 }; 116 } 117 } 118