muttakin2301/ccr2000 huggingface dataset:
Code review comment: Here you can easily use TypeTags for type comparisons.

Code under review:
private static void checkRetryStmtValidity(RetryStmt stmt) {
        
        StatementKind parentStmtType = stmt.getParent().getKind();
        if (StatementKind.FAILED_BLOCK != parentStmtType) {
            BLangExceptionHelper.throwSemanticError(stmt, SemanticErrors.INVALID_RETRY_STMT_LOCATION);
        }
        
        Expression retryCountExpr = stmt.getRetryCountExpression();
        boolean error = true;
        if (retryCountExpr instanceof BasicLiteral) {
            if (TypeConstants.INT_TNAME.equals(((BasicLiteral) retryCountExpr).getTypeName().getName())) {
                if (((BasicLiteral) retryCountExpr).getBValue().intValue() >= 0) {
                    error = false;
                }
            }
        } else if (retryCountExpr instanceof VariableReferenceExpr) {
            VariableDef variableDef = ((SimpleVarRefExpr) retryCountExpr).getVariableDef();
            if (variableDef.getKind() == VariableDef.Kind.CONSTANT) {
                if (TypeConstants.INT_TNAME.equals(variableDef.getTypeName().getName())) {
                    error = false;
                }
            }
        }
        if (error) {
            BLangExceptionHelper.throwSemanticError(stmt, SemanticErrors.INVALID_RETRY_COUNT);
        }
    }

Line commented on: if (TypeConstants.INT_TNAME.equals(((BasicLiteral) retryCountExpr).getTypeName().getName())) {

Revised code:
private static void checkRetryStmtValidity(RetryStmt stmt) {
        
        StatementKind parentStmtType = stmt.getParent().getKind();
        if (StatementKind.FAILED_BLOCK != parentStmtType) {
            BLangExceptionHelper.throwSemanticError(stmt, SemanticErrors.INVALID_RETRY_STMT_LOCATION);
        }
        
        Expression retryCountExpr = stmt.getRetryCountExpression();
        boolean error = true;
        if (retryCountExpr instanceof BasicLiteral) {
            if (retryCountExpr.getType().getTag() == TypeTags.INT_TAG) {
                if (((BasicLiteral) retryCountExpr).getBValue().intValue() >= 0) {
                    error = false;
                }
            }
        } else if (retryCountExpr instanceof VariableReferenceExpr) {
            VariableDef variableDef = ((SimpleVarRefExpr) retryCountExpr).getVariableDef();
            if (variableDef.getKind() == VariableDef.Kind.CONSTANT) {
                if (variableDef.getType().getTag() == TypeTags.INT_TAG) {
                    error = false;
                }
            }
        }
        if (error) {
            BLangExceptionHelper.throwSemanticError(stmt, SemanticErrors.INVALID_RETRY_COUNT);
        }
    }
Code review comment: adaptive scheduler -> dynamic graph  This is more accurate.

Code under review:
public boolean canBeReleased() {
        if (releasedPartitionGroups.size()
                != edgeManager.getNumberOfConsumedPartitionGroupsById(partitionId)) {
            return false;
        }
        for (JobVertexID jobVertexID : consumerVertices) {
            
            
            if (!producer.getExecutionGraphAccessor().getJobVertex(jobVertexID).isInitialized()) {
                return false;
            }
        }
        return true;
    }


Revised code:
public boolean canBeReleased() {
        if (releasablePartitionGroups.size()
                != edgeManager.getNumberOfConsumedPartitionGroupsById(partitionId)) {
            return false;
        }
        for (JobVertexID jobVertexId : totalResult.getConsumerVertices()) {
            
            
            if (!producer.getExecutionGraphAccessor().getJobVertex(jobVertexId).isInitialized()) {
                return false;
            }
        }
        return true;
    }
Code review comment: No? The only thing I can find that calls this code is ONNX-models, but they also explicitly throw if the type is URI ...

Code under review:
public FileReference addUri(String uri, Path path) {
        throw new UnsupportedOperationException("URI type is not supported");
        /* TODO: this needs to be super-restricted if the config server should ever do this.
        try (TmpDir tmp = new TmpDir()) {
            return addFile(download(uri, tmp.dir, path.getRelative()));
        }
        catch (IOException e) {
            throw new IllegalArgumentException(e);
        }
        */
    }

Line commented on: throw new UnsupportedOperationException("URI type is not supported");

Revised code:
public FileReference addUri(String uri, Path path) {
        throw new UnsupportedOperationException("URI type is not supported");
        /* TODO: this needs to be super-restricted if the config server should ever do this.
        try (TmpDir tmp = new TmpDir()) {
            return addFile(download(uri, tmp.dir, path.getRelative()));
        }
        catch (IOException e) {
            throw new IllegalArgumentException(e);
        }
        */
    }
Code review comment: Ah. I totally missed the second one was not a `else`. Probably better to initialize that one to `Collections.emptyList()` then.  That way, you don't have to special case the null.  Sorry about that.

Code under review:
private boolean restJsonSupportNeeded(CombinedIndexBuildItem indexBuildItem, DotName mediaTypeAnnotation) {
        for (AnnotationInstance annotationInstance : indexBuildItem.getIndex().getAnnotations(mediaTypeAnnotation)) {
            final AnnotationValue annotationValue = annotationInstance.value();
            if (annotationValue == null) {
                continue;
            }

            List<String> mediaTypes = null;
            if (annotationValue.kind() == Kind.ARRAY) {
                mediaTypes = Arrays.asList(annotationValue.asStringArray());
            } else if (annotationValue.kind() == Kind.STRING) {
                mediaTypes = Collections.singletonList(annotationValue.asString());
            }
            return (mediaTypes != null)
                    && (mediaTypes.contains(MediaType.APPLICATION_JSON)
                            || mediaTypes.contains(MediaType.APPLICATION_JSON_PATCH_JSON));
        }

        return false;
    }

Line commented on: List<String> mediaTypes = null;

Revised code:
private boolean restJsonSupportNeeded(CombinedIndexBuildItem indexBuildItem, DotName mediaTypeAnnotation) {
        for (AnnotationInstance annotationInstance : indexBuildItem.getIndex().getAnnotations(mediaTypeAnnotation)) {
            final AnnotationValue annotationValue = annotationInstance.value();
            if (annotationValue == null) {
                continue;
            }

            List<String> mediaTypes = Collections.emptyList();
            if (annotationValue.kind() == Kind.ARRAY) {
                mediaTypes = Arrays.asList(annotationValue.asStringArray());
            } else if (annotationValue.kind() == Kind.STRING) {
                mediaTypes = Collections.singletonList(annotationValue.asString());
            }
            return mediaTypes.contains(MediaType.APPLICATION_JSON)
                    || mediaTypes.contains(MediaType.APPLICATION_JSON_PATCH_JSON);
        }

        return false;
    }
Code review comment: I'm not sure we should use Optional here if we pass the null further to Options() anyway. Notice that in case when optional is empty the defaultValue is assigned to null anyway

Code under review:
private static List<Option> extractOptions(boolean isPython) {
    List<Option> options = new ArrayList<>();
    for (Method method : FlinkPipelineOptions.class.getDeclaredMethods()) {
      String name;
      String description;
      String defaultValue = null;
      name = method.getName();
      if (name.matches("^(get|is).*")) {
        name = name.replaceFirst("^(get|is)", "");

        if (isPython) {
          name = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name);
        } else {
          name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
        }

        Description descriptionAnnotation = method.getAnnotation(Description.class);
        if (descriptionAnnotation == null) {
          throw new RuntimeException(
              "All pipeline options should have a description. Please add one for " + name);
        }
        description = descriptionAnnotation.value();

        Optional<String> defaultValueFromAnnotation = getDefaultValueFromAnnotation(method);
        if (defaultValueFromAnnotation.isPresent()) {
          defaultValue = defaultValueFromAnnotation.get();
        }

        options.add(new Option(name, description, defaultValue));
      }
    }
    options.sort(Comparator.comparing(option -> option.name));
    return options;
  }

