Search in sources :

Example 1 with OutVar

use of org.knime.base.node.jsnippet.util.field.OutVar in project knime-core by knime.

the class JavaSnippet method createFieldsSection.

/**
 * Create the system variable (input and output) section of the snippet.
 */
private String createFieldsSection() {
    StringBuilder out = new StringBuilder();
    out.append("// system variables\n");
    out.append("public class JSnippet extends AbstractJSnippet {\n");
    if (m_fields.getInColFields().size() > 0) {
        out.append("  // Fields for input columns\n");
        for (InCol field : m_fields.getInColFields()) {
            out.append("/** Input column: \"");
            out.append(field.getKnimeName());
            out.append("\" */\n");
            appendFields(out, field);
        }
    }
    if (m_fields.getInVarFields().size() > 0) {
        out.append("  // Fields for input flow variables\n");
        for (InVar field : m_fields.getInVarFields()) {
            out.append("/** Input flow variable: \"");
            out.append(field.getKnimeName());
            out.append("\" */\n");
            appendFields(out, field);
        }
    }
    out.append("\n");
    if (m_fields.getOutColFields().size() > 0) {
        out.append("  // Fields for output columns\n");
        for (OutCol field : m_fields.getOutColFields()) {
            out.append("/** Output column: \"");
            out.append(field.getKnimeName());
            out.append("\" */\n");
            appendFields(out, field);
        }
    }
    if (m_fields.getOutVarFields().size() > 0) {
        out.append("  // Fields for output flow variables\n");
        for (OutVar field : m_fields.getOutVarFields()) {
            out.append("/** Output flow variable: \"");
            out.append(field.getKnimeName());
            out.append("\" */\n");
            appendFields(out, field);
        }
    }
    out.append("\n");
    return out.toString();
}
Also used : OutCol(org.knime.base.node.jsnippet.util.field.OutCol) InVar(org.knime.base.node.jsnippet.util.field.InVar) InCol(org.knime.base.node.jsnippet.util.field.InCol) OutVar(org.knime.base.node.jsnippet.util.field.OutVar)

Example 2 with OutVar

use of org.knime.base.node.jsnippet.util.field.OutVar in project knime-core by knime.

the class JavaSnippet method validateSettings.

/**
 * Validate settings which is typically called in the configure method of a node.
 *
 * What is checked:
 * <ul>
 * <li>Whether converter factories matching the ids from the settings exist</li>
 * <li>Whether the code compiles</li>
 * <li>Whether columns required by input mappings still exist.</li>
 * </ul>
 *
 * @param spec the spec of the data table at the inport
 * @param flowVariableRepository the flow variables at the inport
 * @return the validation results
 */
