Java tutorial
/* * Copyright (c) 2008, the JUNG Project and the Regents of the University * of California * All rights reserved. * * This software is open-source under the BSD license; see either * "license.txt" or * http://jung.sourceforge.net/license.txt for a description. */ package edu.uci.ics.jung.io.graphml; import java.io.IOException; import java.io.Reader; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import org.apache.commons.collections15.Transformer; import edu.uci.ics.jung.graph.Hypergraph; import edu.uci.ics.jung.io.GraphReader; import edu.uci.ics.jung.io.GraphIOException; import edu.uci.ics.jung.io.graphml.parser.ElementParserRegistry; import edu.uci.ics.jung.io.graphml.parser.GraphMLEventFilter; /** * Reads in data from a GraphML-formatted file and generates graphs based on * that data. Does not currently support nested graphs. * <p/> * <p/> * Note that the user is responsible for supplying a graph * <code>Transformer</code> that will create graphs capable of supporting the * edge types in the supplied GraphML file. If the graph generated by the * <code>Factory</code> is not compatible (for example: if the graph does not * accept directed edges, and the GraphML file contains a directed edge) then * the results are graph-implementation-dependent. * * @author Nathan Mittler - nathan.mittler@gmail.com * * @param <G> * The graph type to be read from the GraphML file * @param <V> * The vertex type used by the graph * @param <E> * The edge type used by the graph * @see "http://graphml.graphdrawing.org/specification.html" */ public class GraphMLReader2<G extends Hypergraph<V, E>, V, E> implements GraphReader<G, V, E> { protected XMLEventReader xmlEventReader; protected Reader fileReader; protected Transformer<GraphMetadata, G> graphTransformer; protected Transformer<NodeMetadata, V> vertexTransformer; protected Transformer<EdgeMetadata, E> edgeTransformer; protected Transformer<HyperEdgeMetadata, E> hyperEdgeTransformer; protected boolean initialized; final protected GraphMLDocument document = new GraphMLDocument(); final protected ElementParserRegistry<G, V, E> parserRegistry; /** * Constructs a GraphML reader around the given reader. This constructor * requires the user to supply transformation functions to convert from the * GraphML metadata to Graph, Vertex, Edge instances. These transformer * functions can be used as purely factories (i.e. the metadata is * disregarded) or can use the metadata to set particular fields in the * objects. * * @param fileReader the reader for the input GraphML document. * @param graphTransformer Transformation function to convert from GraphML GraphMetadata * to graph objects. This must be non-null. * @param vertexTransformer Transformation function to convert from GraphML NodeMetadata * to vertex objects. This must be non-null. * @param edgeTransformer Transformation function to convert from GraphML EdgeMetadata * to edge objects. This must be non-null. * @param hyperEdgeTransformer Transformation function to convert from GraphML * HyperEdgeMetadata to edge objects. This must be non-null. * @throws IllegalArgumentException thrown if any of the arguments are null. */ public GraphMLReader2(Reader fileReader, Transformer<GraphMetadata, G> graphTransformer, Transformer<NodeMetadata, V> vertexTransformer, Transformer<EdgeMetadata, E> edgeTransformer, Transformer<HyperEdgeMetadata, E> hyperEdgeTransformer) { if (fileReader == null) { throw new IllegalArgumentException("Argument fileReader must be non-null"); } if (graphTransformer == null) { throw new IllegalArgumentException("Argument graphTransformer must be non-null"); } if (vertexTransformer == null) { throw new IllegalArgumentException("Argument vertexTransformer must be non-null"); } if (edgeTransformer == null) { throw new IllegalArgumentException("Argument edgeTransformer must be non-null"); } if (hyperEdgeTransformer == null) { throw new IllegalArgumentException("Argument hyperEdgeTransformer must be non-null"); } this.fileReader = fileReader; this.graphTransformer = graphTransformer; this.vertexTransformer = vertexTransformer; this.edgeTransformer = edgeTransformer; this.hyperEdgeTransformer = hyperEdgeTransformer; // Create the parser registry. this.parserRegistry = new ElementParserRegistry<G, V, E>(document.getKeyMap(), graphTransformer, vertexTransformer, edgeTransformer, hyperEdgeTransformer); } /** * Gets the current transformer that is being used for graph objects. * * @return the current transformer. */ public Transformer<GraphMetadata, G> getGraphTransformer() { return graphTransformer; } /** * Gets the current transformer that is being used for vertex objects. * * @return the current transformer. */ public Transformer<NodeMetadata, V> getVertexTransformer() { return vertexTransformer; } /** * Gets the current transformer that is being used for edge objects. * * @return the current transformer. */ public Transformer<EdgeMetadata, E> getEdgeTransformer() { return edgeTransformer; } /** * Gets the current transformer that is being used for hyperedge objects. * * @return the current transformer. */ public Transformer<HyperEdgeMetadata, E> getHyperEdgeTransformer() { return hyperEdgeTransformer; } /** * Verifies the object state and initializes this reader. All transformer * properties must be set and be non-null or a <code>GraphReaderException * </code> will be thrown. This method may be called more than once. * Successive calls will have no effect. * * @throws edu.uci.ics.jung.io.GraphIOException thrown if an error occurred. */ public void init() throws GraphIOException { try { if (!initialized) { // Create the event reader. XMLInputFactory factory = XMLInputFactory.newInstance(); xmlEventReader = factory.createXMLEventReader(fileReader); xmlEventReader = factory.createFilteredReader(xmlEventReader, new GraphMLEventFilter()); initialized = true; } } catch (Exception e) { ExceptionConverter.convert(e); } } /** * Closes the GraphML reader and disposes of any resources. * * @throws edu.uci.ics.jung.io.GraphIOException thrown if an error occurs. */ public void close() throws GraphIOException { try { // Clear the contents of the document. document.clear(); if (xmlEventReader != null) { xmlEventReader.close(); } if (fileReader != null) { fileReader.close(); } } catch (IOException e) { throw new GraphIOException(e); } catch (XMLStreamException e) { throw new GraphIOException(e); } finally { fileReader = null; xmlEventReader = null; graphTransformer = null; vertexTransformer = null; edgeTransformer = null; hyperEdgeTransformer = null; } } /** * Returns the object that contains the metadata read in from the GraphML * document * * @return the GraphML document */ public GraphMLDocument getGraphMLDocument() { return document; } /** * Reads a single graph object from the GraphML document. Automatically * calls <code>init</code> to initialize the state of the reader. * * @return the graph that was read if one was found, otherwise null. */ @SuppressWarnings("unchecked") public G readGraph() throws GraphIOException { try { // Initialize if not already. init(); while (xmlEventReader.hasNext()) { XMLEvent event = xmlEventReader.nextEvent(); if (event.isStartElement()) { StartElement element = (StartElement) event; String name = element.getName().getLocalPart(); // The element should be one of: key, graph, graphml if (GraphMLConstants.KEY_NAME.equals(name)) { // Parse the key object. Key key = (Key) parserRegistry.getParser(name).parse(xmlEventReader, element); // Add the key to the key map. document.getKeyMap().addKey(key); } else if (GraphMLConstants.GRAPH_NAME.equals(name)) { // Parse the graph. GraphMetadata graph = (GraphMetadata) parserRegistry.getParser(name).parse(xmlEventReader, element); // Add it to the graph metadata list. document.getGraphMetadata().add(graph); // Return the graph object. return (G) graph.getGraph(); } else if (GraphMLConstants.GRAPHML_NAME.equals(name)) { // Ignore the graphML object. } else { // Encounted an unknown element - just skip by it. parserRegistry.getUnknownElementParser().parse(xmlEventReader, element); } } else if (event.isEndDocument()) { break; } } } catch (Exception e) { ExceptionConverter.convert(e); } // We didn't read anything from the document. throw new GraphIOException("Unable to read Graph from document - the document could be empty"); } }