Line commented on: Optional<String> defaultValueFromAnnotation = getDefaultValueFromAnnotation(method);

Revised code:
private static List<Option> extractOptions(boolean isPython) {
    List<Option> options = new ArrayList<>();
    for (Method method : FlinkPipelineOptions.class.getDeclaredMethods()) {
      String name;
      String description;
      String defaultValue = null;
      name = method.getName();
      if (name.matches("^(get|is).*")) {
        name = name.replaceFirst("^(get|is)", "");

        if (isPython) {
          name = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name);
        } else {
          name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
        }

        Description descriptionAnnotation = method.getAnnotation(Description.class);
        if (descriptionAnnotation == null) {
          throw new RuntimeException(
              "All pipeline options should have a description. Please add one for " + name);
        }
        description = descriptionAnnotation.value();

        Optional<String> defaultValueFromAnnotation = getDefaultValueFromAnnotation(method);
        if (defaultValueFromAnnotation.isPresent()) {
          defaultValue = defaultValueFromAnnotation.get();
        }

        options.add(new Option(name, description, defaultValue));
      }
    }
    options.sort(Comparator.comparing(option -> option.name));
    return options;
  }
Code review comment: This PR now looks great, after we fix this one, it is time to merge it, I suppose.

Code under review:
public static List<SqlNode> convertOrderByItems(final Collection<OrderByItemSegment> orderByItems) {
        List<SqlNode> sqlNodes = Lists.newArrayList();
        for (OrderByItemSegment orderByItemSegment : orderByItems) {
            Optional<SqlNode> optional = Optional.empty();
            if (orderByItemSegment instanceof ColumnOrderByItemSegment) {
                optional = new ColumnOrderByItemSqlNodeConverter().convert((ColumnOrderByItemSegment) orderByItemSegment);
            } else if (orderByItemSegment instanceof ExpressionOrderByItemSegment) {
                throw new UnsupportedOperationException("unsupported ExpressionOrderByItemSegment");
            } else if (orderByItemSegment instanceof IndexOrderByItemSegment) {
                throw new UnsupportedOperationException("unsupported IndexOrderByItemSegment");
            } else if (orderByItemSegment instanceof TextOrderByItemSegment) {
                throw new UnsupportedOperationException("unsupported TextOrderByItemSegment");
            }

            if (optional.isPresent()) {
                sqlNodes.add(optional.get());
            }
        }
        return sqlNodes;
    }

Line commented on: List<SqlNode> sqlNodes = Lists.newArrayList();

Revised code:
public static List<SqlNode> convertOrderByItems(final Collection<OrderByItemSegment> orderByItems) {
        List<SqlNode> sqlNodes = Lists.newArrayList();
        for (OrderByItemSegment orderByItemSegment : orderByItems) {
            Optional<SqlNode> optional = Optional.empty();
            if (orderByItemSegment instanceof ColumnOrderByItemSegment) {
                optional = new ColumnOrderByItemSqlNodeConverter().convert((ColumnOrderByItemSegment) orderByItemSegment);
            } else if (orderByItemSegment instanceof ExpressionOrderByItemSegment) {
                throw new UnsupportedOperationException("unsupported ExpressionOrderByItemSegment");
            } else if (orderByItemSegment instanceof IndexOrderByItemSegment) {
                throw new UnsupportedOperationException("unsupported IndexOrderByItemSegment");
            } else if (orderByItemSegment instanceof TextOrderByItemSegment) {
                throw new UnsupportedOperationException("unsupported TextOrderByItemSegment");
            }

            if (optional.isPresent()) {
                sqlNodes.add(optional.get());
            }
        }
        return sqlNodes;
    }