public ValidationReport validateSettings(final DataTableSpec spec, final FlowVariableRepository flowVariableRepository) {
    List<String> errors = new ArrayList<>();
    List<String> warnings = new ArrayList<>();
    // check input fields
    for (final InCol field : m_fields.getInColFields()) {
        final int index = spec.findColumnIndex(field.getKnimeName());
        if (index < 0) {
            errors.add("The column \"" + field.getKnimeName() + "\" is not found in the input table.");
        } else {
            final DataColumnSpec colSpec = spec.getColumnSpec(index);
            final DataType type = colSpec.getType();
            if (!type.equals(field.getDataType())) {
                // Input column type changed, try to find new converter
                final Optional<?> factory = ConverterUtil.getConverterFactory(type, field.getJavaType());
                if (factory.isPresent()) {
                    warnings.add("The type of the column \"" + field.getKnimeName() + "\" has changed but is compatible.");
                    field.setConverterFactory(type, (DataCellToJavaConverterFactory<?, ?>) factory.get());
                } else {
                    errors.add("The type of the column \"" + field.getKnimeName() + "\" has changed.");
                }
            }
        }
        if (!field.getConverterFactory().isPresent()) {
            errors.add(String.format("Missing converter for column '%s' to java field '%s' (converter id: '%s')", field.getKnimeName(), field.getJavaName(), field.getConverterFactoryId()));
        }
    }
    // check input variables
    for (InVar field : m_fields.getInVarFields()) {
        FlowVariable var = flowVariableRepository.getFlowVariable(field.getKnimeName());
        if (var != null) {
            if (!var.getType().equals(field.getFlowVarType())) {
                errors.add("The type of the flow variable \"" + field.getKnimeName() + "\" has changed.");
            }
        } else {
            errors.add("The flow variable \"" + field.getKnimeName() + "\" is not found in the input.");
        }
    }
    // check output fields
    for (OutCol field : m_fields.getOutColFields()) {
        if (field.getJavaType() == null) {
            errors.add("Java type could not be loaded. Providing plugin may be missing.");
        }
        int index = spec.findColumnIndex(field.getKnimeName());
        if (field.getReplaceExisting() && index < 0) {
            errors.add("The output column \"" + field.getKnimeName() + "\" is marked to be a replacement, " + "but an input with this name does not exist.");
        }
        if (!field.getReplaceExisting() && index > 0) {
            errors.add("The output column \"" + field.getKnimeName() + "\" is marked to be new, " + "but an input with this name does exist.");
        }
        if (!field.getConverterFactory().isPresent()) {
            errors.add(String.format("Missing converter for java field '%s' to column '%s' (converter id: '%s')", field.getJavaName(), field.getKnimeName(), field.getConverterFactoryId()));
        }
    }
    // check output variables
    for (OutVar field : m_fields.getOutVarFields()) {
        FlowVariable var = flowVariableRepository.getFlowVariable(field.getKnimeName());
        if (field.getReplaceExisting() && var == null) {
            errors.add("The output flow variable \"" + field.getKnimeName() + "\" is marked to be a replacement, " + "but an input with this name does not exist.");
        }
        if (!field.getReplaceExisting() && var != null) {
            errors.add("The output flow variable \"" + field.getKnimeName() + "\" is marked to be new, " + "but an input with this name does exist.");
        }
    }
    // Check additional bundles
    for (final String bundleName : m_settings.getBundles()) {
        final Bundle bundle = Platform.getBundle(bundleName);
        if (bundle == null) {
            errors.add("Bundle \"" + bundleName + "\" required by this snippet was not found.");
        } else {
        // TODO Version warning?
        }
    }
    try {
        // test if snippet compiles and if the file can be created
        createSnippetClass();
    } catch (Exception e) {
        errors.add(e.getMessage());
    } finally {
        close();
    }
    return new ValidationReport(errors.toArray(new String[errors.size()]), warnings.toArray(new String[warnings.size()]));
}
Also used : Bundle(org.osgi.framework.Bundle) OutCol(org.knime.base.node.jsnippet.util.field.OutCol) ArrayList(java.util.ArrayList) InCol(org.knime.base.node.jsnippet.util.field.InCol) OutVar(org.knime.base.node.jsnippet.util.field.OutVar) CanceledExecutionException(org.knime.core.node.CanceledExecutionException) BadLocationException(javax.swing.text.BadLocationException) IOException(java.io.IOException) FlowVariableException(org.knime.base.node.jsnippet.expression.FlowVariableException) InvalidSettingsException(org.knime.core.node.InvalidSettingsException) ColumnException(org.knime.base.node.jsnippet.expression.ColumnException) TypeException(org.knime.base.node.jsnippet.expression.TypeException) MalformedURLException(java.net.MalformedURLException) DataColumnSpec(org.knime.core.data.DataColumnSpec) ValidationReport(org.knime.base.node.jsnippet.util.ValidationReport) DataType(org.knime.core.data.DataType) InVar(org.knime.base.node.jsnippet.util.field.InVar) FlowVariable(org.knime.core.node.workflow.FlowVariable)

Example 3 with OutVar

use of org.knime.base.node.jsnippet.util.field.OutVar in project knime-core by knime.

the class JavaSnippetCellFactory method getCells.

