All Downloads are FREE. Search and download functionalities are using the official Maven repository.

reactor.ipc.stream.StreamSetup Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2011-2017 Pivotal Software Inc, All Rights Reserved.
 *
 * 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 reactor.ipc.stream;

import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import reactor.core.Disposable;
import reactor.core.publisher.DirectProcessor;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoSink;
import reactor.ipc.connector.Connector;
import reactor.ipc.connector.Inbound;
import reactor.ipc.connector.Outbound;

abstract class StreamSetup {

	private StreamSetup() {
	}

	static , OO extends Outbound, API> Mono connect(
			Connector connector,
			Supplier receiverSupplier,
			Class api,
			BiConsumer decoder,
			Function encoder) {

		return Mono.create(new OnConnectorSubscribe<>(connector,
				receiverSupplier,
				api,
				decoder,
				encoder));
	}

	static final class OnConnectorSubscribe, OO extends Outbound, API>
			implements Consumer> {

		final Connector                        connector;
		final Supplier                                    localSupplier;
		final Class                           remoteApi;
		final String                                         endpointName;
		final BiConsumer       ipcReader;
		final Function ipcWriter;

		OnConnectorSubscribe(Connector connector,
				Supplier localSupplier,
				Class remoteApi,
				BiConsumer ipcReader,
				Function ipcWriter) {
			this.connector = Objects.requireNonNull(connector, "connector");
			this.endpointName = connector.getClass()
			                             .getSimpleName()
			                             .toLowerCase();
			this.ipcReader = ipcReader;
			this.ipcWriter = ipcWriter;
			this.localSupplier = localSupplier;
			this.remoteApi = remoteApi;
		}

		@Override
		@SuppressWarnings("unchecked")
		public void accept(MonoSink sink) {
			Object localAPI;

			if (localSupplier == null) {
				localAPI = null;
			}
			else {
				localAPI = Objects.requireNonNull(localSupplier.get(), "localSupplier");
			}

			Mono connect = connector.newHandler((in, out) -> {
				Map clientMap;
				Map serverMap;

				StreamOperationsImpl[] am = {null};
				API api;
				final DirectProcessor closing;

				if (remoteApi != null) {
					clientMap = IpcServiceMapper.clientServiceMap(remoteApi);
					if (Disposable.class.isAssignableFrom(remoteApi)) {
						closing = DirectProcessor.create();
					}
					else {
						closing = null;
					}
					api =
							remoteApi.cast(Proxy.newProxyInstance(remoteApi.getClassLoader(),
									new Class[]{remoteApi},
									(o, m, args) -> {
										String name = m.getName();
										Ipc a = m.getAnnotation(Ipc.class);
										if (a == null) {
											if (closing != null && m.getDeclaringClass()
											                        .equals(Disposable.class)) {
												closing.onComplete();
												return null;
											}
											throw new IllegalArgumentException(
													"The method '" + m.getName() + "' is not annotated with Ipc");
										}
										String aname = a.name();
										if (!aname.isEmpty()) {
											name = aname;
										}

										Object action = clientMap.get(name);
										if (action == null) {
											throw new IllegalArgumentException(
													"The method '" + m.getName() + "' is not a proper Ipc method");
										}
										return IpcServiceMapper.dispatchClient(name,
												action,
												args,
												am[0]);
									}));
				}
				else {
					api = null;
					closing = null;
				}

				StreamContextImpl ctx = new StreamContextImpl<>(api);
				StreamOutbound streamOutbound =
						Objects.requireNonNull(ipcWriter.apply(out), "remote");

				if (localAPI != null) {
					serverMap = IpcServiceMapper.serverServiceMap(localAPI);

					am[0] = new StreamOperationsImpl<>(endpointName,
							(streamId, function, iom) -> {
								Object action = serverMap.get(function);
								if (action == null) {
									throw new IllegalStateException("Function " + function + " not found");
								}
								return IpcServiceMapper.dispatchServer(streamId,
										action,
										iom,
										ctx);
							}, streamOutbound, in,
							() -> IpcServiceMapper.invokeDone(localAPI, ctx));

					IpcServiceMapper.invokeInit(localAPI, ctx);
				}
				else {
					am[0] = new StreamOperationsImpl<>(endpointName,
							(streamId, function, iom) -> false,
							streamOutbound,
							in,
							() -> {
							});
				}

				if (ipcReader != null) {
					ipcReader.accept(in, am[0]);
				}

				if (api != null) {
					sink.success(api);
				}

				return closing != null ? closing : Mono.never();
			});

			Disposable c;
			if (remoteApi != null) {
				c = connect.subscribe(null, sink::error);
			}
			else {
				c =
						connect.subscribe(connectedState -> sink.success((API) connectedState),
								sink::error);
			}
			sink.onCancel(c);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy