package com.epam.wilma.webapp.stub.response;
/*==========================================================================
Copyright 2013-2017 EPAM Systems
This file is part of Wilma.
Wilma is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Wilma is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Wilma. If not, see <http://www.gnu.org/licenses/>.
===========================================================================*/
import com.epam.wilma.common.helper.StackTraceToStringConverter;
import com.epam.wilma.core.MapBasedResponseDescriptorAccess;
import com.epam.wilma.domain.http.WilmaHttpEntity;
import com.epam.wilma.domain.http.WilmaHttpRequest;
import com.epam.wilma.domain.stubconfig.dialog.response.ResponseDescriptor;
import com.epam.wilma.domain.stubconfig.dialog.response.template.TemplateFormatter;
import com.epam.wilma.domain.stubconfig.dialog.response.template.TemplateFormatterDescriptor;
import com.epam.wilma.domain.sequence.WilmaSequence;
import com.epam.wilma.router.domain.ResponseDescriptorDTO;
import com.epam.wilma.sequence.helper.SequenceHeaderUtil;
import com.epam.wilma.sequence.matcher.SequenceMatcher;
import com.epam.wilma.webapp.stub.response.support.HttpServletRequestTransformer;
import com.epam.wilma.webapp.stub.response.support.SequenceResponseGuard;
import com.epam.wilma.webapp.stub.response.support.StubResponseHeaderConfigurer;
import com.epam.wilma.webapp.stub.servlet.helper.WaitProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Set;
/**
* Generates the appropriate response for a request.
* Gets the response descriptor data transfer object from the key-value store using the request's WilmaLoggerId and generates the response.
* @author Tamas_Bihari
*
*/
@Component
public class StubResponseGenerator {
private final Logger logger = LoggerFactory.getLogger(StubResponseGenerator.class);
@Autowired
private MapBasedResponseDescriptorAccess responseDescriptorAccess;
@Autowired
private StackTraceToStringConverter stackTraceConverter;
@Autowired
private WaitProvider waitProvider;
@Autowired
private StubResponseHeaderConfigurer headerConfigurer;
@Autowired
private HttpServletRequestTransformer requestTransformer;
@Autowired
private SequenceHeaderUtil headerCreator;
@Autowired
private SequenceMatcher matcher;
@Autowired
private SequenceResponseGuard sequenceResponseGuard;
/**
* Gets the response descriptor data transfer object from the key-value store using the request's WilmaLoggerId and generates the response.
* @param req is the request for the response generation
* @param resp is the response
* @return with the generated response as byte array
*/
public byte[] generateResponse(final HttpServletRequest req, final HttpServletResponse resp) {
String wilmaLoggerId = req.getHeader(WilmaHttpRequest.WILMA_LOGGER_ID);
byte[] result = null;
if (wilmaLoggerId != null) {
ResponseDescriptorDTO responseDescriptorDTO = responseDescriptorAccess.getResponseDescriptor(wilmaLoggerId);
Set<TemplateFormatterDescriptor> templateFormatterDescriptors = responseDescriptorDTO.getResponseDescriptor().getTemplateFormatters();
//generate pure WilmaHttpRequest
WilmaHttpRequest wilmaRequest = requestTransformer.transformToWilmaHttpRequest(wilmaLoggerId, req, responseDescriptorDTO);
//add wilma information to response header
headerConfigurer.addWilmaInfoToResponseHeader(req, resp, responseDescriptorDTO.getDialogDescriptorName());
//set headers generate response body
result = generate(resp, responseDescriptorDTO, templateFormatterDescriptors, wilmaRequest);
}
return result;
}
private byte[] generate(final HttpServletResponse resp, final ResponseDescriptorDTO responseDescriptorDTO,
final Set<TemplateFormatterDescriptor> templateFormatterDescriptors, final WilmaHttpRequest wilmaRequest) {
byte[] result;
ResponseDescriptor responseDescriptor = responseDescriptorDTO.getResponseDescriptor();
try {
result = responseDescriptor.getAttributes().getTemplate().getResource();
String sequenceKeysParam = wilmaRequest.getHeader(WilmaHttpEntity.WILMA_SEQUENCE_ID);
String[] sequenceIds = headerCreator.resolveSequenceHeader(sequenceKeysParam);
WilmaSequence actualSequence = matcher.matchSequenceKeyWithDescriptor(responseDescriptor.getAttributes().getSequenceDescriptorKey(),
sequenceIds);
if (actualSequence != null) {
wilmaRequest.setSequence(actualSequence);
sequenceResponseGuard.waitForResponses(wilmaRequest, actualSequence);
}
//set response status and content type
headerConfigurer.setResponseContentTypeAndStatus(resp, responseDescriptorDTO);
//run formatters, with formatters we can overwrite both mime type and status code
if (templateFormatterDescriptors != null && !templateFormatterDescriptors.isEmpty()) {
for (TemplateFormatterDescriptor templateFormatterDescriptor : templateFormatterDescriptors) {
TemplateFormatter templateFormatter = templateFormatterDescriptor.getTemplateFormatter();
result = templateFormatter.formatTemplate(wilmaRequest, resp, result, templateFormatterDescriptor.getParams());
}
}
//delay response if necessary
delayResponse(responseDescriptor.getAttributes().getDelay());
} catch (Exception e) {
headerConfigurer.setErrorResponseContentTypeAndStatus(resp);
result = getErrorMessageWithStackTrace(e);
}
return result;
}
private byte[] getErrorMessageWithStackTrace(final Exception e) {
return stackTraceConverter.getStackTraceAsString(e).getBytes();
}
private void delayResponse(final int delay) {
try {
if (delay > 0) {
waitProvider.waitMilliSeconds(delay);
}
} catch (InterruptedException e) {
logger.error("Could not return response. Exception while thread.sleep", e);
}
}
}