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

com.mockrunner.connector.StreamableRecordByteArrayInteraction Maven / Gradle / Ivy

There is a newer version: 2.0.7
Show newest version
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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy