001/*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020package org.apache.hadoop.hbase.rest.provider.consumer;
021
022import java.io.ByteArrayOutputStream;
023import java.io.IOException;
024import java.io.InputStream;
025import java.lang.annotation.Annotation;
026import java.lang.reflect.InvocationTargetException;
027import java.lang.reflect.Type;
028
029import javax.ws.rs.Consumes;
030import javax.ws.rs.WebApplicationException;
031import javax.ws.rs.core.MediaType;
032import javax.ws.rs.core.MultivaluedMap;
033import javax.ws.rs.ext.MessageBodyReader;
034import javax.ws.rs.ext.Provider;
035
036import org.apache.yetus.audience.InterfaceAudience;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039import org.apache.hadoop.hbase.rest.Constants;
040import org.apache.hadoop.hbase.rest.ProtobufMessageHandler;
041
042/**
043 * Adapter for hooking up Jersey content processing dispatch to
044 * ProtobufMessageHandler interface capable handlers for decoding protobuf input.
045 */
046@Provider
047@Consumes({Constants.MIMETYPE_PROTOBUF, Constants.MIMETYPE_PROTOBUF_IETF})
048@InterfaceAudience.Private
049public class ProtobufMessageBodyConsumer
050    implements MessageBodyReader<ProtobufMessageHandler> {
051  private static final Logger LOG =
052    LoggerFactory.getLogger(ProtobufMessageBodyConsumer.class);
053
054  @Override
055  public boolean isReadable(Class<?> type, Type genericType,
056      Annotation[] annotations, MediaType mediaType) {
057    return ProtobufMessageHandler.class.isAssignableFrom(type);
058  }
059
060  @Override
061  public ProtobufMessageHandler readFrom(Class<ProtobufMessageHandler> type, Type genericType,
062      Annotation[] annotations, MediaType mediaType,
063      MultivaluedMap<String, String> httpHeaders, InputStream inputStream)
064      throws IOException, WebApplicationException {
065    ProtobufMessageHandler obj = null;
066    try {
067      obj = type.getDeclaredConstructor().newInstance();
068      ByteArrayOutputStream baos = new ByteArrayOutputStream();
069      byte[] buffer = new byte[4096];
070      int read;
071      do {
072        read = inputStream.read(buffer, 0, buffer.length);
073        if (read > 0) {
074          baos.write(buffer, 0, read);
075        }
076      } while (read > 0);
077      if (LOG.isTraceEnabled()) {
078        LOG.trace(getClass() + ": read " + baos.size() + " bytes from " +
079          inputStream);
080      }
081      obj = obj.getObjectFromMessage(baos.toByteArray());
082    } catch (InstantiationException | NoSuchMethodException | InvocationTargetException
083        | IllegalAccessException e) {
084      throw new WebApplicationException(e);
085    }
086    return obj;
087  }
088}