/**
 * {@inheritDoc}
 */
@SuppressWarnings("unchecked")
@Override
public DataCell[] getCells(final DataRow row) {
    try {
        if (null == m_jsnippet) {
            m_jsnippet = m_snippet.createSnippetInstance();
            // populate the fields in the m_jsnippet that are constant
            // across the rows.
            Field[] fs = m_jsnippet.getClass().getSuperclass().getDeclaredFields();
            for (Field field : fs) {
                if (field.getName().equals("m_flowVars")) {
                    field.setAccessible(true);
                    field.set(m_jsnippet, m_flowVars);
                }
                if (field.getName().equals(JavaSnippet.ROWCOUNT)) {
                    field.setAccessible(true);
                    field.set(m_jsnippet, m_rowCount);
                }
            }
        }
        // populate data structure with the input cells
        Map<String, Cell> cellsMap = createCellsMap(row);
        if (null == m_columns) {
            m_columns = new ArrayList<>();
            m_columns.addAll(cellsMap.keySet());
        }
        Field[] fs = m_jsnippet.getClass().getSuperclass().getDeclaredFields();
        for (Field field : fs) {
            if (field.getName().equals("m_cellsMap")) {
                field.setAccessible(true);
                field.set(m_jsnippet, cellsMap);
            }
            if (field.getName().equals("m_cells")) {
                field.setAccessible(true);
                List<Cell> cells = new ArrayList<>();
                cells.addAll(cellsMap.values());
                field.set(m_jsnippet, cells);
            }
            if (field.getName().equals("m_columns")) {
                field.setAccessible(true);
                field.set(m_jsnippet, m_columns);
            }
            if (field.getName().equals("m_inSpec")) {
                field.setAccessible(true);
                field.set(m_jsnippet, m_spec);
            }
            if (field.getName().equals(JavaSnippet.ROWID)) {
                field.setAccessible(true);
                field.set(m_jsnippet, row.getKey().getString());
            }
            if (field.getName().equals(JavaSnippet.ROWINDEX)) {
                field.setAccessible(true);
                field.set(m_jsnippet, m_rowIndex);
            }
        }
        // populate the system input column fields with data
        for (InCol inCol : m_snippet.getSystemFields().getInColFields()) {
            Field field = m_jsnippet.getClass().getField(inCol.getJavaName());
            final DataCell cell = row.getCell(m_spec.findColumnIndex(inCol.getKnimeName()));
            if (cell.isMissing()) {
                field.set(m_jsnippet, null);
                continue;
            }
            // Get the converter factory for this column
            final Optional<DataCellToJavaConverterFactory<?, ?>> factory = ConverterUtil.getDataCellToJavaConverterFactory(inCol.getConverterFactoryId());
            if (!factory.isPresent()) {
                throw new RuntimeException("Missing converter factory with ID: " + inCol.getConverterFactoryId());
            }
            final Object converted = factory.get().create().convertUnsafe(cell);
            field.set(m_jsnippet, converted);
        }
        // reset the system output fields to null (see also bug 3781)
        for (OutCol outCol : m_snippet.getSystemFields().getOutColFields()) {
            Field field = m_jsnippet.getClass().getField(outCol.getJavaName());
            field.set(m_jsnippet, null);
        }
        // populate the system input flow variable fields with data
        for (InVar inCol : m_snippet.getSystemFields().getInVarFields()) {
            Field field = m_jsnippet.getClass().getField(inCol.getJavaName());
            Object v = m_flowVars.getValueOfType(inCol.getKnimeName(), inCol.getJavaType());
            field.set(m_jsnippet, v);
        }
    } catch (Exception e) {
        // re-throw exception
        throw new RuntimeException(e);
    }
    try {
        // evaluate user script
        m_jsnippet.snippet();
    } catch (Throwable thr) {
        if (thr instanceof Abort) {
            StringBuilder builder = new StringBuilder("Calculation aborted: ");
            String message = thr.getMessage();
            builder.append(message == null ? "<no details>" : message);
            throw new RuntimeException(builder.toString(), thr);
        } else {
            Integer lineNumber = null;
            for (StackTraceElement ste : thr.getStackTrace()) {
                if (ste.getClassName().equals("JSnippet")) {
                    lineNumber = ste.getLineNumber();
                }
            }
            StringBuilder msg = new StringBuilder();
            msg.append("Evaluation of java snippet failed for row \"");
            msg.append(row.getKey());
            msg.append("\". ");
            if (lineNumber != null) {
                msg.append("The exception is caused by line ");
                msg.append(lineNumber);
                msg.append(" of the snippet. ");
            }
            if (thr.getMessage() != null) {
                msg.append("Exception message:");
                msg.append(thr.getMessage());
            }
            LOGGER.warn(msg.toString(), thr);
            OutVarList outVars = m_snippet.getSystemFields().getOutVarFields();
            if (outVars.size() > 0) {
                // Abort if flow variables are defined
                throw new RuntimeException("An error occured in an " + "expression with output flow variables.", thr);
            }
            OutColList outFields = m_snippet.getSystemFields().getOutColFields();
            DataCell[] out = new DataCell[outFields.size()];
            for (int i = 0; i < out.length; i++) {
                // Return missing values for output fields
                out[i] = DataType.getMissingCell();
            }
            m_rowIndex++;
            return out;
        }
    }
    try {
        // update m_flowVars with output flow variable fields.
        for (OutVar var : m_snippet.getSystemFields().getOutVarFields()) {
            Field field = m_jsnippet.getClass().getField(var.getJavaName());
            Object value = field.get(m_jsnippet);
            if (null != value) {
                Type type = var.getFlowVarType();
                FlowVariable flowVar = null;
                if (type.equals(Type.INTEGER)) {
                    flowVar = new FlowVariable(var.getKnimeName(), (Integer) value);
                } else if (type.equals(Type.DOUBLE)) {
                    flowVar = new FlowVariable(var.getKnimeName(), (Double) value);
                } else {
                    // case type.equals(Type.String)
                    flowVar = new FlowVariable(var.getKnimeName(), (String) value);
                }
                m_flowVars.put(flowVar);
            } else {
                throw new RuntimeException("Flow variable \"" + var.getKnimeName() + "\" has no value.");
            }
        }
        // get output column fields
        OutColList outFields = m_snippet.getSystemFields().getOutColFields();
        DataCell[] out = new DataCell[outFields.size()];
        for (int i = 0; i < out.length; i++) {
            OutCol outField = outFields.get(i);
            Field field = m_jsnippet.getClass().getField(outField.getJavaName());
            Object value = field.get(m_jsnippet);
            if (null == value) {
                out[i] = DataType.getMissingCell();
            } else {
                final String id = outField.getConverterFactoryId();
                Optional<JavaToDataCellConverterFactory<?>> factory = ConverterUtil.getJavaToDataCellConverterFactory(id);
                if (!factory.isPresent()) {
                    throw new RuntimeException("Missing converter factory with ID: " + id);
                }
                out[i] = ((JavaToDataCellConverterFactory<Object>) factory.get()).create(m_context).convert(value);
            }
        }
        // Cleanup Closeable inputs
        for (final OutCol outCol : m_snippet.getSystemFields().getOutColFields()) {
            final Field field = m_jsnippet.getClass().getField(outCol.getJavaName());
            final Object value = field.get(m_jsnippet);
            if (value instanceof Closeable) {
                ((Closeable) value).close();
            }
            if (value instanceof AutoCloseable) {
                // From the doc: Calling close more than once *can* have visible side effects!
                ((AutoCloseable) value).close();
            }
        }
        m_rowIndex++;
        return out;
    } catch (Exception e) {
        // but in case re-throw exception
        throw new RuntimeException(e);
    }
}
Also used : OutCol(org.knime.base.node.jsnippet.util.field.OutCol) Closeable(java.io.Closeable) ArrayList(java.util.ArrayList) OutColList(org.knime.base.node.jsnippet.util.JavaFieldList.OutColList) InCol(org.knime.base.node.jsnippet.util.field.InCol) DataCellToJavaConverterFactory(org.knime.core.data.convert.java.DataCellToJavaConverterFactory) Field(java.lang.reflect.Field) Abort(org.knime.base.node.jsnippet.expression.Abort) OutVarList(org.knime.base.node.jsnippet.util.JavaFieldList.OutVarList) InVar(org.knime.base.node.jsnippet.util.field.InVar) Cell(org.knime.base.node.jsnippet.expression.Cell) DataCell(org.knime.core.data.DataCell) OutVar(org.knime.base.node.jsnippet.util.field.OutVar) TypeException(org.knime.base.node.jsnippet.expression.TypeException) Type(org.knime.core.node.workflow.FlowVariable.Type) DataType(org.knime.core.data.DataType) DataCell(org.knime.core.data.DataCell) FlowVariable(org.knime.core.node.workflow.FlowVariable) JavaToDataCellConverterFactory(org.knime.core.data.convert.datacell.JavaToDataCellConverterFactory)

