/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.datatools.views;
import java.io.IOException;
import java.io.StringReader;
import java.util.Stack;
import org.apache.xerces.parsers.SAXParser;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.teiid.datatools.connectivity.ui.Activator;
import org.teiid.datatools.connectivity.ui.Messages;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.LocatorImpl;
/**
*
*
* @since 8.0
*/
public class ExecutionPlanParser {
public static final String VALIDATION_FEATURE = "http://xml.org/sax/features/validation"; //$NON-NLS-1$
public static final String VALUE_ELEM = "value"; //$NON-NLS-1$
public static final String PROPERTY_ELEM = "property"; //$NON-NLS-1$
public static final String NODE_ELEM = "node"; //$NON-NLS-1$
public static final String NAME_ATTR = "name"; //$NON-NLS-1$
private ExecutionPlan executionPlan;
public ExecutionPlanParser() {
}
public IStatus parse( String xmlString ) {
InputSource inputSource = new InputSource(new StringReader(xmlString));
return internalParse(inputSource);
}
private IStatus internalParse( InputSource inputSource ) {
boolean parseError = false;
executionPlan = null;
Handler contentHandler = new Handler();
XMLReader reader = new SAXParser();
reader.setErrorHandler(null);
reader.setContentHandler(contentHandler);
try {
reader.setFeature(VALIDATION_FEATURE, true);
reader.parse(inputSource);
} catch (SAXNotRecognizedException e) {
parseError = true;
String message = Messages.getString("ExecutionPlanParser.parseError"); //$NON-NLS-1$
IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, e);
Activator.getDefault().getLog().log(status);
} catch (SAXNotSupportedException e) {
parseError = true;
String message = Messages.getString("ExecutionPlanParser.parseError"); //$NON-NLS-1$
IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, e);
Activator.getDefault().getLog().log(status);
} catch (IOException e) {
parseError = true;
String message = Messages.getString("ExecutionPlanParser.ioError"); //$NON-NLS-1$
IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, e);
Activator.getDefault().getLog().log(status);
} catch (SAXException e) {
parseError = true;
String message = Messages.getString("ExecutionPlanParser.parseError"); //$NON-NLS-1$
IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, e);
Activator.getDefault().getLog().log(status);
}
if (parseError) {
executionPlan = new ExecutionPlan(null);
String message = Messages.getString("ExecutionPlanParser.parseError"); //$NON-NLS-1$
return new Status(IStatus.ERROR, Activator.PLUGIN_ID, message);
}
executionPlan = new ExecutionPlan(contentHandler.getRootElement());
String message = Messages.getString("ExecutionPlanParser.parseSuccessful"); //$NON-NLS-1$
return new Status(IStatus.OK, Activator.PLUGIN_ID, message);
}
public ExecutionPlan getExecutionPlan() {
return this.executionPlan;
}
/**
* The handler used by the parser. Each instance should be only used to parse one file.
*/
class Handler extends DefaultHandler {
private static final String VALUE_ELEM = "value"; //$NON-NLS-1$
private StringBuffer sbuffer = new StringBuffer();
private Stack<String> elements = new Stack<String>();
private PlanElement rootElement;
private PlanElement parentElement;
public Handler() {
super();
setDocumentLocator(new LocatorImpl());
}
@Override
public void startElement( String uri,
String lName,
String qName,
Attributes attributes ) throws SAXException {
this.elements.push(qName);
if (rootElement == null) {
rootElement = new PlanElement(qName);
rootElement.setRoot(true);
if (attributes != null) {
int attributeLength = attributes.getLength();
for (int i = 0; i < attributeLength; i++) {
String value = attributes.getValue(i);
String localName = attributes.getLocalName(i);
rootElement.addChildAttribute(new PlanAttribute(localName, value));
}
}
parentElement = rootElement;
} else {
PlanElement newElement = new PlanElement(qName);
if (attributes != null) {
int attributeLength = attributes.getLength();
for (int i = 0; i < attributeLength; i++) {
String value = attributes.getValue(i);
String localName = attributes.getLocalName(i);
newElement.addChildAttribute(new PlanAttribute(localName, value));
}
}
parentElement.addChildElement(newElement);
parentElement = newElement;
}
sbuffer.setLength(0);
super.startElement(uri, lName, qName, attributes);
}
@Override
public void endElement( String uri,
String localName,
String qName ) throws SAXException {
String currentElem = getCurrentElement();
if (VALUE_ELEM.equals(currentElem)) {
parentElement.setValue(sbuffer.toString());
}
parentElement = parentElement.getParent();
this.elements.pop();
super.endElement(uri, localName, qName);
}
/**
* {@inheritDoc}
*
* @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
*/
@Override
public void characters( char[] ch,
int start,
int length ) throws SAXException {
sbuffer.append(ch, start, length);
super.characters(ch, start, length);
}
/**
* @return the element currently being parsed
*/
private String getCurrentElement() {
if (this.elements.empty()) {
return null;
}
return this.elements.peek();
}
public PlanElement getRootElement() {
return rootElement;
}
}
}