content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You 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 org.apache.camel.component.grpc;
  
  import java.net.URI;
  import java.util.Collections;
  import java.util.List;
  import java.util.concurrent.TimeUnit;
  
  import io.grpc.ClientInterceptor;
  import io.grpc.ServerInterceptor;
  import io.grpc.internal.GrpcUtil;
  import io.grpc.netty.NegotiationType;
  import io.grpc.netty.NettyChannelBuilder;
  import io.grpc.netty.NettyServerBuilder;
  import org.apache.camel.component.grpc.auth.jwt.JwtAlgorithm;
  import org.apache.camel.spi.Metadata;
  import org.apache.camel.spi.UriParam;
  import org.apache.camel.spi.UriParams;
  import org.apache.camel.spi.UriPath;
  
  @UriParams
  public class GrpcConfiguration {
  
      @UriPath
      @Metadata(required = true)
      private String host;
  
      @UriPath
      @Metadata(required = true)
      private int port = -1;
  
      @UriPath
      @Metadata(required = true)
      private String service;
  
      @UriParam(label = "producer")
      private String method;
  
      @UriParam(label = "security", defaultValue = "PLAINTEXT")
      private NegotiationType negotiationType = NegotiationType.PLAINTEXT;
  
      @UriParam(label = "security", defaultValue = "NONE")
      private GrpcAuthType authenticationType = GrpcAuthType.NONE;
  
      @UriParam(label = "security", defaultValue = "HMAC256")
      private JwtAlgorithm jwtAlgorithm = JwtAlgorithm.HMAC256;
  
      @UriParam(label = "security", secret = true)
      private String jwtSecret;
  
      @UriParam(label = "security")
      private String jwtIssuer;
  
      @UriParam(label = "security")
      private String jwtSubject;
  
      @UriParam(label = "security")
      @Metadata(supportFileReference = true)
      private String serviceAccountResource;
  
      @UriParam(label = "security")
      @Metadata(supportFileReference = true)
      private String keyCertChainResource;
  
      @UriParam(label = "security")
      @Metadata(supportFileReference = true)
      private String keyResource;
  
      @UriParam(label = "security", secret = true)
      private String keyPassword;
  
      @UriParam(label = "security")
      @Metadata(supportFileReference = true)
      private String trustCertCollectionResource;
  
      @UriParam(label = "producer", defaultValue = "SIMPLE")
      private GrpcProducerStrategy producerStrategy = GrpcProducerStrategy.SIMPLE;
  
      @UriParam(label = "producer")
      private String streamRepliesTo;
  
      @UriParam(label = "producer")
      private String userAgent;
  
      @UriParam(label = "consumer", defaultValue = "PROPAGATION")
      private GrpcConsumerStrategy consumerStrategy = GrpcConsumerStrategy.PROPAGATION;
  
      @UriParam(label = "consumer", defaultValue = "false")
      private boolean forwardOnCompleted;
  
      @UriParam(label = "consumer", defaultValue = "false")
      private boolean forwardOnError;
  
      @UriParam(defaultValue = "" + NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW)
      private int flowControlWindow = NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW;
  
      @UriParam(defaultValue = "" + GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE)
      private int maxMessageSize = GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
  
      @UriParam(label = "consumer", defaultValue = "" + Integer.MAX_VALUE)
      private int maxConcurrentCallsPerConnection = Integer.MAX_VALUE;
  
      @UriParam(label = "consumer", defaultValue = "false")
      private boolean routeControlledStreamObserver;
  
      private List<ServerInterceptor> serverInterceptors = Collections.emptyList();
  
      @UriParam(label = "consumer", defaultValue = "true")
      private boolean autoDiscoverServerInterceptors = true;
  
      private List<ClientInterceptor> clientInterceptors = Collections.emptyList();
  
      @UriParam(label = "producer", defaultValue = "true")
      private boolean autoDiscoverClientInterceptors = true;
  
      @UriParam(defaultValue = "false", label = "advanced",
                description = "Sets whether synchronous processing should be strictly used")
      private boolean synchronous;
  
      @UriParam(defaultValue = "false", label = "producer",
                description = "Copies exchange properties from original exchange to all exchanges created for route defined by streamRepliesTo.")
      private boolean inheritExchangePropertiesForReplies = false;
  
      @UriParam(defaultValue = "false", label = "producer",
                description = "Expects that exchange property GrpcConstants.GRPC_RESPONSE_OBSERVER is set. Takes its value and calls onNext, onError and onComplete on that StreamObserver. All other gRPC parameters are ignored.")
      private boolean toRouteControlledStreamObserver = false;
  
      @UriParam(label = "consumer", defaultValue = "" + NettyServerBuilder.DEFAULT_FLOW_CONTROL_WINDOW)
      private int initialFlowControlWindow = NettyServerBuilder.DEFAULT_FLOW_CONTROL_WINDOW;
  
      @UriParam(label = "consumer", defaultValue = "7200000")
      private long keepAliveTime = TimeUnit.NANOSECONDS.toMillis(GrpcUtil.DEFAULT_SERVER_KEEPALIVE_TIME_NANOS);
  
      @UriParam(label = "consumer", defaultValue = "20000")
      private long keepAliveTimeout = TimeUnit.NANOSECONDS.toMillis(GrpcUtil.DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS);
  
      @UriParam(label = "consumer", defaultValue = "" + Long.MAX_VALUE)
      private long maxConnectionAge = Long.MAX_VALUE;
  
      @UriParam(label = "consumer", defaultValue = "" + Long.MAX_VALUE)
      private long maxConnectionIdle = Long.MAX_VALUE;
  
      @UriParam(label = "consumer", defaultValue = "" + Long.MAX_VALUE)
      private long maxConnectionAgeGrace = Long.MAX_VALUE;
  
      @UriParam(label = "consumer", defaultValue = "" + GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE)
      private int maxInboundMetadataSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
  
      @UriParam(label = "consumer", defaultValue = "0")
      private int maxRstFramesPerWindow;
  
      @UriParam(label = "consumer", defaultValue = "0")
      private int maxRstPeriodSeconds;
  
      @UriParam(label = "consumer", defaultValue = "300000")
      private long permitKeepAliveTime = TimeUnit.MINUTES.toMillis(5);
  
      @UriParam(label = "consumer", defaultValue = "false")
      private boolean permitKeepAliveWithoutCalls;
  
      /**
       * Fully qualified service name from the protocol buffer descriptor file (package dot service definition name)
       */
      public String getService() {
          return service;
      }
  
      public void setService(String service) {
          this.service = service;
      }
  
      /**
       * gRPC method name
       */
      public String getMethod() {
          return method;
      }
  
      public void setMethod(String method) {
          this.method = method;
      }
  
      /**
       * The gRPC server host name. This is localhost or 0.0.0.0 when being a consumer or remote server host name when
       * using producer.
       */
      public String getHost() {
          return host;
      }
  
      public void setHost(String host) {
          this.host = host;
      }
  
      /**
       * The gRPC local or remote server port
       */
      public int getPort() {
          return port;
      }
  
      public void setPort(int port) {
          this.port = port;
      }
  
      public NegotiationType getNegotiationType() {
          return negotiationType;
      }
  
      /**
       * Identifies the security negotiation type used for HTTP/2 communication
       */
      public void setNegotiationType(NegotiationType negotiationType) {
          this.negotiationType = negotiationType;
      }
  
      /**
       * Authentication method type in advance to the SSL/TLS negotiation
       */
      public GrpcAuthType getAuthenticationType() {
          return authenticationType;
      }
  
      public void setAuthenticationType(GrpcAuthType authenticationType) {
          this.authenticationType = authenticationType;
      }
  
      /**
       * JSON Web Token sign algorithm
       */
      public JwtAlgorithm getJwtAlgorithm() {
          return jwtAlgorithm;
      }
  
      public void setJwtAlgorithm(JwtAlgorithm jwtAlgorithm) {
          this.jwtAlgorithm = jwtAlgorithm;
      }
  
      /**
       * JSON Web Token secret
       */
      public String getJwtSecret() {
          return jwtSecret;
      }
  
      public void setJwtSecret(String jwtSecret) {
          this.jwtSecret = jwtSecret;
      }
  
      /**
       * JSON Web Token issuer
       */
      public String getJwtIssuer() {
          return jwtIssuer;
      }
  
      public void setJwtIssuer(String jwtIssuer) {
          this.jwtIssuer = jwtIssuer;
      }
  
      /**
       * JSON Web Token subject
       */
      public String getJwtSubject() {
          return jwtSubject;
      }
  
      public void setJwtSubject(String jwtSubject) {
          this.jwtSubject = jwtSubject;
      }
  
      /**
       * Service Account key file in JSON format resource link supported by the Google Cloud SDK
       */
      public String getServiceAccountResource() {
          return serviceAccountResource;
      }
  
      public void setServiceAccountResource(String serviceAccountResource) {
          this.serviceAccountResource = serviceAccountResource;
      }
  
      public String getKeyCertChainResource() {
          return keyCertChainResource;
      }
  
      /**
       * The X.509 certificate chain file resource in PEM format link
       */
      public void setKeyCertChainResource(String keyCertChainResource) {
          this.keyCertChainResource = keyCertChainResource;
      }
  
      public String getKeyResource() {
          return keyResource;
      }
  
      /**
       * The PKCS#8 private key file resource in PEM format link
       */
      public void setKeyResource(String keyResource) {
          this.keyResource = keyResource;
      }
  
      /**
       * The PKCS#8 private key file password
       */
      public String getKeyPassword() {
          return keyPassword;
      }
  
      public void setKeyPassword(String keyPassword) {
          this.keyPassword = keyPassword;
      }
  
      public String getTrustCertCollectionResource() {
          return trustCertCollectionResource;
      }
  
      /**
       * The trusted certificates collection file resource in PEM format for verifying the remote endpoint's certificate
       */
      public void setTrustCertCollectionResource(String trustCertCollectionResource) {
          this.trustCertCollectionResource = trustCertCollectionResource;
      }
  
      /**
       * This option specifies the top-level strategy for processing service requests and responses in streaming mode. If
       * an aggregation strategy is selected, all requests will be accumulated in the list, then transferred to the flow,
       * and the accumulated responses will be sent to the sender. If a propagation strategy is selected, request is sent
       * to the stream, and the response will be immediately sent back to the sender. If a delegation strategy is
       * selected, request is sent to the stream, but no response generated under the assumption that all necessary
       * responses will be sent at another part of route. Delegation strategy always comes with
       * routeControlledStreamObserver=true to be able to achieve the assumption.
       */
      public GrpcConsumerStrategy getConsumerStrategy() {
          return consumerStrategy;
      }
  
      public void setConsumerStrategy(GrpcConsumerStrategy consumerStrategy) {
          this.consumerStrategy = consumerStrategy;
      }
  
      public boolean isForwardOnCompleted() {
          return forwardOnCompleted;
      }
  
      /**
       * Determines if onCompleted events should be pushed to the Camel route.
       */
      public void setForwardOnCompleted(boolean forwardOnCompleted) {
          this.forwardOnCompleted = forwardOnCompleted;
      }
  
      public boolean isForwardOnError() {
          return forwardOnError;
      }
  
      /**
       * Determines if onError events should be pushed to the Camel route. Exceptions will be set as message body.
       */
      public void setForwardOnError(boolean forwardOnError) {
          this.forwardOnError = forwardOnError;
      }
  
      public GrpcProducerStrategy getProducerStrategy() {
          return producerStrategy;
      }
  
      /**
       * The mode used to communicate with a remote gRPC server. In SIMPLE mode a single exchange is translated into a
       * remote procedure call. In STREAMING mode all exchanges will be sent within the same request (input and output of
       * the recipient gRPC service must be of type 'stream').
       */
      public void setProducerStrategy(GrpcProducerStrategy producerStrategy) {
          this.producerStrategy = producerStrategy;
      }
  
      public String getStreamRepliesTo() {
          return streamRepliesTo;
      }
  
      /**
       * When using STREAMING client mode, it indicates the endpoint where responses should be forwarded.
       */
      public void setStreamRepliesTo(String streamRepliesTo) {
          this.streamRepliesTo = streamRepliesTo;
      }
  
      /**
       * The user agent header passed to the server
       */
      public String getUserAgent() {
          return userAgent;
      }
  
      public void setUserAgent(String userAgent) {
          this.userAgent = userAgent;
      }
  
      /**
       * The HTTP/2 flow control window size (MiB)
       */
      public int getFlowControlWindow() {
          return flowControlWindow;
      }
  
      public void setFlowControlWindow(int flowControlWindow) {
          this.flowControlWindow = flowControlWindow;
      }
  
      public int getMaxMessageSize() {
          return maxMessageSize;
      }
  
      /**
       * The maximum message size allowed to be received/sent (MiB)
       */
      public void setMaxMessageSize(int maxMessageSize) {
          this.maxMessageSize = maxMessageSize;
      }
  
      /**
       * Lets the route to take control over stream observer. If this value is set to true, then the response observer of
       * gRPC call will be set with the name {@link GrpcConstants.GRPC_RESPONSE_OBSERVER} in the Exchange object.
       * <p>
       * Please note that the stream observer's onNext(), onError(), onCompleted() methods should be called in the route.
       */
      public boolean isRouteControlledStreamObserver() {
          return routeControlledStreamObserver;
      }
  
      public void setRouteControlledStreamObserver(boolean routeControlledStreamObserver) {
          this.routeControlledStreamObserver = routeControlledStreamObserver;
      }
  
      public int getMaxConcurrentCallsPerConnection() {
          return maxConcurrentCallsPerConnection;
      }
  
      /**
       * The maximum number of concurrent calls permitted for each incoming server connection. Defaults to no limit.
       */
      public void setMaxConcurrentCallsPerConnection(int maxConcurrentCallsPerConnection) {
          this.maxConcurrentCallsPerConnection = maxConcurrentCallsPerConnection;
      }
  
      public List<ServerInterceptor> getServerInterceptors() {
          return serverInterceptors;
      }
  
      /**
       * Setting the server interceptors on the netty channel in order to intercept incoming calls before they are
       * received by the server.
       */
      public void setServerInterceptors(List<ServerInterceptor> serverInterceptors) {
          this.serverInterceptors = serverInterceptors;
      }
  
      public boolean isAutoDiscoverServerInterceptors() {
          return autoDiscoverServerInterceptors;
      }
  
      /**
       * Setting the autoDiscoverServerInterceptors mechanism, if true, the component will look for a ServerInterceptor
       * instance in the registry automatically otherwise it will skip that checking.
       */
      public void setAutoDiscoverServerInterceptors(boolean autoDiscoverServerInterceptors) {
          this.autoDiscoverServerInterceptors = autoDiscoverServerInterceptors;
      }
  
      public List<ClientInterceptor> getClientInterceptors() {
          return clientInterceptors;
      }
  
      /**
       * Setting the client interceptors on the netty channel in order to intercept outgoing calls before they are
       * dispatched by the channel.
       */
      public void setClientInterceptors(List<ClientInterceptor> clientInterceptors) {
          this.clientInterceptors = clientInterceptors;
      }
  
      public boolean isAutoDiscoverClientInterceptors() {
          return autoDiscoverClientInterceptors;
      }
  
      /**
       * Setting the autoDiscoverClientInterceptors mechanism, if true, the component will look for a ClientInterceptor
       * instance in the registry automatically otherwise it will skip that checking.
       */
      public void setAutoDiscoverClientInterceptors(boolean autoDiscoverClientInterceptors) {
          this.autoDiscoverClientInterceptors = autoDiscoverClientInterceptors;
      }
  
      public boolean isSynchronous() {
          return synchronous;
      }
  
      public void setSynchronous(boolean synchronous) {
          this.synchronous = synchronous;
      }
  
      public boolean isInheritExchangePropertiesForReplies() {
          return inheritExchangePropertiesForReplies;
      }
  
      public void setInheritExchangePropertiesForReplies(boolean inheritExchangePropertiesForReplies) {
          this.inheritExchangePropertiesForReplies = inheritExchangePropertiesForReplies;
      }
  
      public boolean isToRouteControlledStreamObserver() {
          return toRouteControlledStreamObserver;
      }
  
      public void setToRouteControlledStreamObserver(boolean toRouteControlledStreamObserver) {
          this.toRouteControlledStreamObserver = toRouteControlledStreamObserver;
      }
  
      public int getInitialFlowControlWindow() {
          return initialFlowControlWindow;
      }
  
      /**
       * Sets the initial flow control window in bytes.
       */
      public void setInitialFlowControlWindow(int initialFlowControlWindow) {
          this.initialFlowControlWindow = initialFlowControlWindow;
      }
  
      public long getKeepAliveTime() {
          return keepAliveTime;
      }
  
      /**
       * Sets a custom keepalive time in milliseconds, the delay time for sending next keepalive ping. A value of
       * Long.MAX_VALUE or a value greater or equal to NettyServerBuilder.AS_LARGE_AS_INFINITE will disable keepalive.
       */
      public void setKeepAliveTime(long keepAliveTime) {
          this.keepAliveTime = keepAliveTime;
      }
  
      public long getKeepAliveTimeout() {
          return keepAliveTimeout;
      }
  
      /**
       * Sets a custom keepalive timeout in milliseconds, the timeout for keepalive ping requests.
       */
      public void setKeepAliveTimeout(long keepAliveTimeout) {
          this.keepAliveTimeout = keepAliveTimeout;
      }
  
      public long getMaxConnectionAge() {
          return maxConnectionAge;
      }
  
      /**
       * Sets a custom max connection age in milliseconds. Connections lasting longer than which will be gracefully
       * terminated. A random jitter of +/-10% will be added to the value. A value of Long.MAX_VALUE (the default) or a
       * value greater or equal to NettyServerBuilder.AS_LARGE_AS_INFINITE will disable max connection age.
       */
      public void setMaxConnectionAge(long maxConnectionAge) {
          this.maxConnectionAge = maxConnectionAge;
      }
  
      public long getMaxConnectionIdle() {
          return maxConnectionIdle;
      }
  
      /**
       * Sets a custom max connection idle time in milliseconds. Connection being idle for longer than which will be
       * gracefully terminated. A value of Long.MAX_VALUE (the default) or a value greater or equal to
       * NettyServerBuilder.AS_LARGE_AS_INFINITE will disable max connection idle
       */
      public void setMaxConnectionIdle(long maxConnectionIdle) {
          this.maxConnectionIdle = maxConnectionIdle;
      }
  
      public long getMaxConnectionAgeGrace() {
          return maxConnectionAgeGrace;
      }
  
      /**
       * Sets a custom grace time in milliseconds for the graceful connection termination. A value of Long.MAX_VALUE (the
       * default) or a value greater or equal to NettyServerBuilder.AS_LARGE_AS_INFINITE is considered infinite.
       */
      public void setMaxConnectionAgeGrace(long maxConnectionAgeGrace) {
          this.maxConnectionAgeGrace = maxConnectionAgeGrace;
      }
  
      public int getMaxInboundMetadataSize() {
          return maxInboundMetadataSize;
      }
  
      /**
       * Sets the maximum size of metadata allowed to be received. The default is 8 KiB.
       */
      public void setMaxInboundMetadataSize(int maxInboundMetadataSize) {
          this.maxInboundMetadataSize = maxInboundMetadataSize;
      }
  
      public int getMaxRstFramesPerWindow() {
          return maxRstFramesPerWindow;
      }
  
      /**
       * Limits the rate of incoming RST_STREAM frames per connection to maxRstFramesPerWindow per maxRstPeriodSeconds.
       * This option MUST be used in conjunction with maxRstPeriodSeconds for it to be effective.
       */
      public void setMaxRstFramesPerWindow(int maxRstFramesPerWindow) {
          this.maxRstFramesPerWindow = maxRstFramesPerWindow;
      }
  
      public int getMaxRstPeriodSeconds() {
          return maxRstPeriodSeconds;
      }
  
      /**
       * Limits the rate of incoming RST_STREAM frames per maxRstPeriodSeconds. This option MUST be used in conjunction
       * with maxRstFramesPerWindow for it to be effective.
       */
      public void setMaxRstPeriodSeconds(int maxRstPeriodSeconds) {
          this.maxRstPeriodSeconds = maxRstPeriodSeconds;
      }
  
      public long getPermitKeepAliveTime() {
          return permitKeepAliveTime;
      }
  
      /**
       * Sets the most aggressive keep-alive time in milliseconds that clients are permitted to configure. The server will
       * try to detect clients exceeding this rate and will forcefully close the connection.
       */
      public void setPermitKeepAliveTime(long permitKeepAliveTime) {
          this.permitKeepAliveTime = permitKeepAliveTime;
      }
  
      public boolean isPermitKeepAliveWithoutCalls() {
          return permitKeepAliveWithoutCalls;
      }
  
      /**
       * Sets whether to allow clients to send keep-alive HTTP/ 2 PINGs even if there are no outstanding RPCs on the
       * connection.
       */
      public void setPermitKeepAliveWithoutCalls(boolean permitKeepAliveWithoutCalls) {
          this.permitKeepAliveWithoutCalls = permitKeepAliveWithoutCalls;
      }
  
      public void parseURI(URI uri) {
          setHost(uri.getHost());
  
          if (uri.getPort() != -1) {
              setPort(uri.getPort());
          }
  
          setService(uri.getPath().substring(1));
      }
  }
  