Hi, I have one exception when I transmit the my customized portObject from one node(let’s call it Reader) to another node(called Writer) as input. In Writer, it shows the method
protected PortObject execute(final PortObject inData, final ExecutionContext exec)
PortObject inData includes an initialized portObject which differs from the Reader output, since I have put some values into the portObject in Reader.
I debug in Ecli[se and found out some parts I don’t understand:
<1> execute method of NodeModel.class rawOutData is generated
PortObject rawOutData = new PortObject[getNrOutPorts() + 1];
rawOutData[0] = FlowVariablePortObject.INSTANCE;
System.arraycopy(outData, 0, rawOutData, 1, outData.length);
return rawOutData;
It adds one flow Variable connection into the rawOutData in the first place.
<2> execute method in Node.class, it creates newOutData again.
newOutData = Arrays.copyOf(rawOutData, rawOutData.length);
Even until this step, the values in newOutData is the expected portObject.
////////////////////////////////////
after this, I get lost in codes, but anyway, when I try to connect to Writer and execute it with inData[0], it is not expected…
SO any suggestions to find out the cause and solve it??
@swebb Thanks for your reply at first. My explanation might be not good. The problem is, I think, about the transmit between the PortObject from one KNIME node to another KNIME node.
In Reader, I create the a PortObject in execute method by using the
/////////////// m_netPort is the PortObject
protected PortObject execute(final PortObject inData,
final ExecutionContext exec) throws Exception {
…
return new PortObject {m_netPort};
}
///////////////////
Also set the InSpec in the configure method
////////////////////
protected PortObjectSpec configure(final PortObjectSpec inSpecs)
throws InvalidSettingsException { m_netPort = new PetriNetPortObject((PetriNetPortObjectSpec) inSpecs[0], m_fileName);
PetriNetPortObjectSpec spec = (PetriNetPortObjectSpec) m_netPort.getSpec();
return new PortObjectSpec{spec};
}
But I found out in Writer KNIME Node, I get the portObject named as pnObj in execute method
///////////////////////////
protected PortObject execute(final PortObject inData, final ExecutionContext exec) throws Exception {
PetriNetPortObject pnObj = (PetriNetPortObject) inData[0];
}
///////////////////////// pnObj is not generated by Reader in execute method but just by default constructor.
Then I tackled the code and found the transmit is all right until
////////////////////////////////////////// shown above
<2> execute method in Node.class, it creates newOutData again.
newOutData = Arrays.copyOf(rawOutData, rawOutData.length);
///////////////////////////
I will try to add some standard output and check if they work.
Regards
Kefang
Could you explain what the actual issue is, I’m having trouble working this bit out. The object you make in your reader isn’t making it to the writer?
I believe KNIME copies the objects when you read them so this may be a serialization issue if that is the problem.
Have you implemented the serialization of your port object?
Do you need to create the PortObject to be able to get a PortObjectSpec? You may be better off being able to create the spec without needing to make the object
What’s classes are in your inData array in your Writer node?
m_netPort is my customized port object of class PetriNetPortObject. It is generated by reading a file in Reader and should be passed as InData in Writer.
For the check list, you are probably right.
serialization, I haven’t… doubt about it. Because the KNIME Writer is going to write the m_netPort object into file, I see this is serialization.
PortObjectSpec . It is created in the PortObject and refered by getPortSpec() method in portObject. Doubt here: I don’t really use the PortObjectSpec in my code, main use in my code is to check if the port is compatible between nodes
my inData array has only one element, which should be generated
//////////////////
return new PortObject { m_netPort };
and used in
//////////////////////
PetriNetPortObject pnObj = (PetriNetPortObject) inData[0];
@swebb
finished the test by adding BufferedDataTable, it works fine, so now I will focus on my customized method… And try them out. But still, not really understand the concept of serialization.
If the serialization of port object has written port object into file, it seems to me no need to create a KNIME Writer node to export the port object.
You need to implement serialization of your port so you can save your workflow, close it, open it again and be able to execute the writer node without having to re execute the node that has your port as an output.
So I guess KNIME works in this way. After executing the node, for example A, KNIME stores the object of output port automatically in a temporary file. The other node B which connects node A just reads from the temporary file and then transfers the file into input port object…
So every customized port object needs serialization. Is that right??
"
4. Do the same for your PortObjectSpec but extending PortObjectSpecSerializer this time
"
Good to know it, not thought it before. But is it also automatically?? Or I need to refer explicitly in code of PortObject, like??
/////////////////////////////Class :: public class PetriNetPortObjectSerializer extends PortObjectSerializer
public void savePortObject(PetriNetPortObject portObject, PortObjectZipOutputStream out, ExecutionMonitor exec)
throws IOException, CanceledExecutionException {
// TODO save port object into temporary file
out.putNextEntry(new ZipEntry(FILE_NAME));
portObject.save(out, exec);
}
////////////////////////////////////Class PortObject
public void save(PortObjectZipOutputStream out, ExecutionMonitor exec) throws IOException {
// m_spec means the PortObjectSpec for it, and also the same OutputStream out
m_spec.save(out, exec);
…
}
In your method of the MyCustomPortObjectSerializer.jave
//////////////////////////// @Override
public MyCustomPortObject loadPortObject(PortObjectZipInputStream in, PortObjectSpec spec,
ExecutionMonitor exec) throws IOException, CanceledExecutionException
{
///////////////////////
PortObjectSpec is not used…
checked it and got lost there…found only one pmml as PortObject… That’s also why I proposed here, much simpler examples are better for me to understand.
You help a lot, Thanks very much.
This is a very trivial port and the spec can be calculated from the PortObject so I didn’t bother explicitly handling the PortObjectSpec in the serialization of the PortObject.
#getSpec() in the PortObject is simply (may not be the best way to implement it):
@Override
public PortObjectSpec getSpec()
{
return new MyCustomPortObjectSpec(m_configuration);
}
I would assume if you use the PortObjectSpec provided in the #loadPortObject you would need a setter for the PortObjectSpec in your PortObject and you’d just do something like
myCustomPortObject.set(spec) in the #loadPortObject method
Fix this problem, the reason for it is without serialization. After making serialization right, it works. Thanks a lot. What’s most important to know is:
The connection between nodes does not pass objects, and the whole environment do not save objects. So between nodes the objects are reloaded from temporary file in KNIME workflow directory.
The difference between KNIME Nodes, Reader and Writer, and the methods of save and loadfrom Serializer is only the visibility of saving path. For KNIME Nodes Reader, Writer the paths are visible.