Skip to content
Snippets Groups Projects
Commit 113c3eb2 authored by OZGCloud's avatar OZGCloud
Browse files

build and add call context

parent f0ac1083
Branches
Tags
No related merge requests found
Showing
with 168 additions and 7 deletions
package de.ozgcloud.apilib.common.callcontext;
import java.util.Collection;
import java.util.UUID;
import de.ozgcloud.apilib.user.OzgCloudUserId;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
@Builder
@Getter
public class CallContext {
private String clientName;
private OzgCloudUserId userId;
@Builder.Default
private String requestId = UUID.randomUUID().toString();
@Builder.Default
private boolean accessLimited = false;
@Singular
private Collection<String> accessLimitedToOrgaIds;
}
package de.ozgcloud.apilib.common.callcontext;
import java.util.Optional;
import java.util.UUID;
import java.util.logging.Level;
import org.springframework.context.ApplicationContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.java.Log;
@Log
@RequiredArgsConstructor
public class DefaultOzgCloudCallContextProvider implements OzgCloudCallContextProvider {
private final ApplicationContext context;
@Override
public CallContext provideContext() {
return CallContext.builder()
.clientName(getClientName())
.requestId(UUID.randomUUID().toString())
.build();
}
private String getClientName() {
return Optional.ofNullable(context.getId()).orElseGet(() -> {
LOG.log(Level.WARNING, "No Client name given. Please configure 'spring.application.name'.");
return "unkown_client";
});
}
}
package de.ozgcloud.apilib.common.callcontext;
import static de.itvsh.kop.common.grpc.GrpcUtil.*;
import java.util.Optional;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import de.ozgcloud.apilib.user.OzgCloudUserId;
import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ForwardingClientCall.SimpleForwardingClientCall;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import lombok.RequiredArgsConstructor;
import net.devh.boot.grpc.client.interceptor.GrpcGlobalClientInterceptor;
@GrpcGlobalClientInterceptor
@RequiredArgsConstructor
public class OzgCloudCallContextAttachingInterceptor implements ClientInterceptor {
static final String KEY_USER_ID = "USER_ID-bin";
static final String KEY_CLIENT_NAME = "CLIENT_NAME-bin";
static final String KEY_REQUEST_ID = "REQUEST_ID-bin";
static final String KEY_ACCESS_LIMITED_ORGAID = "ACCESS_LIMITED_TO_ORGANISATORISCHEEINHEITENID-bin";
static final String KEY_ACCESS_LIMITED = "ACCESS_LIMITED-bin";
private final OzgCloudCallContextProvider callContextProvider;
@Override
public <A, B> ClientCall<A, B> interceptCall(MethodDescriptor<A, B> method, CallOptions callOptions, Channel next) {
return new CallContextAttachingClientCall<>(next.newCall(method, callOptions));
}
final class CallContextAttachingClientCall<A, B> extends SimpleForwardingClientCall<A, B> {
protected CallContextAttachingClientCall(ClientCall<A, B> delegate) {
super(delegate);
}
@Override
public void start(Listener<B> responseListener, Metadata headers) {
headers.merge(buildCallContextMetadata());
super.start(responseListener, headers);
}
private Metadata buildCallContextMetadata() {
var ctxt = callContextProvider.provideContext();
var metadata = new Metadata();
addClientName(ctxt, metadata);
addRequestId(ctxt, metadata);
Optional.ofNullable(ctxt.getUserId())
.map(OzgCloudUserId::toString)
.ifPresent(userId -> addToMetadata(metadata, KEY_USER_ID, userId));
Optional.ofNullable(ctxt.getAccessLimitedToOrgaIds())
.ifPresent(ids -> ids.stream().forEach(id -> addToMetadata(metadata, KEY_ACCESS_LIMITED_ORGAID, id)));
Optional.ofNullable(ctxt.isAccessLimited()).map(Boolean::valueOf)
.ifPresent(limited -> addToMetadata(metadata, KEY_ACCESS_LIMITED, limited.toString()));
return metadata;
}
private void addRequestId(CallContext ctxt, Metadata metadata) {
Optional.ofNullable(ctxt.getRequestId()).ifPresentOrElse(reqId -> metadata.put(createKeyOf(KEY_REQUEST_ID), reqId.getBytes()),
() -> addToMetadata(metadata, KEY_REQUEST_ID, UUID.randomUUID().toString()));
}
private void addClientName(CallContext ctxt, Metadata metadata) {
Optional.ofNullable(ctxt.getClientName())
.filter(StringUtils::isNoneBlank)
.ifPresentOrElse(clientName -> addToMetadata(metadata, KEY_CLIENT_NAME, clientName),
() -> {
throw new IllegalStateException("CLIENT_NAME must not be blank");
});
}
private void addToMetadata(Metadata metadata, String key, String value) {
metadata.put(createKeyOf(key), value.getBytes());
}
}
}
package de.ozgcloud.apilib.common.callcontext;
public interface OzgCloudCallContextProvider {
public CallContext provideContext();
}
......@@ -22,7 +22,7 @@ import net.devh.boot.grpc.client.inject.GrpcClient;
@Service
@ConditionalOnProperty("ozgcloud.vorgang-manager.address")
@RequiredArgsConstructor
public class GrpcVorgangService implements OzgCloudVorgangService {
public class GrpcOzgCloudVorgangService implements OzgCloudVorgangService {
@GrpcClient("vorgang-manager")
private final VorgangServiceBlockingStub vorgangServiceStub;
......
......@@ -21,10 +21,10 @@ import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStubTestFactory;
import de.ozgcloud.apilib.vorgang.OzgCloudVorgangTestFactory;
import de.ozgcloud.apilib.vorgang.Page;
class GrpcVorgangServiceTest {
class GrpcOzgCloudVorgangServiceTest {
@InjectMocks
private GrpcVorgangService service;
private GrpcOzgCloudVorgangService service;
@Mock
private VorgangServiceBlockingStub stub;
......
......@@ -20,7 +20,7 @@ class DemoRunner implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println(vorgangService.getById(OzgCloudVorgangId.from("647885a50b105b1e4995378e")));
System.out.println(vorgangService.getById(OzgCloudVorgangId.from("64bfd6597a08cf6e8a5185c6")));
System.out.println(fileService.getFile(OzgCloudFileId.from("630363d5b5816c0d8efd6f19")));
......
......@@ -4,15 +4,20 @@ import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import de.ozgcloud.apilib.common.callcontext.DefaultOzgCloudCallContextProvider;
import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextAttachingInterceptor;
import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider;
import de.ozgcloud.apilib.file.dummy.DummyOzgCloudFileService;
import de.ozgcloud.apilib.file.grpc.GrpcOzgCloudFileService;
import de.ozgcloud.apilib.vorgang.dummy.DummyVorgangService;
import de.ozgcloud.apilib.vorgang.grpc.GrpcVorgangService;
import de.ozgcloud.apilib.vorgang.grpc.GrpcOzgCloudVorgangService;
import net.devh.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration;
import net.devh.boot.grpc.client.config.GrpcChannelProperties;
import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
......@@ -20,8 +25,9 @@ import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
@AutoConfiguration(before = GrpcClientAutoConfiguration.class)
@ComponentScan("de.ozgcloud.client.autoconfigure")
@Import({
GrpcVorgangService.class, DummyVorgangService.class,
GrpcOzgCloudFileService.class, DummyOzgCloudFileService.class
GrpcOzgCloudVorgangService.class, DummyVorgangService.class,
GrpcOzgCloudFileService.class, DummyOzgCloudFileService.class,
OzgCloudCallContextAttachingInterceptor.class
})
public class OzgCloudClientAutoConfiguration {
......@@ -60,4 +66,10 @@ public class OzgCloudClientAutoConfiguration {
clientMap.put(CLIENT_NAME_FILE_MANAGER, channelProps);
}
@Bean
@ConditionalOnMissingBean
OzgCloudCallContextProvider callContextProvider(ApplicationContext ctxt) {
return new DefaultOzgCloudCallContextProvider(ctxt);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment