package org.teiid.query.function.metadata;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.teiid.core.types.XMLType;
import org.teiid.metadata.FunctionMethod;
import org.teiid.metadata.FunctionParameter;
public class FunctionMetadataReader {
List<FunctionMethod> functionMethods = new ArrayList<FunctionMethod>();
public static List<FunctionMethod> loadFunctionMethods(InputStream source) throws XMLStreamException {
FunctionMetadataReader md = parseFunctions(source);
return md.functionMethods;
}
public static FunctionMetadataReader parseFunctions(InputStream content) throws XMLStreamException {
XMLInputFactory inputFactory=XMLType.getXmlInputFactory();
XMLStreamReader reader = inputFactory.createXMLStreamReader(content);
FunctionMetadataReader fmr = new FunctionMetadataReader();
while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
switch (Namespace.forUri(reader.getNamespaceURI())) {
case XMI: {
Element element = Element.forName(reader.getLocalName());
switch (element) {
case XMI:
parseFunctions(reader, fmr);
while(reader.hasNext() && reader.next() != XMLStreamConstants.END_DOCUMENT);
break;
}
break;
}
}
}
return fmr;
}
private static void parseFunctions(XMLStreamReader reader, FunctionMetadataReader fmr) throws XMLStreamException {
while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
String elementName = reader.getLocalName();
switch (Element.forName(elementName)) {
case SCALAR_FUNCTION:
fmr.functionMethods.add(parseScalarFunction(reader));
break;
default:
// skip the elements not needed.
while (reader.hasNext()) {
if (reader.nextTag() == XMLStreamConstants.END_ELEMENT && reader.getLocalName().equals(elementName)) {
break;
}
}
break;
}
}
}
private static FunctionMethod parseScalarFunction(XMLStreamReader reader) throws XMLStreamException {
FunctionMethod function = new FunctionMethod();
if (reader.getAttributeCount() > 0) {
for(int i=0; i<reader.getAttributeCount(); i++) {
String attrName = reader.getAttributeLocalName(i);
String attrValue = reader.getAttributeValue(i);
if (Element.NAME.getLocalName().equals(attrName)) {
function.setName(attrValue);
}
else if (Element.CATEGORY.getLocalName().equals(attrName)) {
function.setCategory(attrValue);
}
else if (Element.INVOCATION_CLASS.getLocalName().equals(attrName)) {
function.setInvocationClass(attrValue);
// TODO: set class loader
// function.setClassloader();
}
else if (Element.INVOCATION_METHOD.getLocalName().equals(attrName)) {
function.setInvocationMethod(attrValue);
}
else if (Element.PUSHDOWN.getLocalName().equals(attrName)) {
function.setPushDown(attrValue);
}
else if (Element.DETERMINISTIC.getLocalName().equals(attrName)) {
function.setDeterministicBoolean(Boolean.parseBoolean(attrValue));
}
}
}
LinkedList<FunctionParameter> inputs = new LinkedList<FunctionParameter>();
while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
switch (Element.forName(reader.getLocalName())) {
case INPUT_PARAMTERS:
inputs.addLast(parseParameter(reader));
break;
case RETURN_PARAMETER:
function.setOutputParameter(parseParameter(reader));
break;
}
}
function.setInputParameters(inputs);
return function;
}
private static FunctionParameter parseParameter(XMLStreamReader reader) throws XMLStreamException {
FunctionParameter fp = new FunctionParameter();
if (reader.getAttributeCount() > 0) {
for(int i=0; i<reader.getAttributeCount(); i++) {
String attrName = reader.getAttributeLocalName(i);
String attrValue = reader.getAttributeValue(i);
if (Element.NAME.getLocalName().equals(attrName)) {
fp.setName(attrValue);
}
else if (Element.DESCRIPTION.getLocalName().equals(attrName)) {
fp.setDescription(attrValue);
}
else if (Element.TYPE.getLocalName().equals(attrName)) {
fp.setType(attrValue);
}
}
}
while(reader.nextTag() != XMLStreamConstants.END_ELEMENT);
return fp;
}
enum Element {
// must be first
UNKNOWN(null),
XMI("XMI"),//$NON-NLS-1$
SCALAR_FUNCTION("ScalarFunction"),//$NON-NLS-1$
NAME("name"), //$NON-NLS-1$
INPUT_PARAMTERS("inputParameters"),//$NON-NLS-1$
DESCRIPTION("description"),//$NON-NLS-1$
CATEGORY("category"),//$NON-NLS-1$
PUSHDOWN("pushDown"),//$NON-NLS-1$
INVOCATION_CLASS("invocationClass"),//$NON-NLS-1$
INVOCATION_METHOD("invocationMethod"),//$NON-NLS-1$
RETURN_PARAMETER("returnParameter"),//$NON-NLS-1$
DETERMINISTIC("deterministic"),//$NON-NLS-1$
TYPE("type");//$NON-NLS-1$
private final String name;
Element(final String name) {
this.name = name;
}
/**
* Get the local name of this element.
*
* @return the local name
*/
public String getLocalName() {
return name;
}
private static final Map<String, Element> elements;
static {
final Map<String, Element> map = new HashMap<String, Element>();
for (Element element : values()) {
final String name = element.getLocalName();
if (name != null) map.put(name, element);
}
elements = map;
}
public static Element forName(String localName) {
final Element element = elements.get(localName);
return element == null ? UNKNOWN : element;
}
}
enum Namespace {
// must be first
UNKNOWN(null),
XMI("http://www.omg.org/XMI"), //$NON-NLS-1$
FUNCTION("http://www.metamatrix.com/metamodels/MetaMatrixFunction"); //$NON-NLS-1$
private final String uri;
Namespace(String uri) {
this.uri = uri;
}
public String getUri() {
return uri;
}
private static final Map<String, Namespace> namespaces;
static {
final Map<String, Namespace> map = new HashMap<String, Namespace>();
for (Namespace namespace : values()) {
final String name = namespace.getUri();
if (name != null) map.put(name, namespace);
}
namespaces = map;
}
public static Namespace forUri(String uri) {
final Namespace element = namespaces.get(uri);
return element == null ? UNKNOWN : element;
}
}
}