To extend an extension

Hello all as I said in a previous post (http://tech.knime.org/node/20466), I've been able to follow the excelent documentation to create simple custom nodes, and in some cases I've used functionality from other nodes (e.g. csvwriter). But now I have a situation where existing nodes already do 99% of what I need, so I'd like to concentrate on the remaining 1%. I could just copy the code, but besides being "ugly" I would also miss out on updates to the base node. So my question is, is it "proper" to create a node that extends another node instead of NodeModel/NodeFactory/etc.? Miguel

Proper or not, I tried creating a node that inherits from AnotherNodeModel/Factory/Dialog, for now without adding anything, and (after finaly realizing that I was missing a dependency in plugin.xml) it worked as I intended.

However, what I tried to change first (which probably doesn’t quite qualify as the 1% I mentioned :slight_smile: ), was the number of ports. Since the node I’m inheriting from has a parameterless constructor which calls its superclass’s constructor with the original number of ports, I would have to call something like super.super(int, int), which led me to http://michaelscharf.blogspot.com/2006/07/why-is-supersuper-illegal.html

Is there a better way to do this, or should I just abandon this thought and start copy-pasting?

No, such things really don’t work. Even if super.super would work, you would need to reimplement almost all methods from the original node (configure, execute, load/save/validateSettings). You could, however, instantiate the “base” NodeModel as a member in your node and delegate some work to its configure/execute/… methods. This lets you define the number of ports freely and you do not need to copy lots of code.

that sounds nice, at least when the changes are additions, but aren’t those methods usually “protected”? If I understood correctly, “protected” in Java is less restrictive than in C++, but only if my new nodes were in the same package (or am I missing something?)

With a similar motivation as above (lazyness), I’ve been meaning to try a way of looping over SettingsModels instead of copy-pasting code since the first node I created (because the thing had about thirty fields).

So today I tried using a Map of SettingsModels and iterating over it (see below). This would also simplify the use of the same SettingsModels in the NodeDialog and, at least superficially, it seems to be working. Does this break anything that I’m not aware of?

public class LazyNodeModel extends NodeModel { static final Map m_settings = new HashMap(); protected LazyNodeModel() { super(1, 1); String key = "aString"; m_settings.put(key, createSettingsModelString(key, null, enabled)); key = "aBoolean"; m_settings.put(key, createSettingsModelBoolean(key, false, enabled)); // etc. } static SettingsModelBoolean createSettingsModelBoolean(String s, Boolean init, Boolean status) { SettingsModelBoolean result = new SettingsModelBoolean(s, init); result.setEnabled(status); return result; } static SettingsModelString createSettingsModelString(String s, String init, Boolean status) { SettingsModelString result = new SettingsModelString(s, init); result.setEnabled(status); return result; } protected void validateSettings(NodeSettingsRO settings) throws InvalidSettingsException { Collection c = m_settings.values(); Iterator itr = c.iterator(); while(itr.hasNext()) { SettingsModel sm = (SettingsModel)itr.next(); sm.validateSettings(settings); } } protected void saveSettingsTo(NodeSettingsWO settings) { Collection c = m_settings.values(); Iterator itr = c.iterator(); while(itr.hasNext()) { SettingsModel sm = (SettingsModel)itr.next(); sm.saveSettingsTo(settings); } } protected void loadValidatedSettingsFrom(NodeSettingsRO settings) throws InvalidSettingsException { Collection c = m_settings.values(); Iterator itr = c.iterator(); while(itr.hasNext()) { SettingsModel sm = (SettingsModel)itr.next(); sm.loadSettingsFrom(settings); } }