// Path: spring-cloud-sockets/src/main/java/org/springframework/cloud/reactive/socket/ServiceMethodInfo.java
// public class ServiceMethodInfo {
// 
// 	private final Method method;
// 
// 	private final ServiceMappingInfo mappingInfo;
// 
// 	ResolvableType returnType;
// 
// 	MethodParameter payloadParameter;
// 
// 	ResolvableType payloadType;
// 
// 	MethodParameter metadataParameter;
// 
// 	public ServiceMethodInfo(Method method) {
// 		this.method = method;
// 		ReactiveSocket annotated = AnnotatedElementUtils.findMergedAnnotation(method, ReactiveSocket.class);
// 		if(annotated == null){
// 			throw new IllegalStateException("Service methods must be annotated with a one of {@OneWayMapping, @RequestOneMapping, @RequestManyMapping, @RequestStreamMapping} ");
// 		}
// 		this.mappingInfo = new ServiceMappingInfo(annotated.value(), annotated.mimeType(), annotated.exchangeMode());
// 		this.returnType = ResolvableType.forMethodReturnType(method);
// 		findPayloadParameter();
// 		validate();
// 
// 	}
// 
// 	public void validate(){
// 		switch (this.mappingInfo.getExchangeMode()){
// 			case REQUEST_ONE:
// 				if(Void.TYPE.equals(method.getReturnType())){
// 					throw new IllegalArgumentException("Request One methods must return");
// 				}
// 				break;
// 			case REQUEST_MANY:
// 				if(!Flux.class.isAssignableFrom(method.getReturnType())){
// 					throw new IllegalArgumentException("Request Many methods must return a Flux");
// 				}
// 				break;
// 			case REQUEST_STREAM:
// 				if(!Flux.class.isAssignableFrom(method.getReturnType()) || !Flux.class.isAssignableFrom(this.payloadType.resolve())){
// 					throw new IllegalArgumentException("Request Many methods must return and receive a Flux");
// 				}
// 				break;
// 		}
// 	}
// 
// 	private void findPayloadParameter(){
// 		if(this.method.getParameterCount() == 0){
// 			throw new IllegalStateException("Service methods must have at least one receiving parameter");
// 		}
// 
// 		else if(this.method.getParameterCount() == 1){
// 			this.payloadParameter = new MethodParameter(this.method, 0);
// 		}
// 		int payloadAnnotations = Flux.just(this.method.getParameters())
// 				.filter(parameter -> parameter.getAnnotation(Payload.class) != null)
// 				.reduce(0, (a, parameter) -> { return a+1; })
// 				.block();
// 		if(payloadAnnotations > 1){
// 			throw new IllegalStateException("Service methods can have at most one @Payload annotated parameters");
// 		}
// 
// 		for(int i=0; i<this.method.getParameters().length; i++){
// 			Parameter p = this.method.getParameters()[i];
// 			if(p.getAnnotation(Payload.class) != null){
// 				this.payloadParameter = new MethodParameter(this.method, i);
// 				break;
// 			}
// 		}
// 		if(this.payloadParameter == null){
// 			throw new IllegalStateException("Service methods annotated with more than one parameter must declare one @Payload parameter");
// 		}
// 		resolvePayloadType();
// 	}
// 
// 	private void resolvePayloadType(){
// 		this.payloadType = ResolvableType.forMethodParameter(this.method, payloadParameter.getParameterIndex());
// 	}
// 
// 	public ResolvableType getReturnType() {
// 		return returnType;
// 	}
// 
// 	public ResolvableType getParameterType() {
// 		return payloadType;
// 	}
// 
// 	public Method getMethod() {
// 		return method;
// 	}
// 
// 	public ServiceMappingInfo getMappingInfo() {
// 		return mappingInfo;
// 	}
// 
// 	public Object[] buildInvocationArguments(Object payload, Object metadata){
// 		Object[] args = new Object[method.getParameterCount()];
// 		for(int i=0; i<args.length; i++){
// 			if(i == payloadParameter.getParameterIndex()){
// 				args[i] = payload;
// 			}
// 			else if(metadataParameter != null && i == metadataParameter.getParameterIndex()){
// 				args[i] = metadata;
// 			}
// 			else{
// 				args[i] = getDefaultValue(new MethodParameter(this.method, i));
// 			}
// 		}
// 		return args;
// 	}
// 
// 	private Object getDefaultValue(MethodParameter parameter) {
// 		if (Boolean.TYPE.equals(parameter.getNestedParameterType())) {
// 			return Boolean.FALSE;
// 		}
// 		return null;
// 	}
// }
// 
// Path: spring-cloud-sockets/src/main/java/org/springframework/cloud/reactive/socket/converter/Converter.java
// public interface Converter {
// 
// 	Object read(byte[] payload, Class<?> targetType);
// 
// 	byte[] write(Object target);
// 
// 	boolean accept(MimeType mimeType);
// 
// }


import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import io.rsocket.RSocket;
import org.springframework.cloud.reactive.socket.ServiceMethodInfo;
import org.springframework.cloud.reactive.socket.converter.Converter;
/*
 *  Copyright 2017 original author or authors.
 *
 *  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 org.springframework.cloud.reactive.socket.client;




/**
 * @author Vinicius Carvalho
 */
public abstract class AbstractRemoteHandler {

	protected RSocket socket;

	protected ServiceMethodInfo info;


