Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* This file is part of GraphStream .
*
* GraphStream is a library whose purpose is to handle static or dynamic
* graph, create them from scratch, file or any source and display them.
*
* This program is free software distributed under the terms of two licenses, the
* CeCILL-C license that fits European law, and the GNU Lesser General Public
* License. You can use, modify and/ or redistribute the software under the terms
* of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
* URL or under the terms of the GNU LGPL as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
*/
/**
* @since 2011-09-21
*
* @author Guilhelm Savin
* @author Hicham Brahimi
*/
package org.graphstream.stream.file;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.Stack;
import java.util.logging.Logger;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.graphstream.stream.SourceBase;
/**
* Base for XML-based file format. It uses an xml events stream (
* {@link javax.xml.stream}). One who want to define a new xml-based fiel source
* has to define actions after the document start and before the document end.
* The {@link #nextEvents()}, called between start and end, has to be defined
* too.
*
* @author Guilhelm Savin
*/
public abstract class FileSourceXML extends SourceBase implements FileSource, XMLStreamConstants {
private static final Logger LOGGER = Logger.getLogger(FileSourceXML.class.getName());
/**
* XML events stream. Should not be used directly but with
* {@link #getNextEvent()}.
*/
protected XMLEventReader reader;
/*
* Used to allow 'pushback' of events.
*/
private Stack events;
protected boolean strictMode = true;
protected FileSourceXML() {
events = new Stack<>();
}
/**
* If strict mode is enabled, will produce errors while encountering unexpected
* attributes or elements. This is enabled by default.
*
* @return true if strict mode is enabled
*/
public boolean isStrictMode() {
return strictMode;
}
public void setStrictMode(boolean strictMode) {
this.strictMode = strictMode;
}
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#readAll(java.lang.String)
*/
public void readAll(String fileName) throws IOException {
readAll(new FileReader(fileName));
}
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#readAll(java.net.URL)
*/
public void readAll(URL url) throws IOException {
readAll(url.openStream());
}
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#readAll(java.io.InputStream)
*/
public void readAll(InputStream stream) throws IOException {
readAll(new InputStreamReader(stream));
}
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#readAll(java.io.Reader)
*/
public void readAll(Reader reader) throws IOException {
begin(reader);
while (nextEvents())
;
end();
}
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#begin(java.lang.String)
*/
public void begin(String fileName) throws IOException {
begin(new FileReader(fileName));
}
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#begin(java.net.URL)
*/
public void begin(URL url) throws IOException {
begin(url.openStream());
}
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#begin(java.io.InputStream)
*/
public void begin(InputStream stream) throws IOException {
begin(new InputStreamReader(stream));
}
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#begin(java.io.Reader)
*/
public void begin(Reader reader) throws IOException {
openStream(reader);
}
/**
* Called after the event
* {@link javax.xml.stream.events.XMLEvent#START_DOCUMENT} has been received.
*
* @throws IOException
* @throws XMLStreamException
*/
protected abstract void afterStartDocument() throws IOException, XMLStreamException;
/**
* Called before trying to receive the events
* {@link javax.xml.stream.events.XMLEvent#END_DOCUMENT}.
*
* @throws IOException
* @throws XMLStreamException
*/
protected abstract void beforeEndDocument() throws IOException, XMLStreamException;
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#nextEvents()
*/
public abstract boolean nextEvents() throws IOException;
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#nextStep()
*/
public boolean nextStep() throws IOException {
return nextEvents();
}
/*
* (non-Javadoc)
*
* @see org.graphstream.stream.file.FileSource#end()
*/
public void end() throws IOException {
closeStream();
}
/**
* Get a new event from the stream. This method has to be used to allow the
* {@link #pushback(XMLEvent)} method to work.
*
* @return the next event in the stream
* @throws IOException
* @throws XMLStreamException
*/
protected XMLEvent getNextEvent() throws IOException, XMLStreamException {
skipWhiteSpaces();
if (events.size() > 0)
return events.pop();
return reader.nextEvent();
}
/**
* Pushback an event in the stream.
*
* @param e
* the event
*/
protected void pushback(XMLEvent e) {
events.push(e);
}
/**
* Generate a new parse exception.
*
* @param e
* event producing an error
* @param critical
* if true, will always produce an exception, else if strict mode is
* disable, will only produce a warning
* @param msg
* message to put in the exception
* @param args
* arguments of the message
*/
protected void newParseError(XMLEvent e, boolean critical, String msg, Object... args) throws XMLStreamException {
if (!critical && !strictMode) {
LOGGER.warning(String.format(msg, args));
} else {
throw new XMLStreamException(String.format(msg, args), e.getLocation());
}
}
/**
* Check is an event has an expected type and name.
*
* @param e
* event to check
* @param type
* expected type
* @param name
* expected name
* @return true is type and name are valid
*/
protected boolean isEvent(XMLEvent e, int type, String name) {
boolean valid = e.getEventType() == type;
if (valid) {
switch (type) {
case START_ELEMENT:
valid = e.asStartElement().getName().getLocalPart().equals(name);
break;
case END_ELEMENT:
valid = e.asEndElement().getName().getLocalPart().equals(name);
break;
case ATTRIBUTE:
valid = ((Attribute) e).getName().getLocalPart().equals(name);
break;
case CHARACTERS:
case NAMESPACE:
case PROCESSING_INSTRUCTION:
case COMMENT:
case START_DOCUMENT:
case END_DOCUMENT:
case DTD:
}
}
return valid;
}
/**
* Check is the event has valid type and name. If not, a new exception is
* thrown.
*
* @param e
* event to check
* @param type
* expected type
* @param name
* expected name
* @throws XMLStreamException
* if event has invalid type or name
*/
protected void checkValid(XMLEvent e, int type, String name) throws XMLStreamException {
boolean valid = isEvent(e, type, name);
if (!valid)
newParseError(e, true, "expecting %s, got %s", gotWhat(type, name), gotWhat(e));
}
private String gotWhat(XMLEvent e) {
String v = null;
switch (e.getEventType()) {
case START_ELEMENT:
v = e.asStartElement().getName().getLocalPart();
break;
case END_ELEMENT:
v = e.asEndElement().getName().getLocalPart();
break;
case ATTRIBUTE:
v = ((Attribute) e).getName().getLocalPart();
break;
}
return gotWhat(e.getEventType(), v);
}
private String gotWhat(int type, String v) {
switch (type) {
case START_ELEMENT:
return String.format("'<%s>'", v);
case END_ELEMENT:
return String.format("''", v);
case ATTRIBUTE:
return String.format("attribute '%s'", v);
case NAMESPACE:
return "namespace";
case PROCESSING_INSTRUCTION:
return "processing instruction";
case COMMENT:
return "comment";
case START_DOCUMENT:
return "document start";
case END_DOCUMENT:
return "document end";
case DTD:
return "dtd";
case CHARACTERS:
return "characters";
default:
return "UNKNOWN";
}
}
private void skipWhiteSpaces() throws IOException, XMLStreamException {
XMLEvent e;
do {
if (events.size() > 0)
e = events.pop();
else
e = reader.nextEvent();
} while (isEvent(e, XMLEvent.CHARACTERS, null) && e.asCharacters().getData().matches("^\\s*$"));
pushback(e);
}
/**
* Open a new xml events stream.
*
* @param stream
* @throws IOException
*/
protected void openStream(Reader stream) throws IOException {
if (reader != null)
closeStream();
try {
XMLEvent e;
reader = XMLInputFactory.newInstance().createXMLEventReader(stream);
e = getNextEvent();
checkValid(e, XMLEvent.START_DOCUMENT, null);
afterStartDocument();
} catch (XMLStreamException e) {
throw new IOException(e);
} catch (FactoryConfigurationError e) {
throw new IOException(e);
}
}
/**
* Close the current opened stream.
*
* @throws IOException
*/
protected void closeStream() throws IOException {
try {
beforeEndDocument();
reader.close();
} catch (XMLStreamException e) {
throw new IOException(e);
} finally {
reader = null;
}
}
/**
* Convert an attribute to a valid constant name.
*
* @param a
* @return
* @see #toConstantName(String)
*/
protected String toConstantName(Attribute a) {
return toConstantName(a.getName().getLocalPart());
}
/**
* Convert a string to a valid constant name. String is put to upper case and
* all non-word characters are replaced by '_'.
*
* @param value
* @return
*/
protected String toConstantName(String value) {
return value.toUpperCase().replaceAll("\\W", "_");
}
/**
* Base for parsers, providing some usefull features.
*/
protected class Parser {
/**
* Read a sequence of characters and return these characters as a string.
* Characters are read until a non-character event is reached.
*
* @return a sequence of characters
* @throws IOException
* @throws XMLStreamException
*/
protected String __characters() throws IOException, XMLStreamException {
XMLEvent e;
StringBuilder buffer = new StringBuilder();
e = getNextEvent();
while (e.getEventType() == XMLEvent.CHARACTERS) {
buffer.append(e.asCharacters());
e = getNextEvent();
}
pushback(e);
return buffer.toString();
}
/**
* Get attributes of a start element in a map. Attributes should be described in
* an enumeration such that {@link FileSourceXML#toConstantName(Attribute)}
* correspond to names of enumeration constants.
*
* @param
* type of the enumeration describing attributes
* @param cls
* class of the enumeration T
* @param e
* start event from which attributes have to be extracted
* @return a mapping between enum constants and attribute values.
*/
protected > EnumMap getAttributes(Class cls, StartElement e) {
EnumMap values = new EnumMap(cls);
@SuppressWarnings("unchecked")
Iterator attributes = e.asStartElement().getAttributes();
while (attributes.hasNext()) {
Attribute a = attributes.next();
for (int i = 0; i < cls.getEnumConstants().length; i++) {
if (cls.getEnumConstants()[i].name().equals(toConstantName(a))) {
values.put(cls.getEnumConstants()[i], a.getValue());
break;
}
}
}
return values;
}
/**
* Check if all required attributes are present.
*
* @param
* type of the enumeration describing attributes
* @param e
* the event
* @param attributes
* extracted attributes
* @param required
* array of required attributes
* @throws XMLStreamException
* if at least one required attribute is not found
*/
protected > void checkRequiredAttributes(XMLEvent e, EnumMap attributes,
T... required) throws XMLStreamException {
if (required != null) {
for (int i = 0; i < required.length; i++) {
if (!attributes.containsKey(required[i]))
newParseError(e, true, "'%s' attribute is required for <%s> element",
required[i].name().toLowerCase(), e.asStartElement().getName().getLocalPart());
}
}
}
}
}