CDMSequenceMatrixAdapter now exports sequence metadata.
authorb.stoever <stoever@bioinfweb.info>
Thu, 27 Oct 2016 17:31:58 +0000 (19:31 +0200)
committerb.stoever <stoever@bioinfweb.info>
Thu, 27 Oct 2016 17:31:58 +0000 (19:31 +0200)
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/AlignmentEditor.java
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/CDMSequenceMatrixAdapter.java
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/SingleReadAlignmentPredicates.java [new file with mode: 0644]

index 12b1d8e5a1301ce91b1f558a23c80a490e2e2d83..0b218c832335a4c969bb4bbabdd2a77b461d2b18 100644 (file)
@@ -137,8 +137,8 @@ public class AlignmentEditor extends EditorPart {
     private final Map<String, SingleReadAlignment> cdmMap = new TreeMap<String, SingleReadAlignment>();  //TODO Move this to ContigSequenceDataProvider
     private boolean dirty = false;
 
-    public AlignmentEditor()
-    {
+
+    public AlignmentEditor() {
        super();
        conversationHolder = CdmStore.createConversation();
        //conversationHolder = null;
@@ -187,9 +187,9 @@ public class AlignmentEditor extends EditorPart {
                result.setAllowVerticalScrolling(allowVerticalScrolling);
 
                CharacterTokenSet tokenSet = CharacterTokenSet.newDNAInstance();  //TODO Should NUCLEOTIDE be used instead?
-               AlignmentModel<Character> provider = new PackedAlignmentModel<Character>(tokenSet);
-               result.setAlignmentModel(provider, false);
-               provider.getChangeListeners().add(DIRTY_LISTENER);
+               AlignmentModel<Character> model = new PackedAlignmentModel<Character>(tokenSet);
+               result.setAlignmentModel(model, false);
+               model.getChangeListeners().add(DIRTY_LISTENER);
                result.getPaintSettings().getTokenPainterList().set(0, new NucleotideTokenPainter());
 
                return result;
@@ -328,12 +328,8 @@ public class AlignmentEditor extends EditorPart {
                for (SingleReadAlignment singleReadAlignment : sequenceNode.getSingleReadAlignments()) {
                        try {
                                SingleRead pherogramInfo = singleReadAlignment.getSingleRead();
-                               URI uri = null;
-                               if (pherogramInfo.getPherogram() != null) {
-                                   uri = MediaUtils.getFirstMediaRepresentationPart(pherogramInfo.getPherogram()).getUri();
-                               }
                                String id = addRead(DerivateLabelProvider.getDerivateText(pherogramInfo, conversationHolder),
-                                               uri,
+                                               getPherogramURI(pherogramInfo),
                                                singleReadAlignment.isReverseComplement(),
                                                singleReadAlignment.getEditedSequence(),
                                                singleReadAlignment.getFirstSeqPosition(),
@@ -349,10 +345,10 @@ public class AlignmentEditor extends EditorPart {
                }
 
                // Set consensus sequence:
-               AlignmentModel consensusProvider = getEditableConsensusArea().getAlignmentModel();
-               String id = consensusProvider.addSequence(CONSENSUS_NAME);
-               consensusProvider.insertTokensAt(id, 0, AlignmentModelUtils.charSequenceToTokenList(
-                               sequenceNode.getConsensusSequence().getString(), consensusProvider.getTokenSet()));
+               AlignmentModel consensusModel = getEditableConsensusArea().getAlignmentModel();
+               String id = consensusModel.addSequence(CONSENSUS_NAME);
+               consensusModel.insertTokensAt(id, 0, AlignmentModelUtils.charSequenceToTokenList(
+                               sequenceNode.getConsensusSequence().getString(), consensusModel.getTokenSet()));
                //TODO Can the consensus sequence also be null? / Should it be created here, if nothing is in the DB?
     }
 
@@ -703,7 +699,7 @@ public class AlignmentEditor extends EditorPart {
             Integer firstSeqPos, Integer leftCutPos, Integer rightCutPos, SingleReadAlignment.Shift[] shifts)
             throws IOException, UnsupportedChromatogramFormatException {
 
-               AlignmentModel provider = getReadsArea().getAlignmentModel();
+               AlignmentModel model = getReadsArea().getAlignmentModel();
                PherogramProvider pherogramProvider = null;
                if (pherogramURI != null) {
                    pherogramProvider = readPherogram(pherogramURI);  // Must happen before a sequence is added, because it might throw an exception.
@@ -713,25 +709,25 @@ public class AlignmentEditor extends EditorPart {
                }
 
         // Create sequence:
-               provider.addSequence(name);
-               String id = provider.sequenceIDByName(name);
+               model.addSequence(name);
+               String id = model.sequenceIDByName(name);
 
                // Set edited sequence:
                Collection<Object> tokens = null;  // First save tokens in a collection to avoid GUI updated for each token.
                if (editedSequence != null) {
-                       tokens = AlignmentModelUtils.charSequenceToTokenList(editedSequence, provider.getTokenSet());
+                       tokens = AlignmentModelUtils.charSequenceToTokenList(editedSequence, model.getTokenSet());
                }
                else if (pherogramProvider != null) {  // Copy base call sequence into alignment:
                        tokens = new ArrayList<Object>();
                        for (int i = 0; i < pherogramProvider.getSequenceLength(); i++) {
-                               tokens.add(provider.getTokenSet().tokenByRepresentation(
+                               tokens.add(model.getTokenSet().tokenByRepresentation(
                                        Character.toString(pherogramProvider.getBaseCall(i))));
                        }
                        setDirty();
                }
 
                if (tokens != null) {  // If either an edited sequence or a pherogram URI was provided.
-                   provider.insertTokensAt(id, 0, tokens);
+                   model.insertTokensAt(id, 0, tokens);
 
                    if (pherogramProvider != null) {
                        // Create pherogram area:
@@ -739,16 +735,16 @@ public class AlignmentEditor extends EditorPart {
                                new PherogramAreaModel(pherogramProvider));
 
                        // Set position properties and shifts:
-                       PherogramAreaModel model = pherogramArea.getModel();
+                       PherogramAreaModel phergramModel = pherogramArea.getModel();
                        if ((firstSeqPos != null) && (leftCutPos != null)) {
-                           model.setFirstSeqLeftCutPos(firstSeqPos, leftCutPos);
+                           phergramModel.setFirstSeqLeftCutPos(firstSeqPos, leftCutPos);
                        }
                        if (rightCutPos != null) {
-                           model.setRightCutPosition(rightCutPos);
+                           phergramModel.setRightCutPosition(rightCutPos);
                        }
                        if ((shifts != null) && (shifts.length > 0)) {
                            for (int i = 0; i < shifts.length; i++) {
-                               model.addShiftChange(shifts[i].position, shifts[i].shift);
+                               phergramModel.addShiftChange(shifts[i].position, shifts[i].shift);
                            }
                            setDirty();
                        }
@@ -760,4 +756,14 @@ public class AlignmentEditor extends EditorPart {
                }
                return id;
        }
+
+
+    public static URI getPherogramURI(SingleRead pherogramInfo) {
+        if (pherogramInfo.getPherogram() != null) {
+            return MediaUtils.getFirstMediaRepresentationPart(pherogramInfo.getPherogram()).getUri();
+        }
+        else {
+            return null;
+        }
+    }
 }
\ No newline at end of file
index 307d27238c392487d7773d63df618d1bff13d81a..0b635b703fdfd3263f85c0d9f2318ce88f06ac9e 100644 (file)
@@ -11,6 +11,7 @@ package eu.etaxonomy.taxeditor.molecular.io;
 \r
 \r
 import info.bioinfweb.commons.bio.CharacterStateSetType;\r
+import info.bioinfweb.commons.io.W3CXSConstants;\r
 import info.bioinfweb.commons.text.StringUtils;\r
 import info.bioinfweb.jphyloio.ReadWriteConstants;\r
 import info.bioinfweb.jphyloio.ReadWriteParameterMap;\r
@@ -24,27 +25,39 @@ import info.bioinfweb.jphyloio.events.LinkedLabeledIDEvent;
 import info.bioinfweb.jphyloio.events.SequenceTokensEvent;\r
 import info.bioinfweb.jphyloio.events.TokenSetDefinitionEvent;\r
 import info.bioinfweb.jphyloio.events.type.EventContentType;\r
+import info.bioinfweb.jphyloio.utils.JPhyloIOWritingUtils;\r
 \r
 import java.io.IOException;\r
+import java.net.URI;\r
+import java.util.ArrayList;\r
 import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import javax.xml.namespace.QName;\r
 \r
 import eu.etaxonomy.cdm.model.molecular.Sequence;\r
+import eu.etaxonomy.cdm.model.molecular.SingleReadAlignment;\r
+import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;\r
 \r
 \r
 \r
 /**\r
  * In implementation of {@link MatrixDataAdapter} that delegates to a {@link Sequence} object.\r
+ * <p>\r
+ * Note that this adapter stores information on the {@link Sequence} in creation. Modifying the sequence or linked\r
+ * objects will require to create a new instance of this class. Otherwise unexpected behavior may be the consequence.\r
  *\r
  * @author Ben Stöver\r
  * @date 29.04.2016\r
  */\r
-public class CDMSequenceMatrixAdapter extends NoCharDefsNoSetsMatrixDataAdapter implements ReadWriteConstants {\r
+public class CDMSequenceMatrixAdapter extends NoCharDefsNoSetsMatrixDataAdapter implements ReadWriteConstants, SingleReadAlignmentPredicates {\r
     public static final String MATRIX_ID = DEFAULT_MATRIX_ID_PREFIX + "ContigAlignment";\r
     public static final String SINGLE_READ_SEQUENCE_ID_PREFIX = DEFAULT_SEQUENCE_ID_PREFIX + "SingleRead";\r
     public static final String CONSENSUS_SEQUENCE_ID= DEFAULT_SEQUENCE_ID_PREFIX + "Consensus";\r
 \r
 \r
     private Sequence sequence;\r
+    private List<SingleReadAlignment> singleReadList;\r
     private String consensusSequenceLabel;\r
     private ObjectListDataAdapter<TokenSetDefinitionEvent> tokenSetList;\r
     //TODO Also allow specifying single read labels?\r
@@ -61,6 +74,8 @@ public class CDMSequenceMatrixAdapter extends NoCharDefsNoSetsMatrixDataAdapter
         this.sequence = sequence;\r
         this.consensusSequenceLabel = consensusSequenceLabel;\r
         tokenSetList = createTokenSetList();\r
+        singleReadList = new ArrayList<SingleReadAlignment>(sequence.getSingleReadAlignments());  // Store references of single reads in defined order to allow random access.\r
+                //TODO Omit single reads that do not have an edited sequece yet?\r
     }\r
 \r
 \r
@@ -116,7 +131,7 @@ public class CDMSequenceMatrixAdapter extends NoCharDefsNoSetsMatrixDataAdapter
 \r
     @Override\r
     public long getSequenceCount(ReadWriteParameterMap parameters) {\r
-        return /*sequence.getSingleReadAlignments().size() +*/ 1;\r
+        return singleReadList.size() + 1;  // The last sequence is the consensus sequence.\r
     }\r
 \r
 \r
@@ -130,8 +145,13 @@ public class CDMSequenceMatrixAdapter extends NoCharDefsNoSetsMatrixDataAdapter
     public long getSequenceLength(ReadWriteParameterMap parameters, String sequenceID) throws IllegalArgumentException {\r
         int singleReadIndex = extractSingleReadIndexFromID(sequenceID);\r
         if (singleReadIndex >= 0) {\r
-            //TODO Determine single read length. (Current problem: Reads are not ordered in the set of the Sequence object.)\r
-            return 0;\r
+            String sequence = singleReadList.get(singleReadIndex).getEditedSequence();\r
+            if (sequence != null) {\r
+                return sequence.length();\r
+            }\r
+            else {  // This would happen e.g. if not edited sequence was copied from pherogram yet.\r
+                return 0;\r
+            }\r
         }\r
         else if (CONSENSUS_SEQUENCE_ID.equals(sequenceID)) {\r
             return getCDMSequence().getSequenceString().length();\r
@@ -158,21 +178,58 @@ public class CDMSequenceMatrixAdapter extends NoCharDefsNoSetsMatrixDataAdapter
     }\r
 \r
 \r
+    private void writeStringPart(JPhyloIOEventReceiver receiver, String string, long startColumn, long endColumn) throws IOException {\r
+        if (string != null) {\r
+            receiver.add(new SequenceTokensEvent(StringUtils.charSequenceToStringList(\r
+                    string.substring((int)startColumn, (int)endColumn))));\r
+        }\r
+    }\r
+\r
+\r
+    private String createMetadataID(String sequenceID, QName predicate) {\r
+        return sequenceID + "META" + predicate.getLocalPart();\r
+    }\r
+\r
+\r
+    private void writeMetadataEvents(JPhyloIOEventReceiver receiver, String sequenceID, QName predicate, Object objectValue)\r
+            throws IOException {\r
+\r
+        if (objectValue != null) {\r
+            JPhyloIOWritingUtils.writeSimpleLiteralMetadata(receiver, createMetadataID(sequenceID, predicate), null,\r
+                    predicate, W3CXSConstants.DATA_TYPE_BOOLEAN, objectValue, null);\r
+        }\r
+    }\r
+\r
+\r
     @Override\r
-    public void writeSequencePartContentData(ReadWriteParameterMap parameters, JPhyloIOEventReceiver receiver, String sequenceID, long startColumn,\r
-            long endColumn) throws IOException, IllegalArgumentException {\r
+    public void writeSequencePartContentData(ReadWriteParameterMap parameters, JPhyloIOEventReceiver receiver, String sequenceID,\r
+            long startColumn, long endColumn) throws IOException, IllegalArgumentException {\r
 \r
         int singleReadIndex = extractSingleReadIndexFromID(sequenceID);\r
         if (singleReadIndex >= 0) {\r
-            //TODO Implement single read output.\r
+            SingleReadAlignment singleRead = singleReadList.get(singleReadIndex);\r
+            if (startColumn == 0) {\r
+                writeMetadataEvents(receiver, sequenceID, PREDICATE_IS_SINGLE_READ, new Boolean(true));\r
+                writeMetadataEvents(receiver, sequenceID, PREDICATE_IS_REVERSE_COMPLEMENTED, new Boolean(singleRead.isReverseComplement()));\r
+                writeMetadataEvents(receiver, sequenceID, PREDICATE_HAS_LEFT_CUT_POSITION, singleRead.getLeftCutPosition());\r
+                writeMetadataEvents(receiver, sequenceID, PREDICATE_HAS_RIGHT_CUT_POSITION, singleRead.getRightCutPosition());\r
+\r
+                URI pherogramURI = AlignmentEditor.getPherogramURI(singleRead.getSingleRead());\r
+                if (pherogramURI != null) {\r
+                    JPhyloIOWritingUtils.writeTerminalResourceMetadata(receiver, createMetadataID(sequenceID, PREDICATE_HAS_PHEROGRAM),\r
+                            null, PREDICATE_HAS_PHEROGRAM, pherogramURI);\r
+                }\r
+\r
+                //TODO Add pherogram alignment metadata. (Use LibrAlign DataModel writer implementation.)\r
+            }\r
+            writeStringPart(receiver, singleRead.getEditedSequence(), startColumn, endColumn);\r
         }\r
         else if (CONSENSUS_SEQUENCE_ID.equals(sequenceID)) {\r
             if (startColumn == 0) {\r
-                //TODO Add consensus sequence metadata.\r
-                //TODO Possibly export additional properties of sequence (e.g. isBarcode(), getDdbjId(), ...) as metadata.\r
+                writeMetadataEvents(receiver, sequenceID, PREDICATE_IS_CONSENSUS_SEQUENCE, new Boolean(true));\r
+                //TODO Possibly export additional properties of sequence (e.g. isBarcode(), getDdbjId(), ...) as metadata?\r
             }\r
-            receiver.add(new SequenceTokensEvent(StringUtils.charSequenceToStringList(\r
-                    getCDMSequence().getSequenceString().substring((int)startColumn, (int)endColumn))));\r
+            writeStringPart(receiver, getCDMSequence().getSequenceString(), startColumn, endColumn);\r
         }\r
         else {\r
             throw new IllegalArgumentException("No sequence with the ID \"" + sequenceID + "\" could be found.");\r
diff --git a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/SingleReadAlignmentPredicates.java b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/SingleReadAlignmentPredicates.java
new file mode 100644 (file)
index 0000000..46c20e5
--- /dev/null
@@ -0,0 +1,34 @@
+// $Id$
+/**
+* Copyright (C) 2016 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.taxeditor.molecular.io;
+
+
+import javax.xml.namespace.QName;
+
+
+
+/**
+ * Contains constants for <i>RDF</i> predicates used in the I/O of single read alignments e.g. from and to the <i>NeXML</i> format.
+ *
+ * @author Ben Stöver
+ * @date 27.10.2016
+ */
+public interface SingleReadAlignmentPredicates {
+    public static final String NAMESPACE_URI = "http://bioinfweb.info/xmlns/PhyDE/Annotations/";  //TODO Possibly change this namespace, when according decision is made.
+    public static final String NAMESPACE_PREFIX = "phy";
+
+    public static final QName PREDICATE_IS_SINGLE_READ = new QName(NAMESPACE_URI, "isSingleRead", NAMESPACE_PREFIX);
+    public static final QName PREDICATE_IS_CONSENSUS_SEQUENCE = new QName(NAMESPACE_URI, "isConsensus", NAMESPACE_PREFIX);
+    public static final QName PREDICATE_IS_REVERSE_COMPLEMENTED = new QName(NAMESPACE_URI, "isRCed", NAMESPACE_PREFIX);
+    public static final QName PREDICATE_HAS_PHEROGRAM = new QName(NAMESPACE_URI, "hasPherogram", NAMESPACE_PREFIX);
+    public static final QName PREDICATE_HAS_PHEROGRAM_ALIGNMENT = new QName(NAMESPACE_URI, "hasPherogramAlignment", NAMESPACE_PREFIX);
+    public static final QName PREDICATE_HAS_LEFT_CUT_POSITION = new QName(NAMESPACE_URI, "hasLeftCutPosition", NAMESPACE_PREFIX);
+    public static final QName PREDICATE_HAS_RIGHT_CUT_POSITION = new QName(NAMESPACE_URI, "hasRightCutPosition", NAMESPACE_PREFIX);
+}