Code review comment: Shall we add a test case for this change?

Code under review:
public void onMessage(HttpCarbonMessage inboundMessage) {
        try {
            HttpResource httpResource;
            if (accessed(inboundMessage)) {
                httpResource = (HttpResource) inboundMessage.getProperty(HTTP_RESOURCE);
                extractPropertiesAndStartResourceExecution(inboundMessage, httpResource);
                return;
            }
            httpResource = HttpDispatcher.findResource(httpServicesRegistry, inboundMessage);
            if (HttpDispatcher.shouldDiffer(httpResource)) {
                inboundMessage.setProperty(HTTP_RESOURCE, httpResource);
                
                
                inboundMessage.removeInboundContentListener();
                return;
            }
            if (httpResource != null) {
                extractPropertiesAndStartResourceExecution(inboundMessage, httpResource);
            }
        } catch (BallerinaException ex) {
            try {
                HttpUtil.handleFailure(inboundMessage, new BallerinaConnectorException(ex.getMessage(), ex.getCause()));
            } catch (Exception e) {
                log.error("Cannot handle error using the error handler for: " + e.getMessage(), e);
            }
        }
    }

Line commented on: inboundMessage.removeInboundContentListener();

Revised code:
public void onMessage(HttpCarbonMessage inboundMessage) {
        try {
            HttpResource httpResource;
            if (accessed(inboundMessage)) {
                httpResource = (HttpResource) inboundMessage.getProperty(HTTP_RESOURCE);
                extractPropertiesAndStartResourceExecution(inboundMessage, httpResource);
                return;
            }
            httpResource = HttpDispatcher.findResource(httpServicesRegistry, inboundMessage);
            if (HttpDispatcher.shouldDiffer(httpResource)) {
                inboundMessage.setProperty(HTTP_RESOURCE, httpResource);
                
                
                inboundMessage.removeInboundContentListener();
                return;
            }
            if (httpResource != null) {
                extractPropertiesAndStartResourceExecution(inboundMessage, httpResource);
            }
        } catch (BallerinaException ex) {
            try {
                HttpUtil.handleFailure(inboundMessage, new BallerinaConnectorException(ex.getMessage(), ex.getCause()));
            } catch (Exception e) {
                log.error("Cannot handle error using the error handler for: " + e.getMessage(), e);
            }
        }
    }
Code review comment: Is Funqy layered on top of this?  One thing to consider is that Funqy needs to be consistent across all cloud platform on what JSON marshalling layer it uses.  We can't use GSON for Funqy GCF and Jackson for Funqy Lambda.

Code under review:
public void accept(String event, Context context) throws Exception {
        if (!started) {
            throw new IOException(deploymentStatus);
        }

        
        if ((delegate == null && rawDelegate == null) || (delegate != null && rawDelegate != null)) {
            throw new IOException("We didn't found any BackgroundFunction or RawBackgroundFunction to run " +
                    "(or there is multiple one and none selected inside your application.properties)");
        }

        if (rawDelegate != null) {
            rawDelegate.accept(event, context);
        } else {
            
            ObjectMapper mapper = new ObjectMapper();
            Object eventObj = mapper.readValue(event, parameterType);
            delegate.accept(eventObj, context);
        }
    }

Line commented on: Object eventObj = mapper.readValue(event, parameterType);

Revised code:
public void accept(String event, Context context) throws Exception {
        if (!started) {
            throw new IOException(deploymentStatus);
        }

        
        if ((delegate == null && rawDelegate == null) || (delegate != null && rawDelegate != null)) {
            throw new IOException("We didn't found any BackgroundFunction or RawBackgroundFunction to run " +
                    "(or there is multiple one and none selected inside your application.properties)");
        }

        if (rawDelegate != null) {
            rawDelegate.accept(event, context);
        } else {
            
            
            
            
            
            Gson gson = new Gson();
            try {
                Object eventObj = gson.fromJson(event, parameterType);
                delegate.accept(eventObj, context);
            } catch (JsonParseException e) {
                throw new RuntimeException("Could not parse received event payload into type "
                        + parameterType.getCanonicalName(), e);
            }
        }
    }
Code review comment: We should clarify in the comment that this in an optimization which only works for embedded execution or when the user code has been added to the Flink classpath (e.g. via the lib folder). Potentially we also need to invert class loading behavior via the Flink config to ensure that the parent is searched first.

Code under review:
private void scheduleRelease(JobInfo jobInfo) {
    WrappedContext wrapper = getCache().get(jobInfo.jobId());
    Preconditions.checkState(
        wrapper != null, "Releasing context for unknown job: " + jobInfo.jobId());

    PipelineOptions pipelineOptions =
        PipelineOptionsTranslation.fromProto(jobInfo.pipelineOptions());
    int environmentCacheTTLMillis =
        pipelineOptions.as(PortablePipelineOptions.class).getEnvironmentCacheMillis();
    if (environmentCacheTTLMillis > 0) {
      if (this.getClass().getClassLoader() != ExecutionEnvironment.class.getClassLoader()) {
        LOG.warn(
            "{} is not loaded on parent Flink classloader. "
                + "Falling back to synchronous environment release for job {}.",
            this.getClass(),
            jobInfo.jobId());
        release(wrapper);
      } else {
        
        
        getExecutor()
            .schedule(() -> release(wrapper), environmentCacheTTLMillis, TimeUnit.MILLISECONDS);
      }
    } else {
      
      
      release(wrapper);
    }
  }

