| /* |
| * Copyright 2009-2010 by The Regents of the University of California |
| * 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 from |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License 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 edu.uci.ics.hyracks.api.topology; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Stack; |
| |
| import org.xml.sax.Attributes; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.XMLReader; |
| import org.xml.sax.helpers.DefaultHandler; |
| import org.xml.sax.helpers.XMLReaderFactory; |
| |
| import edu.uci.ics.hyracks.api.topology.NetworkEndpoint.EndpointType; |
| |
| public class TopologyDefinitionParser { |
| private final Stack<ElementStackEntry> stack; |
| |
| private boolean inPropertyElement; |
| |
| private TopologyDefinitionParser() { |
| stack = new Stack<ElementStackEntry>(); |
| inPropertyElement = false; |
| } |
| |
| public static ClusterTopology parse(InputSource in) throws IOException, SAXException { |
| TopologyDefinitionParser parser = new TopologyDefinitionParser(); |
| return parser.parseInternal(in); |
| } |
| |
| private ClusterTopology parseInternal(InputSource in) throws IOException, SAXException { |
| XMLReader parser; |
| parser = XMLReaderFactory.createXMLReader(); |
| SAXContentHandler handler = new SAXContentHandler(); |
| parser.setContentHandler(handler); |
| parser.parse(in); |
| if (stack.size() != 1) { |
| throw new IllegalStateException("Malformed topology definition"); |
| } |
| ElementStackEntry e = stack.pop(); |
| if (e.ports.size() != 1) { |
| throw new IllegalArgumentException("Malformed topology definition"); |
| } |
| NetworkEndpoint endpoint = e.ports.get(0).getEndpoint(); |
| if (endpoint.getType() != EndpointType.NETWORK_SWITCH) { |
| throw new IllegalArgumentException("Top level content in cluster-topology must be network-switch"); |
| } |
| return new ClusterTopology((NetworkSwitch) endpoint); |
| } |
| |
| private class SAXContentHandler extends DefaultHandler { |
| @Override |
| public void endElement(String uri, String localName, String qName) throws SAXException { |
| if ("network-switch".equals(localName) || "terminal".equals(localName)) { |
| ElementStackEntry e = stack.pop(); |
| NetworkEndpoint endpoint = e.type == EndpointType.NETWORK_SWITCH ? new NetworkSwitch(e.name, |
| e.properties, e.ports.toArray(new NetworkSwitch.Port[e.ports.size()])) : new NetworkTerminal( |
| e.name, e.properties); |
| stack.peek().ports.add(new NetworkSwitch.Port(endpoint)); |
| } else if ("property".equals(localName)) { |
| if (!inPropertyElement) { |
| throw new IllegalStateException("Improperly nested property element encountered"); |
| } |
| inPropertyElement = false; |
| } |
| } |
| |
| @Override |
| public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { |
| if ("cluster-topology".equals(localName)) { |
| if (!stack.isEmpty()) { |
| throw new IllegalStateException("Encountered unexpected " + qName); |
| } |
| stack.push(new ElementStackEntry(null, "")); |
| } else if ("network-switch".equals(localName) || "terminal".equals(localName)) { |
| String name = atts.getValue("", "name"); |
| if (name == null) { |
| throw new IllegalStateException("Encountered " + localName + " element with no name attribute"); |
| } |
| EndpointType type = "network-switch".equals(localName) ? EndpointType.NETWORK_SWITCH |
| : EndpointType.NETWORK_TERMINAL; |
| ElementStackEntry e = new ElementStackEntry(type, name); |
| stack.push(e); |
| } else if ("property".equals(localName)) { |
| if (inPropertyElement) { |
| throw new IllegalStateException("Improperly nested property element encountered"); |
| } |
| String name = atts.getValue("", "name"); |
| if (name == null) { |
| throw new IllegalStateException("Encountered " + localName + " element with no name attribute"); |
| } |
| String value = atts.getValue("", "value"); |
| if (value == null) { |
| throw new IllegalStateException("Encountered " + localName + " element with no value attribute"); |
| } |
| stack.peek().properties.put(name, value); |
| inPropertyElement = true; |
| } |
| } |
| } |
| |
| private static class ElementStackEntry { |
| private final EndpointType type; |
| |
| private final String name; |
| |
| private final Map<String, String> properties; |
| |
| private final List<NetworkSwitch.Port> ports; |
| |
| public ElementStackEntry(EndpointType type, String name) { |
| this.type = type; |
| this.name = name; |
| this.properties = new HashMap<String, String>(); |
| ports = new ArrayList<NetworkSwitch.Port>(); |
| } |
| } |
| } |