/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.apidocs.differencing;
import com.emc.apidocs.model.ApiClass;
import com.emc.apidocs.model.ApiField;
import com.emc.apidocs.model.ApiMethod;
import com.emc.apidocs.model.ApiService;
import com.google.common.collect.Maps;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPathFactory;
import java.io.InputStream;
import java.util.Map;
public class EnunciateFileReader {
private static XPathFactory xpathFactory;
private static DocumentBuilderFactory documentBuilderFactory;
private Map<String, ApiClass> resolvedClasses;
private Map<String, ApiClass> resolvedElementTypes;
public synchronized Map<String, ApiService> loadServices(InputStream inputStream) {
resolvedClasses = Maps.newHashMap();
resolvedElementTypes = Maps.newHashMap();
Document document = XMLUtils.loadDocument(inputStream);
return loadServices(document);
}
private Map<String, ApiService> loadServices(Document document) {
Map<String, ApiClass> apiClasses = loadTypes(document);
Map<String, ApiService> apiServices = Maps.newHashMap();
NodeList resourceNodes = XMLUtils.getNodeList(document, EnunciateConstants.RESOURCES);
for (int f = 0; f < resourceNodes.getLength(); f++) {
Node resourceNode = resourceNodes.item(f);
String serviceClass = XMLUtils.getNodeText(resourceNode, EnunciateConstants.RESOURCE_SERVICE_CLASS);
ApiService apiService = null;
if (apiClasses.containsKey(serviceClass)) {
apiService = apiServices.get(serviceClass);
}
else {
apiService = new ApiService();
apiService.javaClassName = serviceClass;
apiServices.put(serviceClass, apiService);
}
ApiMethod apiMethod = toApiMethod(resourceNode, apiClasses);
System.out.println("Loaded Method " + serviceClass + " " + apiMethod.httpMethod + " " + apiMethod.path);
apiService.addMethod(apiMethod);
}
return apiServices;
}
private Map<String, ApiClass> loadTypes(Document document) {
Map<String, ApiClass> types = Maps.newHashMap();
NodeList typeNodes = XMLUtils.getNodeList(document, EnunciateConstants.TYPE);
for (int i = 0; i < typeNodes.getLength(); i++) {
Node typeNode = typeNodes.item(i);
ApiClass apiClass = toApiClass(typeNode);
types.put(apiClass.name, apiClass);
}
return types;
}
public ApiMethod toApiMethod(Node resourceNode, Map<String, ApiClass> types) {
ApiMethod apiMethod = new ApiMethod();
apiMethod.httpMethod = XMLUtils.getNodeText(resourceNode, EnunciateConstants.RESOURCE_HTTP_OPERATION);
apiMethod.path = XMLUtils.getNodeText(resourceNode, EnunciateConstants.RESOURCE_PATH);
String requestElementName = XMLUtils.getNodeText(resourceNode, EnunciateConstants.RESOURCE_REQUEST_ELEMENT_TYPE);
if (requestElementName != null) {
apiMethod.input = findElementType(requestElementName, types, resourceNode.getOwnerDocument());
}
String responseElementName = XMLUtils.getNodeText(resourceNode, EnunciateConstants.RESOURCE_RESPONSE_ELEMENT_TYPE);
if (responseElementName != null) {
apiMethod.output = findElementType(responseElementName, types, resourceNode.getOwnerDocument());
}
return apiMethod;
}
private ApiClass findElementType(String elementName, Map<String, ApiClass> types, Document document) {
if (resolvedElementTypes.containsKey(elementName)) {
return resolvedElementTypes.get(elementName);
}
Node node = XMLUtils.getNode(document, XMLUtils.getXPath("//schema/elements/element[@name=\"" + elementName + "\"]"));
if (node == null) {
throw new RuntimeException("Unable to find element " + elementName);
}
String elementType = XMLUtils.getNodeText(node, EnunciateConstants.ELEMENT_TYPENAME);
if (!types.containsKey(elementType)) {
throw new RuntimeException("Unable to find type " + elementType + " for element " + elementName);
}
resolvedElementTypes.put(elementName, types.get(elementType));
return types.get(elementType);
}
private ApiClass loadType(String name, Document document) {
if (resolvedClasses.containsKey(name)) {
return resolvedClasses.get(name);
}
Node typeNode = XMLUtils.getNode(document, XMLUtils.getXPath("//schema/types/type[@name=\"" + name + "\"]"));
if (typeNode == null) {
throw new RuntimeException("Type " + name + " not found in document");
}
ApiClass apiClass = toApiClass(typeNode);
resolvedClasses.put(name, apiClass);
System.out.println("Loaded Class " + name);
return apiClass;
}
private ApiClass toApiClass(Node typeNode) {
ApiClass apiClass = new ApiClass();
apiClass.name = XMLUtils.getNodeText(typeNode, EnunciateConstants.TYPE_NAME);
NodeList elementList = XMLUtils.getNodeList(typeNode, EnunciateConstants.TYPE_ELEMENT);
for (int f = 0; f < elementList.getLength(); f++) {
Node element = elementList.item(f);
apiClass.addField(toApiField(element));
}
NodeList attributeList = XMLUtils.getNodeList(typeNode, EnunciateConstants.TYPE_ATTRIBUTE);
for (int f = 0; f < attributeList.getLength(); f++) {
Node attribute = attributeList.item(f);
String attributeType = XMLUtils.getNodeText(attribute, EnunciateConstants.ATTRIBUTE_TYPE);
String attributeName = XMLUtils.getNodeText(attribute, EnunciateConstants.ATTRIBUTE_NAME);
ApiField attributeField = new ApiField();
attributeField.name = attributeName;
attributeField.primitiveType = attributeType;
apiClass.addAttribute(attributeField);
}
return apiClass;
}
private ApiField toApiField(Node elementNode) {
ApiField apiField = new ApiField();
apiField.name = XMLUtils.getNodeText(elementNode, EnunciateConstants.ELEMENT_NAME);
String typeName = XMLUtils.getNodeText(elementNode, EnunciateConstants.ELEMENT_CHOICE_TYPENAME);
if (typeName == null) {
typeName = XMLUtils.getNodeText(elementNode, EnunciateConstants.ELEMENT_TYPENAME);
}
if (typeName != null) {
boolean isPrimitive = typeName.equals("string") ||
typeName.equals("dateTime") ||
typeName.equals("long") ||
typeName.equals("boolean") ||
typeName.equals("int") ||
typeName.equals("double");
if (isPrimitive) {
apiField.primitiveType = typeName;
}
else {
apiField.type = loadType(typeName, elementNode.getOwnerDocument());
}
}
else {
System.out.println("Warning: Unable to find typeName for element " + apiField.name);
}
return apiField;
}
}