package de.mpicbg.knime.knutils; import org.knime.core.data.*; import org.knime.core.data.date.DateAndTimeCell; import org.knime.core.data.def.DoubleCell; import org.knime.core.data.def.IntCell; import org.knime.core.data.def.StringCell; import org.knime.core.data.image.ImageValue; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; /** * @author Holger Brandl */ public class Attribute<AttributeType> { private final String attributeName; private final DataType attributeType; public Attribute(String attributeName, DataType type) { this.attributeName = attributeName; this.attributeType = type; } public DataType getType() { return attributeType; } public String getName() { return attributeName; } public DataColumnSpec getColumnSpec() { DataColumnSpecCreator columnSpecCreator = new DataColumnSpecCreator(getName(), getType()); return columnSpecCreator.createSpec(); } // // cell generation // public DataCell createCell(DataRow dataRow) { return createCell(getValue(dataRow)); } public DataCell createCell(Object value) { if (value == null) { return DataType.getMissingCell(); } if (getType().equals(DoubleCell.TYPE)) { if (value instanceof String) { if (((String) value).trim().isEmpty()) { return DataType.getMissingCell(); } value = Double.parseDouble((String) value); } if (value instanceof Integer) { value = ((Integer) value).doubleValue(); } return new DoubleCell((Double) value); } else if (getType().equals(IntCell.TYPE)) { if (value instanceof String) { if (((String) value).trim().isEmpty()) { return DataType.getMissingCell(); } value = Integer.parseInt((String) value); } return postProcessCreatedCell(new IntCell((Integer) value)); } else if (getType().equals(StringCell.TYPE)) { return postProcessCreatedCell(new StringCell("" + value)); } else if (getType().equals(DateAndTimeCell.TYPE)) { Date date = (Date) value; Calendar cal = GregorianCalendar.getInstance(); cal.setTime(date); return new DateAndTimeCell(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)); } else { throw new RuntimeException("Unsupported attribute-type"); } } protected DataCell postProcessCreatedCell(DataCell cell) { return cell; } // // attribute value extraction // public String getNominalAttribute(DataRow dataRow) { if (!isNominalAttribute()) { throw new RuntimeException("Could not cast attribute value to string"); } DataCell dataCell = dataRow.getCell(getColumnIndex()); if (dataCell.isMissing()) { return null; } if (dataCell instanceof StringCell) { return ((StringCell) dataCell).getStringValue(); } else { throw new RuntimeException("Could not extract value of cell with type " + dataCell); } } public Integer getIntAttribute(DataRow dataRow) { Double doubleAttribute = getDoubleAttribute(dataRow); return doubleAttribute != null ? doubleAttribute.intValue() : null; } public Double getDoubleAttribute(DataRow dataRow) { if (!isNumerical()) { throw new RuntimeException("Could not cast attribute " + this + " to double. Use the String2Number node to convert the type"); } DataCell dataCell = dataRow.getCell(getColumnIndex()); if (dataCell.isMissing()) { return null; } else if (dataCell instanceof IntCell) { return ((IntCell) dataCell).getDoubleValue(); } else if (dataCell instanceof DoubleCell) { return ((DoubleCell) dataCell).getDoubleValue(); } else { throw new RuntimeException("type of cell not yet mappd: " + dataCell); } } public Date getDateAttribute(DataRow dataRow) { if (!isDateAttribute()) { throw new RuntimeException("Could not cast attribute value to date"); } DataCell cell = dataRow.getCell(getColumnIndex()); if (cell.isMissing()) { return null; } DateAndTimeCell dateCell = (DateAndTimeCell) cell; SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); try { return dateFormat.parse(dateCell.getDayOfMonth() + "." + (dateCell.getMonth() + 1) + "." + dateCell.getYear()); } catch (ParseException e) { e.printStackTrace(); } return null; } /** * This is a hacky approach to get image cells. The data is kept in the DataCell form to stay generic * since different plugins have different methods to access the image data. * * @param dataRow row from the {@link DataTable} * @return cell of the row. */ public DataCell getImageAttribute(DataRow dataRow) { if ( !isImageAttribute() ) { throw new RuntimeException(("Could not cast attribute to Image value.")); } DataCell cell = dataRow.getCell(getColumnIndex()); if ( cell.isMissing() ) { return null; } return cell; } public boolean isNumerical() { return isDoubleType() || isIntegerType(); } public boolean isDoubleType() { return getType().equals(DoubleCell.TYPE); } public boolean isIntegerType() { return getType().equals(IntCell.TYPE); } public boolean isDateAttribute() { return getColumnSpec().getType().equals(DateAndTimeCell.TYPE); } public boolean isMissing(DataRow dataRow) { return dataRow.getCell(getColumnIndex()).isMissing(); } public boolean isNominalAttribute() { // todo that's the proper way to do it; we should adapt this everywhere! // return getColumnSpec().getType().getValueClasses().contains(StringValue.class); return getColumnSpec().getType().equals(StringCell.TYPE); } public boolean isImageAttribute() { // hack to recognise the KNIME Image Processing Toolbox CellTypes without the dependency. return getColumnSpec().getType().isCompatible(ImageValue.class) || getColumnSpec().getType().getPreferredValueClass().getName().contains("org.knime.knip.base.data"); } public AttributeType getValue(DataRow dataRow) { if (isNominalAttribute()) { return (AttributeType) getNominalAttribute(dataRow); } else if (isDateAttribute()) { return (AttributeType) getDateAttribute(dataRow); } else if (isIntegerType()) { Integer intAttribute = getIntAttribute(dataRow); return intAttribute != null ? (AttributeType) new Integer(intAttribute) : null; } else if (isNumerical()) { Double doubleAttribute = getDoubleAttribute(dataRow); return doubleAttribute != null ? (AttributeType) new Double(doubleAttribute) : null; } throw new RuntimeException("Not supported column type"); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Attribute)) return false; Attribute attribute = (Attribute) o; if (!getName().equals(attribute.getName())) return false; return true; } @Override public int hashCode() { return getName().hashCode(); } @Override public String toString() { String type = null; if (isNumerical()) { type = "numerical"; } else if (isNominalAttribute()) { type = "nominal"; } else if (isDateAttribute()) { type = "date"; } return getName() + " (" + type + ")"; } public String getRawValue(DataRow dataRow) { if (isNominalAttribute()) { return getNominalAttribute(dataRow); } return dataRow.getCell(getColumnIndex()).toString(); } public Integer getColumnIndex() { throw new RuntimeException("not implemented for generic attributes. Use InputTableAttribute for reading from input tables"); } }