Coverage Report - org.dishevelled.graph.io.graphml.GraphMLReader
 
Classes in this File Line Coverage Branch Coverage Complexity
GraphMLReader
68%
30/44
66%
8/12
2.75
GraphMLReader$1
N/A
N/A
2.75
GraphMLReader$GraphHandler
100%
21/21
90%
9/10
2.75
GraphMLReader$GraphHandler$EdgeHandler
100%
22/22
100%
10/10
2.75
GraphMLReader$GraphHandler$EdgePlaceholder
100%
10/10
N/A
2.75
GraphMLReader$GraphHandler$NodeHandler
100%
15/15
100%
6/6
2.75
 
 1  
 /*
 2  
 
 3  
     dsh-graph-io  Directed graph readers and writers.
 4  
     Copyright (c) 2008-2013 held jointly by the individual authors.
 5  
 
 6  
     This library is free software; you can redistribute it and/or modify it
 7  
     under the terms of the GNU Lesser General Public License as published
 8  
     by the Free Software Foundation; either version 3 of the License, or (at
 9  
     your option) any later version.
 10  
 
 11  
     This library is distributed in the hope that it will be useful, but WITHOUT
 12  
     ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
 13  
     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 14  
     License for more details.
 15  
 
 16  
     You should have received a copy of the GNU Lesser General Public License
 17  
     along with this library;  if not, write to the Free Software Foundation,
 18  
     Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
 19  
 
 20  
     > http://www.fsf.org/licensing/licenses/lgpl.html
 21  
     > http://www.opensource.org/licenses/lgpl-license.php
 22  
 
 23  
 */
 24  
 package org.dishevelled.graph.io.graphml;
 25  
 
 26  
 import java.net.URL;
 27  
 
 28  
 import java.io.BufferedInputStream;
 29  
 import java.io.File;
 30  
 import java.io.FileInputStream;
 31  
 import java.io.IOException;
 32  
 import java.io.InputStream;
 33  
 
 34  
 import java.util.ArrayList;
 35  
 import java.util.HashMap;
 36  
 import java.util.List;
 37  
 import java.util.Map;
 38  
 
 39  
 import net.sf.stax.SAX2StAXAdaptor;
 40  
 import net.sf.stax.StAXContentHandler;
 41  
 import net.sf.stax.StAXContentHandlerBase;
 42  
 import net.sf.stax.StAXContext;
 43  
 import net.sf.stax.StAXDelegationContext;
 44  
 
 45  
 import org.xml.sax.XMLReader;
 46  
 import org.xml.sax.Attributes;
 47  
 import org.xml.sax.InputSource;
 48  
 import org.xml.sax.SAXException;
 49  
 import org.xml.sax.ContentHandler;
 50  
 
 51  
 import org.dishevelled.graph.Graph;
 52  
 import org.dishevelled.graph.Node;
 53  
 
 54  
 import org.dishevelled.graph.impl.GraphUtils;
 55  
 
 56  
 import org.dishevelled.graph.io.GraphReader;
 57  
 
 58  
 /**
 59  
  * GraphML reader.
 60  
  *
 61  
  * @param <N> node value type
 62  
  * @param <E> edge value type
 63  
  * @author  Michael Heuer
 64  
  * @version $Revision$ $Date$
 65  
  */
 66  166
 public final class GraphMLReader<N, E>
 67  
     implements GraphReader<N, E>
 68  
 {
 69  
     /** XML reader. */
 70  
     private final XMLReader xmlReader;
 71  
 
 72  
     /** Optional node value handler.  */
 73  
     private StAXContentHandler nodeValueHandler;
 74  
 
 75  
     /** Optional edge value handler. */
 76  
     private StAXContentHandler edgeValueHandler;
 77  
 
 78  
 
 79  
     /**
 80  
      * Create a new GraphML reader with the specified XML reader.
 81  
      *
 82  
      * @param xmlReader XML reader, must not be null
 83  
      */
 84  
     public GraphMLReader(final XMLReader xmlReader)
 85  22
     {
 86  22
         if (xmlReader == null)
 87  
         {
 88  1
             throw new IllegalArgumentException("xmlReader must not be null");
 89  
         }
 90  21
         this.xmlReader = xmlReader;
 91  21
     }
 92  
 
 93  
 
 94  
     /**
 95  
      * Set the node value handler for this GraphML reader to <code>nodeValueHandler</code>.
 96  
      * <p>
 97  
      * The specified node value handler will be delegated to with the XML subtree within the
 98  
      * <code>&lt;node&gt;</code> element, typically with one or more <code>&lt;data&gt;</code>
 99  
      * elements.
 100  
      * </p>
 101  
      *
 102  
      * @param nodeValueHandler node value handler
 103  
      */
 104  
     public void setNodeValueHandler(final StAXContentHandler nodeValueHandler)
 105  
     {
 106  8
         this.nodeValueHandler = nodeValueHandler;
 107  8
     }
 108  
 
 109  
     /**
 110  
      * Set the edge value handler for this GraphML reader to <code>edgeValueHandler</code>.
 111  
      * <p>
 112  
      * The specified edge value handler will be delegated to with the XML subtree within the
 113  
      * <code>&lt;edge&gt;</code> element, typically with one or more <code>&lt;data&gt;</code>
 114  
      * elements.
 115  
      * </p>
 116  
      *
 117  
      * @param edgeValueHandler edge value handler
 118  
      */
 119  
     public void setEdgeValueHandler(final StAXContentHandler edgeValueHandler)
 120  
     {
 121  8
         this.edgeValueHandler = edgeValueHandler;
 122  8
     }
 123  
 
 124  
     /** {@inheritDoc} */
 125  
     public Graph<N, E> read(final File file)
 126  
         throws IOException
 127  
     {
 128  3
         if (file == null)
 129  
         {
 130  1
             throw new IllegalArgumentException("file must not be null");
 131  
         }
 132  2
         BufferedInputStream inputStream = null;
 133  
         try
 134  
         {
 135  2
             inputStream = new BufferedInputStream(new FileInputStream(file));
 136  2
             return read(inputStream);
 137  
         }
 138  0
         catch (IOException e)
 139  
         {
 140  0
             throw e;
 141  
         }
 142  
         finally
 143  
         {
 144  0
             try
 145  
             {
 146  2
                 if (inputStream != null)
 147  
                 {
 148  2
                     inputStream.close();
 149  
                 }
 150  
             }
 151  0
             catch (IOException e)
 152  
             {
 153  
                 // ignore
 154  4
             }
 155  
         }
 156  
     }
 157  
 
 158  
     /** {@inheritDoc} */
 159  
     public Graph<N, E> read(final InputStream inputStream)
 160  
         throws IOException
 161  
     {
 162  17
         if (inputStream == null)
 163  
         {
 164  1
             throw new IllegalArgumentException("inputStream must not be null");
 165  
         }
 166  16
         InputSource inputSource = new InputSource(inputStream);
 167  16
         GraphHandler graphHandler = new GraphHandler();
 168  16
         ContentHandler contentHandler = new SAX2StAXAdaptor(graphHandler);
 169  16
         xmlReader.setContentHandler(contentHandler);
 170  
         try
 171  
         {
 172  16
             xmlReader.parse(inputSource);
 173  14
             return graphHandler.getGraph();
 174  
         }
 175  2
         catch (SAXException e)
 176  
         {
 177  
             //throw new IOException(e); jdk 1.6+
 178  2
             throw new IOException(e.getMessage());
 179  
         }
 180  
     }
 181  
 
 182  
     /** {@inheritDoc} */
 183  
     public Graph<N, E> read(final URL url)
 184  
         throws IOException
 185  
     {
 186  1
         if (url == null)
 187  
         {
 188  1
             throw new IllegalArgumentException("url must not be null");
 189  
         }
 190  0
         InputStream inputStream = null;
 191  
         try
 192  
         {
 193  0
             inputStream = url.openStream();
 194  0
             return read(inputStream);
 195  
         }
 196  0
         catch (IOException e)
 197  
         {
 198  0
             throw e;
 199  
         }
 200  
         finally
 201  
         {
 202  0
             try
 203  
             {
 204  0
                 if (inputStream != null)
 205  
                 {
 206  0
                     inputStream.close();
 207  
                 }
 208  
             }
 209  0
             catch (IOException e)
 210  
             {
 211  
                 // ignore
 212  0
             }
 213  
         }
 214  
     }
 215  
 
 216  
     /**
 217  
      * Graph element handler.
 218  
      */
 219  669
     private class GraphHandler
 220  
         extends StAXContentHandlerBase
 221  
     {
 222  
         /** Graph. */
 223  16
         private final Graph<N, E> graph = GraphUtils.createGraph();
 224  
 
 225  
         /** Nodes keyed by id. */
 226  16
         private final Map<String, Node<N, E>> nodes = new HashMap<String, Node<N, E>>();
 227  
 
 228  
         /** List of deferred edges. */
 229  16
         private final List<EdgePlaceholder> deferredEdges = new ArrayList<EdgePlaceholder>();
 230  
 
 231  
         /** Node handler. */
 232  16
         private final NodeHandler nodeHandler = new NodeHandler();
 233  
 
 234  
         /** Edge handler. */
 235  16
         private final EdgeHandler edgeHandler = new EdgeHandler();
 236  
 
 237  
 
 238  
         /** {@inheritDoc} */
 239  
         public void startElement(final String nsURI,
 240  
                                  final String localName,
 241  
                                  final String qName,
 242  
                                  final Attributes attrs,
 243  
                                  final StAXDelegationContext dctx)
 244  
             throws SAXException
 245  
         {
 246  274
             if ("node".equals(qName))
 247  
             {
 248  47
                 dctx.delegate(nodeHandler);
 249  
             }
 250  227
             else if ("edge".equals(qName))
 251  
             {
 252  181
                 dctx.delegate(edgeHandler);
 253  
             }
 254  274
         }
 255  
 
 256  
         /** {@inheritDoc} */
 257  
         public Object endTree(final StAXContext context)
 258  
             throws SAXException
 259  
         {
 260  15
             for (EdgePlaceholder edge : deferredEdges)
 261  
             {
 262  9
                 Node<N, E> source = nodes.get(edge.getSourceId());
 263  9
                 Node<N, E> target = nodes.get(edge.getTargetId());
 264  9
                 if (source != null && target != null)
 265  
                 {
 266  8
                     graph.createEdge(source, target, edge.getValue());
 267  
                 }
 268  
                 else
 269  
                 {
 270  1
                     throw new SAXException("could not resolve deferred edge, id=" + edge.getEdgeId()
 271  
                                            + " source=" + edge.getSourceId() + " target=" + edge.getTargetId());
 272  
                 }
 273  8
             }
 274  14
             return graph;
 275  
         }
 276  
 
 277  
         /**
 278  
          * Return the graph for this graph element handler.
 279  
          *
 280  
          * @return the graph for this graph element handler
 281  
          */
 282  
         Graph<N, E> getGraph()
 283  
         {
 284  14
             return graph;
 285  
         }
 286  
 
 287  
         /**
 288  
          * Node element handler.
 289  
          */
 290  32
         private class NodeHandler
 291  
             extends StAXContentHandlerBase
 292  
         {
 293  
             /** Node id. */
 294  
             private String id;
 295  
 
 296  
             /** Node value. */
 297  
             private N value;
 298  
 
 299  
 
 300  
             /** {@inheritDoc} */
 301  
             public void startTree(final StAXContext context)
 302  
                 throws SAXException
 303  
             {
 304  47
                 id = null;
 305  47
                 value = null;
 306  47
             }
 307  
 
 308  
             /** {@inheritDoc} */
 309  
             public void startElement(final String nsURI,
 310  
                                      final String localName,
 311  
                                      final String qName,
 312  
                                      final Attributes attrs,
 313  
                                      final StAXDelegationContext dctx)
 314  
                 throws SAXException
 315  
             {
 316  74
                 if ("node".equals(qName))
 317  
                 {
 318  47
                     id = attrs.getValue("id");
 319  
                 }
 320  
                 else
 321  
                 {
 322  27
                     if (nodeValueHandler != null)
 323  
                     {
 324  13
                         dctx.delegate(nodeValueHandler);
 325  
                     }
 326  
                 }
 327  74
             }
 328  
 
 329  
             /** {@inheritDoc} */
 330  
             public void endElement(final String nsURI,
 331  
                                    final String localName,
 332  
                                    final String qName,
 333  
                                    final Object result,
 334  
                                    final StAXContext context)
 335  
                 throws SAXException
 336  
             {
 337  74
                 if ("node".equals(qName))
 338  
                 {
 339  47
                     Node<N, E> node = graph.createNode(value);
 340  47
                     nodes.put(id, node);
 341  47
                 }
 342  
                 else
 343  
                 {
 344  27
                     value = (N) result;
 345  
                 }
 346  74
             }
 347  
         }
 348  
 
 349  
         /**
 350  
          * Edge element handler.
 351  
          */
 352  32
         private class EdgeHandler
 353  
             extends StAXContentHandlerBase
 354  
         {
 355  
             /** Edge id. */
 356  
             private String edgeId;
 357  
 
 358  
             /** Source id. */
 359  
             private String sourceId;
 360  
 
 361  
             /** Target id. */
 362  
             private String targetId;
 363  
 
 364  
             /** Edge value. */
 365  
             private E value;
 366  
 
 367  
 
 368  
             /** {@inheritDoc} */
 369  
             public void startTree(final StAXContext context)
 370  
                 throws SAXException
 371  
             {
 372  181
                 edgeId = null;
 373  181
                 sourceId = null;
 374  181
                 targetId = null;
 375  181
                 value = null;
 376  181
             }
 377  
 
 378  
             /** {@inheritDoc} */
 379  
             public void startElement(final String nsURI,
 380  
                                      final String localName,
 381  
                                      final String qName,
 382  
                                      final Attributes attrs,
 383  
                                      final StAXDelegationContext dctx)
 384  
                 throws SAXException
 385  
             {
 386  266
                 if ("edge".equals(qName))
 387  
                 {
 388  181
                     edgeId = attrs.getValue("id");
 389  181
                     sourceId = attrs.getValue("source");
 390  181
                     targetId = attrs.getValue("target");
 391  
                 }
 392  
                 else
 393  
                 {
 394  85
                     if (edgeValueHandler != null)
 395  
                     {
 396  41
                         dctx.delegate(edgeValueHandler);
 397  
                     }
 398  
                 }
 399  266
             }
 400  
 
 401  
             /** {@inheritDoc} */
 402  
             public void endElement(final String nsURI,
 403  
                                    final String localName,
 404  
                                    final String qName,
 405  
                                    final Object result,
 406  
                                    final StAXContext context)
 407  
                 throws SAXException
 408  
             {
 409  266
                 if ("edge".equals(qName))
 410  
                 {
 411  181
                     Node<N, E> source = nodes.get(sourceId);
 412  181
                     Node<N, E> target = nodes.get(targetId);
 413  181
                     if (source != null && target != null)
 414  
                     {
 415  165
                         graph.createEdge(source, target, value);
 416  
                     }
 417  
                     else
 418  
                     {
 419  16
                         deferredEdges.add(new EdgePlaceholder(edgeId, sourceId, targetId, value));
 420  
                     }
 421  181
                 }
 422  
                 else
 423  
                 {
 424  85
                     value = (E) result;
 425  
                 }
 426  266
             }
 427  
         }
 428  
 
 429  
         /**
 430  
          * Edge placeholder.
 431  
          */
 432  16
         private class EdgePlaceholder
 433  
         {
 434  
             /** Edge id. */
 435  
             private final String edgeId;
 436  
 
 437  
             /** Source id. */
 438  
             private final String sourceId;
 439  
 
 440  
             /** Target id. */
 441  
             private final String targetId;
 442  
 
 443  
             /** Edge value. */
 444  
             private final E value;
 445  
 
 446  
 
 447  
             /**
 448  
              * Create a new edge placeholder.
 449  
              *
 450  
              * @param edgeId edge id
 451  
              * @param sourceId source id
 452  
              * @param targetId target id
 453  
              * @param value edge value
 454  
              */
 455  
             EdgePlaceholder(final String edgeId, final String sourceId, final String targetId, final E value)
 456  16
             {
 457  16
                 this.edgeId = edgeId;
 458  16
                 this.sourceId = sourceId;
 459  16
                 this.targetId = targetId;
 460  16
                 this.value = value;
 461  16
             }
 462  
 
 463  
             /**
 464  
              * Return the edge id.
 465  
              *
 466  
              * @return the edge id
 467  
              */
 468  
             String getEdgeId()
 469  
             {
 470  1
                 return edgeId;
 471  
             }
 472  
 
 473  
             /**
 474  
              * Return the source id.
 475  
              *
 476  
              * @return the source id
 477  
              */
 478  
             String getSourceId()
 479  
             {
 480  10
                 return sourceId;
 481  
             }
 482  
 
 483  
             /**
 484  
              * Return the target id.
 485  
              *
 486  
              * @return the target id
 487  
              */
 488  
             String getTargetId()
 489  
             {
 490  10
                 return targetId;
 491  
             }
 492  
 
 493  
             /**
 494  
              * Return the edge value.
 495  
              *
 496  
              * @return the edge value
 497  
              */
 498  
             E getValue()
 499  
             {
 500  8
                 return value;
 501  
             }
 502  
         }
 503  
     }
 504  
 }