From f91c4cb5166c4729df87eba9372f716d68d2fe9a Mon Sep 17 00:00:00 2001
From: izabel <izabel>
Date: Tue, 30 Nov 2010 15:18:54 +0000
Subject: [PATCH] dynamic feature converter

SVN: 18942
---
 .../feature_converter/CategoryOracle.java     |  81 +++++++++
 .../FeatureVectorConverter.java               |  66 +++++++
 .../tools/feature_converter/Features.java     | 167 ++++++++++++++++++
 .../tools/feature_converter/InputRow.java     |  75 ++++++++
 .../feature_converter/InputRowFactory.java    |  33 ++++
 .../feature_converter/InputRowsHelper.java    |  78 ++++++++
 .../InputRowsNamedCollection.java             |  50 ++++++
 .../tools/feature_converter/OutputRow.java    |  81 +++++++++
 .../tools/feature_converter/TsvBuilder.java   |  62 +++++++
 9 files changed, 693 insertions(+)
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/CategoryOracle.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/FeatureVectorConverter.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/Features.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRow.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowFactory.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowsHelper.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowsNamedCollection.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/OutputRow.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/TsvBuilder.java

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/CategoryOracle.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/CategoryOracle.java
new file mode 100644
index 00000000000..d1f81eff1eb
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/CategoryOracle.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dynamix.tools.feature_converter;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * @author Izabela Adamczyk
+ */
+class CategoryOracle
+{
+    private static final String DISCARD = "Discard";
+
+    private static final String UP = "up";
+
+    private static final String YES = "yes";
+
+    private static final String NO = "no";
+
+    private static final String CONSTANT = "Constant";
+
+    private static final String GOOD = "Good";
+
+    private enum Category
+    {
+        OTHER, DISCARDED_CHAMBER, GOOD_CHAMBER_INTENSITY_AND_LOCALIZATION_CHANGE,
+        GOOD_CHAMBER_LOCALIZATION_CHANGE, GOOD_CHAMBER_INTENSITY_UP, GOOD_CHAMBER_NO_CHANGE;
+    }
+
+    public static String calculateCategory(InputRow in)
+    {
+        String quality = in.getQuality();
+        String intensityChange = in.getIntensityChange();
+        String localizationChange = in.getLocalizationChange();
+        return calculateCategory(quality, intensityChange, localizationChange).toString();
+    }
+
+    private static Category calculateCategory(String quality, String intensityChange,
+            String localizationChange)
+    {
+        if (eq(quality, GOOD) && eq(intensityChange, CONSTANT) && eq(localizationChange, NO))
+        {
+            return Category.GOOD_CHAMBER_NO_CHANGE;
+        } else if (eq(quality, GOOD) && eq(intensityChange, UP) && eq(localizationChange, NO))
+        {
+            return Category.GOOD_CHAMBER_INTENSITY_UP;
+        } else if (eq(quality, GOOD) && eq(intensityChange, NO) && eq(localizationChange, YES))
+        {
+            return Category.GOOD_CHAMBER_LOCALIZATION_CHANGE;
+        } else if (eq(quality, GOOD) && eq(intensityChange, CONSTANT)
+                && eq(localizationChange, YES))
+        {
+            return Category.GOOD_CHAMBER_INTENSITY_AND_LOCALIZATION_CHANGE;
+        } else if (eq(quality, DISCARD))
+        {
+            return Category.DISCARDED_CHAMBER;
+        } else
+        {
+            return Category.OTHER;
+        }
+    }
+
+    private static boolean eq(String property, String value)
+    {
+        return StringUtils.equalsIgnoreCase(property, value);
+    }
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/FeatureVectorConverter.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/FeatureVectorConverter.java
new file mode 100644
index 00000000000..dfa494b18ab
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/FeatureVectorConverter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dynamix.tools.feature_converter;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+
+import ch.systemsx.cisd.common.filesystem.FileUtilities;
+import ch.systemsx.cisd.common.parser.IParserObjectFactory;
+import ch.systemsx.cisd.common.parser.IParserObjectFactoryFactory;
+import ch.systemsx.cisd.common.parser.IPropertyMapper;
+import ch.systemsx.cisd.common.parser.ParserException;
+import ch.systemsx.cisd.common.parser.ParsingException;
+import ch.systemsx.cisd.openbis.generic.shared.parser.BisTabFileLoader;
+
+/**
+ * @author Izabela Adamczyk
+ */
+public class FeatureVectorConverter
+{
+
+    public static void main(String[] args) throws ParserException, ParsingException,
+            IllegalArgumentException, IOException
+    {
+        String in = args[0];
+        IParserObjectFactoryFactory<InputRow> parser = new IParserObjectFactoryFactory<InputRow>()
+            {
+                public IParserObjectFactory<InputRow> createFactory(IPropertyMapper propertyMapper)
+                        throws ParserException
+                {
+                    return new InputRowFactory(InputRow.class, propertyMapper);
+                }
+            };
+        BisTabFileLoader<InputRow> loader = new BisTabFileLoader<InputRow>(parser, false);
+        File inFile = new File(in);
+        List<InputRow> list = loader.load(FileUtils.openInputStream(inFile));
+        List<InputRowsNamedCollection> experiments = InputRowsHelper.extract(list);
+        for (InputRowsNamedCollection e : experiments)
+        {
+            String outName = e.getName() + "__" + inFile.getName();
+            File outFile =
+                    FileUtilities.createNextNumberedFile(new File(inFile.getParent(), outName),
+                            null);
+            FileUtils.writeLines(outFile, InputRowsHelper.toTsv(e.getRows()));
+            System.out.println(outFile.getPath());
+        }
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/Features.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/Features.java
new file mode 100644
index 00000000000..852980a331f
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/Features.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dynamix.tools.feature_converter;
+
+import java.util.Arrays;
+import java.util.List;
+
+import ch.systemsx.cisd.common.annotation.BeanProperty;
+
+/**
+ * @author Izabela Adamczyk
+ */
+public class Features
+{
+
+    private static final String POSITION = "position";
+
+    private static final String SIDE = "side";
+
+    private static final String QUALITY = "quality";
+
+    private static final String QUALITY_DESC = "quality_desc";
+
+    private static final String INTENSITY_CHANGE = "intensity_change";
+
+    private static final String LOCALIZATION_CHANGE = "localization_change";
+
+    private static final String END_LOCALIZATION = "end_localization";
+
+    private static final String INITIAL_LOCALIZATION = "initial_localization";
+
+    private String position;
+
+    private String side;
+
+    private String quality;
+
+    private String qualityDesc;
+
+    private String intensityChange;
+
+    private String localizationChange;
+
+    private String initialLocalization;
+
+    private String endLocalization;
+
+    public Features()
+    {
+    }
+
+    public String getPosition()
+    {
+        return position;
+    }
+
+    @BeanProperty(label = POSITION)
+    public void setPosition(String position)
+    {
+        this.position = position;
+    }
+
+    public String getSide()
+    {
+        return side;
+    }
+
+    @BeanProperty(label = SIDE)
+    public void setSide(String side)
+    {
+        this.side = side;
+    }
+
+    public String getQuality()
+    {
+        return quality;
+    }
+
+    @BeanProperty(label = QUALITY)
+    public void setQuality(String quality)
+    {
+        this.quality = quality;
+    }
+
+    public String getQualityDesc()
+    {
+        return qualityDesc;
+    }
+
+    @BeanProperty(label = QUALITY_DESC)
+    public void setQualityDesc(String qualityDesc)
+    {
+        this.qualityDesc = qualityDesc;
+    }
+
+    public String getIntensityChange()
+    {
+        return intensityChange;
+    }
+
+    @BeanProperty(label = INTENSITY_CHANGE)
+    public void setIntensityChange(String intensityChange)
+    {
+        this.intensityChange = intensityChange;
+    }
+
+    public String getLocalizationChange()
+    {
+        return localizationChange;
+    }
+
+    @BeanProperty(label = LOCALIZATION_CHANGE)
+    public void setLocalizationChange(String localizationChange)
+    {
+        this.localizationChange = localizationChange;
+    }
+
+    public String getInitialLocalization()
+    {
+        return initialLocalization;
+    }
+
+    @BeanProperty(label = INITIAL_LOCALIZATION)
+    public void setInitialLocalization(String initialLocalization)
+    {
+        this.initialLocalization = initialLocalization;
+    }
+
+    public String getEndLocalization()
+    {
+        return endLocalization;
+    }
+
+    @BeanProperty(label = END_LOCALIZATION)
+    public void setEndLocalization(String endLocalization)
+    {
+        this.endLocalization = endLocalization;
+    }
+
+    /** NOTE: Order strictly connected with {@link #getColumns()} */
+    public static List<String> getHeaderColumns()
+    {
+        return Arrays.asList(END_LOCALIZATION, INITIAL_LOCALIZATION, INTENSITY_CHANGE,
+                LOCALIZATION_CHANGE, POSITION, QUALITY, QUALITY_DESC, SIDE);
+    }
+
+    /** NOTE: Order strictly connected with {@link #getHeaderColumns()} */
+    public List<String> getColumns()
+    {
+        return Arrays.asList(getEndLocalization(), getInitialLocalization(), getIntensityChange(),
+                getLocalizationChange(), getPosition(), getQuality(), getQualityDesc(), getSide());
+    }
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRow.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRow.java
new file mode 100644
index 00000000000..e60c3fdab8b
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRow.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dynamix.tools.feature_converter;
+
+import ch.systemsx.cisd.common.annotation.BeanProperty;
+
+/**
+ * @author Izabela Adamczyk
+ */
+public final class InputRow extends Features
+{
+    private static final String IDENTIFIER = "identifier";
+
+    private static final String CONTAINER = "container";
+
+    private static final String YORF = "yorf";
+
+    private String yorf;
+
+    private String container;
+
+    private String identifier;
+
+    public InputRow()
+    {
+    }
+
+    public String getContainer()
+    {
+        return container;
+    }
+
+    @BeanProperty(label = CONTAINER)
+    public void setContainer(String container)
+    {
+        this.container = container;
+    }
+
+    public String getIdentifier()
+    {
+        return identifier;
+    }
+
+    @BeanProperty(label = IDENTIFIER)
+    public void setIdentifier(String identifier)
+    {
+        this.identifier = identifier;
+    }
+
+    public String getYorf()
+    {
+        return yorf;
+    }
+
+    @BeanProperty(label = YORF)
+    public void setYorf(String yorf)
+    {
+        this.yorf = yorf;
+    }
+
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowFactory.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowFactory.java
new file mode 100644
index 00000000000..009fab2c86f
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dynamix.tools.feature_converter;
+
+import ch.systemsx.cisd.common.parser.AbstractParserObjectFactory;
+import ch.systemsx.cisd.common.parser.IPropertyMapper;
+
+/**
+ * @author Izabela Adamczyk
+ */
+final class InputRowFactory extends AbstractParserObjectFactory<InputRow>
+{
+
+    protected InputRowFactory(Class<InputRow> beanClass, IPropertyMapper propertyMapper)
+    {
+        super(beanClass, propertyMapper);
+    }
+
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowsHelper.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowsHelper.java
new file mode 100644
index 00000000000..c870a359fbb
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowsHelper.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dynamix.tools.feature_converter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+
+import ch.systemsx.cisd.common.utilities.BeanUtils;
+
+/**
+ * @author Izabela Adamczyk
+ */
+class InputRowsHelper
+{
+
+    public static List<InputRowsNamedCollection> extract(List<InputRow> list)
+    {
+        Map<String, List<InputRow>> map = new HashMap<String, List<InputRow>>();
+        for (InputRow r : list)
+        {
+            String name = r.getContainer();
+            if (map.get(name) == null)
+            {
+                map.put(name, new ArrayList<InputRow>());
+            }
+            map.get(name).add(r);
+        }
+        ArrayList<InputRowsNamedCollection> result = new ArrayList<InputRowsNamedCollection>();
+        for (String key : map.keySet())
+        {
+            InputRowsNamedCollection exp = new InputRowsNamedCollection();
+            exp.setName(key);
+            exp.setRows(map.get(key));
+            result.add(exp);
+        }
+        return result;
+    }
+
+    public static List<String> toTsv(List<InputRow> list)
+    {
+        ArrayList<String> result = new ArrayList<String>();
+        result.add(new TsvBuilder(OutputRow.getHeaderColumns()).toString());
+        for (InputRow r : list)
+        {
+            result.add(new TsvBuilder(convert(r).getColumns()).toString());
+        }
+        return result;
+    }
+
+    private static OutputRow convert(InputRow in)
+    {
+        OutputRow outputRow = new OutputRow();
+        BeanUtils.fillBean(OutputRow.class, outputRow, in);
+        outputRow.setWellName(StringUtils.split(in.getIdentifier(), ":")[1]);
+        String category = CategoryOracle.calculateCategory(in);
+        outputRow.setCategory(category);
+        return outputRow;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowsNamedCollection.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowsNamedCollection.java
new file mode 100644
index 00000000000..7c2f9820a28
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/InputRowsNamedCollection.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dynamix.tools.feature_converter;
+
+import java.util.List;
+
+/**
+ * @author Izabela Adamczyk
+ */
+class InputRowsNamedCollection
+{
+    String name;
+
+    List<InputRow> rows;
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    public List<InputRow> getRows()
+    {
+        return rows;
+    }
+
+    public void setRows(List<InputRow> rows)
+    {
+        this.rows = rows;
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/OutputRow.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/OutputRow.java
new file mode 100644
index 00000000000..625d358947f
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/OutputRow.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dynamix.tools.feature_converter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.systemsx.cisd.common.annotation.BeanProperty;
+
+/**
+ * @author Izabela Adamczyk
+ */
+final class OutputRow extends Features
+{
+
+    private static final String CATEGORY = "category";
+
+    private static final String WELL_NAME = "well_name";
+
+    private String wellName;
+
+    private String category;
+
+    public String getWellName()
+    {
+        return wellName;
+    }
+
+    @BeanProperty(label = WELL_NAME)
+    public void setWellName(String wellName)
+    {
+        this.wellName = wellName;
+    }
+
+    public String getCategory()
+    {
+        return category;
+    }
+
+    @BeanProperty(label = CATEGORY)
+    public void setCategory(String category)
+    {
+        this.category = category;
+    }
+
+    /** NOTE: Order strictly connected with {@link #getColumns()} */
+    public static List<String> getHeaderColumns()
+    {
+        ArrayList<String> list = new ArrayList<String>();
+        list.add(WELL_NAME);
+        list.add(CATEGORY);
+        list.addAll(Features/* super class */.getHeaderColumns());
+        return list;
+    }
+
+    /** NOTE: Order strictly connected with {@link #getHeaderColumns()} */
+    @Override
+    public List<String> getColumns()
+    {
+        ArrayList<String> list = new ArrayList<String>();
+        list.add(getWellName());
+        list.add(getCategory());
+        list.addAll(super.getColumns());
+        return list;
+    }
+
+}
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/TsvBuilder.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/TsvBuilder.java
new file mode 100644
index 00000000000..8cd21d55e93
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dynamix/tools/feature_converter/TsvBuilder.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.etl.dynamix.tools.feature_converter;
+
+import java.util.List;
+
+/**
+ * @author Izabela Adamczyk
+ */
+public class TsvBuilder
+{
+    static final String TSV_SEPARATOR = ";";
+
+    StringBuilder builder = new StringBuilder();
+
+    boolean empty = true;
+
+    public TsvBuilder()
+    {
+    }
+
+    public TsvBuilder(List<String> columns)
+    {
+        addColumns(columns.toArray(new String[0]));
+    }
+
+    public void addColumns(String... columns)
+    {
+        for (String c : columns)
+        {
+            if (empty)
+            {
+                empty = false;
+            } else
+            {
+                builder.append(TsvBuilder.TSV_SEPARATOR);
+            }
+            builder.append(c);
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return builder.toString();
+    }
+
+}
-- 
GitLab