com.mockrunner.connector.StreamableRecordByteArrayInteraction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mockrunner-jca Show documentation
Show all versions of mockrunner-jca Show documentation
Mock classes for Java Connector Architecture
package com.mockrunner.connector;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Arrays;
import javax.resource.ResourceException;
import javax.resource.cci.InteractionSpec;
import javax.resource.cci.Record;
import javax.resource.cci.Streamable;
import com.mockrunner.base.NestedApplicationException;
import com.mockrunner.mock.connector.cci.MockStreamableByteArrayRecord;
import com.mockrunner.util.common.StreamUtil;
/**
* This interaction implementor works with bytes arrays and streamable
* records. It takes a byte array for the request and a byte array or
* a Record
instance for the response. If the request byte array
* is null
, which is the default, the implementor accepts any
* request and returns the specified result. If a request byte array is specified,
* this implementor accepts only requests that are equal to the specified request
* byte array. If a request is accepted, this implementor replies with the specified
* response. You can use the various constructors and set
methods
* to configure the expected request data and the response.
* Please check out the documentation of the various methods for details.
*/
public class StreamableRecordByteArrayInteraction implements InteractionImplementor
{
private boolean enabled;
private byte[] expectedRequest;
private byte[] responseData;
private Class responseClass;
private Record responseRecord;
/**
* Sets the expected request and the response to null
,
* i.e. an empty response is returned for every request.
*/
public StreamableRecordByteArrayInteraction()
{
this(null, null, MockStreamableByteArrayRecord.class);
}
/**
* Sets the expected request to null
and prepares
* the specified response data. The response class for the
* {@link #execute(InteractionSpec,Record)} method is set
* to the default {@link com.mockrunner.mock.connector.cci.MockStreamableByteArrayRecord}.
* It is allowed to pass null
for the response data which is equivalent
* to an empty response.
* The specified response is returned for every request.
* @param responseData the response data
*/
public StreamableRecordByteArrayInteraction(byte[] responseData)
{
this(null, responseData, MockStreamableByteArrayRecord.class);
}
/**
* Sets the specified expected request data and prepares
* the specified response data. The response class for the
* {@link #execute(InteractionSpec,Record)} method is set
* to the default {@link com.mockrunner.mock.connector.cci.MockStreamableByteArrayRecord}.
* It is allowed to pass null
for the request and response data
* which is equivalent to an empty expected request (i.e. every request is accepted)
* or to an empty response respectively.
* The specified response is returned, if the actual request matches the specified expected
* request data.
* @param expectedRequest the expected request data
* @param responseData the response data
*/
public StreamableRecordByteArrayInteraction(byte[] expectedRequest, byte[] responseData)
{
this(expectedRequest, responseData, MockStreamableByteArrayRecord.class);
}
/**
* Sets the expected request to null
and prepares
* the specified response data. The response class for the
* {@link #execute(InteractionSpec,Record)} method is set
* to the specified responseClass
. The specified
* responseClass
must implement Record
* and Streamable
, otherwise an
* IllegalArgumentException
will be thrown.
* It is allowed to pass null
for the response data which is
* equivalent to an empty response.
* The specified response is returned for every request.
* @param responseData the response data
* @param responseClass the response Record
class
* @throws IllegalArgumentException if the responseClass
* is not valid
*/
public StreamableRecordByteArrayInteraction(byte[] responseData, Class responseClass)
{
this(null, responseData, responseClass);
}
/**
* Sets the specified expected request data and prepares
* the specified response data. The response class for the
* {@link #execute(InteractionSpec,Record)} method is set
* to the specified responseClass
. The specified
* responseClass
must implement Record
* and Streamable
, otherwise an
* IllegalArgumentException
will be thrown.
* It is allowed to pass null
for the request and response data
* which is equivalent to an empty expected request (i.e. every request is accepted)
* or to an empty response respectively.
* The specified response is returned, if the actual request matches the specified expected
* request data.
* @param expectedRequest the expected request data
* @param responseData the response data
* @param responseClass the response Record
class
* @throws IllegalArgumentException if the responseClass
* is not valid
*/
public StreamableRecordByteArrayInteraction(byte[] expectedRequest, byte[] responseData, Class responseClass)
{
setExpectedRequest(expectedRequest);
setResponse(responseData, responseClass);
this.enabled = true;
}
/**
* Sets the specified expected request data and the response
* Record
for the {@link #execute(InteractionSpec, Record)}
* method. The response Record
is ignored for
* {@link #execute(InteractionSpec,Record,Record)} but takes precedence
* over the specified response byte data for {@link #execute(InteractionSpec, Record)}.
* It is allowed to pass null
for the request and response Record
* which is equivalent to an empty expected request (i.e. every request is accepted)
* or to no specified response Record
, i.e. the specified response
* byte data is taken.
* The specified response is returned, if the actual request matches the specified expected
* request data.
* @param expectedRequest the expected request data
* @param responseRecord the response Record
*/
public StreamableRecordByteArrayInteraction(byte[] expectedRequest, Record responseRecord)
{
setExpectedRequest(expectedRequest);
setResponse(responseRecord);
this.enabled = true;
}
/**
* Sets the expected request to null
and prepares the response
* Record
for the {@link #execute(InteractionSpec, Record)}
* method. The response Record
is ignored for
* {@link #execute(InteractionSpec,Record,Record)} but takes precedence
* over the specified response byte data for {@link #execute(InteractionSpec, Record)}.
* It is allowed to pass null
for the response Record
* which is equivalent to no specified response Record
, i.e. the specified response
* byte data is taken.
* The specified response is returned for every request.
* @param responseRecord the response Record
*/
public StreamableRecordByteArrayInteraction(Record responseRecord)
{
this(null, responseRecord);
}
/**
* Enables this implementor.
*/
public void enable()
{
this.enabled = true;
}
/**
* Disables this implementor. {@link #canHandle(InteractionSpec, Record, Record)}
* always returns false
, if this implementor is disabled.
*/
public void disable()
{
this.enabled = false;
}
/**
* Sets the specified expected request data. The response is returned,
* if the actual request matches the specified expected request data.
* It is allowed to pass null
for the request data
* which is equivalent to an empty expected request (i.e. every request
* is accepted).
* @param expectedRequest the expected request data
*/
public void setExpectedRequest(byte[] expectedRequest)
{
if(null == expectedRequest)
{
this.expectedRequest = null;
}
else
{
this.expectedRequest = (byte[])expectedRequest.clone();
}
}
/**
* Reads the expected request data from the specified InputStream
.
* The response is returned, if the actual request matches the expected request data.
* It is allowed to pass null
for the InputStream
* which is equivalent to an empty expected request (i.e. every request
* is accepted).
* @param expectedRequest the expected request
*/
public void setExpectedRequest(InputStream expectedRequest)
{
if(null == expectedRequest)
{
this.expectedRequest = null;
}
else
{
this.expectedRequest = StreamUtil.getStreamAsByteArray(expectedRequest);
}
}
/**
* Prepares the specified response data. The response class for the
* {@link #execute(InteractionSpec,Record)} method is set
* to the default {@link com.mockrunner.mock.connector.cci.MockStreamableByteArrayRecord}.
* It is allowed to pass null
for the response data
* which is equivalent to an empty response.
* @param responseData the response data
*/
public void setResponse(byte[] responseData)
{
setResponse(responseData, MockStreamableByteArrayRecord.class);
}
/**
* Prepares the specified response data. The response class for the
* {@link #execute(InteractionSpec,Record)} method is set
* to the specified responseClass
. The specified
* responseClass
must implement Record
* and Streamable
, otherwise an
* IllegalArgumentException
will be thrown.
* It is allowed to pass null
for the response data
* which is equivalent to an empty response.
* @param responseData the response data
* @param responseClass the response Record
class
* @throws IllegalArgumentException if the responseClass
* is not valid
*/
public void setResponse(byte[] responseData, Class responseClass)
{
if(!isResponseClassAcceptable(responseClass))
{
throw new IllegalArgumentException("responseClass must implement " + Streamable.class.getName() + " and " + Record.class.getName());
}
if(null == responseData)
{
this.responseData = null;
}
else
{
this.responseData = (byte[])responseData.clone();
}
this.responseClass = responseClass;
}
/**
* Reads the response data from the specified InputStream
.
* The response class for the {@link #execute(InteractionSpec,Record)} method
* is set to the default
* {@link com.mockrunner.mock.connector.cci.MockStreamableByteArrayRecord}.
* It is allowed to pass null
for the InputStream
* which is equivalent to an empty response.
* @param responseData the response data
*/
public void setResponse(InputStream responseData)
{
setResponse(responseData, MockStreamableByteArrayRecord.class);
}
/**
* Reads the response data from the specified InputStream
.
* The response class for the
* {@link #execute(InteractionSpec,Record)} method is set
* to the specified responseClass
. The specified
* responseClass
must implement Record
* and Streamable
, otherwise an
* IllegalArgumentException
will be thrown.
* It is allowed to pass null
for the InputStream
* which is equivalent to an empty response.
* @param responseData the response data
* @param responseClass the response Record
class
* @throws IllegalArgumentException if the responseClass
* is not valid
*/
public void setResponse(InputStream responseData, Class responseClass)
{
if(!isResponseClassAcceptable(responseClass))
{
throw new IllegalArgumentException("responseClass must implement " + Streamable.class.getName() + " and " + Record.class.getName());
}
if(null == responseData)
{
this.responseData = null;
}
else
{
this.responseData = StreamUtil.getStreamAsByteArray(responseData);
}
this.responseClass = responseClass;
}
/**
* Prepares the response Record
for the
* {@link #execute(InteractionSpec, Record)} method. The response
* Record
is ignored for {@link #execute(InteractionSpec,Record,Record)}
* but takes precedence over the specified response byte data for
* {@link #execute(InteractionSpec, Record)}.
* It is allowed to pass null
for the response Record
* which is equivalent to no specified response Record
, i.e. the specified response
* byte data is taken.
* @param responseRecord the response Record
*/
public void setResponse(Record responseRecord)
{
this.responseRecord = responseRecord;
}
/**
* Returns true
if this implementor is enabled and will handle the request.
* This method returns true
if the following prerequisites are fulfilled:
* It is enabled.
* The response Record
must implement Streamable
* or it must be null
(which is the case, if the actual request
* targets the {@link #execute(InteractionSpec,Record)} method instead of
* {@link #execute(InteractionSpec,Record,Record)}).
* The expected request must be null
(use the various
* setExpectedRequest
methods) or the actual request Record
* must implement Streamable
and must contain the same data as
* the specified expected request.
* Otherwise, false
is returned.
* @param interactionSpec the InteractionSpec
for the actual call
* @param actualRequest the request for the actual call
* @param actualResponse the response for the actual call, may be null
* @return true
if this implementor will handle the request and
* will return the specified response, false
otherwise
*/
public boolean canHandle(InteractionSpec interactionSpec, Record actualRequest, Record actualResponse)
{
if(!enabled) return false;
if(!isResponseAcceptable(actualResponse)) return false;
return doesRequestMatch(actualRequest);
}
private boolean doesRequestMatch(Record request)
{
if(null == expectedRequest) return true;
if(null == request) return false;
if(request instanceof Streamable)
{
try
{
Streamable streamableRequest = (Streamable)request;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
streamableRequest.write(stream);
stream.flush();
return Arrays.equals(expectedRequest, stream.toByteArray());
}
catch(Exception exc)
{
throw new NestedApplicationException(exc);
}
}
return false;
}
private boolean isResponseAcceptable(Record response)
{
return (null == response) || (response instanceof Streamable);
}
private boolean isResponseClassAcceptable(Class responseClass)
{
return (null == responseClass) || ((Streamable.class.isAssignableFrom(responseClass)) && (Record.class.isAssignableFrom(responseClass)));
}
/**
* First version of the execute
methods.
* This method returns null
, if the request does not match
* according to the contract of {@link #canHandle}. This never happens under
* normal conditions since the {@link InteractionHandler} does not call
* execute
, if {@link #canHandle} returns false
.
*
* Otherwise, this method returns the specified response. If a response
* Record
object is specified (use {@link #setResponse(Record)}),
* it always takes precedence, i.e. the byte array response will be ignored.
* If no Record
object is specified, a Record
object
* is created and filled with the specified byte response data. Use the
* setResponse
methods that take a byte array or an InputStream
* to prepare response data. The created Record
is of the the
* specified type (the setResponse
methods that take a second
* Class
parameter allows for specifying a type). If no type
* is specified, a {@link com.mockrunner.mock.connector.cci.MockStreamableByteArrayRecord}
* is created. If no response data is specified at all, an empty
* {@link com.mockrunner.mock.connector.cci.MockStreamableByteArrayRecord}
* will be returned.
* @param interactionSpec the interaction spec
* @param actualRequest the actual request
* @return the response according to the current request
*/
public Record execute(InteractionSpec interactionSpec, Record actualRequest) throws ResourceException
{
if(!canHandle(interactionSpec, actualRequest, null)) return null;
if(null != responseRecord) return responseRecord;
Streamable response = null;
try
{
if(null == responseClass)
{
response = new MockStreamableByteArrayRecord();
}
else
{
response = (Streamable)responseClass.newInstance();
}
if(null != responseData)
{
response.read(new ByteArrayInputStream(responseData));
}
}
catch(Exception exc)
{
ResourceException resExc = new ResourceException("execute() failed");
resExc.setLinkedException(exc);
throw resExc;
}
return (Record)response;
}
/**
* Second version of the execute
methods.
* This method returns false
, if the request does not match
* according to the contract of {@link #canHandle}. This never happens under
* normal conditions since the {@link InteractionHandler} does not call
* execute
, if {@link #canHandle} returns false
.
*
* Otherwise, this method fills the response Record
with the
* specified byte response data. Use the setResponse
methods that
* take a byte array or an InputStream
to prepare response data.
* The response Record
must implement Streamable
* (it does, otherwise the request would have been rejected by
* {@link #canHandle}). If no response data is specified at all,
* the response Record
is not touched but true
* is returned anyway
* @param interactionSpec the interaction spec
* @param actualRequest the actual request
* @param actualResponse the actual response
* @return true
under normal conditions
*/
public boolean execute(InteractionSpec interactionSpec, Record actualRequest, Record actualResponse) throws ResourceException
{
if(!canHandle(interactionSpec, actualRequest, actualResponse)) return false;
try
{
if(null != responseData && null != actualResponse)
{
((Streamable)actualResponse).read(new ByteArrayInputStream(responseData));
}
}
catch(Exception exc)
{
ResourceException resExc = new ResourceException("execute() failed");
resExc.setLinkedException(exc);
throw resExc;
}
return true;
}
}