Example 4 with OutVar

use of org.knime.base.node.jsnippet.util.field.OutVar in project knime-core by knime.

the class JavaSnippet method configure.

/**
 * Create the outspec of the java snippet node. This method is typically used in the configure of a node.
 *
 * @param spec the spec of the data table at the inport
 * @param flowVariableRepository the flow variables at the inport
 * @return the spec at the output
 * @throws InvalidSettingsException when settings are inconsistent with the spec or the flow variables at the inport
 */
public DataTableSpec configure(final DataTableSpec spec, final FlowVariableRepository flowVariableRepository) throws InvalidSettingsException {
    DataTableSpec outSpec = createRearranger(spec, flowVariableRepository, -1, null).createSpec();
    // default values
    for (OutVar outVar : m_fields.getOutVarFields()) {
        FlowVariable flowVar = null;
        if (outVar.getFlowVarType().equals(org.knime.core.node.workflow.FlowVariable.Type.INTEGER)) {
            flowVar = new FlowVariable(outVar.getKnimeName(), -1);
        } else if (outVar.getFlowVarType().equals(org.knime.core.node.workflow.FlowVariable.Type.DOUBLE)) {
            flowVar = new FlowVariable(outVar.getKnimeName(), -1.0);
        } else {
            flowVar = new FlowVariable(outVar.getKnimeName(), "");
        }
        flowVariableRepository.put(flowVar);
    }
    return outSpec;
}
Also used : DataTableSpec(org.knime.core.data.DataTableSpec) OutVar(org.knime.base.node.jsnippet.util.field.OutVar) FlowVariable(org.knime.core.node.workflow.FlowVariable)

