All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.linkedin.restli.examples.greetings.server.StreamingGreetings Maven / Gradle / Ivy

/*
   Copyright (c) 2016 LinkedIn Corp.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package com.linkedin.restli.examples.greetings.server;


import com.linkedin.common.callback.Callback;
import com.linkedin.data.ByteString;
import com.linkedin.r2.message.stream.entitystream.ByteStringWriter;
import com.linkedin.restli.common.HttpStatus;
import com.linkedin.restli.common.attachments.RestLiAttachmentDataSourceWriter;
import com.linkedin.restli.common.attachments.RestLiAttachmentReader;
import com.linkedin.restli.common.attachments.RestLiAttachmentReaderCallback;
import com.linkedin.restli.common.attachments.SingleRestLiAttachmentReaderCallback;
import com.linkedin.restli.examples.greetings.api.Greeting;
import com.linkedin.restli.server.CreateResponse;
import com.linkedin.restli.server.RestLiResponseAttachments;
import com.linkedin.restli.server.RestLiServiceException;
import com.linkedin.restli.server.UpdateResponse;
import com.linkedin.restli.server.annotations.Action;
import com.linkedin.restli.server.annotations.CallbackParam;
import com.linkedin.restli.server.annotations.RestLiAttachmentsParam;
import com.linkedin.restli.server.annotations.RestLiCollection;
import com.linkedin.restli.server.resources.CollectionResourceAsyncTemplate;

import java.io.ByteArrayOutputStream;


/**
 * @author Karim Vidhani
 */
@RestLiCollection(name = "streamingGreetings", namespace = "com.linkedin.restli.examples.greetings.client")
public class StreamingGreetings extends CollectionResourceAsyncTemplate
{
  private static byte[] greetingBytes = "BeginningBytes".getBytes();

  public StreamingGreetings()
  {
  }

