(BUG)Kettle8.1.0.0-365注册自定义插件BUG
时间: 2019-03-03来源:OSCHINA
前景提要
「深度学习福利」大神带你进阶工程师,立即查看>>>
写了两个kettle插件,这两个插件是两个插件项目,且在两个分类,开发完成打包到放到kettle的plugins目录下,启动kettle,结果在kettle设计器中只显示了一个插件。后来改了插件名称,插件在plugins文件夹中的文件夹的名字,发现始终是先扫描到谁就可以注册进来,后续的不管有几个都进不来,后果跟了一下kettle的源代码,发现是kettle里面存储插件TreeSet的Comparator写的有问题。
负责注册插件的类org.pentaho.di.core.plugins.PluginRegistry中声明了一个Map存放所有的插件类型及插件。key是插件类型如作业项插件、步骤插件类型等,value是一个TreeSet,TreeSet中存储的是改插件类型所有的插件。(Kettle8.1.0.0-365版本在PluginRegistry的91行) private final Map<Class<? extends PluginTypeInterface>, Set<String>> categoryMap = new HashMap<>();
下面看一下注册插件的方法 public void registerPlugin( Class<? extends PluginTypeInterface> pluginType, PluginInterface plugin ) throws KettlePluginException { boolean changed = false; // Is this an add or an update? lock.writeLock().lock(); try { if ( plugin.getIds()[0] == null ) { throw new KettlePluginException( "Not a valid id specified in plugin :" + plugin ); } // Keep the list of plugins sorted by name... // Set<PluginInterface> list = pluginMap.computeIfAbsent( pluginType, k -> new TreeSet<>( Plugin.nullStringComparator ) ); if ( !list.add( plugin ) ) { list.remove( plugin ); list.add( plugin ); changed = true; } if ( !Utils.isEmpty( plugin.getCategory() ) ) { // Keep categories sorted in the natural order here too! // categoryMap.computeIfAbsent( pluginType, k -> new TreeSet<>(getNaturalCategoriesOrderComparator(pluginType ))) .add( plugin.getCategory() ); } } finally { lock.writeLock().unlock(); Set<PluginTypeListener> listeners = this.listeners.get( pluginType ); if ( listeners != null ) { for ( PluginTypeListener listener : listeners ) { // Changed or added? if ( changed ) { listener.pluginChanged( plugin ); } else { listener.pluginAdded( plugin ); } } } synchronized ( this ) { notifyAll(); } } }
重点看方法中的这一行代码: categoryMap.computeIfAbsent( pluginType, k -> new TreeSet<>(getNaturalCategoriesOrderComparator(pluginType ))) .add( plugin.getCategory() );
这一行是当map中不存在指定的ke时,返回一个空的TreeSet.关键是TreeSet指定了一个Comparator。
我们接下来看一下getNaturalCategoriesOrderComparator这个方法是怎么创建Comparator的。这个方法的目的是对Kettle自身的插件进行排序按顺序显示。 private static Comparator<String> getNaturalCategoriesOrderComparator( Class<? extends PluginTypeInterface> pluginType ) { PluginTypeCategoriesOrder naturalOrderAnnotation = pluginType.getAnnotation( PluginTypeCategoriesOrder.class ); final String[] naturalOrder; if ( naturalOrderAnnotation != null ) { String[] naturalOrderKeys = naturalOrderAnnotation.getNaturalCategoriesOrder(); Class<?> i18nClass = naturalOrderAnnotation.i18nPackageClass(); naturalOrder = Arrays.stream( naturalOrderKeys ) .map( key -> BaseMessages.getString( i18nClass, key ) ) .toArray( String[]::new ); } else { naturalOrder = null; } return ( s1, s2 ) -> { if ( naturalOrder != null ) { int idx1 = Const.indexOfString( s1, naturalOrder ); int idx2 = Const.indexOfString( s2, naturalOrder ); return idx1 - idx2; } return 0; }; }
按照这个方式的实现,自定了两个插件且插件在两个分类中且分类不是Kettle原有的分类,那么idx1和idx2的值均是-1,如此compare就会返回0,0表示连个分类是相同的就添加不到set中,所以第二个及以后的插件都注册不进来。修改的代码如下: private static Comparator<String> getNaturalCategoriesOrderComparator( Class<? extends PluginTypeInterface> pluginType ) { PluginTypeCategoriesOrder naturalOrderAnnotation = pluginType.getAnnotation( PluginTypeCategoriesOrder.class ); ........ return ( s1, s2 ) -> { if ( naturalOrder != null ) { int idx1 = Const.indexOfString( s1, naturalOrder ); int idx2 = Const.indexOfString( s2, naturalOrder ); // 两个插件分类都不是Kettle自己已有的分类是,则让两个分类进行进行比较 if (-1 == idx1 && -1 == idx2) return s1.compareTo(s2); // 自定义的插件显示在末尾 if (-1 == idx1 || -1 == idx2) return 1; return idx1 - idx2; } return 0; }; }

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

热门排行