Skip to content

Commit

Permalink
Add support for gRPC java
Browse files Browse the repository at this point in the history
closes google#243
  • Loading branch information
shubhwip committed Apr 8, 2023
1 parent c447d21 commit 7f75126
Show file tree
Hide file tree
Showing 12 changed files with 594 additions and 27 deletions.
16 changes: 15 additions & 1 deletion java/sqlcommenter-java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ tracestate='rojo%253D00f067aa0ba902b7%2Ccongo%253Dt61rcWkgMzE''*/
- [ ] Jetty
- [ ] Netty
- [ ] Apache Tomcat
- [ ] gRPC
- [X] gRPC

### Using it

Expand Down Expand Up @@ -173,3 +173,17 @@ public class JPAConfig {

1. Please follow the instructions to add the [Spring interceptor](#spring)
2. Please follow the instructions to add the [Hibernate StatementInspector](#hibernate)

#### Spring gRPC Configuration
Add following configuration into your code
```java
@Configuration
public class gRPCConfig {
@Bean
public GrpcSQLCommenterInterceptor grpcSQLCommenterInterceptor() {
return new GrpcSQLCommenterInterceptor();
}
}
```
99 changes: 74 additions & 25 deletions java/sqlcommenter-java/build.gradle
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
description = 'SQL commenter integration'
buildscript {
repositories {
mavenCentral()
mavenLocal()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.16'
classpath "gradle.plugin.com.github.sherter.google-java-format:google-java-format-gradle-plugin:0.8"
}
}

apply plugin: 'com.github.sherter.google-java-format'
apply plugin: 'idea'
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: "maven-publish"
apply plugin: "net.ltgt.errorprone"
apply plugin: "jacoco"
apply plugin: "signing"
plugins {
id 'com.github.sherter.google-java-format' version "0.7.1"
id 'idea'
id 'java'
id 'maven'
id "maven-publish"
id "net.ltgt.errorprone" version "1.1.0"
id "jacoco"
id "signing"
id "com.google.protobuf" version "0.9.1"
id "com.google.osdetector" version "1.6.2"
}

description = 'SQL commenter integration'

group = "com.google.cloud"
version = "2.0.0" // CURRENT_VERSION
Expand All @@ -28,18 +44,6 @@ jar.manifest {
'Target-Compatibility': targetCompatibility)
}

buildscript {
repositories {
mavenCentral()
mavenLocal()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.16'
classpath "gradle.plugin.com.github.sherter.google-java-format:google-java-format-gradle-plugin:0.7.1"
}
}


def opencensusVersion = '0.28.3'
def errorProneVersion = '2.3.2'
Expand All @@ -49,13 +53,19 @@ def opentelemetryVersion = '1.5.0'

dependencies {
compile "io.opencensus:opencensus-api:${opencensusVersion}"
testImplementation 'org.projectlombok:lombok:1.18.22'
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
testImplementation group: 'org.mockito', name: 'mockito-core', version: '2.1.0'

runtime "io.opencensus:opencensus-impl:${opencensusVersion}"

compileOnly "com.google.code.findbugs:jsr305:${findBugsJsr305Version}"
compileOnly "com.google.errorprone:error_prone_annotations:${errorProneVersion}"
errorprone "com.google.errorprone:error_prone_core:${errorProneVersion}"
implementation "io.opentelemetry:opentelemetry-api:${opentelemetryVersion}"
implementation "io.opentelemetry:opentelemetry-sdk:${opentelemetryVersion}"
implementation 'io.grpc:grpc-all:1.40.1'

// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web
compile (group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.1.5.RELEASE') {
Expand All @@ -71,6 +81,44 @@ dependencies {
testCompile 'org.springframework.boot:spring-boot-starter-data-jpa:2.1.5.RELEASE'
testCompile 'org.springframework.boot:spring-boot-starter-test:2.1.5.RELEASE'
testCompile 'org.hsqldb:hsqldb:2.4.0'
testCompile 'io.github.lognet:grpc-spring-boot-starter:4.9.0'
testCompile "com.google.protobuf:protobuf-java:3.19.1"
runtimeOnly 'io.grpc:grpc-netty-shaded:1.52.1'
implementation 'io.grpc:grpc-protobuf:1.52.1'
implementation 'io.grpc:grpc-stub:1.52.1'
compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+

errorprone("com.google.errorprone:error_prone_core:2.3.3")
errorproneJavac("com.google.errorprone:javac:9+181-r4173-1")

testImplementation group: 'com.h2database', name: 'h2', version: '1.3.148'


}

sourceSets {
test {
java {
srcDirs 'build/generated/source/proto/test/grpc'
srcDirs 'build/generated/source/proto/test/java'
}
}
}

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.21.7"
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.52.1"
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}

compileJava {
Expand All @@ -79,17 +127,17 @@ compileJava {
// We suppress the "processing" warning as suggested in
// https://groups.google.com/forum/#!topic/bazel-discuss/_R3A9TJSoPM
it.options.compilerArgs += ["-Xlint:all", "-Xlint:-try", "-Xlint:-processing"]
it.options.compilerArgs += ["-XepAllDisabledChecksAsWarnings", "-XepDisableWarningsInGeneratedCode"]
//it.options.compilerArgs += ["-XepAllDisabledChecksAsWarnings", "-XepDisableWarningsInGeneratedCode"]

// MutableMethodReturnType can suggest returning Guava types from
// API methods (https://github.com/google/error-prone/issues/982).
it.options.compilerArgs += ["-Xep:MutableMethodReturnType:OFF"]
//it.options.compilerArgs += ["-Xep:MutableMethodReturnType:OFF"]

// ReturnMissingNullable conflicts with Checker Framework null analysis.
it.options.compilerArgs += ["-Xep:ReturnMissingNullable:OFF"]
//it.options.compilerArgs += ["-Xep:ReturnMissingNullable:OFF"]

// We currently don't use Var annotations.
it.options.compilerArgs += ["-Xep:Var:OFF"]
//it.options.compilerArgs += ["-Xep:Var:OFF"]

it.options.encoding = "UTF-8"
it.options.compilerArgs += ["-Xlint:-cast"]
Expand All @@ -110,6 +158,7 @@ if (JavaVersion.current().isJava8Compatible()) {

tasks.verifyGoogleJavaFormat {
source = sourceSets*.allJava
exclude '**/grpc/stubs/**'
include '**/*.java'
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2019 Google LLC
//
// 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.google.cloud.sqlcommenter.interceptors;

import com.google.cloud.sqlcommenter.threadlocalstorage.State;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;

public class GrpcSQLCommenterInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call, Metadata requestHeaders, ServerCallHandler<ReqT, RespT> next) {

if (call == null || next == null) return null;

if (call != null) {
String actionName = call.getMethodDescriptor().getBareMethodName();
String serviceName = call.getMethodDescriptor().getServiceName();
State.Holder.set(
State.newBuilder()
.withControllerName(serviceName)
.withActionName(actionName)
.withFramework("spring-grpc")
.build());
}

return next.startCall(call, requestHeaders);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.google.cloud.sqlcommenter.grpc.backend;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;

import com.google.cloud.sqlcommenter.grpc.backend.service.StudentServiceImpl;
import com.google.cloud.sqlcommenter.grpc.stubs.StudentRequest;
import com.google.cloud.sqlcommenter.grpc.stubs.StudentResponse;
import com.google.cloud.sqlcommenter.threadlocalstorage.State;
import com.google.cloud.sqlcommenter.util.SCHibernateWrapper;
import io.grpc.stub.StreamObserver;
import java.util.List;
import org.junit.Test;

public class GrpcSQLCommenterTests {

@Test
public void givenStudentService_whenGetStudentInfoIsCalled_thenSQLStatementsShouldBeTagged() {
// given
StudentServiceImpl studentService = new StudentServiceImpl();
StreamObserver<StudentResponse> observer = mock(StreamObserver.class);
State.Holder.set(
State.newBuilder()
.withControllerName("StudentServiceImpl")
.withActionName("getStudentInfo")
.withFramework("grpc")
.build());

SCHibernateWrapper.reset();
StudentRequest studentRequest = StudentRequest.newBuilder().setStudentId("st1").build();

// when
studentService.getStudentInfo(studentRequest, observer);
List<String> sqlStatements = SCHibernateWrapper.getAfterSqlStatements();

// then
assertEquals(1, sqlStatements.size());
assertEquals(
1,
sqlStatements
.stream()
.filter(
sql ->
sql.contains(
"/*action='getStudentInfo',controller='StudentServiceImpl',framework='grpc'*/"))
.count());

SCHibernateWrapper.reset();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2019 Google LLC
//
// 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.google.cloud.sqlcommenter.grpc.backend.dao;

import com.google.cloud.sqlcommenter.grpc.backend.domain.Student;
import java.util.NoSuchElementException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class StudentDao {
public Student findById(String studentId) {

// We use entity managers to manage our two entities.
// We use the factory design pattern to get the entity manager.
// Here we should provide the name of the persistence unit that we provided in the
// persistence.xml file.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("student-management-system");
EntityManager em = emf.createEntityManager();

// We can find a record in the database for a given id using the find method.
// for the find method we have to provide our entity class and the id.
Student student = em.find(Student.class, studentId);

// If there is no record found with the provided student id, then we throw a NoSuchElement
// exception.
if (student == null) {
throw new NoSuchElementException("NO DATA FOUND WITH THE ID " + studentId);
}

// If everything worked fine, return the result.
return student;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2019 Google LLC
//
// 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.google.cloud.sqlcommenter.grpc.backend.domain;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Entity
@Table(name = "student")
public class Student {
@Id private String studentId;
private String name;
private Integer age;
}
Loading

0 comments on commit 7f75126

Please sign in to comment.