	protected Converter payloadConverter;

// Path: spring-cloud-sockets/src/main/java/org/springframework/cloud/reactive/socket/ServiceMethodInfo.java
// public class ServiceMethodInfo {
// 
// 	private final Method method;
// 
// 	private final ServiceMappingInfo mappingInfo;
// 
// 	ResolvableType returnType;
// 
// 	MethodParameter payloadParameter;
// 
// 	ResolvableType payloadType;
// 
// 	MethodParameter metadataParameter;
// 
// 	public ServiceMethodInfo(Method method) {
// 		this.method = method;
// 		ReactiveSocket annotated = AnnotatedElementUtils.findMergedAnnotation(method, ReactiveSocket.class);
// 		if(annotated == null){
// 			throw new IllegalStateException("Service methods must be annotated with a one of {@OneWayMapping, @RequestOneMapping, @RequestManyMapping, @RequestStreamMapping} ");
// 		}
// 		this.mappingInfo = new ServiceMappingInfo(annotated.value(), annotated.mimeType(), annotated.exchangeMode());
// 		this.returnType = ResolvableType.forMethodReturnType(method);
// 		findPayloadParameter();
// 		validate();
// 
// 	}
// 
// 	public void validate(){
// 		switch (this.mappingInfo.getExchangeMode()){
// 			case REQUEST_ONE:
// 				if(Void.TYPE.equals(method.getReturnType())){
// 					throw new IllegalArgumentException("Request One methods must return");
// 				}
// 				break;
// 			case REQUEST_MANY:
// 				if(!Flux.class.isAssignableFrom(method.getReturnType())){
// 					throw new IllegalArgumentException("Request Many methods must return a Flux");
// 				}
// 				break;
// 			case REQUEST_STREAM:
// 				if(!Flux.class.isAssignableFrom(method.getReturnType()) || !Flux.class.isAssignableFrom(this.payloadType.resolve())){
// 					throw new IllegalArgumentException("Request Many methods must return and receive a Flux");
// 				}
// 				break;
// 		}
// 	}
// 
// 	private void findPayloadParameter(){
// 		if(this.method.getParameterCount() == 0){
// 			throw new IllegalStateException("Service methods must have at least one receiving parameter");
// 		}
// 
// 		else if(this.method.getParameterCount() == 1){
// 			this.payloadParameter = new MethodParameter(this.method, 0);
// 		}
// 		int payloadAnnotations = Flux.just(this.method.getParameters())
// 				.filter(parameter -> parameter.getAnnotation(Payload.class) != null)
// 				.reduce(0, (a, parameter) -> { return a+1; })
// 				.block();
// 		if(payloadAnnotations > 1){
// 			throw new IllegalStateException("Service methods can have at most one @Payload annotated parameters");
// 		}
// 
// 		for(int i=0; i<this.method.getParameters().length; i++){
// 			Parameter p = this.method.getParameters()[i];
// 			if(p.getAnnotation(Payload.class) != null){
// 				this.payloadParameter = new MethodParameter(this.method, i);
// 				break;
// 			}
// 		}
// 		if(this.payloadParameter == null){
// 			throw new IllegalStateException("Service methods annotated with more than one parameter must declare one @Payload parameter");
// 		}
// 		resolvePayloadType();
// 	}
// 
// 	private void resolvePayloadType(){
// 		this.payloadType = ResolvableType.forMethodParameter(this.method, payloadParameter.getParameterIndex());
// 	}
// 
// 	public ResolvableType getReturnType() {
// 		return returnType;
// 	}
// 
// 	public ResolvableType getParameterType() {
// 		return payloadType;
// 	}
// 
// 	public Method getMethod() {
// 		return method;
// 	}
// 
// 	public ServiceMappingInfo getMappingInfo() {
// 		return mappingInfo;
// 	}
// 
// 	public Object[] buildInvocationArguments(Object payload, Object metadata){
// 		Object[] args = new Object[method.getParameterCount()];
// 		for(int i=0; i<args.length; i++){
// 			if(i == payloadParameter.getParameterIndex()){
// 				args[i] = payload;
// 			}
// 			else if(metadataParameter != null && i == metadataParameter.getParameterIndex()){
// 				args[i] = metadata;
// 			}
// 			else{
// 				args[i] = getDefaultValue(new MethodParameter(this.method, i));
// 			}
// 		}
// 		return args;
// 	}
// 
// 	private Object getDefaultValue(MethodParameter parameter) {
// 		if (Boolean.TYPE.equals(parameter.getNestedParameterType())) {
// 			return Boolean.FALSE;
// 		}
// 		return null;
// 	}
// }
// 
// Path: spring-cloud-sockets/src/main/java/org/springframework/cloud/reactive/socket/converter/Converter.java
// public interface Converter {
// 
// 	Object read(byte[] payload, Class<?> targetType);
// 
// 	byte[] write(Object target);
// 
// 	boolean accept(MimeType mimeType);
// 
// }


// Path: spring-cloud-sockets/src/main/java/org/springframework/cloud/reactive/socket/client/AbstractRemoteHandler.java
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import io.rsocket.RSocket;
import org.springframework.cloud.reactive.socket.ServiceMethodInfo;
import org.springframework.cloud.reactive.socket.converter.Converter;

/*
 *  Copyright 2017 original author or authors.
 *
 *  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 org.springframework.cloud.reactive.socket.client;




/**
 * @author Vinicius Carvalho
 */
public abstract class AbstractRemoteHandler {

	protected RSocket socket;

	protected ServiceMethodInfo info;


	protected Converter payloadConverter;

	protected Converter metadataConverter;