However, did you know you can register your own FileListeners? There is a pretty straightforward interface:
public interface FileListener { public boolean open( Node transNode, String fname, boolean importfile ) throws KettleMissingPluginsException; public boolean save( EngineMetaInterface meta, String fname, boolean isExport ); public void syncMetaName( EngineMetaInterface meta, String name ); public boolean accepts( String fileName ); public boolean acceptsXml( String nodeName ); public String[] getSupportedExtensions(); public String[] getFileTypeDisplayNames( Locale locale ); public String getRootNodeName(); }
You can implement this interface and it will be called at various points, including when a file is dragged onto the canvas. You can use this to add support to currently unsupported file types. I will show how I implemented a quick CsvListener to add drag-and-drop support to PDI. With this, if you drag a CSV file onto a transformation on the canvas, a "CSV file input" step will be added to the transformation, with the filename already filled in:
I didn't bother with doing a "Get Fields" automatically because I won't know if there's a header row, etc. Plus this is just a fun proof-of-concept, hopefully I/we will have a more robust Drag-n-Drop system in the future.
The trick is getting your FileListener registered with Spoon. There is no extension point directly for that purpose, but you can use a LifecycleListener plugin and implement the registration in your onStart() callback.
To get this going quickly, I wrote the CsvListener in Groovy, and put that in a file called onStart.groovy. I did that so I could leverage my PDI Extension Point Scripting plugin (available on the Marketplace), then drop my onStart.groovy file into plugins/pdi-script-extension-points/ and start Spoon.
The Groovy script is as follows, and is also available as a Gist:
There's lots of PDI voodoo going on in the open() method; I won't explain it all here, as I intend to write a proper plugin to do this for various file types. I just wanted to (again) show off how powerful and flexible PDI can be, and have some fun hacking the APIs :)import org.w3c.dom.* import org.pentaho.di.core.* import org.pentaho.di.core.exception.* import org.pentaho.di.core.gui.* import org.pentaho.di.core.plugins.* import org.pentaho.di.trans.step.* import org.pentaho.di.ui.spoon.* class CsvListener implements FileListener { public boolean open( Node transNode, String fname, boolean importfile ) throws KettleMissingPluginsException { def csvInputPlugin = PluginRegistry.instance.findPluginWithName(StepPluginType, 'CSV file input') def csvInputMetaClass = PluginRegistry.instance.loadClass(csvInputPlugin) csvInputMetaClass.setDefault() def pid = PluginRegistry.instance.getPluginId(csvInputPlugin.pluginType, csvInputMetaClass) def csv = new StepMeta(pid, csvInputPlugin.name, csvInputMetaClass) csv.stepMetaInterface.setFilename(fname) csv.setName(fname?.substring(fname?.lastIndexOf(File.separator)+1,fname?.indexOf('.')) ?: 'CSV file input') csv?.location= new Point(20,20) csv?.draw = true Spoon.instance.activeTransformation?.addStep(csv) Spoon.instance.activeTransGraph?.redraw() true } public boolean save( EngineMetaInterface meta, String fname, boolean isExport ) { false } public void syncMetaName( EngineMetaInterface meta, String name ) { } public boolean accepts( String fileName ) { def x = Arrays.asList(getSupportedExtensions()).contains(fileName?.substring(fileName?.indexOf('.')+1)) } public boolean acceptsXml( String nodeName ) { false } public String[] getSupportedExtensions() { ['csv'] as String[] } public String[] getFileTypeDisplayNames( Locale locale ) { ['CSV'] as String[] } public String getRootNodeName() { null } } Spoon.instance.addFileListener(new CsvListener())
Cheers!
No comments:
Post a Comment