blob: b33b8540b06d57d6f60bcc4108e3febb09b4b6d1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ptp.rm.mpi.mpich2.core.rtsystem;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ptp.core.attributes.IllegalValueException;
import org.eclipse.ptp.rm.mpi.mpich2.core.MPICH2NodeAttributes;
import org.eclipse.ptp.rm.mpi.mpich2.core.MPICH2Plugin;
import org.eclipse.ptp.rm.mpi.mpich2.core.messages.Messages;
import org.eclipse.ptp.rm.mpi.mpich2.core.rtsystem.MPICH2ProcessMap.Node;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
/**
*
* @author Daniel Felix Ferber
*
*/
public class MPICH2ProcessMapXml13Parser {
private MPICH2ProcessMapXml13Parser() {
// Do not allow instances.
}
private class StackContextHandler extends DefaultHandler {
Stack<ContextHandler> handlers = new Stack<ContextHandler>();
public StackContextHandler(ContextHandler documentHandler) {
handlers.push(documentHandler);
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
// Notify listeners that parsing has started
for (Object listener : listeners.getListeners()) {
try {
((IOpenMpiProcessMapXml13ParserListener ) listener).startDocument();
} catch (Exception e) {
MPICH2Plugin.log(e);
}
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
super.startElement(uri, localName, name, attributes);
// System.out.println("Start element: "+name);
ContextHandler handler = handlers.peek();
ContextHandler childHandler = null;
if (handler != null) {
childHandler = handler.newElement(name);
if (childHandler != null) {
childHandler.start();
for (int i = 0; i < attributes.getLength(); i++) {
String attr_name = attributes.getQName(i);
String attr_value = attributes.getValue(i);
childHandler.setAttribute(attr_name, attr_value);
}
childHandler.prepare();
}
}
handlers.push(childHandler);
}
@Override
public void endElement(String uri, String localName, String name) throws SAXException {
super.endElement(uri, localName, name);
// System.out.println("End element: "+name);
ContextHandler handler = handlers.pop();
if (handler != null) {
handler.finish();
}
}
@Override
public void error(SAXParseException e) throws SAXException {
// TODO Auto-generated method stub
super.error(e);
}
@Override
public void fatalError(SAXParseException e) throws SAXException {
// TODO Auto-generated method stub
// System.out.println(e.getClass());
super.fatalError(e);
}
}
protected final MPICH2ProcessMap map = new MPICH2ProcessMap();
protected final StackContextHandler handler = new StackContextHandler(new DocumentHandler());
protected final ListenerList listeners = new ListenerList();
public static interface IOpenMpiProcessMapXml13ParserListener {
void startDocument();
void endDocument();
}
private class UnknownElementException extends SAXException {
private static final long serialVersionUID = 1L;
public UnknownElementException(String name) {
super(NLS.bind(Messages.MPICH2ProcessMapXml13Parser_Exception_UnknownElement, name));
}
}
private class UnknownAttributeException extends SAXException {
private static final long serialVersionUID = 1L;
public UnknownAttributeException(String name) {
super(NLS.bind(Messages.MPICH2ProcessMapXml13Parser_Exception_UnknownAttribute, name));
}
}
private class MissingAttributeException extends SAXException {
private static final long serialVersionUID = 1L;
public MissingAttributeException(String name) {
super(NLS.bind(Messages.MPICH2ProcessMapXml13Parser_Exception_MissingAttribute, name));
}
}
private class InvalidIntegerAttributeException extends SAXException {
private static final long serialVersionUID = 1L;
public InvalidIntegerAttributeException(String name, String value) {
super(NLS.bind(Messages.MPICH2ProcessMapXml13Parser_Exception_AttributeNotInteger, name, value));
}
}
private class ParseInterruptedException extends SAXException {
private static final long serialVersionUID = 1L;
}
private abstract class ContextHandler {
public ContextHandler newElement(String name) throws SAXException {
throw new UnknownElementException(name);
}
/** Called when reading the beginning of the tag. */
public void start() throws SAXException {
// Empty
}
/** Called for each argument found at the beginning of the tag. */
public void setAttribute(String name, String value) throws SAXException {
throw new UnknownAttributeException(name);
}
/** Called when all attributes have been read and tag content is going to be read. */
public void prepare() throws SAXException {
// Empty
}
/** Called when finished reading the end of the tag. */
public void finish() throws SAXException {
// Empty
}
}
private class DocumentHandler extends ContextHandler {
@Override
public ContextHandler newElement(String name) throws SAXException {
if (name.equalsIgnoreCase("map")) //$NON-NLS-1$
return new MapHandler();
else if (name.equalsIgnoreCase("allocation")) //$NON-NLS-1$
return null; // ignore
else
return super.newElement(name);
}
}
public class MapHandler extends ContextHandler {
@Override
public ContextHandler newElement(String name) throws SAXException {
if (name.equalsIgnoreCase("host")) //$NON-NLS-1$
return new HostHandler();
else
return super.newElement(name);
}
@Override
public void finish() throws SAXException {
super.finish();
// Notify listeners that end has been reached.
for (Object listener : listeners.getListeners()) {
try {
((IOpenMpiProcessMapXml13ParserListener ) listener).endDocument();
} catch (Exception e) {
MPICH2Plugin.log(e);
}
}
// Throw exception to force stop parsing.
// Or else, the parser would complain about content not allows after in trailing section.
throw new ParseInterruptedException();
}
}
public class HostHandler extends ContextHandler {
private int host_counter = 0;
private String name;
private boolean has_num_slots = false;
private boolean has_max_slots = false;
private int num_slots = 0;
private int max_slots = 0;
private Node node;
private List<MPICH2ProcessMap.Process> processes = new ArrayList<MPICH2ProcessMap.Process>();
@Override
public ContextHandler newElement(String name) throws SAXException {
if (name.equalsIgnoreCase("process")) //$NON-NLS-1$
return new ProcessHandler(node);
else
return super.newElement(name);
}
@Override
public void setAttribute(String name, String value) throws SAXException {
if (name.equalsIgnoreCase("name")) { //$NON-NLS-1$
this.name = value;
} else if (name.equalsIgnoreCase("slots")) { //$NON-NLS-1$
try {
num_slots = Integer.parseInt(value);
if (num_slots < 0)
throw new InvalidIntegerAttributeException(name, value);
has_num_slots = true;
} catch (NumberFormatException e) {
throw new InvalidIntegerAttributeException(name, value);
}
} else if (name.equalsIgnoreCase("max_slots")) { //$NON-NLS-1$
try {
max_slots = Integer.parseInt(value);
if (max_slots < 0)
throw new InvalidIntegerAttributeException(name, value);
if (max_slots != 0) {
has_max_slots = true;
}
} catch (NumberFormatException e) {
throw new InvalidIntegerAttributeException(name, value);
}
} else {
super.setAttribute(name, value);
}
}
@Override
public void prepare() throws SAXException {
if (name == null)
throw new MissingAttributeException("name"); //$NON-NLS-1$
if (! has_num_slots)
throw new MissingAttributeException("slots"); //$NON-NLS-1$
node = new Node(host_counter++, name);
map.addNode(node);
try {
node.getAttributeManager().addAttribute(MPICH2NodeAttributes.getNumberOfNodesAttributeDefinition().create(num_slots));
} catch (IllegalValueException e) {
// This is not possible
MPICH2Plugin.log(e);
}
if (has_max_slots) {
try {
node.getAttributeManager().addAttribute(MPICH2NodeAttributes.getMaximalNumberOfNodesAttributeDefinition().create(max_slots));
} catch (IllegalValueException e) {
// This is not possible
MPICH2Plugin.log(e);
}
}
super.prepare();
}
@Override
public void finish() throws SAXException {
/*
* Count how many processes are running on the host and check if the number is greater than the allowed one.
* If yes, then the node is oversubcribed.
*/
assert node != null;
node.getAttributeManager().addAttribute(MPICH2NodeAttributes.getOversubscribedAttributeDefinition().create(processes.size() > num_slots));
super.finish();
}
}
public class ProcessHandler extends ContextHandler {
private Node node;
private int rank;
private boolean has_rank = false;
public ProcessHandler(Node node) {
this.node = node;
}
@Override
public void setAttribute(String name, String value) throws SAXException {
if (name.equalsIgnoreCase("rank")) { //$NON-NLS-1$
try {
rank = Integer.parseInt(value);
if (rank < 0)
throw new InvalidIntegerAttributeException(name, value);
has_rank = true;
} catch (NumberFormatException e) {
throw new InvalidIntegerAttributeException(name, value);
}
} else {
super.setAttribute(name, value);
}
}
@Override
public void finish() throws SAXException {
MPICH2ProcessMap.Process process = new MPICH2ProcessMap.Process(node, rank, Integer.toString(rank), 1);
map.addProcess(process);
super.finish();
}
}
public static MPICH2ProcessMap parse(InputStream is) throws IOException {
return parse(is, null);
}
public static MPICH2ProcessMap parse(InputStream is, IOpenMpiProcessMapXml13ParserListener listener) throws IOException {
MPICH2ProcessMapXml13Parser parser = new MPICH2ProcessMapXml13Parser();
if (listener != null) {
parser.addListener(listener);
}
try {
BufferedInputStream bis = new BufferedInputStream(is);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(bis, parser.handler);
} catch (ParseInterruptedException e) {
// this is ok and expected
} catch (SAXException e) {
throw new IOException(e.getMessage());
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
}
return parser.map;
}
public void addListener(IOpenMpiProcessMapXml13ParserListener listener) {
listeners.add(listener);
}
public void removeListener(IOpenMpiProcessMapXml13ParserListener listener) {
listeners.remove(listener);
}
public static void main(String[] args) {
try {
FileInputStream is = new FileInputStream("xml_sample.txt"); //$NON-NLS-1$
MPICH2ProcessMap map = MPICH2ProcessMapXml13Parser.parse(is);
} catch (Exception e) {
e.printStackTrace();
}
}
}