Line commented on: if (this.getClass().getClassLoader() != ExecutionEnvironment.class.getClassLoader()) {

Revised code:
private void scheduleRelease(JobInfo jobInfo) {
    WrappedContext wrapper = getCache().get(jobInfo.jobId());
    Preconditions.checkState(
        wrapper != null, "Releasing context for unknown job: " + jobInfo.jobId());

    PipelineOptions pipelineOptions =
        PipelineOptionsTranslation.fromProto(jobInfo.pipelineOptions());
    int environmentCacheTTLMillis =
        pipelineOptions.as(PortablePipelineOptions.class).getEnvironmentCacheMillis();
    if (environmentCacheTTLMillis > 0) {
      if (this.getClass().getClassLoader() != ExecutionEnvironment.class.getClassLoader()) {
        LOG.warn(
            "{} is not loaded on parent Flink classloader. "
                + "Falling back to synchronous environment release for job {}.",
            this.getClass(),
            jobInfo.jobId());
        release(wrapper);
      } else {
        
        
        getExecutor()
            .schedule(() -> release(wrapper), environmentCacheTTLMillis, TimeUnit.MILLISECONDS);
      }
    } else {
      
      
      release(wrapper);
    }
  }
Code review comment: You might use `Strings.isNullOrEmpty` instead of two checks.

Code under review:
public ConnectionConfiguration withApiKey(String apiKey) {
      checkArgument(apiKey != null, "apiKey can not be null");
      checkArgument(!apiKey.isEmpty(), "apiKey can not be empty");
      return builder().setApiKey(apiKey).build();
    }

Line commented on: checkArgument(!apiKey.isEmpty(), "apiKey can not be empty");

Revised code:
public ConnectionConfiguration withApiKey(String apiKey) {
      checkArgument(!Strings.isNullOrEmpty(apiKey), "apiKey can not be null or empty");
      return builder().setApiKey(apiKey).build();
    }
Code review comment: `instanceof` also means that `readTimeout` is not `null` (and IntelliJ hints as much if one tries to add the null check)

Code under review:
public Future<HttpClientRequest> createRequest(RestClientRequestContext state) {
        HttpClient httpClient = state.getHttpClient();
        URI uri = state.getUri();
        boolean isHttps = "https".equals(uri.getScheme());
        int port = uri.getPort() != -1 ? uri.getPort() : (isHttps ? 443 : 80);
        RequestOptions requestOptions = new RequestOptions();
        requestOptions.setHost(uri.getHost());
        requestOptions.setPort(port);
        requestOptions.setMethod(HttpMethod.valueOf(state.getHttpMethod()));
        requestOptions.setURI(uri.getPath() + (uri.getQuery() == null ? "" : "?" + uri.getQuery()));
        requestOptions.setFollowRedirects(followRedirects);
        requestOptions.setSsl(isHttps);
        Object readTimeout = state.getConfiguration().getProperty(QuarkusRestClientProperties.READ_TIMEOUT);
        if ((readTimeout instanceof Long)) {
            requestOptions.setTimeout((Long) readTimeout);
        }
        return httpClient.request(requestOptions);
    }

Line commented on: if ((readTimeout instanceof Long)) {

Revised code:
public Future<HttpClientRequest> createRequest(RestClientRequestContext state) {
        HttpClient httpClient = state.getHttpClient();
        URI uri = state.getUri();
        boolean isHttps = "https".equals(uri.getScheme());
        int port = uri.getPort() != -1 ? uri.getPort() : (isHttps ? 443 : 80);
        RequestOptions requestOptions = new RequestOptions();
        requestOptions.setHost(uri.getHost());
        requestOptions.setPort(port);
        requestOptions.setMethod(HttpMethod.valueOf(state.getHttpMethod()));
        requestOptions.setURI(uri.getPath() + (uri.getQuery() == null ? "" : "?" + uri.getQuery()));
        requestOptions.setFollowRedirects(followRedirects);
        requestOptions.setSsl(isHttps);
        Object readTimeout = state.getConfiguration().getProperty(QuarkusRestClientProperties.READ_TIMEOUT);
        if (readTimeout instanceof Long) {
            requestOptions.setTimeout((Long) readTimeout);
        }
        return httpClient.request(requestOptions);
    }
Code review comment: We could also, extend `ObjectOps` class with `CommonOps` similar to other places and get rid of overrides to union, intersect, and diff() here.

Code under review:
private static boolean objectBddIsEmpty(Context cx, Bdd b) {
        return bddEveryPositive(cx, b, null, null, MappingOps::mappingFormulaIsEmpty);
    }

Line commented on: return bddEveryPositive(cx, b, null, null, MappingOps::mappingFormulaIsEmpty);

Revised code:
private static boolean objectBddIsEmpty(Context cx, Bdd b) {
        return bddEveryPositive(cx, b, null, null, MappingOps::mappingFormulaIsEmpty);
    }
Code review comment: Do we want to keep that?

Code under review:
public void testThatTheKogitoApplicationRuns() throws MavenInvocationException, IOException {
        testDir = initProject("projects/simple-kogito", "projects/project-classic-run-kogito");
        run("-e");

        await()
                .pollDelay(1, TimeUnit.SECONDS)
                .atMost(1, TimeUnit.MINUTES).until(() -> getHttpResponse("/persons").equals("[]"));

    }

Line commented on: run("-e");

Revised code:
public void testThatTheKogitoApplicationRuns() throws MavenInvocationException, IOException {
        testDir = initProject("projects/simple-kogito", "projects/project-classic-run-kogito");
        run("-e");

        await()
                .pollDelay(1, TimeUnit.SECONDS)
                .atMost(1, TimeUnit.MINUTES).until(() -> getHttpResponse("/persons").equals("[]"));

    }
Code review comment: <!--thread_id:cc_182896317_t; commit:1fd121da1417624b3b84f0300648251da64b9cb5; resolved:1--> <!--section:context-quote--> > **jkff** wrote: > Ditto, reference the JIRA here too if any  <!--section:body--> Done.

Code under review:
public void testIncomingConnection() throws Exception {
    StreamObserver<BeamFnApi.InstructionRequest> requestObserver = mock(StreamObserver.class);
    StreamObserver<BeamFnApi.InstructionResponse> responseObserver =
        controlService.control(requestObserver);

    
    
    InstructionRequestHandler client = pool.getSource().get(null);

    
    String id = "fakeInstruction";
    CompletionStage<BeamFnApi.InstructionResponse> responseFuture =
        client.handle(BeamFnApi.InstructionRequest.newBuilder().setInstructionId(id).build());
    verify(requestObserver).onNext(any(BeamFnApi.InstructionRequest.class));
    assertThat(MoreFutures.isDone(responseFuture), is(false));

    
    responseObserver.onNext(
        BeamFnApi.InstructionResponse.newBuilder().setInstructionId(id).build());
    MoreFutures.get(responseFuture);
  }


Revised code:
public void testIncomingConnection() throws Exception {
    StreamObserver<BeamFnApi.InstructionRequest> requestObserver = mock(StreamObserver.class);
    StreamObserver<BeamFnApi.InstructionResponse> responseObserver =
        controlService.control(requestObserver);

    
    InstructionRequestHandler client = pool.getSource().take("", Duration.ofSeconds(2));

    
    String id = "fakeInstruction";
    CompletionStage<BeamFnApi.InstructionResponse> responseFuture =
        client.handle(BeamFnApi.InstructionRequest.newBuilder().setInstructionId(id).build());
    verify(requestObserver).onNext(any(BeamFnApi.InstructionRequest.class));
    assertThat(MoreFutures.isDone(responseFuture), is(false));

    
    responseObserver.onNext(
        BeamFnApi.InstructionResponse.newBuilder().setInstructionId(id).build());
    MoreFutures.get(responseFuture);
  }
Code review comment: Can we include more information about the construct here? Like a qualified name instead of just the name?  e.g., `ballerina/lang.value:isReadOnly`  For object methods it may have to be like `Obj.method`.  For anonymous object methods we can probably give only the method name though.

Code under review:
public void testDeprecatedWarningForIsReadOnly() {
        CompileResult result = BCompileUtil.compile(
                "test-src/expressions/builtinoperations/is_readonly_deprecated_warning.bal");
        int index = 0;
        validateWarning(result, index++, "usage of construct 'isReadOnly' is deprecated", 22, 9);
        validateWarning(result, index++, "usage of construct 'isReadOnly' is deprecated", 24, 17);
        Assert.assertEquals(result.getDiagnostics().length, index);
    }

Line commented on: validateWarning(result, index++, "usage of construct 'isReadOnly' is deprecated", 22, 9);

Revised code:
public void testDeprecatedWarningForIsReadOnly() {
        CompileResult result = BCompileUtil.compile(
                "test-src/expressions/builtinoperations/is_readonly_deprecated_warning.bal");
        int index = 0;
        validateWarning(result, index++, 
                "usage of construct 'ballerina/lang.value:0.0.0:isReadOnly' is deprecated", 22, 9);
        validateWarning(result, index++, 
                "usage of construct 'ballerina/lang.value:0.0.0:isReadOnly' is deprecated", 24, 17);
        Assert.assertEquals(result.getDiagnostics().length, index);
    }
Code review comment: @StefanRRichter , thanks a lot for your careful review.   It is a real bug. I have fixed it. In addition, I have added test cases by making BitSetTest parameterized. So the clear method is tested against different amounts of bits.

Code under review:
public void clear() {
		int index = 0;
		while (index < byteLength) {
			memorySegment.putLong(offset + index, 0L);
			index += 8;
		}
		while (index < byteLength) {
			memorySegment.put(offset + index, (byte) 0);
		}
	}

Line commented on: while (index < byteLength) {

Revised code:
public void clear() {
		int index = 0;
		while (index + 8 <= byteLength) {
			memorySegment.putLong(offset + index, 0L);
			index += 8;
		}
		while (index < byteLength) {
			memorySegment.put(offset + index, (byte) 0);
			index += 1;
		}
	}
Code review comment: @dpcollins-google On this constructor argument change, I replaced the Beam code with the default values by reading the diff in https://github.com/googleapis/java-pubsublite/pull/475/files. But the PartitionCountWatchingPublisher constructor changed its accessor from public to package-default. Do you have a suggestion on how to adopt the change here?  ``` > Task :sdks:java:io:google-cloud-platform:compileJava /Users/suztomo/beam/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/pubsublite/Publishers.java:51: error:  PartitionCountWatchingPublisher(PartitionPublisherFactory,     com.google.cloud.pubsublite.internal.RoutingPolicy.Factory,     com.google.cloud.pubsublite.internal.wire.PartitionCountWatcher.Factory) is not public in PartitionCountWatchingPublisher; cannot be accessed from outside package     return new PartitionCountWatchingPublisher(            ^ ```

Code under review:
static Publisher<MessageMetadata> newPublisher(PublisherOptions options) throws ApiException {
    SerializableSupplier<Object> supplier = options.publisherSupplier();
    if (supplier != null) {
      Object supplied = supplier.get();
      TypeToken<Publisher<MessageMetadata>> token = new TypeToken<Publisher<MessageMetadata>>() {};
      checkArgument(token.isSupertypeOf(supplied.getClass()));
      return (Publisher<MessageMetadata>) supplied;
    }
    TopicPath topic = options.topicPath();
    return new PartitionCountWatchingPublisher(
        partition ->
            SinglePartitionPublisherBuilder.newBuilder()
                .setTopic(topic)
                .setPartition(partition)
                .build(),
        DefaultRoutingPolicy::new,
        new PartitionCountWatcherImpl.Factory(
            topic,
            AdminClient.create(
                AdminClientSettings.newBuilder().setRegion(topic.location().region()).build()),
            Duration.ofMinutes(10)));
  }

Line commented on: return new PartitionCountWatchingPublisher(

Revised code:
static Publisher<MessageMetadata> newPublisher(PublisherOptions options) throws ApiException {
    SerializableSupplier<Object> supplier = options.publisherSupplier();
    if (supplier != null) {
      Object supplied = supplier.get();
      TypeToken<Publisher<MessageMetadata>> token = new TypeToken<Publisher<MessageMetadata>>() {};
      checkArgument(token.isSupertypeOf(supplied.getClass()));
      return (Publisher<MessageMetadata>) supplied;
    }

    TopicPath topic = options.topicPath();
    PartitionCountWatchingPublisherSettings.Builder publisherSettings =
        PartitionCountWatchingPublisherSettings.newBuilder()
            .setTopic(topic)
            .setPublisherFactory(
                partition ->
                    SinglePartitionPublisherBuilder.newBuilder()
                        .setTopic(topic)
                        .setPartition(partition)
                        .build())
            .setAdminClient(
                AdminClient.create(
                    AdminClientSettings.newBuilder().setRegion(topic.location().region()).build()));
    return publisherSettings.build().instantiate();
  }
Code review comment: This leaves the reserved node with the application for 20-27 mins (until it is expired by `ReservationExpirer`), this is especially unfortunate in CD when we want to fail integration tests when some node are stuck in a non-active state.  We should prepare the application again with the node unmarked as wantToRetire or move it directly to dirty if that is safe.  FYI: @hmusum

Code under review:
private boolean deployTo(Move move) {
        ApplicationId application = move.node.allocation().get().owner();
        try (MaintenanceDeployment deployment = new MaintenanceDeployment(application, deployer, nodeRepository())) {
            if ( ! deployment.isValid()) return false;

            boolean couldMarkRetiredNow = markWantToRetire(move.node, true);
            if ( ! couldMarkRetiredNow) return false;

            try {
                if ( ! deployment.prepare()) return false;
                if (nodeRepository().getNodes(application, Node.State.reserved).stream().noneMatch(node -> node.hasParent(move.toHost.hostname())))
                    return false; 
                if ( ! deployment.activate()) return false;

                log.info("Rebalancer redeployed " + application + " to " + move);
                return true;
            }
            finally {
                markWantToRetire(move.node, false); 
            }
        }
    }

Line commented on: return false;

Revised code:
private boolean deployTo(Move move) {
        ApplicationId application = move.node.allocation().get().owner();
        try (MaintenanceDeployment deployment = new MaintenanceDeployment(application, deployer, nodeRepository())) {
            if ( ! deployment.isValid()) return false;

            boolean couldMarkRetiredNow = markWantToRetire(move.node, true);
            if ( ! couldMarkRetiredNow) return false;

            try {
                if ( ! deployment.prepare()) return false;
                if (nodeRepository().getNodes(application, Node.State.reserved).stream().noneMatch(node -> node.hasParent(move.toHost.hostname())))
                    return false; 
                if ( ! deployment.activate()) return false;

                log.info("Rebalancer redeployed " + application + " to " + move);
                return true;
            }
            finally {
                markWantToRetire(move.node, false); 
            }
        }
    }
Code review comment: `DescribeStmt` is only for `describe table`. `files()` is a table function table, so i put it here.

Code under review:
public DescribeStmt(Map<String, String> tableFunctionProperties, NodePosition pos) {
        super(pos);
        this.dbTableName = null;
        this.totalRows = new LinkedList<>();
        this.isTableFunctionTable = true;
        this.tableFunctionProperties = tableFunctionProperties;
    }

Line commented on: this.isTableFunctionTable = true;

Revised code:
public DescribeStmt(Map<String, String> tableFunctionProperties, NodePosition pos) {
        super(pos);
        this.dbTableName = null;
        this.totalRows = new LinkedList<>();
        this.isTableFunctionTable = true;
        this.tableFunctionProperties = tableFunctionProperties;
    }
Code review comment: Didn't see the purpose of re-wrapping an IOException

Code under review:
public boolean start() throws IOException {
      try {
        ConnectionHandler connectionHandler = new ConnectionHandler(source.spec.uri());
        connectionHandler.start();

        Channel channel = connectionHandler.getChannel();

        String queueName = source.spec.queue();
        if (source.spec.queueDeclare()) {
          
          
          channel.queueDeclare(queueName, false, false, false, null);
        }
        if (source.spec.exchange() != null) {
          if (source.spec.exchangeDeclare()) {
            channel.exchangeDeclare(source.spec.exchange(), source.spec.exchangeType());
          }
          if (queueName == null) {
            queueName = channel.queueDeclare().getQueue();
          }
          channel.queueBind(queueName, source.spec.exchange(), source.spec.routingKey());
        }
        checkpointMark.channel = channel;
        consumer = new QueueingConsumer(channel);
        channel.txSelect();
        
        channel.setDefaultConsumer(consumer);
        channel.basicConsume(queueName, false, consumer);
      } catch (IOException e) {
        throw e;
      } catch (Exception e) {
        throw new IOException(e);
      }
      return advance();
    }

Line commented on: channel.queueBind(queueName, source.spec.exchange(), source.spec.routingKey());

Revised code:
public boolean start() throws IOException {
      try {
        connectionHandler = new ConnectionHandler(source.spec.uri());
        connectionHandler.start();

        Channel channel = connectionHandler.getChannel();

        queueName = source.spec.queue();
        if (source.spec.queueDeclare()) {
          
          
          channel.queueDeclare(queueName, false, false, false, null);
        }
        if (source.spec.exchange() != null) {
          if (source.spec.exchangeDeclare()) {
            channel.exchangeDeclare(source.spec.exchange(), source.spec.exchangeType());
          }
          if (queueName == null) {
            queueName = channel.queueDeclare().getQueue();
          }
          channel.queueBind(queueName, source.spec.exchange(), source.spec.routingKey());
        }
        checkpointMark.channel = channel;
        channel.txSelect();
      } catch (IOException e) {
        throw e;
      } catch (Exception e) {
        throw new IOException(e);
      }
      return advance();
    }
Code review comment: How about just removing the shortcut?

Code under review:
public History recordStateTransition(Node.State from, Node.State to, Agent agent, Instant at) {
        
        if (from == to && from != Node.State.reserved) return this;
        switch (to) {
            case provisioned: return this.with(new Event(Event.Type.provisioned, agent, at));
            case ready:       return this.withoutApplicationEvents().with(new Event(Event.Type.readied, agent, at));
            case active:      return this.with(new Event(Event.Type.activated, agent, at));
            case inactive:    return this.with(new Event(Event.Type.deactivated, agent, at));
            case reserved:    return this.with(new Event(Event.Type.reserved, agent, at));
            case failed:      return this.with(new Event(Event.Type.failed, agent, at));
            case dirty:       return this.with(new Event(Event.Type.deallocated, agent, at));
            case parked:      return this.with(new Event(Event.Type.parked, agent, at));
            default:          return this;
        }
    }


Revised code:
public History recordStateTransition(Node.State from, Node.State to, Agent agent, Instant at) {
        
        if (from == to && from != Node.State.reserved) return this;
        switch (to) {
            case provisioned: return this.with(new Event(Event.Type.provisioned, agent, at));
            case ready:       return this.withoutApplicationEvents().with(new Event(Event.Type.readied, agent, at));
            case active:      return this.with(new Event(Event.Type.activated, agent, at));
            case inactive:    return this.with(new Event(Event.Type.deactivated, agent, at));
            case reserved:    return this.with(new Event(Event.Type.reserved, agent, at));
            case failed:      return this.with(new Event(Event.Type.failed, agent, at));
            case dirty:       return this.with(new Event(Event.Type.deallocated, agent, at));
            case parked:      return this.with(new Event(Event.Type.parked, agent, at));
            default:          return this;
        }
    }
Code review comment: Yes, I forgot about that. Excellent catch!

Code under review:
private static void deferConfigChangesForClustersToBeRestarted(List<ConfigChangeAction> actions, VespaModel model) {
        Set<ClusterSpec.Id> clustersToBeRestarted = actions.stream()
                                                           .filter(action -> action.getType() == ConfigChangeAction.Type.RESTART)
                                                           .map(action -> action.clusterId())
                                                           .collect(Collectors.toSet());
        for (var clusterToRestart : clustersToBeRestarted) {
            var containerCluster = model.getContainerClusters().get(clusterToRestart.value());
            if (containerCluster != null)
                containerCluster.deferChangesUntilRestart();

            var contentCluster = model.getContentClusters().get(clusterToRestart.value());
            if (contentCluster != null)
                contentCluster.deferChangesUntilRestart();
        }
    }

Line commented on: var containerCluster = model.getContainerClusters().get(clusterToRestart.value());

Revised code:
private static void deferConfigChangesForClustersToBeRestarted(List<ConfigChangeAction> actions, VespaModel model) {
        Set<ClusterSpec.Id> clustersToBeRestarted = actions.stream()
                                                           .filter(action -> action.getType() == ConfigChangeAction.Type.RESTART)
                                                           .filter(action -> action.clusterId() != null) 
                                                           .map(action -> action.clusterId())
                                                           .collect(Collectors.toSet());
        for (var clusterToRestart : clustersToBeRestarted) {
            var containerCluster = model.getContainerClusters().get(clusterToRestart.value());
            if (containerCluster != null)
                containerCluster.deferChangesUntilRestart();

            var contentCluster = model.getContentClusters().get(clusterToRestart.value());
            if (contentCluster != null)
                contentCluster.deferChangesUntilRestart();
        }
    }
Code review comment: Does this properly handle multi-catch blocks, ex `catch (IOException | UncheckIOException ex)`?

Code under review:
public void visitToken(DetailAST catchBlockToken) {
        final DetailAST catchStatement = catchBlockToken.findFirstToken(TokenTypes.PARAMETER_DEF);
        final String caughtExceptionVariableName = catchStatement.findFirstToken(TokenTypes.IDENT).getText();

        final List<DetailAST> throwStatements = getThrowStatements(catchBlockToken);
        final List<String> wrappedExceptions =
            getWrappedExceptions(catchBlockToken, catchBlockToken, caughtExceptionVariableName);

        throwStatements.forEach(throwToken -> {
            final List<String> throwParamNames = new LinkedList<>();
            getThrowParamNames(throwToken, throwParamNames);
            
            wrappedExceptions.add(caughtExceptionVariableName);

            
            
            List<String> intersect =
                wrappedExceptions.stream().filter(throwParamNames::contains).collect(Collectors.toList());
            if (intersect.size() == 0) {
                log(throwToken, String.format(UNUSED_CAUGHT_EXCEPTION_ERROR, caughtExceptionVariableName));
            }
        });
    }

Line commented on: final List<String> wrappedExceptions =

Revised code:
public void visitToken(DetailAST catchBlockToken) {
        
        final DetailAST catchStatement = catchBlockToken.findFirstToken(TokenTypes.PARAMETER_DEF);
        final String caughtExceptionVariableName = catchStatement.findFirstToken(TokenTypes.IDENT).getText();

        
        final List<DetailAST> throwStatements = getThrowStatements(catchBlockToken);

        
        final List<String> wrappedExceptions =
            getWrappedExceptions(catchBlockToken, catchBlockToken, caughtExceptionVariableName);

        throwStatements.forEach(throwToken -> {
            final List<String> throwParamNames = new LinkedList<>();
            getThrowParamNames(throwToken, throwParamNames);
            
            wrappedExceptions.add(caughtExceptionVariableName);

            
            
            
            
            List<String> intersect =
                wrappedExceptions.stream().filter(throwParamNames::contains).collect(Collectors.toList());
            if (intersect.size() == 0) {
                log(throwToken, String.format(UNUSED_CAUGHT_EXCEPTION_ERROR, caughtExceptionVariableName));
            }
        });
    }
Code review comment: I run ValidatesRunner tests and the result is green.

Code under review:
private void checkNoMoreMatches(final List<PTransformOverride> overrides) {
    traverseTopologically(
        new PipelineVisitor.Defaults() {
          SetMultimap<Node, PTransformOverride> matched = HashMultimap.create();

          @Override
          public CompositeBehavior enterCompositeTransform(Node node) {
            if (!node.isRootNode()) {
              checkForMatches(node);
            }
            if (matched.containsKey(node)) {
              return CompositeBehavior.DO_NOT_ENTER_TRANSFORM;
            } else {
              return CompositeBehavior.ENTER_TRANSFORM;
            }
          }

          @Override
          public void leaveCompositeTransform(Node node) {
            if (node.isRootNode()) {
              checkState(
                  matched.isEmpty(), "Found nodes that matched overrides. Matches: %s", matched);
            }
          }

          @Override
          public void visitPrimitiveTransform(Node node) {
            checkForMatches(node);
          }

          private void checkForMatches(Node node) {
            for (PTransformOverride override : overrides) {
              if (override.getMatcher()
                  .matchesDuringValidation(node.toAppliedPTransform(getPipeline()))) {
                matched.put(node, override);
              }
            }
          }
        });
  }

Line commented on: SetMultimap<Node, PTransformOverride> matched = HashMultimap.create();

Revised code:
private void checkNoMoreMatches(final List<PTransformOverride> overrides) {
    traverseTopologically(
        new PipelineVisitor.Defaults() {
          SetMultimap<Node, PTransformOverride> matched = HashMultimap.create();

          @Override
          public CompositeBehavior enterCompositeTransform(Node node) {
            if (!node.isRootNode()) {
              checkForMatches(node);
            }
            if (matched.containsKey(node)) {
              return CompositeBehavior.DO_NOT_ENTER_TRANSFORM;
            } else {
              return CompositeBehavior.ENTER_TRANSFORM;
            }
          }

          @Override
          public void leaveCompositeTransform(Node node) {
            if (node.isRootNode()) {
              checkState(
                  matched.isEmpty(), "Found nodes that matched overrides. Matches: %s", matched);
            }
          }

          @Override
          public void visitPrimitiveTransform(Node node) {
            checkForMatches(node);
          }

          private void checkForMatches(Node node) {
            for (PTransformOverride override : overrides) {
              if (override
                  .getMatcher()
                  .matchesDuringValidation(node.toAppliedPTransform(getPipeline()))) {
                matched.put(node, override);
              }
            }
          }
        });
  }
Code review comment: Why do we traverse the children here? Can't we use the specific APIs instead?

Code under review:
public Optional<DocumentSymbol> transform(ClassDefinitionNode classDefinitionNode) {
        String name = classDefinitionNode.className().text();
        SymbolKind symbolKind = SymbolKind.Class;
        Range range = DocumentSymbolUtil.generateNodeRange(classDefinitionNode);
        Optional<MetadataNode> metadata = classDefinitionNode.metadata();
        boolean isDeprecated = metadata.isPresent() &&
                DocumentSymbolUtil.isDeprecated(metadata.get());
        List<DocumentSymbol> children = transformChildren(classDefinitionNode.children());
        return Optional.ofNullable(createDocumentSymbol(name, symbolKind,
                null, range, range, isDeprecated, children, this.context));
    }

Line commented on: Optional<MetadataNode> metadata = classDefinitionNode.metadata();

Revised code:
public Optional<DocumentSymbol> transform(ClassDefinitionNode classDefinitionNode) {
        String name = classDefinitionNode.className().text();
        SymbolKind symbolKind = SymbolKind.Class;
        Range range = DocumentSymbolUtil.generateNodeRange(classDefinitionNode);
        Optional<MetadataNode> metadata = classDefinitionNode.metadata();
        boolean isDeprecated = metadata.isPresent() &&
                DocumentSymbolUtil.isDeprecated(metadata.get());
        List<DocumentSymbol> children = transformMembers(classDefinitionNode.members());
        return Optional.ofNullable(createDocumentSymbol(name, symbolKind,
                null, range, range, isDeprecated, children, this.context));
    }