Example 5 with OutVar

use of org.knime.base.node.jsnippet.util.field.OutVar in project knime-core by knime.

the class AddOutFieldDialog method takeOverSettings.

/**
 * Save settings in field m_result.
 */
@SuppressWarnings("rawtypes")
private JavaField takeOverSettings() {
    if (m_fieldType.getSelectedItem().equals(FieldType.Column)) {
        OutCol outCol = new OutCol();
        boolean isReplacing = m_replace.isSelected();
        outCol.setReplaceExisting(isReplacing);
        String colName = isReplacing ? ((DataColumnSpec) m_replacedKnimeName.getSelectedItem()).getName() : m_knimeName.getText();
        outCol.setKnimeName(colName);
        Set<String> taken = new HashSet<>();
        for (int i = 0; i < m_model.getRowCount(); i++) {
            taken.add((String) m_model.getValueAt(i, Column.JAVA_FIELD));
        }
        // collection is now done by a separate checkbox
        // DataType dataType = (DataType)m_knimeType.getSelectedItem();
        // DataType elemType =
        // dataType.isCollectionType() ? dataType
        // .getCollectionElementType() : dataType;
        // boolean isCollection = dataType.isCollectionType();
        DataType dataType = (DataType) m_knimeType.getSelectedItem();
        if (m_isArray.isSelected()) {
            dataType = ListCell.getCollectionType(dataType);
        }
        final Optional<JavaToDataCellConverterFactory<?>> selectedFactory = ConverterUtil.getPreferredFactoryForDestinationType(dataType);
        if (!selectedFactory.isPresent()) {
            // Default to string converter, which always exists. Should not happen, though.
            outCol.setConverterFactory(ConverterUtil.getPreferredFactoryForDestinationType(StringCell.TYPE).get());
        } else {
            outCol.setConverterFactory(selectedFactory.get());
        }
        final String javaName = FieldsTableUtil.createUniqueJavaIdentifier(colName, taken, "out_");
        outCol.setJavaName(javaName);
        return outCol;
    } else {
        // flow variable
        OutVar outVar = new OutVar();
        boolean isReplacing = m_replace.isSelected();
        outVar.setReplaceExisting(isReplacing);
        String colName = isReplacing ? ((FlowVariable) m_replacedKnimeName.getSelectedItem()).getName() : m_knimeName.getText();
        outVar.setKnimeName(colName);
        Set<String> taken = new HashSet<>();
        for (int i = 0; i < m_model.getRowCount(); i++) {
            taken.add((String) m_model.getValueAt(i, Column.JAVA_FIELD));
        }
        String javaName = FieldsTableUtil.createUniqueJavaIdentifier(colName, taken, "out_");
        FlowVariable.Type type = (FlowVariable.Type) m_knimeType.getSelectedItem();
        TypeProvider typeProvider = TypeProvider.getDefault();
        Class javaType = typeProvider.getTypeConverter(type).getPreferredJavaType();
        outVar.setFlowVarType(type);
        outVar.setJavaName(javaName);
        outVar.setJavaType(javaType);
        return outVar;
    }
}
Also used : OutCol(org.knime.base.node.jsnippet.util.field.OutCol) TypeProvider(org.knime.base.node.jsnippet.type.TypeProvider) OutVar(org.knime.base.node.jsnippet.util.field.OutVar) FieldType(org.knime.base.node.jsnippet.util.field.JavaField.FieldType) DataType(org.knime.core.data.DataType) DataType(org.knime.core.data.DataType) HashSet(java.util.HashSet) JavaToDataCellConverterFactory(org.knime.core.data.convert.datacell.JavaToDataCellConverterFactory) FlowVariable(org.knime.core.node.workflow.FlowVariable)

