Skip to content

Commit c2cc519

Browse files
committed
support external sql interceptor call back
1 parent 88f845d commit c2cc519

File tree

6 files changed

+432
-22
lines changed

6 files changed

+432
-22
lines changed

server/odc-service/src/main/java/com/oceanbase/odc/service/integration/ExternalSqlInterceptor.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package com.oceanbase.odc.service.integration;
1717

1818
import java.util.List;
19+
import java.util.Map;
1920
import java.util.Map.Entry;
2021
import java.util.Objects;
2122
import java.util.Optional;
@@ -25,6 +26,7 @@
2526
import org.springframework.stereotype.Component;
2627

2728
import com.oceanbase.odc.common.json.JsonUtils;
29+
import com.oceanbase.odc.common.util.MapUtils;
2830
import com.oceanbase.odc.core.session.ConnectionSession;
2931
import com.oceanbase.odc.core.session.ConnectionSessionUtil;
3032
import com.oceanbase.odc.core.shared.constant.OrganizationType;
@@ -37,8 +39,9 @@
3739
import com.oceanbase.odc.service.connection.model.ConnectionConfig;
3840
import com.oceanbase.odc.service.iam.auth.AuthenticationFacade;
3941
import com.oceanbase.odc.service.integration.client.SqlInterceptorClient;
40-
import com.oceanbase.odc.service.integration.model.SqlCheckStatus;
42+
import com.oceanbase.odc.service.integration.model.SqlCheckResult;
4143
import com.oceanbase.odc.service.integration.model.SqlInterceptorProperties;
44+
import com.oceanbase.odc.service.integration.model.SqlInterceptorProperties.CheckProperties;
4245
import com.oceanbase.odc.service.integration.model.TemplateVariables;
4346
import com.oceanbase.odc.service.integration.model.TemplateVariables.Variable;
4447
import com.oceanbase.odc.service.regulation.ruleset.RuleService;
@@ -100,9 +103,20 @@ public boolean doPreHandle(@NonNull SqlAsyncExecuteReq request, @NonNull SqlAsyn
100103
SqlInterceptorProperties properties =
101104
(SqlInterceptorProperties) integrationService.getIntegrationProperties(interceptorOpt.get().getId());
102105
TemplateVariables variables = buildTemplateVariables(request.getSql(), session);
103-
SqlCheckStatus result = sqlInterceptorClient.check(properties, variables);
104-
switch (result) {
106+
SqlCheckResult result = sqlInterceptorClient.check(properties, variables);
107+
// set variables in template
108+
if (!MapUtils.isEmpty(result.getExtractedResponse())) {
109+
for (Map.Entry<String, String> entry : result.getExtractedResponse().entrySet()) {
110+
variables.setAttribute(Variable.EXTERNAL_PROPERTIES, entry.getKey(), entry.getValue());
111+
}
112+
}
113+
CheckProperties check = properties.getApi().getCheck();
114+
switch (result.getSqlCheckStatus()) {
105115
case IN_WHITE_LIST:
116+
if (null != check.onInWhiteList()) {
117+
sqlInterceptorClient.getIntegrationResponse(properties.getHttp(), check.onInWhiteList(), variables,
118+
properties.getEncryption());
119+
}
106120
return true;
107121
case IN_BLACK_LIST:
108122
ruleService.getByRulesetIdAndName(ruleSetId, SqlConsoleRules.EXTERNAL_SQL_INTERCEPTOR.getRuleName())
@@ -121,6 +135,10 @@ public boolean doPreHandle(@NonNull SqlAsyncExecuteReq request, @NonNull SqlAsyn
121135
violationRule.setViolation(violation);
122136
response.getViolatedRules().add(violationRule);
123137
});
138+
if (null != check.onInBlackList()) {
139+
sqlInterceptorClient.getIntegrationResponse(properties.getHttp(), check.onInBlackList(), variables,
140+
properties.getEncryption());
141+
}
124142
return false;
125143
case NEED_REVIEW:
126144
ruleService.getByRulesetIdAndName(ruleSetId, SqlConsoleRules.EXTERNAL_SQL_INTERCEPTOR.getRuleName())
@@ -139,6 +157,10 @@ public boolean doPreHandle(@NonNull SqlAsyncExecuteReq request, @NonNull SqlAsyn
139157
violationRule.setViolation(violation);
140158
response.getViolatedRules().add(violationRule);
141159
});
160+
if (null != check.onNeedReview()) {
161+
sqlInterceptorClient.getIntegrationResponse(properties.getHttp(), check.onNeedReview(), variables,
162+
properties.getEncryption());
163+
}
142164
return false;
143165
default:
144166
throw new UnexpectedException("SQL intercept failed, unknown intercept status: " + result);

server/odc-service/src/main/java/com/oceanbase/odc/service/integration/client/SqlInterceptorClient.java

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
package com.oceanbase.odc.service.integration.client;
1717

18+
import java.util.HashMap;
19+
import java.util.Map;
20+
1821
import javax.annotation.PostConstruct;
1922

2023
import org.apache.http.client.HttpClient;
@@ -25,17 +28,22 @@
2528
import org.springframework.beans.factory.annotation.Value;
2629
import org.springframework.stereotype.Component;
2730

31+
import com.oceanbase.odc.common.util.MapUtils;
2832
import com.oceanbase.odc.core.shared.Verify;
2933
import com.oceanbase.odc.core.shared.constant.ErrorCodes;
3034
import com.oceanbase.odc.core.shared.exception.ExternalServiceError;
3135
import com.oceanbase.odc.core.shared.exception.UnexpectedException;
3236
import com.oceanbase.odc.service.integration.HttpOperationService;
3337
import com.oceanbase.odc.service.integration.model.ApprovalProperties;
3438
import com.oceanbase.odc.service.integration.model.Encryption;
39+
import com.oceanbase.odc.service.integration.model.IntegrationProperties;
40+
import com.oceanbase.odc.service.integration.model.IntegrationProperties.ApiProperties;
3541
import com.oceanbase.odc.service.integration.model.IntegrationProperties.HttpProperties;
3642
import com.oceanbase.odc.service.integration.model.OdcIntegrationResponse;
43+
import com.oceanbase.odc.service.integration.model.SqlCheckResult;
3744
import com.oceanbase.odc.service.integration.model.SqlCheckStatus;
3845
import com.oceanbase.odc.service.integration.model.SqlInterceptorProperties;
46+
import com.oceanbase.odc.service.integration.model.SqlInterceptorProperties.CallBackProperties;
3947
import com.oceanbase.odc.service.integration.model.SqlInterceptorProperties.CheckProperties;
4048
import com.oceanbase.odc.service.integration.model.TemplateVariables;
4149
import com.oceanbase.odc.service.integration.model.TemplateVariables.Variable;
@@ -82,40 +90,65 @@ public void init() {
8290
* @param variables Template variables for building request, more details reference {@link Variable}
8391
* @return The check result {@link SqlCheckStatus} of SQL content
8492
*/
85-
public SqlCheckStatus check(@NonNull SqlInterceptorProperties properties, TemplateVariables variables) {
93+
public SqlCheckResult check(@NonNull SqlInterceptorProperties properties, TemplateVariables variables) {
8694
CheckProperties check = properties.getApi().getCheck();
8795
HttpProperties http = properties.getHttp();
8896
Encryption encryption = properties.getEncryption();
89-
HttpUriRequest request;
90-
try {
91-
request = httpService.buildHttpRequest(check, http, encryption, variables);
92-
} catch (Exception e) {
93-
throw new UnexpectedException("Build request failed: " + e.getMessage());
94-
}
95-
OdcIntegrationResponse response;
96-
try {
97-
response = httpClient.execute(request, new OdcIntegrationResponseHandler());
98-
} catch (Exception e) {
99-
throw new ExternalServiceError(ErrorCodes.ExternalServiceError,
100-
"Request execute failed: " + e.getMessage());
101-
}
102-
response.setContent(EncryptionUtil.decrypt(response.getContent(), encryption));
97+
OdcIntegrationResponse response = getIntegrationResponse(http, check, variables, encryption);
10398
try {
99+
SqlCheckStatus sqlCheckStatus = null;
104100
String expression = check.getRequestSuccessExpression();
105101
boolean valid = httpService.extractHttpResponse(response, expression, Boolean.class);
106102
Verify.verify(valid, "Response is invalid, except: " + expression + ", response body: " + response);
107103
if (httpService.extractHttpResponse(response, check.getInWhiteListExpression(), Boolean.class)) {
108-
return SqlCheckStatus.IN_WHITE_LIST;
104+
sqlCheckStatus = SqlCheckStatus.IN_WHITE_LIST;
109105
} else if (httpService.extractHttpResponse(response, check.getInBlackListExpression(), Boolean.class)) {
110-
return SqlCheckStatus.IN_BLACK_LIST;
106+
sqlCheckStatus = SqlCheckStatus.IN_BLACK_LIST;
111107
} else if (httpService.extractHttpResponse(response, check.getNeedReviewExpression(), Boolean.class)) {
112-
return SqlCheckStatus.NEED_REVIEW;
108+
sqlCheckStatus = SqlCheckStatus.NEED_REVIEW;
113109
} else {
114110
throw new RuntimeException(
115111
"Response mismatch any check result expression, response body: " + response.getContent());
116112
}
113+
// try extract value from response for future request
114+
Map<String, String> extractedResponse = new HashMap<>();
115+
CallBackProperties callBackProperties = check.getCallback();
116+
if (null != callBackProperties && !MapUtils.isEmpty(callBackProperties.getResponseExtractExpressions())) {
117+
for (Map.Entry<String, String> responseExtractExpressionEntrySet : callBackProperties
118+
.getResponseExtractExpressions().entrySet()) {
119+
String key = responseExtractExpressionEntrySet.getKey();
120+
String responseExtractExpression = responseExtractExpressionEntrySet.getValue();
121+
String value = extractedResponse.put(key,
122+
httpService.extractHttpResponse(response, responseExtractExpression, String.class));
123+
if (null != value) {
124+
extractedResponse.put(key, value);
125+
}
126+
}
127+
}
128+
return new SqlCheckResult(extractedResponse, sqlCheckStatus);
117129
} catch (Exception e) {
118130
throw new UnexpectedException("Extract SQL check result failed: " + e.getMessage());
119131
}
120132
}
133+
134+
public OdcIntegrationResponse getIntegrationResponse(HttpProperties http,
135+
@NonNull IntegrationProperties.ApiProperties api, TemplateVariables variables, Encryption encryption) {
136+
HttpUriRequest request;
137+
try {
138+
request = httpService.buildHttpRequest(api, http, encryption, variables);
139+
} catch (Exception e) {
140+
throw new UnexpectedException("Build request failed: " + e.getMessage());
141+
}
142+
OdcIntegrationResponse response;
143+
try {
144+
response = httpClient.execute(request, new OdcIntegrationResponseHandler());
145+
} catch (Exception e) {
146+
throw new ExternalServiceError(ErrorCodes.ExternalServiceError,
147+
"Request execute failed: " + e.getMessage());
148+
}
149+
response.setContent(EncryptionUtil.decrypt(response.getContent(), encryption));
150+
log.info("sqlInterceptorClient getIntegrationResponse request = {}, response ={}", request,
151+
response.getContent());
152+
return response;
153+
}
121154
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2023 OceanBase.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.oceanbase.odc.service.integration.model;
17+
18+
import java.util.Map;
19+
20+
import lombok.AllArgsConstructor;
21+
import lombok.Data;
22+
23+
/**
24+
* @author longpeng.zlp
25+
* @date 2025/6/19 13:49
26+
*/
27+
@Data
28+
@AllArgsConstructor
29+
public class SqlCheckResult {
30+
private Map<String, String> extractedResponse;
31+
private SqlCheckStatus sqlCheckStatus;
32+
}

server/odc-service/src/main/java/com/oceanbase/odc/service/integration/model/SqlInterceptorProperties.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package com.oceanbase.odc.service.integration.model;
1717

18+
import java.util.Map;
19+
1820
import javax.validation.Valid;
1921
import javax.validation.constraints.NotBlank;
2022
import javax.validation.constraints.NotNull;
@@ -51,6 +53,40 @@ public static class CheckProperties extends ApiProperties {
5153
private String inBlackListExpression;
5254
@NotBlank
5355
private String needReviewExpression;
56+
// call back properties
57+
private CallBackProperties callback;
58+
59+
public ApiProperties onNeedReview() {
60+
if (null != callback) {
61+
return callback.onNeedReview;
62+
} else {
63+
return null;
64+
}
65+
}
66+
67+
public ApiProperties onInBlackList() {
68+
if (null != callback) {
69+
return callback.onInBlackList;
70+
} else {
71+
return null;
72+
}
73+
}
74+
75+
public ApiProperties onInWhiteList() {
76+
if (null != callback) {
77+
return callback.onInWhiteList;
78+
} else {
79+
return null;
80+
}
81+
}
82+
}
83+
84+
@Data
85+
public static class CallBackProperties {
86+
private ApiProperties onNeedReview;
87+
private ApiProperties onInWhiteList;
88+
private ApiProperties onInBlackList;
89+
private Map<String, String> responseExtractExpressions;
5490
}
5591

5692
public static SqlInterceptorProperties from(IntegrationConfig config) {

server/odc-service/src/main/java/com/oceanbase/odc/service/integration/model/TemplateVariables.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ public enum Variable {
7373
PROJECT_OWNER_IDS("project.owner.ids"),
7474
PROJECT_OWNER_ACCOUNTS("project.owner.accounts"),
7575
PROJECT_OWNER_NAMES("project.owner.names"),
76-
ODC_TASK_URL("odc.task.url");
76+
ODC_TASK_URL("odc.task.url"),
77+
EXTERNAL_PROPERTIES("external.response");
7778

7879

7980
private final String key;

0 commit comments

Comments
 (0)