/* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.annotation.Nullable; import javax.management.ObjectName; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; public final class Services { private static final String PROVIDER_KEY = "provider"; private static final String NAME_KEY = "name"; public static final String TYPE_KEY = "type"; public static final String SERVICE_KEY = "service"; private long suffix = 1; private final Map instanceToRef = Maps.newHashMap(); private final Map> serviceNameToRefNameToInstance = Maps .newHashMap(); public String addServiceEntry(String serviceName, ObjectName on) { String moduleName = on.getKeyProperty("moduleFactoryName"); String instanceName = on.getKeyProperty("instanceName"); return addServiceEntry(serviceName, moduleName, instanceName); } public String addServiceEntry(String serviceName, String moduleName, String instanceName) { ServiceInstance serviceInstance = new ServiceInstance(moduleName, instanceName); serviceInstance.setServiceName(serviceName); String refName = instanceToRef.get(serviceInstance); Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); if (refNameToInstance == null) { refNameToInstance = Maps.newHashMap(); serviceNameToRefNameToInstance.put(serviceName, refNameToInstance); } if (refName != null) { if (serviceNameToRefNameToInstance.get(serviceName).containsKey(moduleName) == false) { refNameToInstance.put(refName, serviceInstance); } return refName; } else { refName = "ref_" + instanceName; final Set refNamesAsSet = toSet(instanceToRef.values()); if (refNamesAsSet.contains(refName)) { refName = findAvailableRefName(refName, refNamesAsSet); } instanceToRef.put(serviceInstance, refName); refNameToInstance.put(refName, serviceInstance); return refName; } } private Set toSet(Collection values) { Set refNamesAsSet = Sets.newHashSet(); for (String refName : values) { boolean resultAdd = refNamesAsSet.add(refName); Preconditions.checkState(resultAdd, "Error occurred building services element, reference name {} was present twice", refName); } return refNamesAsSet; } public ServiceInstance getByServiceAndRefName(String serviceName, String refName) { Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , " + serviceNameToRefNameToInstance.keySet()); ServiceInstance serviceInstance = refNameToInstance.get(refName); Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName + " under service name " + serviceName + " , " + refNameToInstance.keySet()); return serviceInstance; } // TODO hide getMappedServices, call it explicitly in toXml public Map> getMappedServices() { Map> retVal = Maps.newHashMap(); for (String serviceName : serviceNameToRefNameToInstance.keySet()) { Map innerRetVal = Maps.transformValues(serviceNameToRefNameToInstance.get(serviceName), new Function() { @Nullable @Override public String apply(@Nullable ServiceInstance serviceInstance) { return serviceInstance.toString(); } }); retVal.put(serviceName, innerRetVal); } return retVal; } // TODO hide resolveServices, call it explicitly in fromXml public static Services resolveServices(Map> mappedServices) { Services tracker = new Services(); for (Entry> serviceEntry : mappedServices.entrySet()) { String serviceName = serviceEntry.getKey(); for (Entry refEntry : serviceEntry.getValue().entrySet()) { Map refNameToInstance = tracker.serviceNameToRefNameToInstance .get(serviceName); if (refNameToInstance == null) { refNameToInstance = Maps.newHashMap(); tracker.serviceNameToRefNameToInstance.put(serviceName, refNameToInstance); } String refName = refEntry.getKey(); Preconditions.checkState(false == refNameToInstance.containsKey(refName), "Duplicate reference name to service " + refName + " under service " + serviceName); ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue()); refNameToInstance.put(refName, serviceInstance); tracker.instanceToRef.put(serviceInstance, refEntry.getKey()); } } return tracker; } public static Map> fromXml(XmlElement xml) { Map> retVal = Maps.newHashMap(); List services = xml.getChildElements(SERVICE_KEY); xml.checkUnrecognisedElements(services); for (XmlElement service : services) { XmlElement typeElement = service.getOnlyChildElement(TYPE_KEY); String serviceName = typeElement.getTextContent(); Map innerMap = Maps.newHashMap(); retVal.put(serviceName, innerMap); List instances = service.getChildElements(XmlNetconfConstants.INSTANCE_KEY); service.checkUnrecognisedElements(instances, typeElement); for (XmlElement instance : instances) { XmlElement nameElement = instance.getOnlyChildElement(NAME_KEY); String refName = nameElement.getTextContent(); XmlElement providerElement = instance.getOnlyChildElement(PROVIDER_KEY); String providerName = providerElement.getTextContent(); instance.checkUnrecognisedElements(nameElement, providerElement); innerMap.put(refName, providerName); } } return retVal; } private String findAvailableRefName(String refName, Set refNamesAsSet) { String intitialRefName = refName; while (true) { refName = intitialRefName + "_" + suffix++; if (refNamesAsSet.contains(refName) == false) return refName; } } public Element toXml(Map> mappedServices, Document document) { Element root = document.createElement(XmlNetconfConstants.SERVICES_KEY); XmlUtil.addNamespaceAttr(root, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG); for (Entry> serviceEntry : mappedServices.entrySet()) { Element serviceElement = document.createElement(SERVICE_KEY); root.appendChild(serviceElement); Element typeElement = XmlUtil.createTextElement(document, TYPE_KEY, serviceEntry.getKey()); serviceElement.appendChild(typeElement); for (Entry instanceEntry : serviceEntry.getValue().entrySet()) { Element instanceElement = document.createElement(XmlNetconfConstants.INSTANCE_KEY); serviceElement.appendChild(instanceElement); Element nameElement = XmlUtil.createTextElement(document, NAME_KEY, instanceEntry.getKey()); instanceElement.appendChild(nameElement); Element providerElement = XmlUtil.createTextElement(document, PROVIDER_KEY, instanceEntry.getValue()); instanceElement.appendChild(providerElement); } } return root; } public static final class ServiceInstance { public ServiceInstance(String moduleName, String instanceName) { this.moduleName = moduleName; this.instanceName = instanceName; } public static ServiceInstance fromString(String instanceId) { instanceId = instanceId.trim(); Matcher matcher = p.matcher(instanceId); Preconditions.checkArgument(matcher.matches(), "Unexpected format for provider, expected " + p.toString() + " but was " + instanceId); String factoryName = matcher.group(1); String instanceName = matcher.group(2); return new ServiceInstance(factoryName, instanceName); } private final String moduleName, instanceName; private String serviceName; public String getServiceName() { return serviceName; } public void setServiceName(String serviceName) { this.serviceName = serviceName; } public String getModuleName() { return moduleName; } public String getInstanceName() { return instanceName; } private static final String blueprint = "/" + XmlNetconfConstants.CONFIG_KEY + "/" + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "[" + XmlNetconfConstants.NAME_KEY + "='%s']/" + XmlNetconfConstants.INSTANCE_KEY + "[" + XmlNetconfConstants.NAME_KEY + "='%s']"; private static final String blueprintR = "/" + XmlNetconfConstants.CONFIG_KEY + "/" + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\[" + XmlNetconfConstants.NAME_KEY + "='%s'\\]/" + XmlNetconfConstants.INSTANCE_KEY + "\\[" + XmlNetconfConstants.NAME_KEY + "='%s'\\]"; private static final Pattern p = Pattern.compile(String.format(blueprintR, "(.+)", "(.+)")); @Override public String toString() { return String.format(blueprint, moduleName, instanceName); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((instanceName == null) ? 0 : instanceName.hashCode()); result = prime * result + ((moduleName == null) ? 0 : moduleName.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ServiceInstance other = (ServiceInstance) obj; if (instanceName == null) { if (other.instanceName != null) return false; } else if (!instanceName.equals(other.instanceName)) return false; if (moduleName == null) { if (other.moduleName != null) return false; } else if (!moduleName.equals(other.moduleName)) return false; return true; } } }