BioInfWeb - JPhyloIO / Source code / Show File - TreeReader.java

JPhyloIO subversion repository

sventon subversion web client - http://www.sventon.org
[show recent changes]
 
  Help
Rev: HEAD (1579) - https://secure.bioinfweb.info/Code/svn/JPhyloIO / trunk / demo / info.bioinfweb.jphyloio.demo.tree / src / info / bioinfweb / jphyloio / demo / tree / TreeReader.java
Show File - TreeReader.java  [show properties]
spinner
/*
 * JPhyloIO - Event based parsing and stream writing of multiple sequence alignment and tree formats. 
 * Copyright (C) 2015-2016  Ben Stöver, Sarah Wiechers
 * <http://bioinfweb.info/JPhyloIO>
 * 
 * This file is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
10   * 
11   * This file is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   * GNU Lesser General Public License for more details.
15   * 
16   * You should have received a copy of the GNU Lesser General Public License
17   * along with this program. If not, see <http://www.gnu.org/licenses/>.
18   */
19  package info.bioinfweb.jphyloio.demo.tree;
20 
21 
22  import info.bioinfweb.jphyloio.JPhyloIOEventReader;
23  import info.bioinfweb.jphyloio.events.EdgeEvent;
24  import info.bioinfweb.jphyloio.events.JPhyloIOEvent;
25  import info.bioinfweb.jphyloio.events.LabeledIDEvent;
26  import info.bioinfweb.jphyloio.events.NodeEvent;
27  import info.bioinfweb.jphyloio.events.type.EventContentType;
28  import info.bioinfweb.jphyloio.events.type.EventTopologyType;
29  import info.bioinfweb.jphyloio.utils.JPhyloIOReadingUtils;
30 
31  import java.io.IOException;
32  import java.util.ArrayList;
33  import java.util.HashMap;
34  import java.util.List;
35  import java.util.Map;
36 
37  import javax.swing.tree.DefaultMutableTreeNode;
38  import javax.swing.tree.DefaultTreeModel;
39 
40 
41 
42  /**
43   * This is the <i>JPhyloIO</i> reader of this demo application that connects the readers available in <i>JPhyloIO</i> with the
44   * business model of the application by extracting relevant data from the <i>JPhyloIO</i> event sequence and storing it in the 
45   * application model.
46   * <p>
47   * Each application based on <i>JPhyloIO</i> needs to implement one such reader to support all available formats. The application 
48   * can use this reader by calling {@link #read(JPhyloIOEventReader, Map)}.
49   * <p>
50   * Each method in this reader handles a sequence of events nested between a start and end event. although there are alternatives,
51   * this is usually a good way to implement pull parsing. Each of these methods corresponds to a grammar node of the <i>JPhyloIO</i>
52   * event sequence that can be found in the documentation of {@link JPhyloIOEventReader}. 
53   * 
54   * @author Ben St&ouml;ver
55   */
56  public class TreeReader {
57      /** Stores the <i>JPhyloIO</i> event reader that is currently used by this instance. */
58      protected JPhyloIOEventReader reader;
59      
60      /** Stores the application model that is the current target for data read by this instance. */
61      protected DefaultTreeModel model;
62      
63      /** 
64       * A map for internal use storing node objects created from encountered node events until they are combined to 
65       * form a tree topology. 
66       */
67      protected Map<String, DefaultMutableTreeNode> idToNodeMap = new HashMap<String, DefaultMutableTreeNode>();
68      
69      /** 
70       * A list of nodes that could become the tree root. (After all branches have been processed this list will 
71       * contain only one entry in case of trees.) 
72       */
73      protected List<String> possiblePaintStartIDs = new ArrayList<String>();
74      
75      
76      /**
77       * Main method of this reader. It reads a tree using the specified <i>JPhyloIO</i> reader to the specified application 
78       * business model.
79       * <p>
80       * The loop in this method processes the event sequence defined by the <i>JPhyloIO</i> grammar node <code>Document</code>. 
81       * (The grammar can be found in the documentation of {@link JPhyloIOEventReader}.)
82       * 
83       * @param reader the <i>JPhyloIO</i> reader providing the event stream to be processed
84       * @param model the application business model to take up the loaded alignment data
85       * @throws IOException exceptions thrown during the I/O operation
86       */
87      public void read(JPhyloIOEventReader reader, DefaultTreeModel model) throws IOException {
88          // Store parameters in instance variables to have them available in all methods:
89          this.reader = reader;
90          this.model = model;
91          
92          // Process JPhyloIO events:
93          while (reader.hasNextEvent()) {  // This loop will run until all events of the JPhyloIO reader are consumed (and the end of the 
94                                             // document is reached). 
95              JPhyloIOEvent event = reader.next();  // Read the next event from the JPhyloIO reader.
96          if (event.getType().getTopologyType().equals(EventTopologyType.START)) {
97                  // We are only interested in start events, since all end events will already be consumed within the loop.
98                  // Other events (e.g. for comments) with the topology type SOLE will just be ignored here.
99              
100            switch (event.getType().getContentType()) {
101                  // This switch statement handles all types of elements on the top level that are 
102                // relevant for this application. The others are skipped in the default block.
103              
104              case DOCUMENT:
105                  model.setRoot(null);  // Remove possible previous data from the model instance.
106                  break;
107                  
108              case TREE_NETWORK_GROUP:
109                  readTreeNetworkGroup();
110                  break;
111                  
112              default:  // Here possible additional events on the top level are handled.
113                  JPhyloIOReadingUtils.reachElementEnd(reader);
114                  break;
115            }
116              }
117          }
118      }
119      
120      
121      /**
122       * Processes the events related to a tree/network group (see grammar node {@code TreeNetworkGroup} in 
123       * {@link JPhyloIOEventReader}). It will delegate reading the first tree to {@link #readTree()} and
124       * ignore all possible subsequent trees as well as all networks and tree/network sets.
125       * 
126       * @throws IOException if an exception is thrown by underlying <i>JPhyloIO</i> classes
127       */
128      private void readTreeNetworkGroup() throws IOException {
129          // Process JPhyloIO events:
130          JPhyloIOEvent event = reader.next();  
131          while ((!event.getType().getTopologyType().equals(EventTopologyType.END))) { 
132          if (event.getType().getTopologyType().equals(EventTopologyType.START)) {
133            if (event.getType().getContentType().equals(EventContentType.TREE)) {  // This application is only interested in tree events 
134                                                                                   // and will skip others on this level (e.g. networks).
135              if (model.getRoot() == null) {
136                  readTree();
137              }
138                  else {
139                      LabeledIDEvent treeEvent = event.asLabeledIDEvent();
140                      System.out.println("Since this application does not support multiple trees, the tree with the ID "
141                              + treeEvent.getID() + " and the name \"" + treeEvent.getLabel() + "\" was skipped.");
142                  }
143            }
144            else {
145                  JPhyloIOReadingUtils.reachElementEnd(reader);
146              }  // Otherwise SOLE elements are skipped.
147          }
148              event = reader.next();  // Read the next event from the JPhyloIO reader.          
149          }
150      }
151      
152      
153      /**
154       * Processes the events related to a tree (see grammar node {@code Tree} in 
155       * {@link JPhyloIOEventReader}).
156       * <p>
157       * Since <i>JPhyloIO</i> events describing tree nodes and edges are not hierarchically nested but all 
158       * node and edge events are on the same level, the hierarchical tree needs to be reconstructed. To 
159       * achieve this {@link #idToNodeMap} is subsequently filled with node objects identified by their 
160       * <i>JPhyloIO</i> IDs as respective node events are encountered. Each time an edge event is 
161       * encountered, the two referenced nodes are connected (by setting their {@code parent) and 
162       * {@code children} properties. (Accessing the referenced nodes is done by searching 
163       * {@link #idToNodeMap}.) The list {@link #possiblePaintStartIDs} is at the same time used to store all
164       * nodes that do not yet have a parent assigned. If the represented structure is really a tree and not
165       * a network, only one event will be left in this list after all events have been processed.
166       * <p>
167       * Note that the algorithm as it is implemented here is only necessary, if a hierarchical business model 
168       * is used. <i>JPhyloIO</i> (as well as <i>NeXML</i>) rely on a non-hierarchical representation that 
169       * also allows to model phylogenetic networks. For applications that use a non-hierarchical model as 
170       * well, reading data would be straight-forward. If you are developing an application relying on a 
171       * hierarchical model, you can use the implementation provided here as a basis for your application reader.
172       * 
173       * @throws IOException if an exception is thrown by underlying <i>JPhyloIO</i> classes
174       */
175      private void readTree() throws IOException {
176          possiblePaintStartIDs.clear();
177          idToNodeMap.clear();
178          
179      JPhyloIOEvent event = reader.next();
180      while (!event.getType().getTopologyType().equals(EventTopologyType.END)) {
181          if (event.getType().getTopologyType().equals(EventTopologyType.START)) {
182              if (event.getType().getContentType().equals(EventContentType.NODE)) {
183                  readNode(event.asNodeEvent());
184              }
185              else if (event.getType().getContentType().equals(EventContentType.EDGE) || event.getType().getContentType().equals(EventContentType.ROOT_EDGE)) {
186                  readEdge(event.asEdgeEvent());
187              }
188            else {  // Possible additional element, which is not read
189              JPhyloIOReadingUtils.reachElementEnd(reader);
190            }
191          }
192        event = reader.next();
193      }
194      
195      if (possiblePaintStartIDs.size() > 1) {
196          throw new IOException("More than one root node was found.");  // Would only happen if the tree is actually a network (not starting with the according NETWORK event).
197      }
198      
199      model.setRoot(idToNodeMap.get(possiblePaintStartIDs.get(0)));
200    }
201      
202      
203      private void readNode(NodeEvent nodeEvent) throws IOException {
204          DefaultMutableTreeNode node = new DefaultMutableTreeNode(nodeEvent.getLabel());
205          idToNodeMap.put(nodeEvent.getID(), node);
206          possiblePaintStartIDs.add(nodeEvent.getID());
207          
208          readNodeContents(node);
209    }
210      
211      
212      /**
213       * Since this application does not model any metadata, this method just skips all events nested under the node event.
214       * <p>
215       * This method is defined to be overwritten in the metadata demo application.
216       * 
217       * @param node the node object that could model the contents
218       * @throws IOException
219       */
220      protected void readNodeContents(DefaultMutableTreeNode node) throws IOException {
221      JPhyloIOReadingUtils.reachElementEnd(reader);  // Consume possible nested events.
222      }
223      
224      
225      private void readEdge(EdgeEvent edgeEvent) throws IOException {
226          DefaultMutableTreeNode targetNode = idToNodeMap.get(edgeEvent.getTargetID());
227          DefaultMutableTreeNode sourceNode = idToNodeMap.get(edgeEvent.getSourceID());       
228          
229          if (targetNode.getParent() == null) {
230              if (sourceNode != null) {
231                  sourceNode.insert(targetNode, sourceNode.getChildCount());  // Will also set sourceNode as the parent of targetNode.
232                  possiblePaintStartIDs.remove(edgeEvent.getTargetID());  // Nodes that have not yet been referenced as target are possible roots.
233              }
234          }
235          else {  // Edge is network edge
236              throw new IOException("Multiple parent nodes were specified for the node \"" + edgeEvent.getTargetID() + 
237                      ", but networks can not be displayed by this application.");
238          }
239          
240          readEdgeContents(targetNode);
241    }
242      
243      
244      /**
245       * Since this application does not model any metadata, this method just skips all events nested under the edge event.
246       * <p>
247       * This method is defined to be overwritten in the metadata demo application.
248       * 
249       * @param targetNode the target node object linked to the current edge
250       * @throws IOException
251       */
252      protected void readEdgeContents(DefaultMutableTreeNode targetNode) throws IOException {
253      JPhyloIOReadingUtils.reachElementEnd(reader);  // Consume possible nested events.
254      }
255  }


feed icon

sventon 2.5.1

Valid XHTML 1.0 Strict   CSS ist valide!
JPhyloIO icon
bioinfweb RSS feed JPhyloIO on ResearchGate bioinfweb on twitter JPhyloIO on GitHub

JPhyloIO poster ECCB 2016 Conference poster at ECCB Sep 2016

bioinfweb - Biology & Informatics Website