Aggregations

OutVar (org.knime.base.node.jsnippet.util.field.OutVar)6 FlowVariable (org.knime.core.node.workflow.FlowVariable)5 OutCol (org.knime.base.node.jsnippet.util.field.OutCol)4 DataType (org.knime.core.data.DataType)4 InCol (org.knime.base.node.jsnippet.util.field.InCol)3 InVar (org.knime.base.node.jsnippet.util.field.InVar)3 ArrayList (java.util.ArrayList)2 TypeException (org.knime.base.node.jsnippet.expression.TypeException)2 OutVarList (org.knime.base.node.jsnippet.util.JavaFieldList.OutVarList)2 FieldType (org.knime.base.node.jsnippet.util.field.JavaField.FieldType)2 JavaToDataCellConverterFactory (org.knime.core.data.convert.datacell.JavaToDataCellConverterFactory)2 Type (org.knime.core.node.workflow.FlowVariable.Type)2 Closeable (java.io.Closeable)1 IOException (java.io.IOException)1 Field (java.lang.reflect.Field)1 MalformedURLException (java.net.MalformedURLException)1 HashSet (java.util.HashSet)1 BadLocationException (javax.swing.text.BadLocationException)1 Abort (org.knime.base.node.jsnippet.expression.Abort)1 Cell (org.knime.base.node.jsnippet.expression.Cell)1