Package com.betfair.cougar.transport.impl.protocol.http.rescript

Source Code of com.betfair.cougar.transport.impl.protocol.http.rescript.RescriptOperationBinding

/*
* 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.cougar.transport.impl.protocol.http.rescript;

import com.betfair.cougar.core.api.ev.OperationDefinition;
import com.betfair.cougar.core.api.ev.OperationKey;
import com.betfair.cougar.core.api.exception.*;
import com.betfair.cougar.core.api.transcription.EnumDerialisationException;
import com.betfair.cougar.core.api.transcription.EnumUtils;
import com.betfair.cougar.core.api.transcription.Parameter;
import com.betfair.cougar.core.api.transcription.ParameterType;
import com.betfair.cougar.marshalling.api.databinding.DataBindingFactory;
import com.betfair.cougar.marshalling.api.databinding.UnMarshaller;
import com.betfair.cougar.marshalling.impl.databinding.DataBindingManager;
import com.betfair.cougar.marshalling.impl.util.BindingUtils;
import com.betfair.cougar.transport.api.protocol.http.rescript.RescriptBody;
import com.betfair.cougar.transport.api.protocol.http.rescript.RescriptOperationBindingDescriptor;
import com.betfair.cougar.transport.api.protocol.http.rescript.RescriptParamBindingDescriptor;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MediaType;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

/**
* This class represents the binding between a rescript operation and an operation definition
*/
public class RescriptOperationBinding {

    private final OperationKey operationKey;
    private final OperationDefinition operationDefinition;
    private final String method;
    private final RescriptParamBindingDescriptor [] paramBindings;
    private final RescriptOperationBindingDescriptor bindingDescriptor;
    private final boolean hardFailEnums;

    public RescriptOperationBinding(RescriptOperationBindingDescriptor bindingDescriptor, OperationDefinition opDef, boolean hardFailEnums) {
        Parameter [] params = opDef.getParameters();
        //this is just to optimize away the lookup of a physical binding from a parameter definition
        //note resultant paramBindings array is in ingress order for the operation, i.e. positional ordering
        paramBindings = new RescriptParamBindingDescriptor[params.length];
        for (int i=0;i<paramBindings.length;i++) {
            paramBindings[i] =
                bindingDescriptor.getHttpParamBindingDescriptor(
                            params[i].getName());
        }
        this.operationKey = bindingDescriptor.getOperationKey();
        this.operationDefinition = opDef;
        this.method = bindingDescriptor.getHttpMethod();
        this.bindingDescriptor = bindingDescriptor;
        this.hardFailEnums = hardFailEnums;
    }

    public String getMethod() {
        return method;
    }

    public OperationKey getOperationKey() {
        return operationKey;
    }

    public RescriptOperationBindingDescriptor getBindingDescriptor() {
    return bindingDescriptor;
  }

  public Object[] resolveArgs(HttpServletRequest request, InputStream inputStream, MediaType mediaType, String encoding) {
        Object[] args = new Object[paramBindings.length];

        String format = mediaType == null || mediaType.getSubtype() == null ? "unknown" : mediaType.getSubtype();
        RescriptBody body = null;
        if (bindingDescriptor.containsBodyData()) {
            //If the request contains body data, then it must be a post request
            if (!request.getMethod().equals("POST")) {
                throw CougarMarshallingException.unmarshallingException(format, "Bad body data", false);
            }
            body = resolveBody(inputStream, mediaType, encoding);
        }

        // jetty 9 handily gives back null when you specify a header with no value, whereas jetty 7 treated this as an empty string.. which we rely on
        // so, we're going to list all the header names, and for each on if the value is null, add them to a set so we can query later..
        Set<String> headersWithNullValues = new HashSet<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String header = headerNames.nextElement();
            if (request.getHeader(header) == null) {
                headersWithNullValues.add(header.toLowerCase());
            }
        }
        try {
            for (int i = 0; i < args.length; ++i) {
                RescriptParamBindingDescriptor descriptor = paramBindings[i];
                Parameter param = operationDefinition.getParameters()[i];
                switch (descriptor.getSource()) {
                    case HEADER :
                        String key = descriptor.getName();
                        args[i] = resolveArgument(headersWithNullValues.contains(key.toLowerCase()) ? "" : request.getHeader(key), param, descriptor, format);
                        break;
                    case QUERY :
                        args[i] = resolveArgument(request.getParameter(descriptor.getName()), param, descriptor, format);
                        break;
                    case BODY :
                        if (body != null) {
                            args[i] = body.getValue(descriptor.getName());
                            // non-null enums get stored as their raw string value so need converting to the true enum value
                            if (param.getParameterType().getType() == ParameterType.Type.ENUM) {
                                if (args[i] != null) {
                                    args[i] = EnumUtils.readEnum(param.getParameterType().getImplementationClass(), (String) args[i]);
                                }
                            }
                        }
                        break;
                    default :
                        throw new PanicInTheCougar("Unsupported argument annotation "+ descriptor.getSource());
                }
                //request.trace("Deserialised argument %d from %s to value %s", i, param.getSource(), args[i]);
            }
        }
        catch (EnumDerialisationException ede) {
            throw CougarMarshallingException.unmarshallingException(format, ede.getMessage(), ede.getCause(), false);
        }
        return args;
    }

    public Object resolveArgument(String value, Parameter param, RescriptParamBindingDescriptor descriptor, String format) {
        if (value != null) {
            //We only support one generic type - no maps etc.
            Class<?> genericClass = null;
            if (param.getParameterType().getComponentTypes() != null &&
                    param.getParameterType().getComponentTypes().length == 1) {
                genericClass = param.getParameterType().getComponentTypes()[0].getImplementationClass();
            }
            return BindingUtils.convertToSimpleType(
                    param.getParameterType().getImplementationClass(),
                    genericClass, param.getName(),  value, false, hardFailEnums, format, false);
        }
        return null;
    }

    public RescriptBody resolveBody(InputStream inputStream, MediaType mediaType, String encoding) {
        // First of all deserialise the body to get the basics of the request
        if (mediaType != null) {
            DataBindingFactory factory = DataBindingManager.getInstance().getFactory(mediaType);
            if(factory == null) {
                throw new CougarFrameworkException("Invalid content type " + mediaType);
            }
            UnMarshaller unMarshaller = factory.getUnMarshaller();
            return (RescriptBody)unMarshaller.unmarshall(inputStream,
                        bindingDescriptor.getBodyClass(),
                        encoding, false);
        }
        return null;
    }

    @Override
    public String toString() {
        return "RescriptOperationBinding{" +
                "operationKey=" + operationKey +
                ", operationDefinition=" + operationDefinition +
                ", method='" + method + '\'' +
                ", paramBindings=" + (paramBindings == null ? null : Arrays.asList(paramBindings)) +
                ", bindingDescriptor=" + bindingDescriptor +
                ", hardFailEnums=" + hardFailEnums +
                '}';
    }
}
TOP

Related Classes of com.betfair.cougar.transport.impl.protocol.http.rescript.RescriptOperationBinding

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.