  @Override
  public void get(Long key, @CallbackParam Callback callback)
  {
    if (getContext().responseAttachmentsSupported())
    {
      final GreetingWriter greetingWriter = new GreetingWriter(ByteString.copy(greetingBytes));
      final RestLiResponseAttachments streamingAttachments =
          new RestLiResponseAttachments.Builder().appendSingleAttachment(greetingWriter).build();
      getContext().setResponseAttachments(streamingAttachments);
      final String headerValue = getContext().getRequestHeaders().get("getHeader");
      getContext().setResponseHeader("getHeader", headerValue);
      callback.onSuccess(new Greeting().setMessage("Your greeting has an attachment since you were kind and "
                                                   + "decided you wanted to read it!").setId(key));
    }
    callback.onError(new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "You must be able to receive attachments!"));
  }

  public void create(Greeting entity, @CallbackParam Callback callback,
                     @RestLiAttachmentsParam RestLiAttachmentReader attachmentReader)
  {
    if (attachmentReader != null)
    {
      final String headerValue = getContext().getRequestHeaders().get("createHeader");
      getContext().setResponseHeader("createHeader", headerValue);
      attachmentReader.registerAttachmentReaderCallback(new GreetingBlobReaderCallback(callback));
      return;
    }
    callback.onError(new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "You must supply some attachments!"));
  }

  //The delete and update resource methods here are simply to show that although not typical, it is possible to return
  //attachments from DELETE, UPDATE, PARTIAL_UPDATE, BATCH_DELETE, BATCH_UPDATE, and BATCH_PARTIAL_UPDATE. For the sake of
  //brevity DELETE and UPDATE are used as examples.
  @Override
  public void delete(Long key, @CallbackParam Callback callback)
  {
    respondWithResponseAttachment(callback);
  }

  @Override
  public void update(Long key, Greeting entity, @CallbackParam Callback callback)
  {
    respondWithResponseAttachment(callback);
  }

  private void respondWithResponseAttachment(final Callback callback)
  {
    if (getContext().responseAttachmentsSupported())
    {
      //Echo the bytes back from the header
      final String headerValue = getContext().getRequestHeaders().get("getHeader");
      final GreetingWriter greetingWriter = new GreetingWriter(ByteString.copy(headerValue.getBytes()));
      final RestLiResponseAttachments streamingAttachments =
          new RestLiResponseAttachments.Builder().appendSingleAttachment(greetingWriter).build();
      getContext().setResponseAttachments(streamingAttachments);
      callback.onSuccess(new UpdateResponse(HttpStatus.S_200_OK));
    }
    callback.onError(new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "You must be able to receive attachments!"));
  }

  @Action(name = "actionNoAttachmentsAllowed")
  public int actionNoAttachmentsAllowed()
  {
    return 100;
  }

  @Action(name = "actionAttachmentsAllowedButDisliked")
  public boolean actionAttachmentsAllowedButDisliked(final @RestLiAttachmentsParam RestLiAttachmentReader attachmentReader)
  {
    //Verify that null was passed in by returning true;
    if (attachmentReader == null)
    {
      return true;
    }
    else
    {
      return false;
    }
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  //For writing the response attachment
  private static class GreetingWriter extends ByteStringWriter implements RestLiAttachmentDataSourceWriter
  {
    private GreetingWriter(final ByteString content)
    {
      super(content);
    }

    @Override
    public String getAttachmentID()
    {
      return "12345";
    }
  }

  //For reading in the request attachment
  private static class GreetingBlobReaderCallback implements RestLiAttachmentReaderCallback
  {
    private final Callback _createResponseCallback;

    private GreetingBlobReaderCallback(final Callback createResponseCallback)
    {
      _createResponseCallback = createResponseCallback;
    }

    @Override
    public void onNewAttachment(RestLiAttachmentReader.SingleRestLiAttachmentReader singleRestLiAttachmentReader)
    {
      final SingleGreetingBlobReaderCallback singleGreetingBlobReaderCallback = new SingleGreetingBlobReaderCallback(this,
                                                                                             singleRestLiAttachmentReader);
      singleRestLiAttachmentReader.registerCallback(singleGreetingBlobReaderCallback);
      singleRestLiAttachmentReader.requestAttachmentData();
    }

    @Override
    public void onFinished()
    {
      _createResponseCallback.onSuccess(new CreateResponse(150));
    }

    @Override
    public void onDrainComplete()
    {
      _createResponseCallback.onError(new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR));
    }

    @Override
    public void onStreamError(Throwable throwable)
    {
      _createResponseCallback.onError(new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR));
    }
  }

  private static class SingleGreetingBlobReaderCallback implements SingleRestLiAttachmentReaderCallback
  {
    private final RestLiAttachmentReaderCallback _topLevelCallback;
    private final RestLiAttachmentReader.SingleRestLiAttachmentReader _singleRestLiAttachmentReader;
    private final ByteArrayOutputStream _byteArrayOutputStream = new ByteArrayOutputStream();

    public SingleGreetingBlobReaderCallback(RestLiAttachmentReaderCallback topLevelCallback,
                                            RestLiAttachmentReader.SingleRestLiAttachmentReader singleRestLiAttachmentReader)
    {
      _topLevelCallback = topLevelCallback;
      _singleRestLiAttachmentReader = singleRestLiAttachmentReader;
    }

    @Override
    public void onAttachmentDataAvailable(ByteString attachmentData)
    {
      try
      {
        _byteArrayOutputStream.write(attachmentData.copyBytes());
        _singleRestLiAttachmentReader.requestAttachmentData();
      }
      catch (Exception exception)
      {
        _topLevelCallback.onStreamError(new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR));
      }
    }

    @Override
    public void onFinished()
    {
      greetingBytes = _byteArrayOutputStream.toByteArray();
    }

    @Override
    public void onDrainComplete()
    {
      _topLevelCallback.onStreamError(new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR));
    }

    @Override
    public void onAttachmentError(Throwable throwable)
    {
      //No need to do anything since the top level callback will get invoked with an error anyway
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy