X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fconfig-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fnetconf%2Fconfignetconfconnector%2Fmapping%2Fconfig%2FServices.java;h=77f3cf283fc2daf77c18766c4a9dacd4185f2536;hb=576aa6018e48dfca8f223b7ac929139a32135201;hp=883dde7564a8785b6145ccec544390478bb9ffe5;hpb=dfe4a744e9b2ebbbd06e3e91b6100258c2744983;p=controller.git diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java index 883dde7564..77f3cf283f 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/config/Services.java @@ -9,10 +9,15 @@ package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import com.google.common.collect.Sets; +import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry; +import org.opendaylight.controller.config.api.jmx.ObjectNameUtil; +import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -21,9 +26,9 @@ import org.slf4j.LoggerFactory; 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.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -32,6 +37,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public final class Services { + private static final Logger logger = LoggerFactory.getLogger(Services.class); private static final String PROVIDER_KEY = "provider"; @@ -41,52 +47,33 @@ public final class Services { private long suffix = 1; - private final Map instanceToRef = Maps.newHashMap(); - private final Map> serviceNameToRefNameToInstance = Maps + private final Map>> namespaceToServiceNameToRefNameToInstance = Maps .newHashMap(); + private ServiceReferenceReadableRegistry configServiceRefRegistry; - public String addServiceEntry(String serviceName, ObjectName on) { - - String moduleName = on.getKeyProperty("moduleFactoryName"); - String instanceName = on.getKeyProperty("instanceName"); - - String refName = addServiceEntry(serviceName, moduleName, instanceName); - logger.trace("Added service entry to tracker. Service name {}, ref name {}, module name {}, instance name {}", - serviceName, refName, moduleName, instanceName); - return refName; + public Services(ServiceReferenceReadableRegistry configServiceRefRegistry) { + this.configServiceRefRegistry = configServiceRefRegistry; } @VisibleForTesting - 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; + public String getNewDefaultRefName(String namespace, String serviceName, String moduleName, String instanceName) { + String refName; + refName = "ref_" + instanceName; - final Set refNamesAsSet = toSet(instanceToRef.values()); - if (refNamesAsSet.contains(refName)) { - refName = findAvailableRefName(refName, refNamesAsSet); - } + Map> serviceNameToRefNameToInstance = getMappedServices().get(namespace); - instanceToRef.put(serviceInstance, refName); - refNameToInstance.put(refName, serviceInstance); + Map refNameToInstance; + if(serviceNameToRefNameToInstance == null || serviceNameToRefNameToInstance.containsKey(serviceName) == false) { + refNameToInstance = Collections.emptyMap(); + } else + refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); - return refName; + final Set refNamesAsSet = toSet(refNameToInstance.keySet()); + if (refNamesAsSet.contains(refName)) { + refName = findAvailableRefName(refName, refNamesAsSet); } + + return refName; } private Set toSet(Collection values) { @@ -101,12 +88,20 @@ public final class Services { return refNamesAsSet; } - public ServiceInstance getByServiceAndRefName(String serviceName, String refName) { - Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); + public ServiceInstance getByServiceAndRefName(String namespace, String serviceName, String refName) { + Map> serviceNameToRefNameToInstance = getMappedServices().get(namespace); + + Preconditions.checkArgument(serviceNameToRefNameToInstance != null, "No serviceInstances mapped to " + namespace); + + Map refNameToInstance = serviceNameToRefNameToInstance.get(serviceName); Preconditions.checkArgument(refNameToInstance != null, "No serviceInstances mapped to " + serviceName + " , " + serviceNameToRefNameToInstance.keySet()); - ServiceInstance serviceInstance = refNameToInstance.get(refName); + String instanceId = refNameToInstance.get(refName); + Preconditions.checkArgument(instanceId != null, "No serviceInstances mapped to " + serviceName + ":" + + refName + ", " + serviceNameToRefNameToInstance.keySet()); + + ServiceInstance serviceInstance = ServiceInstance.fromString(instanceId); Preconditions.checkArgument(serviceInstance != null, "No serviceInstance mapped to " + refName + " under service name " + serviceName + " , " + refNameToInstance.keySet()); return serviceInstance; @@ -114,56 +109,109 @@ public final class Services { // TODO hide getMappedServices, call it explicitly in toXml - public Map> getMappedServices() { - Map> retVal = Maps.newHashMap(); + public Map>> getMappedServices() { + Map>> retVal = Maps.newHashMap(); + + for (String namespace : namespaceToServiceNameToRefNameToInstance.keySet()) { - for (String serviceName : serviceNameToRefNameToInstance.keySet()) { + Map> serviceNameToRefNameToInstance = namespaceToServiceNameToRefNameToInstance + .get(namespace); + Map> innerRetVal = Maps.newHashMap(); - Map innerRetVal = Maps.transformValues(serviceNameToRefNameToInstance.get(serviceName), - new Function() { - @Nullable - @Override - public String apply(@Nullable ServiceInstance serviceInstance) { - return serviceInstance.toString(); - } - }); - retVal.put(serviceName, innerRetVal); + for (String serviceName : serviceNameToRefNameToInstance.keySet()) { + + Map innerInnerRetVal = Maps.newHashMap(); + for (Entry refNameToSi : serviceNameToRefNameToInstance.get(serviceName).entrySet()) { + innerInnerRetVal.put(refNameToSi.getKey(), refNameToSi.getValue().toString()); + } + innerRetVal.put(serviceName, innerInnerRetVal); + } + retVal.put(namespace, innerRetVal); } + Map> serviceMapping = configServiceRefRegistry.getServiceMapping(); + for (String serviceQName : serviceMapping.keySet()) + for (String refName : serviceMapping.get(serviceQName).keySet()) { + + ObjectName on = serviceMapping.get(serviceQName).get(refName); + ServiceInstance si = ServiceInstance.fromObjectName(on); + + // FIXME use QName's new String constructor, after its implemented + Pattern p = Pattern.compile("\\(([^\\(\\?]+)\\?[^\\?\\)]*\\)([^\\)]+)"); + Matcher matcher = p.matcher(serviceQName); + Preconditions.checkArgument(matcher.matches()); + String namespace = matcher.group(1); + String localName = matcher.group(2); + + Map> serviceToRefs = retVal.get(namespace); + if(serviceToRefs==null) { + serviceToRefs = Maps.newHashMap(); + retVal.put(namespace, serviceToRefs); + } + + Map refsToSis = serviceToRefs.get(localName); + if(refsToSis==null) { + refsToSis = Maps.newHashMap(); + serviceToRefs.put(localName, refsToSis); + } + + Preconditions.checkState(refsToSis.containsKey(refName) == false, + "Duplicate reference name %s for service %s:%s, now for instance %s", refName, namespace, + localName, on); + refsToSis.put(refName, si.toString()); + } + return retVal; } + /** + * + */ + public Map>> getNamespaceToServiceNameToRefNameToInstance() { + return namespaceToServiceNameToRefNameToInstance; + } + // TODO hide resolveServices, call it explicitly in fromXml - public static Services resolveServices(Map> mappedServices) { - Services tracker = new Services(); + public static Services resolveServices(Map>> mappedServices, ServiceReferenceReadableRegistry taClient) { + Services tracker = new Services(taClient); - for (Entry> serviceEntry : mappedServices.entrySet()) { + for (Entry>> namespaceEntry : mappedServices.entrySet()) { + String namespace = namespaceEntry.getKey(); - String serviceName = serviceEntry.getKey(); - for (Entry refEntry : serviceEntry.getValue().entrySet()) { + for (Entry> serviceEntry : namespaceEntry.getValue().entrySet()) { - Map refNameToInstance = tracker.serviceNameToRefNameToInstance - .get(serviceName); - if (refNameToInstance == null) { - refNameToInstance = Maps.newHashMap(); - tracker.serviceNameToRefNameToInstance.put(serviceName, refNameToInstance); - } + String serviceName = serviceEntry.getKey(); + for (Entry refEntry : serviceEntry.getValue().entrySet()) { - 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); + Map> namespaceToServices = tracker.namespaceToServiceNameToRefNameToInstance.get(namespace); + if (namespaceToServices == null) { + namespaceToServices = Maps.newHashMap(); + tracker.namespaceToServiceNameToRefNameToInstance.put(namespace, namespaceToServices); + } - tracker.instanceToRef.put(serviceInstance, refEntry.getKey()); + Map refNameToInstance = namespaceToServices + .get(serviceName); + if (refNameToInstance == null) { + refNameToInstance = Maps.newHashMap(); + namespaceToServices.put(serviceName, refNameToInstance); + } + + String refName = refEntry.getKey(); + + ServiceInstance serviceInstance = ServiceInstance.fromString(refEntry.getValue()); + refNameToInstance.put(refName, serviceInstance); + + } } } return tracker; } - public static Map> fromXml(XmlElement xml) { - Map> retVal = Maps.newHashMap(); + // TODO support edit strategies on services + + public static Map>> fromXml(XmlElement xml) { + Map>> retVal = Maps.newHashMap(); List services = xml.getChildElements(SERVICE_KEY); xml.checkUnrecognisedElements(services); @@ -171,10 +219,20 @@ public final class Services { for (XmlElement service : services) { XmlElement typeElement = service.getOnlyChildElement(TYPE_KEY); - String serviceName = typeElement.getTextContent(); + Entry prefixNamespace = typeElement.findNamespaceOfTextContent(); + + Preconditions.checkState(prefixNamespace.getKey()!=null && prefixNamespace.getKey().equals("") == false, "Type attribute was not prefixed"); + + Map> namespaceToServices = retVal.get(prefixNamespace.getValue()); + if(namespaceToServices == null) { + namespaceToServices = Maps.newHashMap(); + retVal.put(prefixNamespace.getValue(), namespaceToServices); + } + + String serviceName = ObjectNameAttributeReadingStrategy.checkPrefixAndExtractServiceName(typeElement, prefixNamespace); Map innerMap = Maps.newHashMap(); - retVal.put(serviceName, innerMap); + namespaceToServices.put(serviceName, innerMap); List instances = service.getChildElements(XmlNetconfConstants.INSTANCE_KEY); service.checkUnrecognisedElements(instances, typeElement); @@ -205,32 +263,82 @@ public final class Services { } } - public Element toXml(Map> mappedServices, Document document) { + 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); + for (String namespace : mappedServices.keySet()) { - Element typeElement = XmlUtil.createTextElement(document, TYPE_KEY, serviceEntry.getKey()); - serviceElement.appendChild(typeElement); + for (Entry> serviceEntry : mappedServices.get(namespace).entrySet()) { + Element serviceElement = document.createElement(SERVICE_KEY); + root.appendChild(serviceElement); - for (Entry instanceEntry : serviceEntry.getValue().entrySet()) { - Element instanceElement = document.createElement(XmlNetconfConstants.INSTANCE_KEY); - serviceElement.appendChild(instanceElement); + Element typeElement = XmlUtil.createPrefixedTextElement(document, TYPE_KEY, XmlNetconfConstants.PREFIX, + serviceEntry.getKey()); + XmlUtil.addPrefixedNamespaceAttr(typeElement, XmlNetconfConstants.PREFIX, namespace); + serviceElement.appendChild(typeElement); - Element nameElement = XmlUtil.createTextElement(document, NAME_KEY, instanceEntry.getKey()); - instanceElement.appendChild(nameElement); + for (Entry instanceEntry : serviceEntry.getValue().entrySet()) { + Element instanceElement = document.createElement(XmlNetconfConstants.INSTANCE_KEY); + serviceElement.appendChild(instanceElement); - Element providerElement = XmlUtil.createTextElement(document, PROVIDER_KEY, instanceEntry.getValue()); - instanceElement.appendChild(providerElement); + 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 String getRefName(String namespace, String serviceName, ObjectName on, Optional expectedRefName) { + Optional refNameOptional = getRefNameOptional(namespace, serviceName, on, expectedRefName); + Preconditions.checkState(refNameOptional.isPresent(), "No reference names mapped to %s, %s, %s", namespace, + serviceName, on); + return refNameOptional.get(); + } + + public Optional getRefNameOptional(String namespace, String serviceName, ObjectName on, + Optional expectedRefName) { + Map> services = getMappedServices().get(namespace); + + if(services == null) return Optional.absent(); + Map refs = services.get(serviceName); + + if(refs == null) return Optional.absent(); + Multimap reverted = revertMap(refs); + + ServiceInstance serviceInstance = ServiceInstance.fromObjectName(on); + Collection references = reverted.get(serviceInstance); + + if (expectedRefName.isPresent() && references.contains(expectedRefName.get())) { + logger.debug("Returning expected ref name {} for {}", expectedRefName.get(), on); + return expectedRefName; + } else if (references.size() > 0) { + String next = references.iterator().next(); + logger.debug("Returning random ref name {} for {}", next, on); + return Optional.of(next); + } else + return Optional.absent(); + } + + private Multimap revertMap(Map refs) { + Multimap multimap = HashMultimap.create(); + + for (Entry e : refs.entrySet()) { + multimap.put(ServiceInstance.fromString(e.getValue()), e.getKey()); + } + + return multimap; + } + + public boolean hasRefName(String key, String value, ObjectName on) { + return getRefNameOptional(key, value, on, Optional.absent()).isPresent(); + } + public static final class ServiceInstance { public ServiceInstance(String moduleName, String instanceName) { this.moduleName = moduleName; @@ -240,8 +348,13 @@ public final class Services { public static ServiceInstance fromString(String instanceId) { instanceId = instanceId.trim(); Matcher matcher = p.matcher(instanceId); + if(matcher.matches() == false) { + matcher = pDeprecated.matcher(instanceId); + } + Preconditions.checkArgument(matcher.matches(), "Unexpected format for provider, expected " + p.toString() - + " but was " + instanceId); + + " or " + pDeprecated.toString() + " but was " + instanceId); + String factoryName = matcher.group(1); String instanceName = matcher.group(2); return new ServiceInstance(factoryName, instanceName); @@ -266,16 +379,25 @@ public final class Services { return instanceName; } - private static final String blueprint = "/" + XmlNetconfConstants.CONFIG_KEY + "/" + private static final String blueprint = "/" + XmlNetconfConstants.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "[" - + XmlNetconfConstants.NAME_KEY + "='%s']/" + XmlNetconfConstants.INSTANCE_KEY + "[" + + XmlNetconfConstants.TYPE_KEY + "='%s'][" + XmlNetconfConstants.NAME_KEY + "='%s']"; - private static final String blueprintR = "/" + XmlNetconfConstants.CONFIG_KEY + "/" + // TODO unify with xpath in RuntimeRpc + + // Previous version of xpath, needs to be supported for backwards compatibility (persisted configs by config-persister) + private static final String blueprintRDeprecated = "/" + 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.MODULES_KEY + "/" + XmlNetconfConstants.MODULE_KEY + "\\[" + + XmlNetconfConstants.TYPE_KEY + "='%s'\\]\\[" + + XmlNetconfConstants.NAME_KEY + "='%s'\\]"; + + private static final Pattern pDeprecated = Pattern.compile(String.format(blueprintRDeprecated, "(.+)", "(.+)")); private static final Pattern p = Pattern.compile(String.format(blueprintR, "(.+)", "(.+)")); @Override @@ -314,6 +436,13 @@ public final class Services { return true; } + public ObjectName getObjectName(String transactionName) { + return ObjectNameUtil.createTransactionModuleON(transactionName, moduleName, instanceName); + } + + public static ServiceInstance fromObjectName(ObjectName on) { + return new ServiceInstance(ObjectNameUtil.getFactoryName(on), ObjectNameUtil.getInstanceName(on)); + } } }