Skip to content

Commit f8bc7ea

Browse files
committed
#AI commit# CC: REQ-01文件数据集导入功能-作业配置BML注入:新增FileDataxSubExchangisJobHandler(反射注册dataSourceType=file,__file_bml_前缀命名空间读取BML引用无需get+remove,path设为BML文件名,ensure txtfilereader参数);DataxExchangisEngineJobBuilder新增file→txtfile插件名映射(得到txtfilereader)与settingFileSourceBmlResource(物化EngineBmlResource,复用既有wds.linkis.engineconn.datax.bml.resources机制供EC启动时自动下载到工作目录) / REQ-01 file dataset import job config BML injection: add FileDataxSubExchangisJobHandler (reflection-registered dataSourceType=file, read BML ref via __file_bml_ namespaced params without get+remove, path=BML filename, ensure txtfilereader params); DataxExchangisEngineJobBuilder adds file→txtfile plugin name mapping (yields txtfilereader) & settingFileSourceBmlResource (materialize EngineBmlResource, reuse existing wds.linkis.engineconn.datax.bml.resources mechanism for EC auto-download to workdir at startup)
1 parent 8d264a0 commit f8bc7ea

2 files changed

Lines changed: 203 additions & 0 deletions

File tree

exchangis-job/exchangis-job-server/src/main/java/com/webank/wedatasphere/exchangis/job/server/builder/engine/DataxExchangisEngineJobBuilder.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.webank.wedatasphere.exchangis.job.exception.ExchangisJobException;
1414
import com.webank.wedatasphere.exchangis.job.exception.ExchangisJobExceptionCode;
1515
import com.webank.wedatasphere.exchangis.job.server.builder.transform.TransformExchangisJob;
16+
import com.webank.wedatasphere.exchangis.job.server.builder.transform.handlers.FileDataxSubExchangisJobHandler;
1617
import com.webank.wedatasphere.exchangis.job.server.render.transform.TransformTypes;
1718
import com.webank.wedatasphere.exchangis.common.util.json.JsonEntity;
1819
import com.webank.wedatasphere.exchangis.job.utils.MemUtils;
@@ -41,6 +42,9 @@ public class DataxExchangisEngineJobBuilder extends AbstractResourceEngineJobBui
4142
//hive use hdfs plugin resource
4243
PLUGIN_NAME_MAPPER.put("hive", "hdfs");
4344
PLUGIN_NAME_MAPPER.put("tdsql", "mysql");
45+
// file source uses the datax txtfilereader plugin (file -> txtfile + "reader" = txtfilereader)
46+
// 文件 source 走 datax txtfilereader 插件(file -> txtfile + "reader" = txtfilereader)
47+
PLUGIN_NAME_MAPPER.put("file", "txtfile");
4448
}
4549

