/* * Copyright 2013, The Sporting Exchange Limited * * 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.betfair.testing.utils.cougar.beans; import com.betfair.testing.utils.JSONHelpers; import com.betfair.testing.utils.cougar.enums.CougarMessageProtocolRequestTypeEnum; import com.betfair.testing.utils.cougar.enums.CougarMessageProtocolResponseTypeEnum; import com.betfair.testing.utils.cougar.helpers.SOAPRequestBuilder; import com.betfair.testing.utils.cougar.misc.XMLHelpers; import org.json.JSONException; import org.json.JSONObject; import org.springframework.beans.BeanUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.soap.SOAPMessage; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; public class HttpCallBean { private String operationName; private String serviceName; private String serviceExtension; private String version; private Map<CougarMessageProtocolRequestTypeEnum, Object> postQueryObjects = new HashMap<CougarMessageProtocolRequestTypeEnum,Object>(); private Map<String, String> pathParams = null; private Map<String, String> queryParams = null; private List<BatchedRequestBean> batchedRequests = null; private Map<String,String> authCredentials = null; private String authority = null; private String subject = null; private Map<String, String> headerParams = null; private JSONHelpers jHelpers = new JSONHelpers(); private XMLHelpers xHelpers = new XMLHelpers(); private Map<CougarMessageProtocolResponseTypeEnum, HttpResponseBean> responses = new HashMap<CougarMessageProtocolResponseTypeEnum, HttpResponseBean>(); private String baseNameSpace = "http://www.betfair.com/servicetypes"; private String nameSpaceVersion; private String nameSpaceServiceName; private Map<String, String> acceptProtocols = new HashMap<String, String>(); private String ipAddress = "87.248.113.14"; private String host = "localhost"; // Default value (can be overridden in tests) private String port = "8080"; // Default value (can be overridden in tests) private String alternativeURL = ""; // Default value to point requests to standard url. Set this parameter to "/www" in the test to use the alternative operation url private String path; private boolean jsonRPC = false; // Set to true in tests if making a batched JSON query // private IUtilityLogger logger = UtilityLoggerFactory.getLogger(); private static final int NOTFOUND_STATUS_CODE = 404; private String fullPath; public String getNameSpace() { if (nameSpaceServiceName==null || nameSpaceVersion==null) { throw new RuntimeException ("serviceName and version must be set before retrieving nameSpace"); } else { return baseNameSpace + "/" + nameSpaceVersion + "/" + nameSpaceServiceName + "/"; } } public void setNameSpace(String nameSpace) { this.baseNameSpace = nameSpace; } public Map<String, String> getQueryParams() { return queryParams; } public void setQueryParams(Map<String, String> queryParam) { this.queryParams = queryParam; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; this.nameSpaceVersion = version.substring(0,2); } public String getOperationName() { return operationName; } public void setOperationName(String operationName) { this.operationName = operationName; this.setPath(operationName); } // Overload for setting the path to be different to the operation name public void setOperationName(String operationName, String path){ this.operationName = operationName; this.setPath(path); } public Map<String, String> getHeaderParams() { return headerParams; } public void setHeaderParams(Map<String, String> headerParams) { this.headerParams = headerParams; } public Map<String, String> getPathParams() { return pathParams; } public void setPathParams(Map<String, String> pathParams) { this.pathParams = pathParams; } public Map<CougarMessageProtocolRequestTypeEnum,Object> getPostQueryObjects() { return postQueryObjects; } public Object getPostQueryObjectsByEnum(CougarMessageProtocolRequestTypeEnum protocolRequestType) { if (postQueryObjects==null) { return null; } else { return postQueryObjects.get(protocolRequestType); } } public void setRestPostQueryObjects(Document document) { if (document==null) { postQueryObjects.put(CougarMessageProtocolRequestTypeEnum.RESTJSON, null); postQueryObjects.put(CougarMessageProtocolRequestTypeEnum.RESTXML, null); } else { Document newDocument = null; try { /* * Changes to the existing cougar interface - now all REST requests are wrapped in * OperationNameRequest tag. This wraps existing test inputs to conform to new standards. */ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); newDocument = builder.newDocument(); String builtServiceName = operationName.substring(0,1).toUpperCase(Locale.ENGLISH) +operationName.substring(1) + "Request"; Element root = (Element)newDocument.createElement(builtServiceName); newDocument.appendChild(root); /* * Due to changes in the main cougar engine where it expects the operation names * to start in lowercase, a bit of string handling to convert old tests' XML to * conform to the new standard. */ XMLHelpers helper = new XMLHelpers(); String tmp = document.getFirstChild().getNodeName(); helper.renameRootElement(document, tmp.substring(0,1).toLowerCase(Locale.ENGLISH) + tmp.substring(1)); root.appendChild( newDocument.importNode(document.getDocumentElement(), true) ); }catch (ParserConfigurationException e) { // logger.LogBetfairDebugEntry("Parser Error Setting REST PostQueryObject. " + e.getMessage()); } JSONObject jsonRequest; String xmlString; if(newDocument == null){ // New Document was not created for some reason so use original document jsonRequest = jHelpers.convertXMLDocumentToJSONObjectRemoveRootElement(document); document.getDocumentElement().setAttribute("xmlns", getNameSpace()); xmlString = xHelpers.getXMLAsString(document); } else{ jsonRequest = jHelpers.convertXMLDocumentToJSONObjectRemoveRootElement(newDocument); newDocument.getDocumentElement().setAttribute("xmlns", getNameSpace()); xmlString = xHelpers.getXMLAsString(newDocument); } jHelpers.removeJSONObjectHoldingSameTypeList(jsonRequest); String jsonString = jsonRequest.toString(); postQueryObjects.put(CougarMessageProtocolRequestTypeEnum.RESTJSON, jsonString); postQueryObjects.put(CougarMessageProtocolRequestTypeEnum.RESTXML, xmlString.split("\\?>")[1]); } } /** * Takes xml doc as arg that consists is fragment of SOAPMessasge Body * * @param document */ public void setSoapPostQueryObjects(Document document) { SOAPRequestBuilder requestBuilder = new SOAPRequestBuilder(); postQueryObjects.put(CougarMessageProtocolRequestTypeEnum.SOAP, requestBuilder.buildSOAPRequest(document, this)); } /** * Used by concurrency test and take a complete SOAPMessage * * @param soapMessage */ public void setSOAPMessage(SOAPMessage soapMessage) { postQueryObjects.put(CougarMessageProtocolRequestTypeEnum.SOAP, soapMessage); } public String getAuthority() { return authority; } public void setAuthority(String authority) { this.authority = authority; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public Map<CougarMessageProtocolResponseTypeEnum, HttpResponseBean> getResponses() { return responses; } public HttpResponseBean getResponseObjectsByEnum(CougarMessageProtocolResponseTypeEnum protocolResponseType) { //return responses.get(CougarMessageProtocolResponseTypeEnum.valueOf(protocolResponseType.toString())); switch (protocolResponseType) { case SOAP: return responses.get(protocolResponseType); case RESTJSONJSON: case RESTXMLJSON: return createRestJSONResponseBean(protocolResponseType); case RESTJSONXML: case RESTXMLXML: return createRestXMLResponseBean(protocolResponseType); case REST: default: return createRestDefaultResponseBean(protocolResponseType); } } private HttpResponseBean createRestJSONResponseBean(CougarMessageProtocolResponseTypeEnum protocolResponseType){ HttpResponseBean jsonResponseBean = responses.get(protocolResponseType); String responseString = (String)jsonResponseBean.getResponseObject(); if (jsonResponseBean.getHttpStatusCode()==NOTFOUND_STATUS_CODE && responseString.contains("html")) { // If not found html page then create as string responseString = responseString.replace("\r", ""); // Clean string of escaped characters for assertion responseString = responseString.replace("\n", ""); responseString = responseString.replace("\t", ""); jsonResponseBean.setResponseObject(responseString); return jsonResponseBean; } else { HttpResponseBean returnJsonResponseBean = new HttpResponseBean(); JSONObject castedJsonResponseObject; if ((responseString==null) || (responseString.equalsIgnoreCase(""))) { castedJsonResponseObject = null; } else { try { //if the returned result does not contain key-value - e.g. enum if(!responseString.substring(0,1).equals("{")){ responseString = "{response:" + responseString + "}"; } castedJsonResponseObject = jHelpers.parseJSONObjectFromJSONString(responseString); } catch (JSONException e) { throw new RuntimeException ("Response is an invalid JSON String", e); } } BeanUtils.copyProperties(jsonResponseBean, returnJsonResponseBean); returnJsonResponseBean.setResponseObject(castedJsonResponseObject); return returnJsonResponseBean; } } private HttpResponseBean createRestXMLResponseBean(CougarMessageProtocolResponseTypeEnum protocolResponseType){ HttpResponseBean xmlResponseBean = responses.get(protocolResponseType); String responseString = (String)xmlResponseBean.getResponseObject(); if (xmlResponseBean.getHttpStatusCode()==NOTFOUND_STATUS_CODE && responseString.contains(("html"))) { // If not found html page then create as string responseString = responseString.replace("\r", ""); // Clean string of escaped characters for assertion responseString = responseString.replace("\n", ""); responseString = responseString.replace("\t", ""); xmlResponseBean.setResponseObject(responseString); return xmlResponseBean; } else { HttpResponseBean returnXmlResponseBean = new HttpResponseBean(); Document castedXmlResponseObject; if ((responseString==null) || (responseString.equalsIgnoreCase(""))) { castedXmlResponseObject = null; } else{ castedXmlResponseObject = xHelpers.getXMLObjectFromString(responseString); } BeanUtils.copyProperties(xmlResponseBean, returnXmlResponseBean); returnXmlResponseBean.setResponseObject(castedXmlResponseObject); return returnXmlResponseBean; } } private HttpResponseBean createRestDefaultResponseBean(CougarMessageProtocolResponseTypeEnum protocolResponseType){ HttpResponseBean unknownResponseBean = responses.get(protocolResponseType); HttpResponseBean returnUnknownResponseBean = new HttpResponseBean(); String unknownResponseString = (String)unknownResponseBean.getResponseObject(); Object castedResponseObject; if ((unknownResponseString==null) || (unknownResponseString.equalsIgnoreCase(""))) { castedResponseObject=null; } else { try { castedResponseObject = new JSONObject(unknownResponseString); } catch (JSONException e) { castedResponseObject = xHelpers.getXMLObjectFromString(unknownResponseString); } } BeanUtils.copyProperties(unknownResponseBean, returnUnknownResponseBean); returnUnknownResponseBean.setResponseObject(castedResponseObject); return returnUnknownResponseBean; } public void setResponseByEnum(CougarMessageProtocolResponseTypeEnum protocolResponseType, HttpResponseBean response) { responses.put(protocolResponseType, response); } /** * Allow request object to be set for given protocol * @param document * @param protocolRequestType */ public void setPostObjectForRequestType(Document document, Object protocolRequestType) { postQueryObjects = new HashMap<CougarMessageProtocolRequestTypeEnum,Object>(); CougarMessageProtocolRequestTypeEnum type = CougarMessageProtocolRequestTypeEnum.valueOf(protocolRequestType.toString()); switch(type) { case RESTXML: document.getDocumentElement().setAttribute("xmlns", getNameSpace()); String xmlString = xHelpers.getXMLAsString(document); postQueryObjects.put(type, xmlString); break; case RESTJSON: JSONObject jsonRequest = jHelpers.convertXMLDocumentToJSONObjectRemoveRootElement(document); jHelpers.removeJSONObjectHoldingSameTypeList(jsonRequest); String jsonString = jsonRequest.toString(); postQueryObjects.put(type, jsonString); break; case SOAP: this.setSoapPostQueryObjects(document); break; default: throw new RuntimeException ("I dont know how to handle : " + type); } } public String getServiceName() { return serviceName; } public String getServiceExtension(){ return serviceExtension; } public void setServiceName(String serviceName) { this.serviceName = serviceName; this.serviceExtension = serviceName; this.nameSpaceServiceName = Character.toUpperCase(serviceName.charAt(0)) + serviceName.substring(1); } // Overload for when service extension is different to service name public void setServiceName(String serviceName, String serviceExtension){ this.serviceName = serviceName; this.serviceExtension = serviceExtension; this.nameSpaceServiceName = Character.toUpperCase(serviceName.charAt(0)) + serviceName.substring(1); } public Map<String, String> getAcceptProtocols() { return acceptProtocols; } public void setAcceptProtocols(Map<String, String> acceptProtocols) { this.acceptProtocols = acceptProtocols; } public void addAcceptProtocol(String protocol, Integer ranking) { this.acceptProtocols.put(protocol, "q="+ranking); } public void setPostQueryObjects( Map<Object, Object> postQueryObjects) { Map<CougarMessageProtocolRequestTypeEnum, Object> castedMap = new HashMap<CougarMessageProtocolRequestTypeEnum, Object>(); CougarMessageProtocolRequestTypeEnum newKey; Object value; for (Map.Entry<Object, Object> entry:postQueryObjects.entrySet()) { Object key = entry.getKey(); if (key.getClass()!=CougarMessageProtocolRequestTypeEnum.class) { newKey = CougarMessageProtocolRequestTypeEnum.valueOf(key.toString()); value = entry.getValue(); castedMap.put(newKey, value); } } this.postQueryObjects = castedMap; } public String getNameSpaceServiceName() { return nameSpaceServiceName; } public void setNameSpaceServiceName(String nameSpaceServiceName) { this.nameSpaceServiceName = nameSpaceServiceName; } public String getIpAddress() { return ipAddress; } public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } public String getHost(){ return host; } public void setHost(String host){ this.host = host; } public String getPort(){ return port; } public void setPort(String port){ this.port = port; } public String getPath(){ return path; } public void setPath(String path){ this.path = path; } public String getAlternativeURL(){ return alternativeURL; } public void setAlternativeURL(String altURL){ this.alternativeURL = altURL; } public void setAuthCredentials(Map<String,String> authCredentials) { this.authCredentials = authCredentials; } public Map<String,String> getAuthCredentials() { return authCredentials; } public void setJSONRPC(boolean batching){ jsonRPC = batching; } public boolean getJSONRPC(){ return jsonRPC; } public void setBatchedRequests(Map<String,String>[] requests){ List<BatchedRequestBean> batch = new ArrayList<BatchedRequestBean>(); for(int i = 0; i < requests.length; i++){ BatchedRequestBean request = new BatchedRequestBean(); request.setMethod(requests[i].get("method")); request.setParams(requests[i].get("params")); request.setId(requests[i].get("id")); request.setVersion(requests[i].containsKey("version")? requests[i].get("version"):"2.0"); //if version not set - default to "2.0" request.setService(requests[i].containsKey("service")? requests[i].get("service"):"Baseline"); //if service not set - default to "Baseline" batch.add(request); } this.batchedRequests = batch; } public void setBatchedRequestsDirect(List<BatchedRequestBean> requests){ this.batchedRequests = requests; } public List<BatchedRequestBean> getBatchedRequests(){ return batchedRequests; } public String getFullPath() { return fullPath; } // allows overriding of the full request path (for aliases etc) public void setFullPath(String fullPath) { this.fullPath = fullPath; } }