/*
* Copyright 2013 Amazon Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://aws.amazon.com/apache2.0
*
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and
* limitations under the License.
*/
package com.amazonaws.eclipse.ec2;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
class InstanceTypesParser {
// Tag names for the instance type description file
private static final String ID = "id";
private static final String REQUIRES_EBS_VOLUME = "RequiresEBSVolume";
private static final String REQUIRES_HVM_IMAGE = "RequiresHvmImage";
private static final String ARCHITECTURE_BITS = "ArchitectureBits";
private static final String VIRTUAL_CORES = "VirtualCores";
private static final String MEMORY = "Memory";
private static final String DISK_SPACE = "DiskSpace";
private static final String INSTANCE_TYPE = "InstanceType";
private static final String DISPLAY_NAME = "DisplayName";
private static final String DEFAULT_INSTANCE_TYPE = "DefaultInstanceType";
private Document doc;
/**
* Creates a new parser for instance type metadata that reads from the
* specified InputStream.
*
* @param inputStream
* The stream to read instance type metadata from.
*
* @throws IOException
* If there were any problems reading from the stream.
*/
public InstanceTypesParser(InputStream inputStream) throws IOException {
try {
doc = parseDocument(inputStream);
} catch (Exception e) {
throw new IOException("Unable to parse instance type descriptions", e);
}
}
/**
* Returns a list of the InstanceType objects parsed from the provided
* descriptions.
*/
public List<InstanceType> parseInstanceTypes() {
LinkedList<InstanceType> instanceTypes = new LinkedList<InstanceType>();
NodeList instanceTypeNodeList = doc.getElementsByTagName(INSTANCE_TYPE);
for (int i = 0; i < instanceTypeNodeList.getLength(); i++) {
Node instanceTypeNode = instanceTypeNodeList.item(i);
instanceTypes.add(parseInstanceTypeElement(instanceTypeNode));
}
return instanceTypes;
}
/**
* Returns the default instance type specified in the instance type
* descriptions.
*/
public String parseDefaultInstanceTypeId() {
NodeList nodes = doc.getElementsByTagName(DEFAULT_INSTANCE_TYPE);
return getAttribute(nodes.item(0), ID);
}
private Document parseDocument(InputStream inputStream)
throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(inputStream);
doc.getDocumentElement().normalize();
return doc;
}
/**
* Parses an InstanceType element from the document:
* <InstanceType id="t1.micro">
* <DisplayName>Micro</DisplayName>
* <Memory>613 MB</Memory>
* <DiskSpace>0 (EBS only)</DiskSpace>
* <VirtualCores>1</VirtualCores>
* <ArchitectureBits>32/64</ArchitectureBits>
* <RequiresEBSVolume>true</RequiresEBSVolume>
* <RequiresHvmImage>false</RequiresHvmImage>
* </InstanceType>
*/
private InstanceType parseInstanceTypeElement(Node instanceTypeNode) {
String id = getAttribute(instanceTypeNode, ID);
String displayName = null;
String memory = null;
String diskSpace = null;
String architecture = null;
int virtualCores = 0;
boolean requiresEbsVolume = false;
boolean requiresHvmImage = false;
Node node = instanceTypeNode.getFirstChild();
do {
String nodeName = node.getNodeName();
if (nodeName.equals(DISPLAY_NAME)) {
displayName = getChildText(node);
} else if (nodeName.equals(MEMORY)) {
memory = getChildText(node);
} else if (nodeName.equals(DISK_SPACE)) {
diskSpace = getChildText(node);
} else if (nodeName.equals(VIRTUAL_CORES)) {
virtualCores = parseInt(node);
} else if (nodeName.equals(ARCHITECTURE_BITS)) {
architecture = getChildText(node);
} else if (nodeName.equals(REQUIRES_EBS_VOLUME)) {
requiresEbsVolume = Boolean.parseBoolean(getChildText(node));
} else if (nodeName.equals(REQUIRES_HVM_IMAGE)) {
requiresHvmImage = Boolean.parseBoolean(getChildText(node));
}
} while ((node = node.getNextSibling()) != null);
return new InstanceType(displayName, id, memory, diskSpace, virtualCores, architecture, requiresEbsVolume, requiresHvmImage);
}
private int parseInt(Node node) {
try {
return Integer.parseInt(getChildText(node));
} catch (NumberFormatException nfe) {
Status status = new Status(IStatus.WARNING, Ec2Plugin.PLUGIN_ID, "Error parsing Amazon EC2 instance type", nfe);
Ec2Plugin.getDefault().getLog().log(status);
return -1;
}
}
private String getAttribute(Node node, String attributeName) {
return node.getAttributes().getNamedItem(attributeName).getTextContent();
}
private String getChildText(Node node) {
return node.getFirstChild().getTextContent();
}
}