kettle5.3扩展step插件支持元数据注入
来源:互联网 发布:号码归属地软件下载 编辑:程序博客网 时间:2024/05/19 02:25
1. 前言
虽然说kettle提供了可视化的操作界面,但对于一些共有相同功能的ETL流程我们不希望每次都在spoon上面拖拉组件去创建流程,感觉比较繁琐,所以在基于kettle做二次开发的时候希望可以把相同类型的流程提取成公共的模板,每次只需要把不同的参数传入到插件里面即可实例化成不同的模板作业,kettle的插件式设计很符合我们的需求,它提供的变量设置、获取以及元数据注入组件基本能满足工们所有的功能。
变量与元数据注入组件一般是结合起来使用才能使用作业设计得通用一点(所有参数都可以做到动态化),使用表输入组件,其中sql与记录数据限制可以通过选取一个变量来设置值:
但是对于其它一些属性,如步骤名称、数据库连接等就只能配置死了,这时候我们可以利用元数据注入插件把其余或者全部参数设置进去,如下图:
当然了,元数据注入只管把参数注入到其它插件,至于注入的参数值是什么一般还是通过获取变量来从外部获得到。
2. 了解ETL元数据注入步骤
元数据注入step可以把元数据注入到模板转换中的step中,从而不用在step设置界面中静态地设置元数据,做到运行时动态,所以可以解决重复ETL工作。
在本文基于kettle5.3版本,也只有一小部分step组件默认支持元数据注入而已,可以看一下StepMetaInjectionInterface
接口的实现类:
在图中还有一些是我们在原来的基础上增加实现的。其实kettle中插件式的设计,每个step都有对应的xxxMeta
类与之对应,这个类就保存着step的所有
所有元数据,ETL元数据注入就是通过设置xxxMeta
类中的属性值把元数据注入到运行时的step中,使作业具有不同的行为。
3. 扩展step支持元数据注入
要想一些默认没支持元数据注入的step实现支持该功能其实很方便,不需要大改动原码,下面以REST Client为示例进行扩展。
3.1 创建RestMetaInjection类
根据名称大概可以找到REST Client步骤相关源码类为Rest
、RestMeta
、RestData
,在同package下创建RestMetaInjection
类,该类需要实现StepMetaInjectionInterface
接口,可以看到子类需要实现接口的3个方法:
//该接口是获取所有需要注入的元数据实体,例如'步骤名称'就是一个需要注入的元数据实体public List<StepInjectionMetaEntry> getStepInjectionMetadataEntries() throws KettleException;//该接口是实现注入的具体实现,主要是初始化一些元数据的值public void injectStepMetadataEntries( List<StepInjectionMetaEntry> metadata ) throws KettleException;//以标准的方式提取出step的元数据,这个接口的逻辑我们可以不实现public List<StepInjectionMetaEntry> extractStepMetadataEntries() throws KettleException;
3.2 为RestMetaInjection类添加构造函数
既然最终都是为了操作元数据,那么我样需要拿到RestMeta
对象,因此添加一个构造函数来接收:
public RestMetaInjection(RestMeta meta) { this.meta = meta; }
3.3 创建Entry枚举
Entry枚举实现了StepMetaInjectionEntryInterface
接口,它描述了需要注入的元数据有哪些,方便下面接口进行具体的注入操作,我们在编写这个枚举时需要参照对应的界面代码类RestDialog
,从界面中找到哪些输入元素是我们将要实现注入的,这些根据一些Label的message信息应该都很容易找得到,代码如下:
public enum Entry implements StepMetaInjectionEntryInterface { PARAMETERS(ValueMetaInterface.TYPE_NONE, BaseMessages.getString(PKG, "RestDialog.Parameters.Label")), PARAMETER(ValueMetaInterface.TYPE_NONE, "one parameter"), //对应grid中的一行记录 PARAMETER_FIELD(ValueMetaInterface.TYPE_STRING, BaseMessages.getString(PKG, "RestDialog.ColumnInfo.ParameterField")), //对应一行的参数字段column PARAMETER_NAME(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.ColumnInfo.ParameterName")), //上面几个描述了参数的tab中的表格属性,最终需要注入的只是PARAMETER_FIELD与PARAMETER_NAME,但其它两个只是需要在元数据注入step中显示 MOTHEDFIELD(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.MethodField.Label")), //注入method BODY(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.Body.Label")), //注入body APPLICATIONTYPE(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.ApplicationType.Label")), //注入applicationType HTTPLOGIN(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.HttpLogin.Label")), //注入Http验证登录 HTTPPASSWORD(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.HttpPassword.Label")),//注入验证密码 PROXYHOST(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.ProxyHost.Label")),//注入代理服务器 PROXYPORT(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.ProxyPort.Label")),//注入代理端口 TRUSTSTOREFILE(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.TrustStoreFile.Label")),//注入Trust store file TRUSTSTOREPASSWORD(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.TrustStorePassword.Label")), //注入Trust store password HEADERS(ValueMetaInterface.TYPE_NONE,BaseMessages.getString(PKG, "RestDialog.Headers.Label")), HEADER(ValueMetaInterface.TYPE_NONE,BaseMessages.getString(PKG, "one header")), HEADER_FIELD(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.ColumnInfo.Field")), HEADER_NAME(ValueMetaInterface.TYPE_STRING,BaseMessages.getString(PKG, "RestDialog.ColumnInfo.Name")), ; //同参数的注入,对于一个表格的注入参考这样的方式即可 private int valueType; private String description; private Entry(int valueType, String description) { this.valueType = valueType; this.description = description; } @Override public int getValueType() { return this.valueType; } @Override public String getDescription() { return this.description; } public static Entry findEntry(String key) { return Entry.valueOf(key); } }
3.4 实现getStepInjectionMetadataEntries方法
getStepInjectionMetadataEntries
是获取所有step中需要注入的StepInjectionMetaEntry
,然后显示在**ETL元数据注入**step的注入元数据树表格中,该方法的逻辑就是根据上面Entry枚举进行组装List,参考以下的代码:
@Override public List<StepInjectionMetaEntry> getStepInjectionMetadataEntries() throws KettleException { List<StepInjectionMetaEntry> all = new ArrayList<StepInjectionMetaEntry>(); Entry[] topEntries = new Entry[] { Entry.MOTHEDFIELD, Entry.BODY, Entry.APPLICATIONTYPE, Entry.HTTPLOGIN, Entry.HTTPPASSWORD, Entry.PROXYHOST, Entry.PROXYPORT ,Entry.TRUSTSTOREFILE,Entry.TRUSTSTOREPASSWORD}; StepInjectionUtil.addTopEntry(topEntries, all); //设置一些顶级的注入实体 StepInjectionMetaEntry parameters = new StepInjectionMetaEntry(Entry.PARAMETERS.name(), Entry.PARAMETERS.getValueType(), Entry.PARAMETERS.getDescription()); StepInjectionMetaEntry parameter = new StepInjectionMetaEntry(Entry.PARAMETER.name(), Entry.PARAMETER.getValueType(), Entry.PARAMETER.getDescription()); Entry[] subEntries1 = new Entry[] { Entry.PARAMETER_FIELD, Entry.PARAMETER_NAME }; StepInjectionUtil.addSubEntry(subEntries1, parameter); parameters.getDetails().add(parameter); all.add(parameters); //对于表格我们分两个层次显示 StepInjectionMetaEntry headers=new StepInjectionMetaEntry(Entry.HEADERS.name(),Entry.HEADERS.getValueType(),Entry.HEADERS.getDescription()); StepInjectionMetaEntry header=new StepInjectionMetaEntry(Entry.HEADER.name(),Entry.HEADER.getValueType(),Entry.HEADER.getDescription()); Entry[] subEntries2 = new Entry[] { Entry.HEADER_FIELD, Entry.HEADER_NAME }; StepInjectionUtil.addSubEntry(subEntries2, header); headers.getDetails().add(header); all.add(headers); //对于表格我们分两个层次显示 return all; }
3.4 实现injectStepMetadataEntries方法
injectStepMetadataEntries
是对元数据注入的具体实现,在这个方法才是真正地改变元数据,这个方法接收一个List<StepInjectionMetaEntry>
参数,对应着上一个方法的返回参数,但是该方法的合集参数中的第一个元素(元数据注入实体)已经包含了需要注入的具体值,而我们需要的是把这个值设置到RestMeta
对象的对应属性中去,因此其实就是上一个方法的逆向解析过程:
@Override public void injectStepMetadataEntries(List<StepInjectionMetaEntry> metadata) throws KettleException { for (StepInjectionMetaEntry lookFields : metadata) { //循环所有注入实体 Entry lookEntry = Entry.findEntry(lookFields.getKey()); if (lookEntry != null) { switch (lookEntry) { case PARAMETERS: //如果是注入参数,由于参数是一个表格,一般对应RestMeta里的集合类型属性,注入逻辑比较多,所以单独实现到一个方法 injectParameterFields(lookFields); break; case HEADERS: //与注入参数一样 injectHeaderFields(lookFields); break; case MOTHEDFIELD: //注入method,一些单一的参数,比较简单在RestMeta就是一个基本类型属性,下同 meta.setMethod(String.valueOf(lookFields.getValue())); break; case BODY: //注入body meta.setBodyField(String.valueOf(lookFields.getValue())); break; case APPLICATIONTYPE: meta.setApplicationType(String.valueOf(lookFields.getValue())); break; case HTTPLOGIN: meta.setHttpLogin(String.valueOf(lookFields.getValue())); break; case HTTPPASSWORD: meta.setHttpPassword(String.valueOf(lookFields.getValue())); break; case PROXYHOST: meta.setProxyHost(String.valueOf(lookFields.getValue())); break; case PROXYPORT: meta.setProxyPort(String.valueOf(lookFields.getValue())); break; case TRUSTSTOREFILE: meta.setTrustStoreFile(String.valueOf(lookFields.getValue())); break; case TRUSTSTOREPASSWORD: meta.setTrustStorePassword(String.valueOf(lookFields.getValue())); break; default: break; } } } }
injectParameterFields
实现代码如下:
/** * 注入http参数 * * @param lookFields */ private void injectParameterFields(StepInjectionMetaEntry lookFields) { List<String> paramFields = new ArrayList<>(); List<String> paramNames = new ArrayList<>(); for (StepInjectionMetaEntry lookField : lookFields.getDetails()) {// 一行(参数字段、参数名称) Entry lookEntry = Entry.findEntry(lookField.getKey()); if (lookEntry == Entry.PARAMETER) { for (StepInjectionMetaEntry lookDetail : lookField.getDetails()) { // 一列:参数字段或参数名称 Entry detailEntry = Entry.findEntry(lookDetail.getKey()); if (detailEntry != null) { String strValue = (String) lookDetail.getValue(); switch (detailEntry) { case PARAMETER_FIELD: paramFields.add(strValue); break; case PARAMETER_NAME: paramNames.add(strValue); break; default: break; } } } } } if (paramFields.size() > 0 && paramNames.size() > 0 && paramFields.size() == paramNames.size()) { String[] paramFieldArr = new String[paramFields.size()]; String[] paramNameArr = new String[paramNames.size()]; meta.setParameterField(paramFields.toArray(paramFieldArr)); meta.setParameterName(paramNames.toArray(paramNameArr)); } }
injectHeaderFields
实现代码如下:
/** * 注入http请求头 * @param lookFields */ private void injectHeaderFields(StepInjectionMetaEntry lookFields) { List<String> headFields = new ArrayList<>(); List<String> headNames = new ArrayList<>(); for (StepInjectionMetaEntry lookField : lookFields.getDetails()) {// 一行(参数字段、参数名称) Entry lookEntry = Entry.findEntry(lookField.getKey()); if (lookEntry == Entry.HEADER) { for (StepInjectionMetaEntry lookDetail : lookField.getDetails()) { // 一列:参数字段或参数名称 Entry detailEntry = Entry.findEntry(lookDetail.getKey()); if (detailEntry != null) { String strValue = (String) lookDetail.getValue(); switch (detailEntry) { case HEADER_FIELD: headFields.add(strValue); break; case HEADER_NAME: headNames.add(strValue); break; default: break; } } } } } if (headFields.size() > 0 && headNames.size() > 0 && headFields.size() == headNames.size()) { String[] headFieldArr = new String[headFields.size()]; String[] headNameArr = new String[headNames.size()]; meta.setHeaderField(headFields.toArray(headFieldArr)); meta.setHeaderName(headNames.toArray(headNameArr)); } }
至此,RestMetaInjection
类已经编写完毕。
3.5 修改RestMeta类
我们虽然实现了RestMetaInjection
类,但还没与step关联起来,还虽然对RestMeta
类稍作修改,重新实现一下getStepMetaInjectionInterface
接口,代码如下:
@Override public StepMetaInjectionInterface getStepMetaInjectionInterface() { return new RestMetaInjection(this); }
4. 重新编译并使用
Rest Client组件的元数据注入已经实现,重新把源码编译,或者单独编译engin模块并更新对应的jar包,然后来验证一下扩展是否成功,随便创建两个转换,一个包含Rest Client插件,另一个包含ETL元数据注入步骤,最直观的方式就是在spoon界面中看下是否获取到Rest Client的注入属性:
经过测试验证,Rest Client通过元数据注入的方式可以正常运行,可以使用同样的方式来扩展我们一些常用的step。
- kettle5.3扩展step插件支持元数据注入
- Kettle5.x step插件开发总结
- Kettle5 log4j插件使用
- kettle5.3源码部署
- 扩展元数据
- Kettle5.3源代码编译详解
- 利用特性扩展元数据
- Openstack文件和元数据注入
- java调用Kettle5.3的任务
- LuaOO DLL插件扩展的支持
- 用System.Attribute扩展元数据
- 用System.Attribute扩展元数据
- 用System.Attribute扩展元数据
- 扩展XDoclet对Spring List引用注入的支持
- jQuery提取元数据Metadata插件
- hdu2815 扩展Baby step,Giant step入门
- 扩展baby step giant step模版
- Step By Step(Lua元表与元方法)
- 分享一波一些github安全资源
- Java反射机制详解
- java中的序列化(Serializable)和反序列化
- 前端学习笔记2-3 CSS
- 时间复杂度
- kettle5.3扩展step插件支持元数据注入
- Android多线程异步任务,在主线程中回调
- Kafka+Log4j实现日志集中管理
- python——使用itemgetter和sorted对列表内的元素进行排序
- Unity常用插件
- 九度OJ-题目1165:字符串匹配
- 一个例子让你彻底明白原型对象和原型链
- C语言函数itoa() 和atoi() 详解
- CSDN日报20170629——《你该关注“硬技术”还是“大道理”呢?》