4650
/**
@@ -155,6 +159,13 @@ public DataxExchangisEngineJob buildJob(SubExchangisJob inputJob, ExchangisEngin
155159
engineJob.setSourceId(dsContent.parseSourceId());
156160
engineJob.setSinkId(dsContent.parseSinkId());
157161
}
162+
// M2: file source BML resource injection (文件 source BML 资源注入)
163+
// The handler stashes the file BML ref into jobParams; materialize it as an
164+
// EngineBmlResource so the launcher serializes it into wds.linkis.engineconn.datax.bml.resources
165+
// for DataxEngineConnLaunchBuilder.getBmlResources() to auto-download to the EC workdir.
166+
if ("file".equalsIgnoreCase(inputJob.getSourceType())) {
167+
settingFileSourceBmlResource(inputJob, engineJob);
168+
}
158169
engineJob.setName(inputJob.getName());
159170
//Unit MB
160171
Optional.ofNullable(engineJob.getRuntimeParams().get(BYTE_SPEED_SETTING_PARAM)).ifPresent(byteLimit -> {
@@ -219,6 +230,48 @@ private void settingProcessorInfo(TransformExchangisJob.TransformSubExchangisJob
219230
codeResource.getResourceId(), codeResource.getVersion(), transformJob.getCreateUser()));
220231
});
221232
}
233+
234+
/**
235+
* Inject the file source BML reference as an {@link EngineBmlResource} (M2).
236+
*
237+
* <p>The {@code FileDataxSubExchangisJobHandler} stashes the file BML ref (resourceId/version/
238+
* owner/name) into {@code jobParams}. Here we materialize it as an {@code EngineBmlResource};
239+
* the launcher then serializes {@code engineJob.getResources()} into
240+
* {@code wds.linkis.engineconn.datax.bml.resources}, which {@code DataxEngineConnLaunchBuilder
241+
* #getBmlResources()} reads to auto-download the file to the EC workdir. txtfilereader reads
242+
* the file from the workdir local path — no engine plugin change needed.
243+
*
244+
* <p>{@code path="."} means Private visibility (only this job's EC can read the file).
245+
*
246+
* <p>handler 将文件 BML 引用暂存到 jobParams;此处物化为 {@link EngineBmlResource},
247+
* launcher 序列化为 {@code wds.linkis.engineconn.datax.bml.resources},由 LaunchBuilder 自动下载到 EC 工作目录。
248+
*/
249+
@SuppressWarnings("unchecked")
250+
private void settingFileSourceBmlResource(SubExchangisJob inputJob, ExchangisEngineJob engineJob) {
251+
Object stashed = inputJob.getJobParams().get(FileDataxSubExchangisJobHandler.FILE_BML_RESOURCE_KEY);
252+
if (!(stashed instanceof Map)) {
253+
LOG.warn("File source job missing stashed BML reference (文件 source 作业缺少暂存的 BML 引用): jobId={}", inputJob.getId());
254+
return;
255+
}
256+
Map<String, Object> bmlRef = (Map<String, Object>) stashed;
257+
String resourceId = bmlRef.get(FileDataxSubExchangisJobHandler.PARAM_BML_RESOURCE_ID) == null ? null
258+
: String.valueOf(bmlRef.get(FileDataxSubExchangisJobHandler.PARAM_BML_RESOURCE_ID));
259+
String version = bmlRef.get(FileDataxSubExchangisJobHandler.PARAM_BML_VERSION) == null ? null
260+
: String.valueOf(bmlRef.get(FileDataxSubExchangisJobHandler.PARAM_BML_VERSION));
261+
if (Objects.isNull(resourceId) || Objects.isNull(version)) {
262+
LOG.warn("File source BML reference missing resourceId/version (BML 引用缺失 resourceId/version): jobId={}", inputJob.getId());
263+
return;
264+
}
265+
String owner = bmlRef.get(FileDataxSubExchangisJobHandler.PARAM_BML_OWNER) == null
266+
? inputJob.getCreateUser()
267+
: String.valueOf(bmlRef.get(FileDataxSubExchangisJobHandler.PARAM_BML_OWNER));
268+
String name = bmlRef.get(FileDataxSubExchangisJobHandler.PARAM_BML_NAME) == null
269+
? resourceId : String.valueOf(bmlRef.get(FileDataxSubExchangisJobHandler.PARAM_BML_NAME));
270+
// path="." -> Private visibility (only this job's EC can read the file)
271+
engineJob.getResources().add(new EngineBmlResource(engineJob.getEngineType(), ".", name, resourceId, version, owner));
272+
LOG.info("File source BML resource injected (文件 source BML 资源已注入): jobId={}, name={}, resourceId={}", inputJob.getId(), name, resourceId);
273+
}
274+
222275
private String[] getResourcesPaths(SubExchangisJob inputJob){
223276
return new String[]{
224277
DataxEngineResourceConf.RESOURCE_PATH_PREFIX.getValue() + IOUtils.DIR_SEPARATOR_UNIX + "reader" + IOUtils.DIR_SEPARATOR_UNIX +
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package com.webank.wedatasphere.exchangis.job.server.builder.transform.handlers;
2+
3+
import com.webank.wedatasphere.exchangis.job.builder.ExchangisJobBuilderContext;
4+
import com.webank.wedatasphere.exchangis.job.domain.SubExchangisJob;
5+
import com.webank.wedatasphere.exchangis.job.domain.params.JobParamDefine;
6+
import com.webank.wedatasphere.exchangis.job.domain.params.JobParamSet;
7+
import com.webank.wedatasphere.exchangis.job.domain.params.JobParams;
8+
import com.webank.wedatasphere.exchangis.job.server.builder.JobParamConstraints;
9+
import org.apache.linkis.common.exception.ErrorException;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
import java.util.Objects;
16+
17+
/**
18+
* File source handler for the datax engine (DataX 引擎的文件 source 处理器)
19+
*
20+
* <p>Registration: auto-discovered via reflection by {@code GenericExchangisTransformJobBuilder.initHandlers()}
21+
* (keyed by {@link #dataSourceType()} = "file"), no manual registration needed.
22+
*
23+
* <p>Architecture ② / M5: the file source does NOT go through datasource management. This handler
24+
* does NOT call {@code DataSourceService}; it only extracts the BML reference from the source
25+
* params and stashes it for the engine builder to materialize as an {@code EngineBmlResource}.
26+
*
27+
* <p>架构②/M5:文件 source 不走数据源管理流程。本 handler 不调用 DataSourceService,
28+
* 仅从 source 参数中提取 BML 引用并暂存,供引擎 builder 物化为 EngineBmlResource。
29+
*
30+
* <h2>Param convention (参数约定)</h2>
31+
* <ul>
32+
* <li>BML reference params are namespaced with the {@code __file_bml_} prefix
33+
* (e.g. {@code __file_bml_resource_id}). They are read with
34+
* {@link JobParams#define(String)} and stay in the source param set; txtfilereader ignores
35+
* these unknown keys, so no manual get+remove is needed.</li>
36+
* <li>txtfilereader params ({@code path}/{@code encoding}/{@code delimiter}/{@code nullFormat})
37+
* are real reader keys. {@code path} is set to the BML file name (the file the EC downloads
38+
* to its workdir); the others are sent by the frontend from the parse result.</li>
39+
* </ul>
40+
*
41+
* <p>BML 引用参数以 {@code __file_bml_} 前缀命名空间隔离,用 {@link JobParams#define(String)} 读取,
42+
* 保留在 source 参数集中(txtfilereader 忽略未知键,无需 get+remove)。txtfilereader 参数
43+
* (path/encoding/delimiter/nullFormat)为真实 reader 键,path 设为 BML 文件名。
44+
*
45+
* <h2>BML injection adaptation (BML 注入适配)</h2>
46+
* The design doc describes writing a plain-JSON {@code wds.linkis.engineconn.datax.bml.resources} job
47+
* property in the handler. This open-source codebase has no {@code getJobProps()} on
48+
* {@link SubExchangisJob}, but it ALREADY serializes {@code engineJob.getResources()} into
49+
* {@code wds.linkis.engineconn.datax.bml.resources} at launch time
50+
* (see {@code ExchangisLauncherConfiguration.LAUNCHER_LINKIS_RESOURCES} +
51+
* {@code DataxEngineConnLaunchBuilder.getBmlResources}). So the handler stashes the BML ref into
52+
* {@link SubExchangisJob#getJobParams()} and {@code DataxExchangisEngineJobBuilder} materializes it
53+
* as an {@code EngineBmlResource} — the same pattern as the existing {@code settingProcessorInfo}.
54+
*
55+
* <p>设计文档描述在 handler 中写入明文 JSON 作业属性。本仓库的 {@link SubExchangisJob} 无
56+
* {@code getJobProps()},但已有机制:launcher 把 {@code engineJob.getResources()} 序列化为
57+
* {@code wds.linkis.engineconn.datax.bml.resources}。故 handler 将 BML 引用暂存到 jobParams,
58+
* 由 {@code DataxExchangisEngineJobBuilder} 物化为 {@code EngineBmlResource}。
59+
*/
60+
public class FileDataxSubExchangisJobHandler extends AuthEnabledSubExchangisJobHandler {
61+
62+
private static final Logger LOG = LoggerFactory.getLogger(FileDataxSubExchangisJobHandler.class);
63+
64+
/**
65+
* Job param key used to stash the file BML reference for the engine builder.
66+
* 暂存文件 BML 引用供引擎 builder 使用的 job param key。
67+
*/
68+
public static final String FILE_BML_RESOURCE_KEY = "__file_bml_resource";
69+
70+
/**
71+
* BML reference source params (namespaced with __file_bml_ prefix).
72+
* BML 引用 source 参数(以 __file_bml_ 前缀命名空间隔离)。
73+
*/
74+
public static final String PARAM_BML_RESOURCE_ID = "__file_bml_resource_id";
75+
public static final String PARAM_BML_VERSION = "__file_bml_version";
76+
public static final String PARAM_BML_OWNER = "__file_bml_owner";
77+
public static final String PARAM_BML_NAME = "__file_bml_name";
78+
79+
private static final JobParamDefine<String> BML_RESOURCE_ID = JobParams.define(PARAM_BML_RESOURCE_ID);
80+
private static final JobParamDefine<String> BML_VERSION = JobParams.define(PARAM_BML_VERSION);
81+
private static final JobParamDefine<String> BML_OWNER = JobParams.define(PARAM_BML_OWNER);
82+
private static final JobParamDefine<String> BML_NAME = JobParams.define(PARAM_BML_NAME);
83+
84+
/**
85+
* txtfilereader params (real reader keys) / txtfilereader 参数(真实 reader 键)
86+
*/
87+
private static final String PARAM_PATH = "path";
88+
private static final String PARAM_DELIMITER = "delimiter";
89+
private static final JobParamDefine<String> ENCODING = JobParams.define(JobParamConstraints.ENCODING);
90+
private static final JobParamDefine<String> DELIMITER = JobParams.define(PARAM_DELIMITER);
91+
private static final JobParamDefine<String> NULL_FORMAT = JobParams.define(JobParamConstraints.NULL_FORMAT);
92+
93+
@Override
94+
public void handleJobSource(SubExchangisJob subExchangisJob, ExchangisJobBuilderContext ctx) throws ErrorException {
95+
JobParamSet paramSet = subExchangisJob.getRealmParams(SubExchangisJob.REALM_JOB_CONTENT_SOURCE);
96+
if (Objects.isNull(paramSet)) {
97+
return;
98+
}
99+
100+
// 1. Read the BML reference from the namespaced __file_bml_ source params.
101+
// They stay in the source param set (txtfilereader ignores the __file_bml_ keys).
102+
// 读取 BML 引用(__file_bml_ 前缀命名空间隔离,保留在 source 参数集中,txtfilereader 忽略)
103+
String resourceId = BML_RESOURCE_ID.getValue(paramSet);
104+
String version = BML_VERSION.getValue(paramSet);
105+
String owner = BML_OWNER.getValue(paramSet);
106+
String name = BML_NAME.getValue(paramSet);
107+
108+
if (Objects.nonNull(resourceId) && Objects.nonNull(version)) {
109+
// 2. Stash into jobParams for the engine builder (暂存到 jobParams 供引擎 builder 使用)
110+
Map<String, String> bmlRef = new HashMap<>();
111+
bmlRef.put(PARAM_BML_RESOURCE_ID, resourceId);
112+
bmlRef.put(PARAM_BML_VERSION, version);
113+
bmlRef.put(PARAM_BML_OWNER, owner);
114+
bmlRef.put(PARAM_BML_NAME, name);
115+
subExchangisJob.getJobParams().put(FILE_BML_RESOURCE_KEY, bmlRef);
116+
LOG.info("File source BML reference stashed (文件 source BML 引用已暂存): name={}, resourceId={}, version={}",
117+
name, resourceId, version);
118+
119+
// 3. path = BML file name. The EC downloads the BML resource to its workdir (PWD) using
120+
// this name, and txtfilereader reads the file by this path.
121+
// path = BML 文件名。EC 将 BML 资源下载到工作目录(PWD)后,txtfilereader 按此 path 读取。
122+
if (Objects.nonNull(name)) {
123+
paramSet.add(JobParams.newOne(PARAM_PATH, name));
124+
}
125+
} else {
126+
LOG.warn("File source handler: missing resourceId/version in source params (source 参数缺失 resourceId/version)");
127+
}
128+
129+
// 4. Ensure the txtfilereader params are present in the output param set.
130+
// 确保 txtfilereader 参数(encoding/delimiter/nullFormat)存在于输出参数集。
131+
paramSet.addNonNull(ENCODING.get(paramSet));
132+
paramSet.addNonNull(DELIMITER.get(paramSet));
133+
paramSet.addNonNull(NULL_FORMAT.get(paramSet));
134+
}
135+
136+
@Override
137+
public void handleJobSink(SubExchangisJob subExchangisJob, ExchangisJobBuilderContext ctx) throws ErrorException {
138+
// FILE is source-only; job validation rejects sink=file. (FILE 仅作 source,不实现 sink)
139+
}
140+
141+
@Override
142+
public String dataSourceType() {
143+
return "file";
144+
}
145+
146+
@Override
147+
public boolean acceptEngine(String engineType) {
148+
return "datax".equalsIgnoreCase(engineType);
149+
}
150+
}

0 commit comments

Comments
 (0)