/*
Copyright (c) 2015 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.multipart.integ;
import com.linkedin.common.callback.Callback;
import com.linkedin.data.ByteString;
import com.linkedin.multipart.MultiPartMIMEReader;
import com.linkedin.multipart.MultiPartMIMEReaderCallback;
import com.linkedin.multipart.SinglePartMIMEReaderCallback;
import com.linkedin.multipart.exceptions.MultiPartIllegalFormatException;
import com.linkedin.multipart.utils.VariableByteStringWriter;
import com.linkedin.r2.filter.R2Constants;
import com.linkedin.r2.message.Messages;
import com.linkedin.r2.message.RequestContext;
import com.linkedin.r2.message.rest.RestException;
import com.linkedin.r2.message.rest.RestResponse;
import com.linkedin.r2.message.rest.RestResponseBuilder;
import com.linkedin.r2.message.rest.RestStatus;
import com.linkedin.r2.message.stream.StreamRequest;
import com.linkedin.r2.message.stream.StreamRequestBuilder;
import com.linkedin.r2.message.stream.StreamResponse;
import com.linkedin.r2.message.stream.entitystream.EntityStream;
import com.linkedin.r2.message.stream.entitystream.EntityStreams;
import com.linkedin.r2.sample.Bootstrap;
import com.linkedin.r2.transport.common.StreamRequestHandler;
import com.linkedin.r2.transport.common.bridge.server.TransportDispatcher;
import com.linkedin.r2.transport.common.bridge.server.TransportDispatcherBuilder;
import com.linkedin.r2.transport.http.client.HttpClientFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.mail.BodyPart;
import javax.mail.Header;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static com.linkedin.multipart.utils.MIMETestUtils.BODY_LESS_BODY;
import static com.linkedin.multipart.utils.MIMETestUtils.BYTES_BODY;
import static com.linkedin.multipart.utils.MIMETestUtils.HEADER_CONTENT_TYPE;
import static com.linkedin.multipart.utils.MIMETestUtils.HEADER_LESS_BODY;
import static com.linkedin.multipart.utils.MIMETestUtils.LARGE_DATA_SOURCE;
import static com.linkedin.multipart.utils.MIMETestUtils.PURELY_EMPTY_BODY;
import static com.linkedin.multipart.utils.MIMETestUtils.SINGLE_ALL;
import static com.linkedin.multipart.utils.MIMETestUtils.SINGLE_ALL_NO_CALLBACK;
import static com.linkedin.multipart.utils.MIMETestUtils.SINGLE_ALTERNATE;
import static com.linkedin.multipart.utils.MIMETestUtils.SINGLE_ALTERNATE_TOP_REMAINING;
import static com.linkedin.multipart.utils.MIMETestUtils.SINGLE_PARTIAL_TOP_REMAINING;
import static com.linkedin.multipart.utils.MIMETestUtils.SMALL_DATA_SOURCE;
import static com.linkedin.multipart.utils.MIMETestUtils.TOP_ALL_NO_CALLBACK;
import static com.linkedin.multipart.utils.MIMETestUtils.TOP_ALL_WITH_CALLBACK;
/**
* A series of integration tests that write multipart mime envelopes using Javax mail, and then use
* {@link com.linkedin.multipart.MultiPartMIMEReader} on the server side to read and subsequently
* drain the data using different strategies.
*
* @author Karim Vidhani
*/
public class TestMIMEIntegrationReaderDrain extends AbstractMIMEIntegrationStreamTest
{
private static final URI SERVER_URI = URI.create("/pegasusDrainServer");
private MimeServerRequestDrainHandler _mimeServerRequestDrainHandler;
private static final String DRAIN_HEADER = "DrainMe";
@Override
protected TransportDispatcher getTransportDispatcher()
{
_mimeServerRequestDrainHandler = new MimeServerRequestDrainHandler();
return new TransportDispatcherBuilder().addStreamHandler(SERVER_URI, _mimeServerRequestDrainHandler).build();
}
@Override
protected Map<String, String> getClientProperties()
{
Map<String, String> clientProperties = new HashMap<String, String>();
clientProperties.put(HttpClientFactory.HTTP_REQUEST_TIMEOUT, "9000000");
return clientProperties;
}
///////////////////////////////////////////////////////////////////////////////////////
@DataProvider(name = "allTypesOfBodiesDataSource")
public Object[][] allTypesOfBodiesDataSource() throws Exception
{
final List<MimeBodyPart> bodyPartList = new ArrayList<MimeBodyPart>();
bodyPartList.add(SMALL_DATA_SOURCE);
bodyPartList.add(LARGE_DATA_SOURCE);
bodyPartList.add(HEADER_LESS_BODY);
bodyPartList.add(BODY_LESS_BODY);
bodyPartList.add(BYTES_BODY);
bodyPartList.add(PURELY_EMPTY_BODY);
bodyPartList.add(PURELY_EMPTY_BODY);
bodyPartList.add(BYTES_BODY);
bodyPartList.add(BODY_LESS_BODY);
bodyPartList.add(HEADER_LESS_BODY);
bodyPartList.add(LARGE_DATA_SOURCE);
bodyPartList.add(SMALL_DATA_SOURCE);
return new Object[][]
{
{1, bodyPartList},
{R2Constants.DEFAULT_DATA_CHUNK_SIZE, bodyPartList}
};
}
///////////////////////////////////////////////////////////////////////////////////////
@Test(dataProvider = "allTypesOfBodiesDataSource")
public void testSingleAllNoCallback(final int chunkSize, final List<MimeBodyPart> bodyPartList) throws Exception
{
executeRequestWithDrainStrategy(chunkSize, bodyPartList, SINGLE_ALL_NO_CALLBACK, "onFinished");
//Single part drains all individually but doesn't use a callback.
List<SinglePartMIMEDrainReaderCallbackImpl> singlePartMIMEReaderCallbacks =
_mimeServerRequestDrainHandler.getTestMultiPartMIMEReaderCallback().getSinglePartMIMEReaderCallbacks();
Assert.assertEquals(singlePartMIMEReaderCallbacks.size(), 0);
}
@Test(dataProvider = "allTypesOfBodiesDataSource")
public void testDrainAllWithCallbackRegistered(final int chunkSize, final List<MimeBodyPart> bodyPartList) throws Exception
{
executeRequestWithDrainStrategy(chunkSize, bodyPartList, TOP_ALL_WITH_CALLBACK, "onDrainComplete");
//Top level drains all after registering a callback and being invoked for the first time on onNewPart().
List<SinglePartMIMEDrainReaderCallbackImpl> singlePartMIMEReaderCallbacks =
_mimeServerRequestDrainHandler.getTestMultiPartMIMEReaderCallback().getSinglePartMIMEReaderCallbacks();
Assert.assertEquals(singlePartMIMEReaderCallbacks.size(), 0);
}
//todo this test is failing - working with Zhenkai on this
@Test(enabled = false, dataProvider = "allTypesOfBodiesDataSource")
public void testDrainAllWithoutCallbackRegistered(final int chunkSize, final List<MimeBodyPart> bodyPartList) throws Exception
{
executeRequestWithDrainStrategy(chunkSize, bodyPartList, TOP_ALL_NO_CALLBACK, "onDrainComplete");
//Top level drains all without registering a top level callback.
Assert.assertNull(_mimeServerRequestDrainHandler.getTestMultiPartMIMEReaderCallback()); //No callback created
}
@Test(dataProvider = "allTypesOfBodiesDataSource")
public void testSinglePartialTopRemaining(final int chunkSize, final List<MimeBodyPart> bodyPartList) throws Exception
{
//Execute the request, verify the correct header came back to ensure the server took the proper draining actions
//and return the payload so we can assert deeper.
MimeMultipart mimeMultipart = executeRequestWithDrainStrategy(chunkSize, bodyPartList, SINGLE_PARTIAL_TOP_REMAINING,
"onDrainComplete");
//Single part drains the first 6 then the top level drains all of remaining
List<SinglePartMIMEDrainReaderCallbackImpl> singlePartMIMEReaderCallbacks =
_mimeServerRequestDrainHandler.getTestMultiPartMIMEReaderCallback().getSinglePartMIMEReaderCallbacks();
Assert.assertEquals(singlePartMIMEReaderCallbacks.size(), 6);
for (int i = 0; i < singlePartMIMEReaderCallbacks.size(); i++)
{
//Actual
final SinglePartMIMEDrainReaderCallbackImpl currentCallback = singlePartMIMEReaderCallbacks.get(i);
//Expected
final BodyPart currentExpectedPart = mimeMultipart.getBodyPart(i);
//Construct expected headers and verify they match
final Map<String, String> expectedHeaders = new HashMap<String, String>();
@SuppressWarnings("unchecked")
final Enumeration<Header> allHeaders = currentExpectedPart.getAllHeaders();
while (allHeaders.hasMoreElements())
{
final Header header = allHeaders.nextElement();
expectedHeaders.put(header.getName(), header.getValue());
}
Assert.assertEquals(currentCallback._headers, expectedHeaders);
//Verify that the bodies are empty
Assert.assertEquals(currentCallback._finishedData, ByteString.empty());
}
}
@Test(dataProvider = "allTypesOfBodiesDataSource")
public void testSingleAlternateTopRemaining(final int chunkSize, final List<MimeBodyPart> bodyPartList)
throws Exception
{
//Execute the request, verify the correct header came back to ensure the server took the proper draining actions
//and return the payload so we can assert deeper.
MimeMultipart mimeMultipart = executeRequestWithDrainStrategy(chunkSize, bodyPartList,
SINGLE_ALTERNATE_TOP_REMAINING, "onDrainComplete");
//Single part alternates between consumption and draining the first 6 parts, then top level drains all of remaining.
//This means that parts 0, 2, 4 will be consumed and parts 1, 3, 5 will be drained.
List<SinglePartMIMEDrainReaderCallbackImpl> singlePartMIMEReaderCallbacks =
_mimeServerRequestDrainHandler.getTestMultiPartMIMEReaderCallback().getSinglePartMIMEReaderCallbacks();
Assert.assertEquals(singlePartMIMEReaderCallbacks.size(), 6);
//First the consumed
for (int i = 0; i < singlePartMIMEReaderCallbacks.size(); i = i + 2)
{
//Actual
final SinglePartMIMEDrainReaderCallbackImpl currentCallback = singlePartMIMEReaderCallbacks.get(i);
//Expected
final BodyPart currentExpectedPart = mimeMultipart.getBodyPart(i);
//Construct expected headers and verify they match
final Map<String, String> expectedHeaders = new HashMap<String, String>();
@SuppressWarnings("unchecked")
final Enumeration<Header> allHeaders = currentExpectedPart.getAllHeaders();
while (allHeaders.hasMoreElements())
{
final Header header = allHeaders.nextElement();
expectedHeaders.put(header.getName(), header.getValue());
}
Assert.assertEquals(currentCallback._headers, expectedHeaders);
//Verify the body matches
if (currentExpectedPart.getContent() instanceof byte[])
{
Assert.assertEquals(currentCallback._finishedData.copyBytes(), currentExpectedPart.getContent());
}
else
{
//Default is String
Assert.assertEquals(new String(currentCallback._finishedData.copyBytes()), currentExpectedPart.getContent());
}
}
//Then the drained
for (int i = 1; i < singlePartMIMEReaderCallbacks.size(); i = i + 2)
{
//Actual
final SinglePartMIMEDrainReaderCallbackImpl currentCallback = singlePartMIMEReaderCallbacks.get(i);
//Expected
final BodyPart currentExpectedPart = mimeMultipart.getBodyPart(i);
//Construct expected headers and verify they match
final Map<String, String> expectedHeaders = new HashMap<String, String>();
@SuppressWarnings("unchecked")
final Enumeration<Header> allHeaders = currentExpectedPart.getAllHeaders();
while (allHeaders.hasMoreElements())
{
final Header header = allHeaders.nextElement();
expectedHeaders.put(header.getName(), header.getValue());
}
Assert.assertEquals(currentCallback._headers, expectedHeaders);
//Verify that the bodies are empty
Assert.assertEquals(currentCallback._finishedData, ByteString.empty());
}
}
@Test(dataProvider = "allTypesOfBodiesDataSource")
public void testSingleAll(final int chunkSize, final List<MimeBodyPart> bodyPartList) throws Exception
{
//Execute the request, verify the correct header came back to ensure the server took the proper drain actions
//and return the payload so we can assert deeper.
MimeMultipart mimeMultipart = executeRequestWithDrainStrategy(chunkSize, bodyPartList, SINGLE_ALL, "onFinished");
//Single part drains all, one by one
List<SinglePartMIMEDrainReaderCallbackImpl> singlePartMIMEReaderCallbacks =
_mimeServerRequestDrainHandler.getTestMultiPartMIMEReaderCallback().getSinglePartMIMEReaderCallbacks();
Assert.assertEquals(singlePartMIMEReaderCallbacks.size(), 12);
//Verify everything was drained
for (int i = 0; i < singlePartMIMEReaderCallbacks.size(); i++)
{
//Actual
final SinglePartMIMEDrainReaderCallbackImpl currentCallback = singlePartMIMEReaderCallbacks.get(i);
//Expected
final BodyPart currentExpectedPart = mimeMultipart.getBodyPart(i);
//Construct expected headers and verify they match
final Map<String, String> expectedHeaders = new HashMap<String, String>();
@SuppressWarnings("unchecked")
final Enumeration<Header> allHeaders = currentExpectedPart.getAllHeaders();
while (allHeaders.hasMoreElements())
{
final Header header = allHeaders.nextElement();
expectedHeaders.put(header.getName(), header.getValue());
}
Assert.assertEquals(currentCallback._headers, expectedHeaders);
//Verify that the bodies are empty
Assert.assertEquals(currentCallback._finishedData, ByteString.empty());
}
}
@Test(dataProvider = "allTypesOfBodiesDataSource")
public void testSingleAlternate(final int chunkSize, final List<MimeBodyPart> bodyPartList) throws Exception
{
//Execute the request, verify the correct header came back to ensure the server took the proper draining actions
//and return the payload so we can assert deeper.
MimeMultipart mimeMultipart = executeRequestWithDrainStrategy(chunkSize, bodyPartList, SINGLE_ALTERNATE,
"onFinished");
//Single part alternates between consumption and draining for all 12 parts.
//This means that parts 0, 2, 4, etc.. will be consumed and parts 1, 3, 5, etc... will be drained.
List<SinglePartMIMEDrainReaderCallbackImpl> singlePartMIMEReaderCallbacks =
_mimeServerRequestDrainHandler.getTestMultiPartMIMEReaderCallback().getSinglePartMIMEReaderCallbacks();
Assert.assertEquals(singlePartMIMEReaderCallbacks.size(), 12);
//First the consumed
for (int i = 0; i < singlePartMIMEReaderCallbacks.size(); i = i + 2)
{
//Actual
final SinglePartMIMEDrainReaderCallbackImpl currentCallback = singlePartMIMEReaderCallbacks.get(i);
//Expected
final BodyPart currentExpectedPart = mimeMultipart.getBodyPart(i);
//Construct expected headers and verify they match
final Map<String, String> expectedHeaders = new HashMap<String, String>();
@SuppressWarnings("unchecked")
final Enumeration<Header> allHeaders = currentExpectedPart.getAllHeaders();
while (allHeaders.hasMoreElements())
{
final Header header = allHeaders.nextElement();
expectedHeaders.put(header.getName(), header.getValue());
}
Assert.assertEquals(currentCallback._headers, expectedHeaders);
//Verify the body matches
if (currentExpectedPart.getContent() instanceof byte[])
{
Assert.assertEquals(currentCallback._finishedData.copyBytes(), currentExpectedPart.getContent());
}
else
{
//Default is String
Assert.assertEquals(new String(currentCallback._finishedData.copyBytes()), currentExpectedPart.getContent());
}
}
//Then the drained
for (int i = 1; i < singlePartMIMEReaderCallbacks.size(); i = i + 2)
{
//Actual
final SinglePartMIMEDrainReaderCallbackImpl currentCallback = singlePartMIMEReaderCallbacks.get(i);
//Expected
final BodyPart currentExpectedPart = mimeMultipart.getBodyPart(i);
//Construct expected headers and verify they match
final Map<String, String> expectedHeaders = new HashMap<String, String>();
@SuppressWarnings("unchecked")
final Enumeration<Header> allHeaders = currentExpectedPart.getAllHeaders();
while (allHeaders.hasMoreElements())
{
final Header header = allHeaders.nextElement();
expectedHeaders.put(header.getName(), header.getValue());
}
Assert.assertEquals(currentCallback._headers, expectedHeaders);
//Verify that the bodies are empty
Assert.assertEquals(currentCallback._finishedData, ByteString.empty());
}
}
///////////////////////////////////////////////////////////////////////////////////////
private MimeMultipart executeRequestWithDrainStrategy(final int chunkSize, final List<MimeBodyPart> bodyPartList,
final String drainStrategy, final String serverHeaderPrefix) throws Exception
{
MimeMultipart multiPartMimeBody = new MimeMultipart();
//Add your body parts
for (final MimeBodyPart bodyPart : bodyPartList)
{
multiPartMimeBody.addBodyPart(bodyPart);
}
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
multiPartMimeBody.writeTo(byteArrayOutputStream);
final ByteString requestPayload = ByteString.copy(byteArrayOutputStream.toByteArray());
final VariableByteStringWriter variableByteStringWriter = new VariableByteStringWriter(requestPayload, chunkSize);
final EntityStream entityStream = EntityStreams.newEntityStream(variableByteStringWriter);
final StreamRequestBuilder builder = new StreamRequestBuilder(Bootstrap.createHttpURI(PORT, SERVER_URI));
StreamRequest request = builder.setMethod("POST").setHeader(HEADER_CONTENT_TYPE, multiPartMimeBody.getContentType())
.setHeader(DRAIN_HEADER, drainStrategy).build(entityStream);
final AtomicInteger status = new AtomicInteger(-1);
final CountDownLatch latch = new CountDownLatch(1);
final Map<String, String> responseHeaders = new HashMap<String, String>();
Callback<StreamResponse> callback = expectSuccessCallback(latch, status, responseHeaders);
_client.streamRequest(request, callback);
latch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
Assert.assertEquals(status.get(), RestStatus.OK);
Assert.assertEquals(responseHeaders.get(DRAIN_HEADER), serverHeaderPrefix + drainStrategy);
return multiPartMimeBody;
}
private static class SinglePartMIMEDrainReaderCallbackImpl implements SinglePartMIMEReaderCallback
{
final MultiPartMIMEReader.SinglePartMIMEReader _singlePartMIMEReader;
final ByteArrayOutputStream _byteArrayOutputStream = new ByteArrayOutputStream();
Map<String, String> _headers;
ByteString _finishedData = ByteString.empty();
static int partCounter = 0;
SinglePartMIMEDrainReaderCallbackImpl(final MultiPartMIMEReader.SinglePartMIMEReader singlePartMIMEReader)
{
_singlePartMIMEReader = singlePartMIMEReader;
_headers = singlePartMIMEReader.dataSourceHeaders();
}
@Override
public void onPartDataAvailable(ByteString partData)
{
try
{
_byteArrayOutputStream.write(partData.copyBytes());
}
catch (IOException ioException)
{
Assert.fail();
}
_singlePartMIMEReader.requestPartData();
}
@Override
public void onFinished()
{
partCounter++;
_finishedData = ByteString.copy(_byteArrayOutputStream.toByteArray());
}
//Delegate to the top level for now for these two
@Override
public void onDrainComplete()
{
partCounter++;
}
@Override
public void onStreamError(Throwable throwable)
{
//MultiPartMIMEReader will end up calling onStreamError(e) on our top level callback
//which will fail the test
}
}
private static class MultiPartMIMEDrainReaderCallbackImpl implements MultiPartMIMEReaderCallback
{
final Callback<StreamResponse> _r2callback;
final String _drainValue;
final MultiPartMIMEReader _reader;
final List<SinglePartMIMEDrainReaderCallbackImpl> _singlePartMIMEReaderCallbacks = new ArrayList<SinglePartMIMEDrainReaderCallbackImpl>();
MultiPartMIMEDrainReaderCallbackImpl(final Callback<StreamResponse> r2callback, final String drainValue,
final MultiPartMIMEReader reader)
{
_r2callback = r2callback;
_drainValue = drainValue;
_reader = reader;
}
public List<SinglePartMIMEDrainReaderCallbackImpl> getSinglePartMIMEReaderCallbacks()
{
return _singlePartMIMEReaderCallbacks;
}
@Override
public void onNewPart(MultiPartMIMEReader.SinglePartMIMEReader singlePartMIMEReader)
{
if (_drainValue.equalsIgnoreCase(SINGLE_ALL_NO_CALLBACK))
{
singlePartMIMEReader.drainPart();
return;
}
if (_drainValue.equalsIgnoreCase(TOP_ALL_WITH_CALLBACK))
{
_reader.drainAllParts();
return;
}
if (_drainValue.equalsIgnoreCase(SINGLE_PARTIAL_TOP_REMAINING) && _singlePartMIMEReaderCallbacks.size() == 6)
{
_reader.drainAllParts();
return;
}
if (_drainValue.equalsIgnoreCase(SINGLE_ALTERNATE_TOP_REMAINING) && _singlePartMIMEReaderCallbacks.size() == 6)
{
_reader.drainAllParts();
return;
}
//Now we know we have to either consume or drain individually using a registered callback, so we
//register with the SinglePartReader and take appropriate action based on the draining strategy:
SinglePartMIMEDrainReaderCallbackImpl singlePartMIMEReaderCallback = new SinglePartMIMEDrainReaderCallbackImpl(singlePartMIMEReader);
singlePartMIMEReader.registerReaderCallback(singlePartMIMEReaderCallback);
_singlePartMIMEReaderCallbacks.add(singlePartMIMEReaderCallback);
if (_drainValue.equalsIgnoreCase(SINGLE_ALL) || _drainValue.equalsIgnoreCase(SINGLE_PARTIAL_TOP_REMAINING))
{
singlePartMIMEReader.drainPart();
return;
}
if (_drainValue.equalsIgnoreCase(SINGLE_ALTERNATE) || _drainValue.equalsIgnoreCase(SINGLE_ALTERNATE_TOP_REMAINING))
{
if (SinglePartMIMEDrainReaderCallbackImpl.partCounter % 2 == 1)
{
singlePartMIMEReader.drainPart();
}
else
{
singlePartMIMEReader.requestPartData();
}
}
}
@Override
public void onFinished()
{
//Happens for SINGLE_ALL_NO_CALLBACK, SINGLE_ALL and SINGLE_ALTERNATE
RestResponse response = new RestResponseBuilder().setStatus(RestStatus.OK).setHeader(DRAIN_HEADER, "onFinished" + _drainValue).build();
_r2callback.onSuccess(Messages.toStreamResponse(response));
}
@Override
public void onDrainComplete()
{
//Happens for TOP_ALL_WITH_CALLBACK, SINGLE_PARTIAL_TOP_REMAINING and SINGLE_ALTERNATE_TOP_REMAINING
RestResponse response = new RestResponseBuilder().setStatus(RestStatus.OK).setHeader(DRAIN_HEADER, "onDrainComplete" + _drainValue).build();
_r2callback.onSuccess(Messages.toStreamResponse(response));
}
@Override
public void onStreamError(Throwable throwable)
{
RestException restException = new RestException(RestStatus.responseForError(400, throwable));
_r2callback.onError(restException);
}
}
private static class MimeServerRequestDrainHandler implements StreamRequestHandler
{
private MultiPartMIMEDrainReaderCallbackImpl _testMultiPartMIMEReaderCallback = null;
MimeServerRequestDrainHandler()
{
}
public MultiPartMIMEDrainReaderCallbackImpl getTestMultiPartMIMEReaderCallback()
{
return _testMultiPartMIMEReaderCallback;
}
@Override
public void handleRequest(StreamRequest request, RequestContext requestContext,
final Callback<StreamResponse> callback)
{
try
{
final MultiPartMIMEReader reader = MultiPartMIMEReader.createAndAcquireStream(request);
final String shouldDrainValue = request.getHeader(DRAIN_HEADER);
//For all cases, except this, we will register a callback
if (shouldDrainValue.equalsIgnoreCase(TOP_ALL_NO_CALLBACK))
{
reader.drainAllParts();
RestResponse response =
new RestResponseBuilder().setStatus(RestStatus.OK).setHeader(DRAIN_HEADER, "onDrainComplete" + TOP_ALL_NO_CALLBACK).build();
callback.onSuccess(Messages.toStreamResponse(response));
}
else
{
_testMultiPartMIMEReaderCallback = new MultiPartMIMEDrainReaderCallbackImpl(callback, shouldDrainValue, reader);
reader.registerReaderCallback(_testMultiPartMIMEReaderCallback);
}
}
catch (MultiPartIllegalFormatException illegalMimeFormatException)
{
RestException restException = new RestException(RestStatus.responseForError(400, illegalMimeFormatException));
callback.onError(restException);
}
}
}
}