
com.zaradai.gluon.client.BaseClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gluon-core Show documentation
Show all versions of gluon-core Show documentation
Gluon - Core micro services implementation.
The newest version!
/**
* Copyright 2017 Zaradai
*
* 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.zaradai.gluon.client;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.AbstractIdleService;
import com.zaradai.gluon.MicroService;
import com.zaradai.gluon.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentMap;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.zaradai.gluon.util.Validations.checkString;
public class BaseClient extends AbstractIdleService implements Client {
private static final Logger LOG = LoggerFactory.getLogger(BaseClient.class);
private final EventBus eventBus;
private final ConcurrentMap futureByRequest;
private final ConcurrentMap serviceByName;
BaseClient(EventBus eventBus) {
this.eventBus = checkNotNull(eventBus, "Invalid event bus");
futureByRequest = Maps.newConcurrentMap();
serviceByName = Maps.newConcurrentMap();
eventBus.register(this);
}
@Override
protected void startUp() throws Exception {
LOG.info("Client started.");
}
@Override
protected void shutDown() throws Exception {
eventBus.unregister(this);
LOG.info("Client shutdown.");
}
@Override
public MicroService newService(String serviceName) {
final MicroServiceClient res = new MicroServiceClient<>(serviceName, this);
// monitor it
if (serviceByName.putIfAbsent(serviceName, res) == null) {
// send out a request for the service to announce availability
eventBus.post(ServiceRequestAnnounce.create(serviceName));
return res;
} else {
LOG.info("Service: {} already registered! Returning already registered service", serviceName);
return serviceByName.get(serviceName);
}
}
protected EventBus getEventBus() {
return eventBus;
}
@VisibleForTesting
@Subscribe
void handleReply(ServiceReply reply) {
LOG.debug("Handling: {}", reply);
CompletableFuture future = futureByRequest.remove(reply.getRequestId());
if (future == null) {
LOG.debug("Ignoring reply for request: {}", reply.getRequestId());
} else {
if (reply.isGood()) {
future.complete(reply.getReply());
} else {
future.completeExceptionally(reply.getError());
}
}
}
@VisibleForTesting
@Subscribe
void handleAnnounce(ServiceAnnouncement serviceAnnouncement) {
LOG.debug("Handling: {}", serviceAnnouncement);
MicroServiceClient microServiceClient = serviceByName.get(serviceAnnouncement.getServiceName());
if (microServiceClient != null) {
microServiceClient.setStatus(serviceAnnouncement.getStatus());
} else {
LOG.info("Service announcement [{}] for unknown service: {}", serviceAnnouncement.getStatus(), serviceAnnouncement.getServiceName());
}
}
private CompletableFuture submit(ServiceRequest serviceRequest) {
final CompletableFuture future = new CompletableFuture<>();
final String requestId = serviceRequest.getRequestId();
// list for cancellation
future.exceptionally((error -> {
if (error instanceof CancellationException) {
// remove from out monitoring
futureByRequest.remove(requestId);
// try and kill it remotely
eventBus.post(ServiceRequestCancellation.create(requestId));
LOG.info("Sent cancellation for request: {}", requestId);
}
return null;
}));
// map future by request
futureByRequest.put(requestId, future);
// submit the request
eventBus.post(serviceRequest);
return future;
}
private static class MicroServiceClient implements MicroService {
private final String serviceName;
private final BaseClient baseClient;
private Status status;
private MicroServiceClient(String serviceName, BaseClient baseClient) {
this.serviceName = checkString(serviceName, "Service name cannot be null or empty.");
this.baseClient = checkNotNull(baseClient, "Kafka client cannot be null.");
this.status = Status.CLOSED;
}
@Override
public Status getStatus() {
return status;
}
public MicroServiceClient setStatus(Status status) {
this.status = status;
return this;
}
@Override
public CompletableFuture apply(Req req) {
return baseClient.submit(ServiceRequest.create(serviceName, req));
}
@Override
public String name() {
return serviceName;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy