/*
* Copyright 2014, The Sporting Exchange Limited
* Copyright 2015, Simon Matić Langford
*
* 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.client.socket;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import com.betfair.cougar.api.export.Protocol;
import com.betfair.cougar.client.api.CompoundContextEmitter;
import com.betfair.cougar.client.socket.resolver.DNSBasedAddressResolver;
import com.betfair.cougar.core.api.OperationBindingDescriptor;
import com.betfair.cougar.core.api.ServiceBindingDescriptor;
import com.betfair.cougar.core.api.ServiceVersion;
import com.betfair.cougar.core.api.ev.ExecutionTimingRecorder;
import com.betfair.cougar.core.api.ev.TimeConstraints;
import com.betfair.cougar.core.api.exception.ServerFaultCode;
import com.betfair.cougar.core.impl.security.CommonNameCertInfoExtractor;
import com.betfair.cougar.core.impl.tracing.CompoundTracer;
import com.betfair.cougar.netutil.nio.marshalling.DefaultExecutionContextResolverFactory;
import com.betfair.cougar.transport.api.DehydratedExecutionContextResolution;
import com.betfair.cougar.transport.api.RequestTimeResolver;
import com.betfair.cougar.transport.impl.DehydratedExecutionContextResolutionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.betfair.cougar.netutil.nio.CougarProtocol;
import com.betfair.cougar.netutil.nio.NioLogger;
import com.betfair.cougar.netutil.nio.TlsNioConfig;
import com.betfair.cougar.netutil.nio.marshalling.DefaultSocketTimeResolver;
import com.betfair.cougar.netutil.nio.marshalling.SocketRMIMarshaller;
import com.betfair.cougar.transport.api.protocol.socket.SocketBindingDescriptor;
import com.betfair.cougar.transport.api.protocol.socket.SocketOperationBindingDescriptor;
import com.betfair.cougar.transport.nio.IoSessionManager;
import com.betfair.cougar.transport.socket.SocketTransportCommandProcessor;
import com.betfair.cougar.util.geolocation.GeoIPLocator;
import com.betfair.cougar.util.JMXReportingThreadPoolExecutor;
import org.mockito.Mockito;
import com.betfair.cougar.api.ExecutionContext;
import com.betfair.cougar.api.security.IdentityResolver;
import com.betfair.cougar.core.api.ev.Executable;
import com.betfair.cougar.core.api.ev.ExecutionObserver;
import com.betfair.cougar.core.api.ev.ExecutionPostProcessor;
import com.betfair.cougar.core.api.ev.ExecutionPreProcessor;
import com.betfair.cougar.core.api.ev.ExecutionResult;
import com.betfair.cougar.core.api.ev.ExecutionVenue;
import com.betfair.cougar.core.api.ev.OperationDefinition;
import com.betfair.cougar.core.api.ev.OperationKey;
import com.betfair.cougar.core.api.exception.CougarServiceException;
import com.betfair.cougar.core.api.security.IdentityResolverFactory;
import com.betfair.cougar.netutil.nio.NioConfig;
import com.betfair.cougar.netutil.nio.hessian.HessianObjectIOFactory;
import com.betfair.cougar.transport.nio.ExecutionVenueNioServer;
import com.betfair.cougar.transport.nio.ExecutionVenueServerHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.mockito.Mockito.mock;
/**
* This class is used as a stub to facilitate NIO unit testing
*/
public class ServerClientFactory {
private static Logger LOGGER = LoggerFactory.getLogger(ServerClientFactory.class);
public static final int COMMAND_STOP_SERVER = 1;
public static final int COMMAND_SLEEP_60S = 2;
public static final int COMMAND_ECHO_ARG2 = 100;
public static final int COMMAND_FRAMEWORK_ERROR = 999;
public static ExecutionVenueNioServer createServer(byte serverVersion, TlsNioConfig cfg) {
CougarProtocol.setMinServerProtocolVersion(serverVersion);
CougarProtocol.setMaxServerProtocolVersion(serverVersion);
final ExecutionVenueNioServer server = new ExecutionVenueNioServer();
server.setNioConfig(cfg);
SocketTransportCommandProcessor cmdProcessor = new SocketTransportCommandProcessor();
cmdProcessor.setTracer(new CompoundTracer());
cmdProcessor.setIdentityResolverFactory(new IdentityResolverFactory());
Executor executor = new Executor() {
@Override
public void execute(Runnable command) {
Thread t = new Thread(command);
t.start();
}
};
DehydratedExecutionContextResolutionImpl contextResolution = new DehydratedExecutionContextResolutionImpl();
contextResolution.registerFactory(new DefaultExecutionContextResolverFactory(mock(GeoIPLocator.class),mock(RequestTimeResolver.class)));
contextResolution.init(false);
SocketRMIMarshaller marshaller = new SocketRMIMarshaller(new CommonNameCertInfoExtractor(), contextResolution);
IdentityResolverFactory identityResolverFactory = new IdentityResolverFactory();
identityResolverFactory.setIdentityResolver(mock(IdentityResolver.class));
ExecutionVenue ev = new ExecutionVenue() {
@Override
public void registerOperation(String namespace, OperationDefinition def, Executable executable, ExecutionTimingRecorder recorder, long maxExecutionTime) {
}
@Override
public OperationDefinition getOperationDefinition(OperationKey key) {
return AbstractClientTest.OPERATION_DEFINITION;
}
@Override
public Set<OperationKey> getOperationKeys() {
return null;
}
@Override
public void execute(ExecutionContext ctx, OperationKey key, Object[] args, ExecutionObserver observer, TimeConstraints timeConstraints) {
switch (Integer.parseInt(args[1].toString())) {
case COMMAND_STOP_SERVER:
LOGGER.info("Stopping server");
server.stop();
break;
case COMMAND_SLEEP_60S:
LOGGER.info("Sleeping for 60s");
try { Thread.sleep(60000L); } catch (Exception e) {}
case COMMAND_ECHO_ARG2:
observer.onResult(new ExecutionResult(args[2]));
break;
case COMMAND_FRAMEWORK_ERROR:
observer.onResult(new ExecutionResult(new CougarServiceException(ServerFaultCode.FrameworkError, AbstractClientTest.BANG)));
break;
}
}
public void execute(final ExecutionContext ctx, final OperationKey key, final Object[] args, final ExecutionObserver observer, Executor executor, final TimeConstraints timeConstraints) {
executor.execute(new Runnable() {
@Override
public void run() {
execute(ctx, key, args, observer, timeConstraints);
}
});
}
@Override
public void setPreProcessors(List<ExecutionPreProcessor> preProcessorList) {
}
@Override
public void setPostProcessors(List<ExecutionPostProcessor> preProcessorList) {
}
};
cmdProcessor.setExecutor(executor);
cmdProcessor.setMarshaller(marshaller);
cmdProcessor.setExecutionVenue(ev);
ServiceBindingDescriptor desc = new SocketBindingDescriptor() {
@Override
public OperationBindingDescriptor[] getOperationBindings() {
return new OperationBindingDescriptor[] { new SocketOperationBindingDescriptor(AbstractClientTest.OPERATION_DEFINITION.getOperationKey()) };
}
@Override
public ServiceVersion getServiceVersion() {
return AbstractClientTest.OPERATION_DEFINITION.getOperationKey().getVersion();
}
@Override
public String getServiceName() {
return AbstractClientTest.OPERATION_DEFINITION.getOperationKey().getServiceName();
}
@Override
public Protocol getServiceProtocol() {
return Protocol.SOCKET;
}
};
cmdProcessor.bind(desc);
cmdProcessor.onCougarStart();
final NioLogger nioLogger = new NioLogger("ALL");
ExecutionVenueServerHandler handler = new ExecutionVenueServerHandler(nioLogger, cmdProcessor, new HessianObjectIOFactory(false));
server.setServerHandler(handler);
IoSessionManager sessionManager = new IoSessionManager();
sessionManager.setNioLogger(nioLogger);
sessionManager.setMaxTimeToWaitForRequestCompletion(5000);
server.setSessionManager(sessionManager);
return server;
}
public static TlsNioConfig getDefaultConfig() {
TlsNioConfig cfg = new TlsNioConfig();
cfg.setNioLogger(new NioLogger("ALL"));
cfg.setReuseAddress(true);
cfg.setTcpNoDelay(true);
return cfg;
}
public static ExecutionVenueNioServer createServer(String host, int port, byte serverVersion) {
return createServer(host, port, serverVersion, getDefaultConfig());
}
public static ExecutionVenueNioServer createServer(String host, int port, byte serverVersion, TlsNioConfig cfg) {
cfg.setListenAddress(host);
cfg.setListenPort(port);
return createServer(serverVersion, cfg);
}
public static ExecutionVenueNioClient createClient (String connectionString, NioConfig cfg) {
DehydratedExecutionContextResolution contextResolution = mock(DehydratedExecutionContextResolution.class);
SocketRMIMarshaller marshaller = new SocketRMIMarshaller(new CommonNameCertInfoExtractor(), contextResolution);
IdentityResolverFactory factory = new IdentityResolverFactory();
factory.setIdentityResolver(mock(IdentityResolver.class));
NioLogger logger = new NioLogger("ALL");
ExecutionVenueNioClient client = new ExecutionVenueNioClient(logger, cfg, new HessianObjectIOFactory(true), new ClientConnectedObjectManager(), null, connectionString,
new JMXReportingThreadPoolExecutor(30, 60, 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()), new JMXReportingThreadPoolExecutor(30, 60, 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()),
new DNSBasedAddressResolver(), new CompoundTracer());
client.setMarshaller(marshaller);
client.setContextEmitter(new CompoundContextEmitter<Map<String, String>, Object>(Collections.EMPTY_LIST));
return client;
}
public static ExecutionVenueNioClient createClient (String connectionString) {
return createClient(connectionString, getDefaultConfig());
}
}