package io.muoncore;
import io.muoncore.channel.Channels;
import io.muoncore.channel.support.Scheduler;
import io.muoncore.codec.Codecs;
import io.muoncore.codec.json.JsonOnlyCodecs;
import io.muoncore.config.AutoConfiguration;
import io.muoncore.descriptors.SchemaDescriptor;
import io.muoncore.descriptors.SchemasDescriptor;
import io.muoncore.descriptors.ServiceExtendedDescriptor;
import io.muoncore.descriptors.ServiceExtendedDescriptorSource;
import io.muoncore.protocol.DynamicRegistrationServerStacks;
import io.muoncore.protocol.ServerRegistrar;
import io.muoncore.protocol.ServerStacks;
import io.muoncore.protocol.defaultproto.DefaultServerProtocol;
import io.muoncore.protocol.introspection.SchemaIntrospectionRequest;
import io.muoncore.protocol.introspection.server.IntrospectionServerProtocolStack;
import io.muoncore.protocol.reactivestream.server.DefaultPublisherLookup;
import io.muoncore.protocol.reactivestream.server.PublisherLookup;
import io.muoncore.protocol.reactivestream.server.ReactiveStreamServerStack;
import io.muoncore.protocol.requestresponse.server.*;
import io.muoncore.transport.MuonTransport;
import io.muoncore.transport.TransportControl;
import io.muoncore.transport.client.MultiTransportClient;
import io.muoncore.transport.client.SimpleTransportMessageDispatcher;
import io.muoncore.transport.client.TransportClient;
import io.muoncore.transport.client.TransportMessageDispatcher;
import io.muoncore.transport.sharedsocket.client.SharedSocketRouter;
import io.muoncore.transport.sharedsocket.server.SharedChannelServerStacks;
import lombok.extern.slf4j.Slf4j;
import reactor.Environment;
import java.util.*;
import java.util.stream.Collectors;
/**
* Simple bundle of default Muon protocol stacks
*/
@Slf4j
public class MultiTransportMuon implements Muon, ServerRegistrarSource {
private MultiTransportClient transportClient;
private TransportControl transportControl;
private Discovery discovery;
private ServerStacks protocols;
private ServerRegistrar registrar;
private RequestResponseHandlers requestResponseHandlers;
private Codecs codecs;
private AutoConfiguration configuration;
private PublisherLookup publisherLookup;
private Scheduler protocolTimer;
private UUID localInstanceId = UUID.randomUUID();
public MultiTransportMuon(
AutoConfiguration configuration,
Discovery discovery,
List<MuonTransport> transports, Codecs codecs) {
Environment.initializeIfEmpty();
this.configuration = configuration;
this.codecs = codecs;
TransportMessageDispatcher wiretap = new SimpleTransportMessageDispatcher();
MultiTransportClient client = new MultiTransportClient(
transports, wiretap, configuration, discovery, codecs);
this.transportClient = client;
this.transportControl = client;
this.discovery = discovery;
this.protocolTimer = new Scheduler();
this.publisherLookup = new DefaultPublisherLookup();
DynamicRegistrationServerStacks stacks = new DynamicRegistrationServerStacks(
new DefaultServerProtocol(codecs, configuration, discovery),
wiretap);
this.protocols = new SharedChannelServerStacks(stacks, codecs);
this.registrar = stacks;
initDefaultRequestHandler();
initServerStacks(stacks);
transports.forEach(tr -> tr.start(discovery, this.protocols, codecs, getScheduler()));
discovery.advertiseLocalService(
new InstanceDescriptor(
localInstanceId.toString(),
configuration.getServiceName(),
configuration.getTags(),
Arrays.asList(codecs.getAvailableCodecs()),
transports.stream().map(MuonTransport::getLocalConnectionURI)
.collect(Collectors.toList()),
generateCapabilities()));
discovery.blockUntilReady();
}
private Set<String> generateCapabilities() {
Set<String> capabilities = new HashSet<>();
capabilities.add(SharedSocketRouter.PROTOCOL);
return capabilities;
}
@Override
public ServerRegistrar getProtocolStacks() {
return registrar;
}
private void initServerStacks(DynamicRegistrationServerStacks stacks) {
stacks.registerServerProtocol(new RequestResponseServerProtocolStack(
requestResponseHandlers, codecs, discovery, configuration));
stacks.registerServerProtocol(new ReactiveStreamServerStack(getPublisherLookup(), getCodecs(), configuration, discovery));
stacks.registerServerProtocol(new IntrospectionServerProtocolStack(
new ServiceExtendedDescriptorSource() {
@Override
public ServiceExtendedDescriptor getServiceExtendedDescriptor() {
return new ServiceExtendedDescriptor(configuration.getServiceName(), registrar.getProtocolDescriptors());
}
@Override
public SchemasDescriptor getSchemasDescriptor(SchemaIntrospectionRequest request) {
return registrar.getSchemasDescriptor(request.getProtocol(), request.getEndpoint());
}
}, codecs, discovery));
}
private void initDefaultRequestHandler() {
this.requestResponseHandlers = new DynamicRequestResponseHandlers(new RequestResponseServerHandler() {
@Override
public HandlerPredicate getPredicate() {
return HandlerPredicates.none();
}
@Override
public void handle(RequestWrapper request) {
request.notFound();
}
@Override
public Map<String, SchemaDescriptor> getDescriptors() {
return Collections.emptyMap();
}
});
}
@Override
public Codecs getCodecs() {
return codecs;
}
@Override
public Discovery getDiscovery() {
return discovery;
}
@Override
public RequestResponseHandlers getRequestResponseHandlers() {
return requestResponseHandlers;
}
@Override
public TransportClient getTransportClient() {
return transportClient;
}
@Override
public AutoConfiguration getConfiguration() {
return configuration;
}
@Override
public void shutdown() {
discovery.shutdown();
transportClient.shutdown();
Channels.shutdown();
}
@Override
public TransportControl getTransportControl() {
return transportControl;
}
@Override
public PublisherLookup getPublisherLookup() {
return publisherLookup;
}
@Override
public Scheduler getScheduler() {
return protocolTimer;
}
}