/* * Copyright (c) 2016 OBiBa. All rights reserved. * * This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.obiba.jersey.protobuf; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import javax.ws.rs.Consumes; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.Message; import com.google.protobuf.Message.Builder; import com.google.protobuf.MessageLite; @Provider @Consumes(ProtobufNativeProvider.APPLICATION_X_PROTOBUF) @Produces(ProtobufNativeProvider.APPLICATION_X_PROTOBUF) public class ProtobufNativeProvider extends AbstractProtobufProvider implements MessageBodyReader<Object>, MessageBodyWriter<Object> { public static final String APPLICATION_X_PROTOBUF = "application/x-protobuf"; @Override public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return Message.class.isAssignableFrom(type) || isWrapped(type, genericType); } @Override public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { Class<Message> messageType = extractMessageType(type, genericType); ExtensionRegistry extensionRegistry = extensions().forMessage(messageType); Builder builder = builders().forMessage(messageType); if(isWrapped(type, genericType)) { Collection<Message> msgs = new ArrayList<>(); Builder builderClone = builder.clone(); while(builderClone.mergeDelimitedFrom(entityStream, extensionRegistry)) { msgs.add(builderClone.build()); builderClone = builder.clone(); } return msgs; } return builder.mergeFrom(entityStream, extensionRegistry).build(); } @Override public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return Message.class.isAssignableFrom(type) || isWrapped(type, genericType); } @Override public long getSize(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { return -1; } @Override @SuppressWarnings({ "unchecked", "PMD.ExcessiveParameterList" }) public void writeTo(Object obj, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { if(isWrapped(type, genericType)) { for(MessageLite message : (Iterable<Message>) obj) { message.writeDelimitedTo(entityStream); } } else { ((MessageLite) obj).writeTo(entityStream); } } }