From: Ed Warnicke Date: Wed, 11 Jun 2014 19:38:36 +0000 (+0000) Subject: Merge "Added move of branding jar to assembly" X-Git-Tag: release/helium~660 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=48814d6a264b8f13e5db1422336d9ef25cb05fa9;hp=5f076ac845a3dd966860b4398cac9d8854306482 Merge "Added move of branding jar to assembly" --- diff --git a/opendaylight/commons/filter-valve/pom.xml b/opendaylight/commons/filter-valve/pom.xml new file mode 100644 index 0000000000..7b5be02514 --- /dev/null +++ b/opendaylight/commons/filter-valve/pom.xml @@ -0,0 +1,81 @@ + + + + 4.0.0 + + org.opendaylight.controller + commons.opendaylight + 1.4.2-SNAPSHOT + ../opendaylight + + filter-valve + bundle + + + + com.google.guava + guava + + + commons-io + commons-io + + + equinoxSDK381 + javax.servlet + + + orbit + org.apache.catalina + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + test + + + junit + junit + test + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.eclipse.gemini.web.tomcat + javax.servlet, + org.apache.catalina, + org.apache.catalina.connector, + org.apache.catalina.valves, + org.slf4j, + javax.xml.bind, + javax.xml.bind.annotation, + org.apache.commons.io, + com.google.common.base, + com.google.common.collect + + + + + org.opendaylight.yangtools + yang-maven-plugin + + + + + diff --git a/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/FilterValve.java b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/FilterValve.java new file mode 100644 index 0000000000..54d8be11aa --- /dev/null +++ b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/FilterValve.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors; + +import java.io.File; +import java.io.IOException; +import java.util.Objects; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.valves.ValveBase; +import org.apache.commons.io.FileUtils; +import org.opendaylight.controller.filtervalve.cors.jaxb.Host; +import org.opendaylight.controller.filtervalve.cors.jaxb.Parser; +import org.opendaylight.controller.filtervalve.cors.model.FilterProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Valve that allows adding filters per context. Each context can have its own filter definitions. + * Main purpose is to allow externalizing security filters from application bundles to a single + * file per OSGi distribution. + */ +public class FilterValve extends ValveBase { + private static final Logger logger = LoggerFactory.getLogger(FilterValve.class); + private FilterProcessor filterProcessor; + + public void invoke(final Request request, final Response response) throws IOException, ServletException { + if (filterProcessor == null) { + throw new IllegalStateException("Initialization error"); + } + + FilterChain nextValveFilterChain = new FilterChain() { + @Override + public void doFilter(ServletRequest req, ServletResponse resp) throws IOException, ServletException { + boolean reqEquals = Objects.equals(request, req); + boolean respEquals = Objects.equals(response, resp); + if (reqEquals == false || respEquals == false) { + logger.error("Illegal change was detected by valve - request {} or " + + "response {} was replaced by a filter. This is not supported by this valve", + reqEquals, respEquals); + throw new IllegalStateException("Request or response was replaced in a filter"); + } + getNext().invoke(request, response); + } + }; + filterProcessor.process(request, response, nextValveFilterChain); + } + + /** + * Called by Tomcat when configurationFile attribute is set. + * @param fileName path to xml file containing valve configuration + * @throws Exception + */ + @SuppressWarnings("UnusedDeclaration") + public void setConfigurationFile(String fileName) throws Exception { + File configurationFile = new File(fileName); + if (configurationFile.exists() == false || configurationFile.canRead() == false) { + throw new IllegalArgumentException( + "Cannot read 'configurationFile' of this valve defined in tomcat-server.xml: " + fileName); + } + String xmlContent; + try { + xmlContent = FileUtils.readFileToString(configurationFile); + } catch (IOException e) { + logger.error("Cannot read {} of this valve defined in tomcat-server.xml", fileName, e); + throw new IllegalStateException("Cannot read " + fileName, e); + } + Host host; + try { + host = Parser.parse(xmlContent, fileName); + } catch (Exception e) { + logger.error("Cannot parse {} of this valve defined in tomcat-server.xml", fileName, e); + throw new IllegalStateException("Error while parsing " + fileName, e); + } + filterProcessor = new FilterProcessor(host); + } + + /** + * @see org.apache.catalina.valves.ValveBase#getInfo() + */ + public String getInfo() { + return getClass() + "/1.0"; + } +} diff --git a/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Context.java b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Context.java new file mode 100644 index 0000000000..dbe0745725 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Context.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.jaxb; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static java.lang.String.format; + +import com.google.common.base.Optional; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import org.opendaylight.controller.filtervalve.cors.model.UrlMatcher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@XmlRootElement +public class Context { + private static final Logger logger = LoggerFactory.getLogger(Context.class); + + private String path; + private List filters = new ArrayList<>(); + private List filterMappings = new ArrayList<>(); + private boolean initialized; + private UrlMatcher urlMatcher; + + + public synchronized void initialize(String fileName, Map namesToTemplates) { + checkState(initialized == false, "Already initialized"); + Map namesToFilters = new HashMap<>(); + for (Filter filter : filters) { + try { + filter.initialize(fileName, Optional.fromNullable(namesToTemplates.get(filter.getFilterName()))); + } catch (Exception e) { + throw new IllegalStateException(format("Error while processing filter %s of context %s, defined in %s", + filter.getFilterName(), path, fileName), e); + } + namesToFilters.put(filter.getFilterName(), filter); + } + filters = Collections.unmodifiableList(new ArrayList<>(filters)); + LinkedHashMap patternMap = new LinkedHashMap<>(); + for (FilterMapping filterMapping : filterMappings) { + filterMapping.initialize(); + Filter found = namesToFilters.get(filterMapping.getFilterName()); + if (found != null) { + patternMap.put(filterMapping.getUrlPattern(), found); + } else { + logger.error("Cannot find matching filter for filter-mapping {} of context {}, defined in {}", + filterMapping.getFilterName(), path, fileName); + throw new IllegalStateException(format( + "Cannot find filter for filter-mapping %s of context %s, defined in %s", + filterMapping.getFilterName(), path, fileName)); + } + } + filterMappings = Collections.unmodifiableList(new ArrayList<>(filterMappings)); + urlMatcher = new UrlMatcher<>(patternMap); + initialized = true; + } + + public List findMatchingFilters(String pathInfo) { + checkState(initialized, "Not initialized"); + return urlMatcher.findMatchingFilters(pathInfo); + } + + @XmlAttribute(name = "path") + public String getPath() { + return path; + } + + public void setPath(String path) { + checkArgument(initialized == false, "Already initialized"); + this.path = path; + } + + @XmlElement(name = "filter") + public List getFilters() { + return filters; + } + + public void setFilters(List filters) { + checkArgument(initialized == false, "Already initialized"); + this.filters = filters; + } + + @XmlElement(name = "filter-mapping") + public List getFilterMappings() { + return filterMappings; + } + + public void setFilterMappings(List filterMappings) { + checkArgument(initialized == false, "Already initialized"); + this.filterMappings = filterMappings; + } + + @Override + public String toString() { + return "Context{" + + "path='" + path + '\'' + + '}'; + } +} diff --git a/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Filter.java b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Filter.java new file mode 100644 index 0000000000..3dde5b1cfa --- /dev/null +++ b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Filter.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.jaxb; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.Optional; +import com.google.common.collect.MapDifference; +import com.google.common.collect.Maps; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@XmlRootElement +public class Filter implements FilterConfig { + private static final Logger logger = LoggerFactory.getLogger(Filter.class); + + private String filterName; + private String filterClass; + private List initParams = new ArrayList<>(); + private javax.servlet.Filter actualFilter; + private boolean initialized, isTemplate; + + + /** + * Called in filter-template nodes defined in node - do not actually initialize the filter. + * In this case filter is only used to hold values of init params to be merged with + * filter defined in + */ + public synchronized void initializeTemplate(){ + checkState(initialized == false, "Already initialized"); + for (InitParam initParam : initParams) { + initParam.inititialize(); + } + isTemplate = true; + initialized = true; + } + + + public synchronized void initialize(String fileName, Optional maybeTemplate) { + checkState(initialized == false, "Already initialized"); + logger.trace("Initializing filter {} : {}", filterName, filterClass); + for (InitParam initParam : initParams) { + initParam.inititialize(); + } + if (maybeTemplate.isPresent()) { + // merge non conflicting init params + Filter template = maybeTemplate.get(); + checkArgument(template.isTemplate); + Map templateParams = template.getInitParamsMap(); + Map currentParams = getInitParamsMap(); + // add values of template that are not present in current + MapDifference difference = Maps.difference(templateParams, currentParams); + for (Entry templateUnique : difference.entriesOnlyOnLeft().entrySet()) { + initParams.add(templateUnique.getValue()); + } + // merge filterClass + if (filterClass == null) { + filterClass = template.filterClass; + } else if (Objects.equals(filterClass, template.filterClass) == false) { + logger.error("Conflict detected in filter-class of {} defined in {}, template class {}, child class {}" , + filterName, fileName, template.filterClass, filterClass); + throw new IllegalStateException("Conflict detected in template/filter filter-class definitions," + + " filter name: " + filterName + " in file " + fileName); + } + } + initParams = Collections.unmodifiableList(new ArrayList<>(initParams)); + Class clazz; + try { + clazz = Class.forName(filterClass); + } catch (Exception e) { + throw new IllegalStateException("Cannot instantiate class defined in filter " + filterName + + " in file " + fileName, e); + } + try { + actualFilter = (javax.servlet.Filter) clazz.newInstance(); + } catch (Exception e) { + throw new IllegalStateException("Cannot instantiate class defined in filter " + filterName + + " in file " + fileName, e); + } + logger.trace("Initializing {} with following init-params:{}", filterName, getInitParams()); + try { + actualFilter.init(this); + } catch (Exception e) { + throw new IllegalStateException("Cannot initialize filter " + filterName + + " in file " + fileName, e); + } + initialized = true; + } + + @Override + public ServletContext getServletContext() { + throw new UnsupportedOperationException("Getting ServletContext is currently not supported"); + } + + @Override + public String getInitParameter(String name) { + for (InitParam initParam : initParams) { + if (Objects.equals(name, initParam.getParamName())) { + return initParam.getParamValue(); + } + } + return null; + } + + @Override + public Enumeration getInitParameterNames() { + final Iterator iterator = initParams.iterator(); + return new Enumeration() { + @Override + public boolean hasMoreElements() { + return iterator.hasNext(); + } + + @Override + public String nextElement() { + return iterator.next().getParamName(); + } + }; + } + + public javax.servlet.Filter getActualFilter() { + checkState(initialized, "Not initialized"); + return actualFilter; + } + + public boolean isInitialized() { + return initialized; + } + + + @XmlElement(name = "filter-name") + public String getFilterName() { + return filterName; + } + + public void setFilterName(String filterName) { + this.filterName = filterName; + } + + @XmlElement(name = "filter-class") + public String getFilterClass() { + return filterClass; + } + + public void setFilterClass(String filterClass) { + this.filterClass = filterClass; + } + + @XmlElement(name = "init-param") + public List getInitParams() { + return initParams; + } + + public void setInitParams(List initParams) { + this.initParams = initParams; + } + + + @Override + public String toString() { + return "Filter{" + + "filterName='" + filterName + '\'' + + '}'; + } + + public Map getInitParamsMap() { + Map result = new HashMap<>(); + for (InitParam initParam : initParams) { + checkState(initParam.isInitialized()); + result.put(initParam.getParamName(), initParam); + } + return result; + } +} diff --git a/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/FilterMapping.java b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/FilterMapping.java new file mode 100644 index 0000000000..03fcbf26ce --- /dev/null +++ b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/FilterMapping.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.jaxb; + +import static com.google.common.base.Preconditions.checkArgument; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class FilterMapping { + private String filterName; + private String urlPattern; + private boolean initialized; + + @XmlElement(name = "filter-name") + public String getFilterName() { + return filterName; + } + + public void setFilterName(String filterName) { + checkArgument(initialized == false, "Already initialized"); + this.filterName = filterName; + } + + @XmlElement(name = "url-pattern") + public String getUrlPattern() { + return urlPattern; + } + + public void setUrlPattern(String urlPattern) { + checkArgument(initialized == false, "Already initialized"); + this.urlPattern = urlPattern; + } + + public synchronized void initialize() { + checkArgument(initialized == false, "Already initialized"); + initialized = true; + } + + public boolean isInitialized() { + return initialized; + } +} diff --git a/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Host.java b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Host.java new file mode 100644 index 0000000000..4e3c3ba1df --- /dev/null +++ b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Host.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.jaxb; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.Optional; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + + +/** + * Root element, arbitrarily named Host to match tomcat-server.xml, but does not allow specifying which host + * name to be matched. + */ +@XmlRootElement(name = "Host") +public class Host { + private List contexts = new ArrayList<>(); + private List filterTemplates = new ArrayList<>(); + private boolean initialized; + private Map contextMap; + + + public synchronized void initialize(String fileName) { + checkState(initialized == false, "Already initialized"); + Map namesToTemplates = new HashMap<>(); + for (Filter template : filterTemplates) { + template.initializeTemplate(); + namesToTemplates.put(template.getFilterName(), template); + } + contextMap = new HashMap<>(); + for (Context context : getContexts()) { + checkState(contextMap.containsKey(context.getPath()) == false, + "Context {} already defined in {}", context.getPath(), fileName); + context.initialize(fileName, namesToTemplates); + contextMap.put(context.getPath(), context); + } + contextMap = Collections.unmodifiableMap(new HashMap<>(contextMap)); + contexts = Collections.unmodifiableList(new ArrayList<>(contexts)); + initialized = true; + } + + public Optional findContext(String contextPath) { + checkState(initialized, "Not initialized"); + Context context = contextMap.get(contextPath); + return Optional.fromNullable(context); + } + + @XmlElement(name = "Context") + public List getContexts() { + return contexts; + } + + public void setContexts(List contexts) { + checkArgument(initialized == false, "Already initialized"); + this.contexts = contexts; + } + + @XmlElement(name = "filter-template") + public List getFilterTemplates() { + return filterTemplates; + } + + public void setFilterTemplates(List filterTemplates) { + checkArgument(initialized == false, "Already initialized"); + this.filterTemplates = filterTemplates; + } +} diff --git a/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/InitParam.java b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/InitParam.java new file mode 100644 index 0000000000..edc9e4560d --- /dev/null +++ b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/InitParam.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.jaxb; + +import static com.google.common.base.Preconditions.checkState; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class InitParam { + private String paramName; + private String paramValue; + private boolean initialized; + + public synchronized void inititialize() { + checkState(initialized == false, "Already initialized"); + initialized = true; + } + + @XmlElement(name = "param-name") + public String getParamName() { + return paramName; + } + + public void setParamName(String paramName) { + this.paramName = paramName; + } + + @XmlElement(name = "param-value") + public String getParamValue() { + return paramValue; + } + + public void setParamValue(String paramValue) { + this.paramValue = paramValue; + } + + public boolean isInitialized() { + return initialized; + } + + @Override + public String toString() { + return "{" + paramName + '=' + paramValue + "}"; + } +} diff --git a/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Parser.java b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Parser.java new file mode 100644 index 0000000000..bc4f12e157 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/jaxb/Parser.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.jaxb; + +import java.io.StringReader; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; + +public class Parser { + + public static Host parse(String xmlFileContent, String fileName) throws JAXBException { + JAXBContext context = JAXBContext.newInstance(Host.class); + javax.xml.bind.Unmarshaller um = context.createUnmarshaller(); + Host host = (Host) um.unmarshal(new StringReader(xmlFileContent)); + host.initialize(fileName); + return host; + } + +} diff --git a/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/model/FilterProcessor.java b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/model/FilterProcessor.java new file mode 100644 index 0000000000..dc3e9dcd49 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/model/FilterProcessor.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.model; + +import com.google.common.base.Optional; +import java.io.IOException; +import java.util.List; +import java.util.ListIterator; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.opendaylight.controller.filtervalve.cors.jaxb.Context; +import org.opendaylight.controller.filtervalve.cors.jaxb.Filter; +import org.opendaylight.controller.filtervalve.cors.jaxb.Host; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FilterProcessor { + private static final Logger logger = LoggerFactory.getLogger(FilterProcessor.class); + + private final Host host; + + public FilterProcessor(Host host) { + this.host = host; + } + + public void process(Request request, Response response, FilterChain nextValveFilterChain) + throws IOException, ServletException { + + String contextPath = request.getContext().getPath(); + String pathInfo = request.getPathInfo(); + + Optional maybeContext = host.findContext(contextPath); + logger.trace("Processing context {} path {}, found {}", contextPath, pathInfo, maybeContext); + if (maybeContext.isPresent()) { + // process filters + Context context = maybeContext.get(); + List matchingFilters = context.findMatchingFilters(pathInfo); + FilterChain fromLast = nextValveFilterChain; + ListIterator it = matchingFilters.listIterator(matchingFilters.size()); + final boolean trace = logger.isTraceEnabled(); + while (it.hasPrevious()) { + final Filter currentFilter = it.previous(); + final FilterChain copy = fromLast; + fromLast = new FilterChain() { + @Override + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { + if (trace) { + logger.trace("Applying {}", currentFilter); + } + javax.servlet.Filter actualFilter = currentFilter.getActualFilter(); + actualFilter.doFilter(request, response, copy); + } + }; + } + // call first filter + fromLast.doFilter(request, response); + } else { + // move to next valve + nextValveFilterChain.doFilter(request, response); + } + } +} diff --git a/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/model/UrlMatcher.java b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/model/UrlMatcher.java new file mode 100644 index 0000000000..9535fb1f70 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/main/java/org/opendaylight/controller/filtervalve/cors/model/UrlMatcher.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.model; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Maps.immutableEntry; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Match incoming URL with user defined patterns according to servlet specification. + * In the Web application deployment descriptor, the following syntax is used to define mappings: + *
    + *
  • A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for path mapping.
  • + *
  • A string beginning with a ‘*.’ prefix is used as an extension mapping.
  • + *
  • All other strings are used for exact matches only.
  • + *
+ */ +public class UrlMatcher { + private static final Logger logger = LoggerFactory.getLogger(UrlMatcher.class); + // order index for each FILTER is kept as Entry.value + private final Map> prefixMap = new HashMap<>(); // contains patterns ending with '/*', '*' is stripped from each key + private final Map> suffixMap = new HashMap<>(); // contains patterns starting with '*.' prefix, '*' is stripped from each key + private final Map> exactMatchMap = new HashMap<>(); // contains exact matches only + + /** + * @param patternMap order preserving map containing path info pattern as key + */ + public UrlMatcher(LinkedHashMap patternMap) { + int idx = 0; + for (Entry entry : patternMap.entrySet()) { + idx++; + String pattern = checkNotNull(entry.getKey()); + FILTER value = entry.getValue(); + Entry valueWithIdx = immutableEntry(value, idx); + if (pattern.startsWith("/") && pattern.endsWith("/*")) { + pattern = pattern.substring(0, pattern.length() - 1); + prefixMap.put(pattern, valueWithIdx); + } else if (pattern.startsWith("*.")) { + pattern = pattern.substring(1); + suffixMap.put(pattern, valueWithIdx); + } else { + exactMatchMap.put(pattern, valueWithIdx); + } + } + } + + /** + * Find filters matching path + * + * @param pathInfo as returned by request.getPathInfo() + * @return list of matching filters + */ + public List findMatchingFilters(String pathInfo) { + checkNotNull(pathInfo); + TreeMap sortedMap = new TreeMap<>(); + // add matching prefixes + for (Entry> prefixEntry : prefixMap.entrySet()) { + if (pathInfo.startsWith(prefixEntry.getKey())) { + put(sortedMap, prefixEntry.getValue()); + } + } + // add matching suffixes + for (Entry> suffixEntry : suffixMap.entrySet()) { + if (pathInfo.endsWith(suffixEntry.getKey())) { + put(sortedMap, suffixEntry.getValue()); + } + } + // add exact match + Entry exactMatch = exactMatchMap.get(pathInfo); + if (exactMatch != null) { + put(sortedMap, exactMatch); + } + ArrayList filters = new ArrayList<>(sortedMap.values()); + logger.trace("Matching filters for path {} are {}", pathInfo, filters); + return filters; + } + + private void put(TreeMap sortedMap, Entry entry) { + sortedMap.put(entry.getValue(), entry.getKey()); + } +} diff --git a/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/jaxb/DummyFilter.java b/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/jaxb/DummyFilter.java new file mode 100644 index 0000000000..d14caf9a86 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/jaxb/DummyFilter.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.jaxb; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class DummyFilter implements javax.servlet.Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + throw new UnsupportedOperationException(); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + throw new UnsupportedOperationException(); + } + + @Override + public void destroy() { + throw new UnsupportedOperationException(); + } +} diff --git a/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/jaxb/MockedFilter.java b/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/jaxb/MockedFilter.java new file mode 100644 index 0000000000..56d851bc3d --- /dev/null +++ b/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/jaxb/MockedFilter.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.jaxb; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class MockedFilter implements javax.servlet.Filter { + private FilterConfig filterConfig; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + this.filterConfig = filterConfig; + } + + public FilterConfig getFilterConfig() { + return filterConfig; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + throw new UnsupportedOperationException(); + } + + @Override + public void destroy() { + throw new UnsupportedOperationException(); + } +} diff --git a/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/jaxb/ParserTest.java b/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/jaxb/ParserTest.java new file mode 100644 index 0000000000..fc6c01b381 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/jaxb/ParserTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.jaxb; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + +import com.google.common.base.Optional; +import java.io.File; +import javax.servlet.FilterConfig; +import org.apache.commons.io.FileUtils; +import org.junit.Test; + +public class ParserTest { + + @Test + public void testParsing() throws Exception { + File xmlFile = new File(getClass().getResource("/sample-cors-config.xml").getFile()); + assertThat(xmlFile.canRead(), is(true)); + String xmlFileContent = FileUtils.readFileToString(xmlFile); + Host host = Parser.parse(xmlFileContent, "fileName"); + assertEquals(1, host.getContexts().size()); + // check that MockedFilter has init params merged/replaced + Optional context = host.findContext("/restconf"); + assertTrue(context.isPresent()); + assertEquals(1, context.get().getFilters().size()); + MockedFilter filter = (MockedFilter) context.get().getFilters().get(0).getActualFilter(); + FilterConfig filterConfig = filter.getFilterConfig(); + assertEquals("*", filterConfig.getInitParameter("cors.allowed.origins")); + assertEquals("11", filterConfig.getInitParameter("cors.preflight.maxage")); + } + + + @Test + public void testParsing_NoFilterDefined() throws Exception { + File xmlFile = new File(getClass().getResource("/no-filter-defined.xml").getFile()); + assertThat(xmlFile.canRead(), is(true)); + String xmlFileContent = FileUtils.readFileToString(xmlFile); + try { + Parser.parse(xmlFileContent, "fileName"); + fail(); + }catch(Exception e){ + assertThat(e.getMessage(), containsString("Cannot find filter for filter-mapping CorsFilter")); + } + } + + @Test + public void testConflictingClass() throws Exception { + File xmlFile = new File(getClass().getResource("/conflicting-class.xml").getFile()); + assertThat(xmlFile.canRead(), is(true)); + String xmlFileContent = FileUtils.readFileToString(xmlFile); + try { + Parser.parse(xmlFileContent, "fileName"); + fail(); + } catch (RuntimeException e) { + assertThat(e.getMessage(), containsString("Error while processing filter CorsFilter of context /restconf")); + assertThat(e.getCause().getMessage(), containsString("Conflict detected in template/filter filter-class definitions, filter name: CorsFilter")); + } + } +} diff --git a/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/model/UrlMatcherTest.java b/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/model/UrlMatcherTest.java new file mode 100644 index 0000000000..07f6354b19 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/test/java/org/opendaylight/controller/filtervalve/cors/model/UrlMatcherTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014 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.filtervalve.cors.model; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +import java.util.LinkedHashMap; +import org.junit.Test; + +public class UrlMatcherTest { + UrlMatcher urlMatcher; + + @Test + public void test() throws Exception { + final String defaultFilter = "default"; + final String exactMatchFilter = "someFilter"; + final String jspFilter = "jspFilter"; + final String exactMatch = "/somePath"; + final String prefixFilter = "prefixFilter"; + LinkedHashMap patternMap = new LinkedHashMap() { + { + put(exactMatch, exactMatchFilter); + put("/*", defaultFilter); + put("*.jsp", jspFilter); + put("/foo/*", prefixFilter); + } + }; + urlMatcher = new UrlMatcher<>(patternMap); + assertMatches("/abc", defaultFilter); + assertMatches(exactMatch, exactMatchFilter, defaultFilter); + assertMatches("/some.jsp", defaultFilter, jspFilter); + assertMatches("/foo/bar", defaultFilter, prefixFilter); + assertMatches("/foo/bar.jsp", defaultFilter, jspFilter, prefixFilter); + } + + public void assertMatches(String testedPath, String... filters) { + assertEquals(asList(filters), urlMatcher.findMatchingFilters(testedPath)); + } + +} diff --git a/opendaylight/commons/filter-valve/src/test/resources/conflicting-class.xml b/opendaylight/commons/filter-valve/src/test/resources/conflicting-class.xml new file mode 100644 index 0000000000..c1faf34b38 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/test/resources/conflicting-class.xml @@ -0,0 +1,34 @@ + + + + + CorsFilter + org.opendaylight.controller.filtervalve.cors.jaxb.MockedFilter + + cors.preflight.maxage + 10 + + + cors.allowed.origins + * + + + + + + CorsFilter + + org.opendaylight.controller.filtervalve.cors.jaxb.DummyFilter + + + CorsFilter + /* + + + diff --git a/opendaylight/commons/filter-valve/src/test/resources/no-filter-defined.xml b/opendaylight/commons/filter-valve/src/test/resources/no-filter-defined.xml new file mode 100644 index 0000000000..521d578da5 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/test/resources/no-filter-defined.xml @@ -0,0 +1,61 @@ + + + + + + CorsFilter + org.opendaylight.controller.filtervalve.cors.jaxb.MockedFilter + + cors.allowed.origins + * + + + cors.allowed.methods + GET,POST,HEAD,OPTIONS,PUT,DELETE + + + cors.allowed.headers + Content-Type,X-Requested-With,accept,authorization, + origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers + + + + cors.exposed.headers + Access-Control-Allow-Origin,Access-Control-Allow-Credentials + + + cors.support.credentials + true + + + cors.preflight.maxage + 10 + + + + + + + CorsFilter + + + + + CorsFilter + /* + + + + + + CorsFilter + /* + + + diff --git a/opendaylight/commons/filter-valve/src/test/resources/sample-cors-config.xml b/opendaylight/commons/filter-valve/src/test/resources/sample-cors-config.xml new file mode 100644 index 0000000000..613dc825d7 --- /dev/null +++ b/opendaylight/commons/filter-valve/src/test/resources/sample-cors-config.xml @@ -0,0 +1,37 @@ + + + + + CorsFilter + org.opendaylight.controller.filtervalve.cors.jaxb.MockedFilter + + cors.preflight.maxage + 10 + + + cors.allowed.origins + * + + + + + + CorsFilter + + + cors.preflight.maxage + 11 + + + + CorsFilter + /* + + + diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index 927c8a3fd2..c3c8168bd7 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -65,6 +65,7 @@ 3.1.0 3.1.6 4.2.0 + 1.4.2-SNAPSHOT 0.4.2-SNAPSHOT 0.4.2-SNAPSHOT 0.5.2-SNAPSHOT @@ -822,6 +823,11 @@ devices.web ${devices.web.version} + + org.opendaylight.controller + filter-valve + ${filtervalve.version} + org.opendaylight.controller flowprogrammer.northbound @@ -957,6 +963,11 @@ ${netconf.version} test-jar + + org.opendaylight.controller + netconf-tcp + ${netconf.version} + org.opendaylight.controller netconf-util diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java index 916ef9a88b..fef2c71969 100644 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java +++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/protocol/framework/AbstractDispatcher.java @@ -7,12 +7,16 @@ */ package org.opendaylight.protocol.framework; +import com.google.common.base.Preconditions; import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; +import io.netty.channel.ServerChannel; +import io.netty.channel.local.LocalServerChannel; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; @@ -21,22 +25,20 @@ import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.concurrent.Promise; - import java.io.Closeable; import java.net.InetSocketAddress; - +import java.net.SocketAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; - /** * Dispatcher class for creating servers and clients. The idea is to first create servers and clients and the run the * start method that will handle sockets in different thread. */ public abstract class AbstractDispatcher, L extends SessionListener> implements Closeable { - protected interface PipelineInitializer> { + + protected interface ChannelPipelineInitializer> { /** * Initializes channel by specifying the handlers in its pipeline. Handlers are protocol specific, therefore this * method needs to be implemented in protocol specific Dispatchers. @@ -44,7 +46,11 @@ public abstract class AbstractDispatcher, L extends * @param channel whose pipeline should be defined, also to be passed to {@link SessionNegotiatorFactory} * @param promise to be passed to {@link SessionNegotiatorFactory} */ - void initializeChannel(SocketChannel channel, Promise promise); + void initializeChannel(CH channel, Promise promise); + } + + protected interface PipelineInitializer> extends ChannelPipelineInitializer { + } @@ -76,25 +82,43 @@ public abstract class AbstractDispatcher, L extends * @return ChannelFuture representing the binding process */ protected ChannelFuture createServer(final InetSocketAddress address, final PipelineInitializer initializer) { + return createServer(address, NioServerSocketChannel.class, initializer); + } + + /** + * Creates server. Each server needs factories to pass their instances to client sessions. + * + * @param address address to which the server should be bound + * @param channelClass The {@link Class} which is used to create {@link Channel} instances from. + * @param initializer instance of PipelineInitializer used to initialize the channel pipeline + * + * @return ChannelFuture representing the binding process + */ + protected ChannelFuture createServer(SocketAddress address, Class channelClass, + final ChannelPipelineInitializer initializer) { final ServerBootstrap b = new ServerBootstrap(); - b.childHandler(new ChannelInitializer() { + b.childHandler(new ChannelInitializer() { @Override - protected void initChannel(final SocketChannel ch) { + protected void initChannel(final CH ch) { initializer.initializeChannel(ch, new DefaultPromise(executor)); } }); b.option(ChannelOption.SO_BACKLOG, 128); - b.childOption(ChannelOption.SO_KEEPALIVE, true); + if (LocalServerChannel.class.equals(channelClass) == false) { + // makes no sense for LocalServer and produces warning + b.childOption(ChannelOption.SO_KEEPALIVE, true); + } customizeBootstrap(b); if (b.group() == null) { b.group(bossGroup, workerGroup); } try { - b.channel(NioServerSocketChannel.class); + b.channel(channelClass); } catch (IllegalStateException e) { + // FIXME: if this is ok, document why LOG.trace("Not overriding channelFactory on bootstrap {}", b, e); } diff --git a/opendaylight/config/pom.xml b/opendaylight/config/pom.xml index 613940144b..5f34a9aa82 100644 --- a/opendaylight/config/pom.xml +++ b/opendaylight/config/pom.xml @@ -152,6 +152,35 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.12 + + false + false + checkstyle-logging.xml + true + true + ${project.basedir} + **\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat,**\/*.yang + **\/target\/,**\/bin\/,**\/target-ide\/,**\/${jmxGeneratorPath}\/,**\/${salGeneratorPath}\/ + + + + org.opendaylight.yangtools + checkstyle-logging + ${yangtools.version} + + + + + + check + + + + org.apache.maven.plugins maven-compiler-plugin diff --git a/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/fixed/FixedThreadPoolConfigBeanTest.java b/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/fixed/FixedThreadPoolConfigBeanTest.java index af7f01a632..62b295be8d 100644 --- a/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/fixed/FixedThreadPoolConfigBeanTest.java +++ b/opendaylight/config/threadpool-config-impl/src/test/java/org/opendaylight/controller/config/threadpool/fixed/FixedThreadPoolConfigBeanTest.java @@ -7,12 +7,16 @@ */ package org.opendaylight.controller.config.threadpool.fixed; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.matchers.JUnitMatchers.containsString; import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.ArrayList; +import java.util.List; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.ObjectName; @@ -28,8 +32,11 @@ import org.opendaylight.controller.config.yang.threadpool.impl.NamingThreadFacto import org.opendaylight.controller.config.yang.threadpool.impl.NamingThreadFactoryModuleMXBean; import org.opendaylight.controller.config.yang.threadpool.impl.fixed.FixedThreadPoolModuleFactory; import org.opendaylight.controller.config.yang.threadpool.impl.fixed.FixedThreadPoolModuleMXBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { + private static final Logger logger = LoggerFactory.getLogger(FixedThreadPoolConfigBeanTest.class); private FixedThreadPoolModuleFactory factory; private final String nameInstance = "fixedInstance"; @@ -37,7 +44,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { @Before public void setUp() { factory = new FixedThreadPoolModuleFactory(); - super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext,factory, + super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, factory, new NamingThreadFactoryModuleFactory())); } @@ -45,7 +52,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { public void testCreateBean() throws InstanceAlreadyExistsException, ValidationException, ConflictingVersionException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, 2); + createFixed(transaction, nameInstance, 2, nameInstance); transaction.validateConfig(); CommitStatus status = transaction.commit(); @@ -58,7 +65,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { public void testReusingOldInstance() throws InstanceAlreadyExistsException, ConflictingVersionException, ValidationException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, 4); + createFixed(transaction, nameInstance, 4, nameInstance); transaction.validateConfig(); transaction.commit(); @@ -76,12 +83,12 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { public void testNegative() throws ConflictingVersionException, ValidationException, InstanceAlreadyExistsException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, 5); + createFixed(transaction, nameInstance, 5, nameInstance); transaction.commit(); transaction = configRegistryClient.createTransaction(); try { - createFixed(transaction, nameInstance, 0); + createFixed(transaction, nameInstance, 0, nameInstance); fail(); } catch (InstanceAlreadyExistsException e) { assertThat( @@ -90,18 +97,35 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { } } + private int countThreadsByPrefix(String prefix) { + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + int result = 0; + List names = new ArrayList<>(); + for (ThreadInfo threadInfo : threadMXBean.dumpAllThreads(false, false)) { + names.add(threadInfo.getThreadName()); + if (threadInfo.getThreadName().startsWith(prefix)) { + result++; + } + } + logger.info("Current threads {}", names); + return result; + } + @Test public void testDestroy() throws InstanceAlreadyExistsException, ValidationException, ConflictingVersionException, - InstanceNotFoundException { + InstanceNotFoundException, InterruptedException { + + String prefix = org.apache.commons.lang3.RandomStringUtils.randomAlphabetic(10); int numberOfThreads = 100; - int threadCount1 = ManagementFactory.getThreadMXBean().getThreadCount(); - assertTrue("Expected less than " + numberOfThreads + " threads, got " + threadCount1, threadCount1 < numberOfThreads); + int threadCount1 = countThreadsByPrefix(prefix); + assertEquals(0, threadCount1); ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, numberOfThreads); + + createFixed(transaction, nameInstance, numberOfThreads, prefix); transaction.commit(); - int threadCount2 = ManagementFactory.getThreadMXBean().getThreadCount(); - assertTrue("Expected more than " + numberOfThreads + " threads, got " + threadCount2, threadCount2 > numberOfThreads); + int threadCount2 = countThreadsByPrefix(prefix); + assertEquals(numberOfThreads, threadCount2); transaction = configRegistryClient.createTransaction(); transaction.destroyModule(factory.getImplementationName(), nameInstance); @@ -109,14 +133,20 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { assertBeanCount(0, factory.getImplementationName()); assertStatus(status, 0, 0, 1); - int threadCount3 = ManagementFactory.getThreadMXBean().getThreadCount(); - assertTrue("Expected less than " + numberOfThreads + " threads, got " + threadCount3, threadCount3 < numberOfThreads); + + for (int i = 0; i < 60; i++) { + if (countThreadsByPrefix(prefix) == 0) { + return; + } + Thread.sleep(1000); + } + assertEquals(0, countThreadsByPrefix(prefix)); } @Test public void testValidationException() throws InstanceAlreadyExistsException { ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction(); - createFixed(transaction, nameInstance, -1); + createFixed(transaction, nameInstance, -1, nameInstance); try { transaction.validateConfig(); fail(); @@ -125,7 +155,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { } } - private ObjectName createFixed(ConfigTransactionJMXClient transaction, String name, int numberOfThreads) + private ObjectName createFixed(ConfigTransactionJMXClient transaction, String name, int numberOfThreads, String prefix) throws InstanceAlreadyExistsException { ObjectName nameCreated = transaction.createModule(factory.getImplementationName(), name); FixedThreadPoolModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, FixedThreadPoolModuleMXBean.class); @@ -134,7 +164,7 @@ public class FixedThreadPoolConfigBeanTest extends AbstractConfigTest { ObjectName threadFactoryON = transaction.createModule(NamingThreadFactoryModuleFactory.NAME, "naming"); NamingThreadFactoryModuleMXBean namingThreadFactoryModuleMXBean = transaction.newMXBeanProxy(threadFactoryON, NamingThreadFactoryModuleMXBean.class); - namingThreadFactoryModuleMXBean.setNamePrefix("prefix"); + namingThreadFactoryModuleMXBean.setNamePrefix(prefix); mxBean.setThreadFactory(threadFactoryON); diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.java index 48a6c15706..8c65eaad14 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsFactoryGeneratedObjectFactory.java @@ -31,9 +31,9 @@ import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.Generated import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.JavaFileInputBuilder; import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.TypeName; import org.opendaylight.yangtools.yang.common.QName; -import org.osgi.framework.BundleContext; public class AbsFactoryGeneratedObjectFactory { + private static final String BUNDLE_CONTEXT = "org.osgi.framework.BundleContext"; public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional copyright) { FullyQualifiedName absFactoryFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractFactoryName()); @@ -91,7 +91,7 @@ public class AbsFactoryGeneratedObjectFactory { "public %s createModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+ "return instantiateModule(instanceName, dependencyResolver, bundleContext);\n"+ "}\n", - Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(), BundleContext.class.getCanonicalName())); + Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(), BUNDLE_CONTEXT)); b.addToBody(getCreateModule(moduleFQN, moduleFields)); @@ -100,12 +100,12 @@ public class AbsFactoryGeneratedObjectFactory { "return new %s(new %s(NAME, instanceName), dependencyResolver, oldModule, oldInstance);\n"+ "}\n", moduleFQN, DependencyResolver.class.getCanonicalName(), moduleFQN, AutoCloseable.class.getCanonicalName(), - BundleContext.class.getCanonicalName(), moduleFQN, ModuleIdentifier.class.getCanonicalName())); + BUNDLE_CONTEXT, moduleFQN, ModuleIdentifier.class.getCanonicalName())); b.addToBody(format("\n"+ "public %s instantiateModule(String instanceName, %s dependencyResolver, %s bundleContext) {\n"+ "return new %s(new %s(NAME, instanceName), dependencyResolver);\n"+ - "}\n", moduleFQN, DependencyResolver.class.getCanonicalName(), BundleContext.class.getCanonicalName(), + "}\n", moduleFQN, DependencyResolver.class.getCanonicalName(), BUNDLE_CONTEXT, moduleFQN, ModuleIdentifier.class.getCanonicalName() )); @@ -118,7 +118,7 @@ public class AbsFactoryGeneratedObjectFactory { "@Override\n"+ "public java.util.Set<%s> getDefaultModules(org.opendaylight.controller.config.api.DependencyResolverFactory dependencyResolverFactory, %s bundleContext) {\n"+ "return new java.util.HashSet<%s>();\n"+ - "}\n", moduleFQN, BundleContext.class.getCanonicalName(), moduleFQN)); + "}\n", moduleFQN, BUNDLE_CONTEXT, moduleFQN)); return new GeneratedObjectBuilder(b.build()).toGeneratedObject(); } @@ -127,8 +127,8 @@ public class AbsFactoryGeneratedObjectFactory { String result = "\n"+ "@Override\n"+ format("public %s createModule(String instanceName, %s dependencyResolver, %s old, %s bundleContext) throws Exception {\n", - Module.class.getCanonicalName(),DependencyResolver.class.getCanonicalName(), - DynamicMBeanWithInstance.class.getCanonicalName(),BundleContext.class.getCanonicalName())+ + Module.class.getCanonicalName(), DependencyResolver.class.getCanonicalName(), + DynamicMBeanWithInstance.class.getCanonicalName(), BUNDLE_CONTEXT)+ format("%s oldModule = null;\n",moduleFQN)+ "try {\n"+ format("oldModule = (%s) old.getModule();\n",moduleFQN)+ diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java index 6da8dfc663..89f3a4a519 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java @@ -18,7 +18,6 @@ import com.google.common.base.Optional; import com.google.common.collect.Collections2; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -96,14 +95,10 @@ final class ModuleMXBeanEntryBuilder { // TODO: the XPath should be parsed by code generator IMO private static final String MAGIC_STRING = "MAGIC_STRING"; private static final String MODULE_CONDITION_XPATH_TEMPLATE = "^/MAGIC_STRING:modules/MAGIC_STRING:module/MAGIC_STRING:type\\s*=\\s*['\"](.+)['\"]$"; - private static final SchemaPath expectedConfigurationAugmentationSchemaPath = new SchemaPath( - Arrays.asList(createConfigQName("modules"), - createConfigQName("module"), - createConfigQName("configuration")), true); - private static final SchemaPath expectedStateAugmentationSchemaPath = new SchemaPath( - Arrays.asList(createConfigQName("modules"), - createConfigQName("module"), createConfigQName("state")), - true); + private static final SchemaPath expectedConfigurationAugmentationSchemaPath = SchemaPath.create(true, + createConfigQName("modules"), createConfigQName("module"), createConfigQName("configuration")); + private static final SchemaPath expectedStateAugmentationSchemaPath = SchemaPath.create(true, + createConfigQName("modules"), createConfigQName("module"), createConfigQName("state")); private static final Pattern PREFIX_COLON_LOCAL_NAME = Pattern .compile("^(.+):(.+)$"); diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 5b44bb7569..3916e05496 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -862,6 +862,10 @@ org.opendaylight.controller config-persister-impl + + org.opendaylight.controller + filter-valve + org.opendaylight.controller logback-config @@ -902,6 +906,10 @@ org.opendaylight.controller netconf-ssh + + org.opendaylight.controller + netconf-tcp + org.opendaylight.controller netconf-util diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini index f15f8f7404..f05afbb346 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini @@ -14,13 +14,11 @@ osgi.bundles=\ # Netconf startup configuration -# Netconf tcp address:port is optional with default value 127.0.0.1:8383 +# Netconf tcp address:port is optional #netconf.tcp.address=127.0.0.1 -#netconf.tcp.port=8384 - -#netconf.tcp.client.address=127.0.0.1 -#netconf.tcp.client.port=8384 +#netconf.tcp.port=8383 +# Netconf tcp address:port is optional netconf.ssh.address=0.0.0.0 netconf.ssh.port=1830 netconf.ssh.pk.path = ./configuration/RSA.pk diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/cors-config.xml b/opendaylight/distribution/opendaylight/src/main/resources/configuration/cors-config.xml new file mode 100644 index 0000000000..00abf6cf33 --- /dev/null +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/cors-config.xml @@ -0,0 +1,54 @@ + + + + + + CorsFilter + org.apache.catalina.filters.CorsFilter + + cors.allowed.origins + * + + + cors.allowed.methods + GET,POST,HEAD,OPTIONS,PUT,DELETE + + + cors.allowed.headers + Content-Type,X-Requested-With,accept,authorization, + origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers + + + + cors.exposed.headers + Access-Control-Allow-Origin,Access-Control-Allow-Credentials + + + cors.support.credentials + true + + + cors.preflight.maxage + 10 + + + + + + CorsFilter + + + + + CorsFilter + /* + + + + diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/tomcat-server.xml b/opendaylight/distribution/opendaylight/src/main/resources/configuration/tomcat-server.xml index 56d469b599..da2500be62 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/tomcat-server.xml +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/tomcat-server.xml @@ -56,6 +56,9 @@ rotatable="true" fileDateFormat="yyyy-MM" pattern="%{yyyy-MM-dd HH:mm:ss.SSS z}t - [%a] - %r"/> +
diff --git a/opendaylight/distribution/opendaylight/src/main/resources/run.sh b/opendaylight/distribution/opendaylight/src/main/resources/run.sh index dba996a994..1e903d0650 100755 --- a/opendaylight/distribution/opendaylight/src/main/resources/run.sh +++ b/opendaylight/distribution/opendaylight/src/main/resources/run.sh @@ -13,7 +13,7 @@ if [[ $platform == 'linux' ]]; then if [[ -z ${JAVA_HOME} ]]; then # Find the actual location of the Java launcher: - java_launcher=`which java` + java_launcher=`command -v java` java_launcher=`readlink -f "${java_launcher}"` # Compute the Java home from the location of the Java launcher: diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml index 18fb785dd1..fc58ed96e1 100644 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/pom.xml @@ -14,10 +14,6 @@ com.google.guava guava - - org.eclipse.xtend - org.eclipse.xtend.lib - org.opendaylight.controller forwardingrulesmanager @@ -84,10 +80,6 @@ - - org.eclipse.xtend - xtend-maven-plugin - diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.java new file mode 100644 index 0000000000..b37b50159f --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.java @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2014 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.md.compatibility.inventory; + +import java.util.ArrayList; +import java.util.Set; + +import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; +import org.opendaylight.controller.sal.compatibility.InventoryMapping; +import org.opendaylight.controller.switchmanager.ISwitchManager; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class InventoryReader implements RuntimeDataProvider { + private static final Logger LOG = LoggerFactory.getLogger(InventoryReader.class); + private ISwitchManager switchManager; + + public ISwitchManager getSwitchManager() { + return switchManager; + } + + public void setSwitchManager(final ISwitchManager switchManager) { + this.switchManager = switchManager; + } + + @Override + public DataObject readConfigurationData(final InstanceIdentifier path) { + // Topology and Inventory are operational only + return null; + } + + @SuppressWarnings("unchecked") + @Override + public DataObject readOperationalData(final InstanceIdentifier path) { + final Class type = path.getTargetType(); + if (Nodes.class.equals(type)) { + return readNodes(((InstanceIdentifier) path)); + } + if (Node.class.equals(type)) { + return readNode(((InstanceIdentifier) path)); + } + if (NodeConnector.class.equals(type)) { + return readNodeConnector(((InstanceIdentifier) path)); + } + + LOG.debug("Unsupported type {}", type); + return null; + } + + private NodeConnector readNodeConnector(final InstanceIdentifier identifier) { + return constructNodeConnector(InventoryMapping.toAdNodeConnector(identifier)); + } + + private Node readNode(final InstanceIdentifier identifier) { + return constructNode(InventoryMapping.toAdNode(identifier)); + } + + private Node constructNode(final org.opendaylight.controller.sal.core.Node node) { + final Set connectors = getSwitchManager().getNodeConnectors(node); + final ArrayList tpList = new ArrayList(connectors.size()); + for (final org.opendaylight.controller.sal.core.NodeConnector connector : connectors) { + tpList.add(constructNodeConnector(connector)); + } + + return new NodeBuilder() + .setKey(InventoryMapping.toNodeKey(node)) + .setNodeConnector(tpList) + .build(); + } + + private Nodes readNodes(final InstanceIdentifier identifier) { + final Set nodes = getSwitchManager().getNodes(); + final ArrayList nodeList = new ArrayList(nodes.size()); + for (final org.opendaylight.controller.sal.core.Node node : nodes) { + nodeList.add(constructNode(node)); + } + + return new NodesBuilder().setNode(nodeList).build(); + } + + private static NodeConnector constructNodeConnector(final org.opendaylight.controller.sal.core.NodeConnector connector) { + return new NodeConnectorBuilder().setKey(InventoryMapping.toNodeConnectorKey(connector)).build(); + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.xtend deleted file mode 100644 index 9b71369593..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/inventory/InventoryReader.xtend +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2014 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.md.compatibility.inventory - -import org.opendaylight.controller.switchmanager.ISwitchManager -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider -import java.util.ArrayList -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector -import static extension org.opendaylight.controller.sal.compatibility.InventoryMapping.*; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder - -class InventoryReader implements RuntimeDataProvider { - - @Property - var ISwitchManager switchManager; - - override readConfigurationData(InstanceIdentifier path) { - - // Topology and Inventory are operational only - return null; - } - - override readOperationalData(InstanceIdentifier path) { - val type = path.targetType; - var DataObject data = null; - switch (type) { - case Nodes: - data = readNodes(path as InstanceIdentifier) - case Node: - data = readNode(path as InstanceIdentifier) - case NodeConnector: - data = readNodeConnector(path as InstanceIdentifier) - } - return data; - } - - def DataObject readNodeConnector(InstanceIdentifier identifier) { - val nodeConnector = identifier.toAdNodeConnector(); - return constructNodeConnector(nodeConnector) - } - - def DataObject readNode(InstanceIdentifier identifier) { - val node = identifier.toAdNode(); - return constructNode(node); - } - - - def Node constructNode(org.opendaylight.controller.sal.core.Node node) { - val connectors = switchManager.getNodeConnectors(node) - - val tpList = new ArrayList(connectors.size) - for (connector : connectors) { - tpList.add(constructNodeConnector(connector)); - } - - val it = new NodeBuilder() - key = node.toNodeKey(); - nodeConnector = tpList - return build(); - } - - def NodeConnector constructNodeConnector(org.opendaylight.controller.sal.core.NodeConnector connector) { - val it = new NodeConnectorBuilder() - key = connector.toNodeConnectorKey() - return build(); - } - - def readNodes(InstanceIdentifier identifier) { - val nodes = switchManager.nodes - val nodeList = new ArrayList(nodes.size) - for (node : nodes) { - nodeList.add(constructNode(node)) - } - val it = new NodesBuilder(); - node = nodeList - return build() - - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.java new file mode 100644 index 0000000000..82c5b7bf61 --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.java @@ -0,0 +1,347 @@ +/** + * Copyright (c) 2014 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.md.compatibility.switchmanager; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.compatibility.NodeMapping; +import org.opendaylight.controller.sal.core.Bandwidth; +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.core.Description; +import org.opendaylight.controller.sal.core.ForwardingMode; +import org.opendaylight.controller.sal.core.MacAddress; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.controller.sal.core.Tier; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.switchmanager.ISwitchManager; +import org.opendaylight.controller.switchmanager.Subnet; +import org.opendaylight.controller.switchmanager.Switch; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CompatibleSwitchManager extends ConfigurableSwitchManager implements ISwitchManager { + private static final Logger LOG = LoggerFactory.getLogger(CompatibleSwitchManager.class); + + private DataBrokerService _dataService; + + public DataBrokerService getDataService() { + return this._dataService; + } + + public void setDataService(final DataBrokerService dataService) { + this._dataService = dataService; + } + + @Override + public Status addNodeConnectorProp(final NodeConnector nodeConnector, final Property prop) { + final DataModificationTransaction it = getDataService().beginTransaction(); + final NodeConnectorRef path = NodeMapping.toNodeConnectorRef(nodeConnector); + return null; + } + + @Override + public Property createProperty(final String propName, final String propValue) { + try { + if (propName.equalsIgnoreCase(Description.propertyName)) { + return new Description(propValue); + } else if (propName.equalsIgnoreCase(Tier.TierPropName)) { + return new Tier(Integer.parseInt(propValue)); + } else if (propName.equalsIgnoreCase(Bandwidth.BandwidthPropName)) { + return new Bandwidth(Long.parseLong(propValue)); + } else if (propName.equalsIgnoreCase(ForwardingMode.name)) { + return new ForwardingMode(Integer.parseInt(propValue)); + } else if (propName.equalsIgnoreCase(MacAddress.name)) { + return new MacAddress(propValue); + } else { + LOG.debug("Not able to create {} property", propName); + } + } catch (Exception e) { + LOG.debug("createProperty caught exception {}", e.getMessage()); + } + + return null; + } + + @Override + public boolean doesNodeConnectorExist(final NodeConnector nc) { + return (getDataService().readOperationalData(NodeMapping.toNodeConnectorRef(nc).getValue()) != null); + } + + @Override + public byte[] getControllerMAC() { + final Enumeration nis; + try { + nis = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException e) { + LOG.error("Failed to acquire list of interfaces, cannot determine controller MAC", e); + return null; + } + + while (nis.hasMoreElements()) { + final NetworkInterface ni = nis.nextElement(); + try { + return ni.getHardwareAddress(); + } catch (SocketException e) { + LOG.error("Failed to acquire controller MAC from interface {}", ni, e); + } + } + + // This happens when running controller on windows VM, for example + // Try parsing the OS command output + LOG.warn("Failed to acquire controller MAC: No physical interface found"); + return null; + } + + @Override + public Map getControllerProperties() { + return Collections.emptyMap(); + } + + @Override + public Property getControllerProperty(final String propertyName) { + return null; + } + + @Override + public List getNetworkDevices() { + final InstanceIdentifier path = InstanceIdentifier.builder(Nodes.class).toInstance(); + final Nodes data = ((Nodes) getDataService().readOperationalData(path)); + final ArrayList ret = new ArrayList<>(); + for (final Node node : data.getNode()) { + try { + ret.add(toSwitch(node)); + } catch (ConstructionException e) { + throw new IllegalStateException(String.format("Failed to create switch {}", node), e); + } + } + return ret; + } + + @Override + public NodeConnector getNodeConnector(final org.opendaylight.controller.sal.core.Node node, final String nodeConnectorName) { + final NodeConnectorKey key = new NodeConnectorKey(new NodeConnectorId(nodeConnectorName)); + try { + return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, node); + } catch (ConstructionException e) { + throw new IllegalStateException(String.format("Failed to create node connector for {} {}", node, nodeConnectorName), e); + } + } + + @Override + public Property getNodeConnectorProp(final NodeConnector nodeConnector, final String propName) { + return getNodeConnectorProps(nodeConnector).get(propName); + } + + @Override + public Map getNodeConnectorProps(final NodeConnector nodeConnector) { + final NodeConnectorRef ref = NodeMapping.toNodeConnectorRef(nodeConnector); + return toAdProperties(readNodeConnector(ref.getValue())); + } + + @Override + public Set getNodeConnectors(final org.opendaylight.controller.sal.core.Node node) { + final Node data = this.readNode(NodeMapping.toNodeRef(node).getValue()); + final HashSet ret = new HashSet<>(); + for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc : data.getNodeConnector()) { + try { + ret.add(new NodeConnector(NodeMapping.MD_SAL_TYPE, nc.getKey(), node)); + } catch (ConstructionException e) { + throw new IllegalStateException(String.format("Failed to create node {} connector", node, nc.getKey()), e); + } + } + return ret; + } + + @Override + public String getNodeDescription(final org.opendaylight.controller.sal.core.Node node) { + return ((Description) getNodeProps(node).get(Description.propertyName)).getValue(); + } + + @Override + public byte[] getNodeMAC(final org.opendaylight.controller.sal.core.Node node) { + return ((MacAddress) getNodeProps(node).get(MacAddress.name)).getMacAddress(); + } + + @Override + public Property getNodeProp(final org.opendaylight.controller.sal.core.Node node, final String propName) { + return getNodeProps(node).get(propName); + } + + @Override + public Map getNodeProps(final org.opendaylight.controller.sal.core.Node node) { + final NodeRef ref = NodeMapping.toNodeRef(node); + return toAdProperties(((Node) getDataService().readOperationalData(ref.getValue()))); + } + + @Override + public Set getNodes() { + final InstanceIdentifier path = InstanceIdentifier.builder(Nodes.class).toInstance(); + final Nodes data = ((Nodes) getDataService().readOperationalData(path)); + final HashSet ret = new HashSet<>(); + for (final Node node : data.getNode()) { + try { + ret.add(new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, node.getKey())); + } catch (ConstructionException e) { + throw new IllegalStateException(String.format("Failed to create node for {}", node), e); + } + } + return ret; + } + + private static Switch toSwitch(final Node node) throws ConstructionException { + return new Switch(new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, node.getKey())); + } + + @Override + public Set getPhysicalNodeConnectors(final org.opendaylight.controller.sal.core.Node node) { + final NodeRef ref = NodeMapping.toNodeRef(node); + final Node data = readNode(ref.getValue()); + final HashSet ret = new HashSet<>(); + for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc : data.getNodeConnector()) { + final FlowCapableNodeConnector flowConnector = nc.getAugmentation(FlowCapableNodeConnector.class); + try { + ret.add(new NodeConnector(NodeMapping.MD_SAL_TYPE, nc.getKey(), node)); + } catch (ConstructionException e) { + throw new IllegalStateException(String.format("Failed to create connector for {} on node {}", nc.getKey(), node), e); + } + } + return ret; + } + + private static Map toAdProperties(final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector connector) { + return Collections.emptyMap(); + } + + private static Map toAdProperties(final Node connector) { + return Collections.emptyMap(); + } + + private Node readNode(final InstanceIdentifier ref) { + return (Node) getDataService().readOperationalData((ref)); + } + + private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector readNodeConnector(final InstanceIdentifier ref) { + return ((org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector) getDataService().readOperationalData(ref)); + } + + @Override + public List getSpanPorts(final org.opendaylight.controller.sal.core.Node node) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public Subnet getSubnetByNetworkAddress(final InetAddress networkAddress) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public Set getUpNodeConnectors(final org.opendaylight.controller.sal.core.Node node) { + final Node data = readNode(NodeMapping.toNodeRef(node).getValue()); + final HashSet ret = new HashSet<>(); + for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc : data.getNodeConnector()) { + final FlowCapableNodeConnector flowConn = nc.getAugmentation(FlowCapableNodeConnector.class); + if (flowConn != null && flowConn.getState() != null && !flowConn.getState().isLinkDown()) { + try { + ret.add(new NodeConnector(NodeMapping.MD_SAL_TYPE, nc.getKey(), node)); + } catch (ConstructionException e) { + throw new IllegalStateException(String.format("Failed to create node connector for node {} connector {}", node, nc), e); + } + } + } + return ret; + } + + @Override + public Boolean isNodeConnectorEnabled(final NodeConnector nodeConnector) { + final NodeConnectorRef ref = NodeMapping.toNodeConnectorRef(nodeConnector); + final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector data = readNodeConnector(ref.getValue()); + return true; + } + + @Override + public boolean isSpecial(final NodeConnector p) { + final NodeConnectorRef ref = NodeMapping.toNodeConnectorRef(p); + final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector data = readNodeConnector(ref.getValue()); + return true; + } + + @Override + public Status removeControllerProperty(final String propertyName) { + return null; + } + + @Override + public Status removeNodeAllProps(final org.opendaylight.controller.sal.core.Node node) { + return null; + } + + @Override + public Status removeNodeConnectorAllProps(final NodeConnector nodeConnector) { + return null; + } + + @Override + public Status removeNodeConnectorProp(final NodeConnector nc, final String propName) { + return null; + } + + @Override + public Status removeNodeProp(final org.opendaylight.controller.sal.core.Node node, final String propName) { + return null; + } + + @Override + public Status removePortsFromSubnet(final String name, final List nodeConnectors) { + return null; + } + + @Override + public Status removeSubnet(final String name) { + return null; + } + + @Override + public Status setControllerProperty(final Property property) { + return null; + } + + @Override + public void setNodeProp(final org.opendaylight.controller.sal.core.Node node, final Property prop) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public Status addPortsToSubnet(final String name, final List nodeConnectors) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public Set getConfiguredNotConnectedSwitches() { + return null; + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend deleted file mode 100644 index 20d375fc78..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/CompatibleSwitchManager.xtend +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2014 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.md.compatibility.switchmanager - -import java.net.InetAddress -import java.net.NetworkInterface -import java.net.SocketException -import java.util.ArrayList -import java.util.Collections -import java.util.HashSet -import java.util.List -import java.util.Map -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService -import org.opendaylight.controller.sal.core.Bandwidth -import org.opendaylight.controller.sal.core.Description -import org.opendaylight.controller.sal.core.ForwardingMode -import org.opendaylight.controller.sal.core.MacAddress -import org.opendaylight.controller.sal.core.Node -import org.opendaylight.controller.sal.core.NodeConnector -import org.opendaylight.controller.sal.core.Property -import org.opendaylight.controller.sal.core.Tier -import org.opendaylight.controller.switchmanager.ISwitchManager -import org.opendaylight.controller.switchmanager.Switch -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey -import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.slf4j.LoggerFactory - -import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* - -class CompatibleSwitchManager extends ConfigurableSwitchManager implements ISwitchManager { - - private static val log = LoggerFactory.getLogger(CompatibleSwitchManager) - - @org.eclipse.xtend.lib.Property - var DataBrokerService dataService; - - override addNodeConnectorProp(NodeConnector nodeConnector, Property prop) { - val it = dataService.beginTransaction - val path = nodeConnector.toNodeConnectorRef - - // TODO: Update FlowCapableNode - return null; - } - - override createProperty(String propName, String propValue) { - try { - if (propName.equalsIgnoreCase(Description.propertyName)) { - return new Description(propValue); - } else if (propName.equalsIgnoreCase(Tier.TierPropName)) { - val tier = Integer.parseInt(propValue); - return new Tier(tier); - } else if (propName.equalsIgnoreCase(Bandwidth.BandwidthPropName)) { - val bw = Long.parseLong(propValue); - return new Bandwidth(bw); - } else if (propName.equalsIgnoreCase(ForwardingMode.name)) { - val mode = Integer.parseInt(propValue); - return new ForwardingMode(mode); - } else if (propName.equalsIgnoreCase(MacAddress.name)) { - return new MacAddress(propValue); - } else { - log.debug("Not able to create {} property", propName); - } - } catch (Exception e) { - log.debug("createProperty caught exception {}", e.getMessage()); - } - return null; - } - - override doesNodeConnectorExist(NodeConnector nc) { - val ref = nc.toNodeConnectorRef - return dataService.readOperationalData(ref.value as InstanceIdentifier) !== null - } - - override getControllerMAC() { - var byte[] macAddress = null; - - try { - val nis = NetworkInterface.getNetworkInterfaces(); - while (nis.hasMoreElements()) { - val ni = nis.nextElement(); - try { - macAddress = ni.getHardwareAddress(); - return macAddress; - } catch (SocketException e) { - log.error("Failed to acquire controller MAC: ", e); - } - } - } catch (SocketException e) { - log.error("Failed to acquire controller MAC: ", e); - return macAddress; - } - - if (macAddress == null) { - log.warn("Failed to acquire controller MAC: No physical interface found"); - - // This happens when running controller on windows VM, for example - // Try parsing the OS command output - } - return macAddress; - } - - override getControllerProperties() { - return Collections.emptyMap() - } - - override getControllerProperty(String propertyName) { - return null; - } - - override getNetworkDevices() { - val path = InstanceIdentifier.builder(Nodes).toInstance; - val data = dataService.readOperationalData(path) as Nodes; - val ret = new ArrayList(); - for (node : data.node) { - ret.add(node.toSwitch()); - } - return ret; - } - - override getNodeConnector(Node node, String nodeConnectorName) { - val key = new NodeConnectorKey(new NodeConnectorId(nodeConnectorName)); - return new NodeConnector(MD_SAL_TYPE, key, node); - } - - override getNodeConnectorProp(NodeConnector nodeConnector, String propName) { - getNodeConnectorProps(nodeConnector).get(propName); - } - - override getNodeConnectorProps(NodeConnector nodeConnector) { - val ref = nodeConnector.toNodeConnectorRef - val data = readNodeConnector(ref.value); - return data.toAdProperties(); - } - - override getNodeConnectors(Node node) { - val ref = node.toNodeRef; - val data = readNode(ref.value); - val ret = new HashSet(); - for (nc : data.nodeConnector) { - - val adConnector = new NodeConnector(MD_SAL_TYPE, nc.key, node); - ret.add(adConnector); - } - return ret; - } - - override getNodeDescription(Node node) { - (getNodeProps(node).get(Description.propertyName) as Description).value; - } - - override getNodeMAC(Node node) { - (getNodeProps(node).get(MacAddress.name) as MacAddress).macAddress; - } - - override getNodeProp(Node node, String propName) { - getNodeProps(node).get(propName) - } - - override getNodeProps(Node node) { - val ref = node.toNodeRef; - val data = dataService.readOperationalData(ref.value as InstanceIdentifier) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; - return data.toAdProperties(); - } - - override getNodes() { - val path = InstanceIdentifier.builder(Nodes).toInstance; - val data = dataService.readOperationalData(path) as Nodes; - val ret = new HashSet(); - for (node : data.node) { - ret.add(new Node(MD_SAL_TYPE, node.key)); - } - return ret; - } - - def Switch toSwitch(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node) { - val adNode = new Node(MD_SAL_TYPE, node.key); - val sw = new Switch(adNode) - return sw; - } - - override getPhysicalNodeConnectors(Node node) { - val ref = node.toNodeRef; - val data = readNode(ref.value); - val ret = new HashSet(); - for (nc : data.nodeConnector) { - val flowConnector = nc.getAugmentation(FlowCapableNodeConnector) - val adConnector = new NodeConnector(MD_SAL_TYPE, nc.key, node); - ret.add(adConnector); - } - return ret; - } - - def Map toAdProperties( - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector connector) { - return Collections.emptyMap - } - - def Map toAdProperties( - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node connector) { - return Collections.emptyMap - } - - def readNode(InstanceIdentifier ref) { - dataService.readOperationalData(ref as InstanceIdentifier) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node - } - - def readNodeConnector(InstanceIdentifier ref) { - dataService.readOperationalData(ref as InstanceIdentifier) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector - } - - override getSpanPorts(Node node) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override getSubnetByNetworkAddress(InetAddress networkAddress) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override getUpNodeConnectors(Node node) { - val ref = node.toNodeRef - val data = readNode(ref.value); - val ret = new HashSet(); - for (nc : data.nodeConnector) { - val flowConn = nc.getAugmentation(FlowCapableNodeConnector); - if (flowConn != null && flowConn.state != null && !flowConn.state.linkDown) { - ret.add(new NodeConnector(MD_SAL_TYPE, nc.key, node)); - } - } - return ret; - } - - override isNodeConnectorEnabled(NodeConnector nodeConnector) { - val ref = nodeConnector.toNodeConnectorRef - val data = readNodeConnector(ref.value); - - return true; - } - - override isSpecial(NodeConnector p) { - val ref = p.toNodeConnectorRef - val data = readNodeConnector(ref.value); - - return true; - } - - override removeControllerProperty(String propertyName) { - // NOOP - } - - override removeNodeAllProps(Node node) { - // NOOP: not supported node has more properties than AD-SAL is capable to see - } - - override removeNodeConnectorAllProps(NodeConnector nodeConnector) { - // NOOP: not supported node has more properties than AD-SAL is capable to see - } - - override removeNodeConnectorProp(NodeConnector nc, String propName) { - // NOOP: not supported node has more properties than AD-SAL is capable to see - } - - override removeNodeProp(Node node, String propName) { - // NOOP: not supported node has more properties than AD-SAL is capable to see - } - - override removePortsFromSubnet(String name, List nodeConnectors) { - // NOOP - } - - override removeSubnet(String name) { - // NOOP - } - - override setControllerProperty(Property property) { - // NOOP - } - - override setNodeProp(Node node, Property prop) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override addPortsToSubnet(String name, List nodeConnectors) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override getConfiguredNotConnectedSwitches() { - return null; - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.java new file mode 100644 index 0000000000..63f682a361 --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.java @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2014 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.md.compatibility.switchmanager; + +import java.util.List; + +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.switchmanager.ISwitchManager; +import org.opendaylight.controller.switchmanager.SpanConfig; +import org.opendaylight.controller.switchmanager.SubnetConfig; +import org.opendaylight.controller.switchmanager.SwitchConfig; + +/** + * These methods should be backed by config subsystem. + */ +public abstract class ConfigurableSwitchManager implements ISwitchManager { + @Override + public Status saveSwitchConfig() { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public Status removeSpanConfig(final SpanConfig cfgObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public Status addSubnet(final SubnetConfig configObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public final Status addSpanConfig(final SpanConfig configObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public final List getSpanConfigList() { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public final void updateSwitchConfig(final SwitchConfig cfgObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public final Status updateNodeConfig(final SwitchConfig switchConfig) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public final SubnetConfig getSubnetConfig(final String subnet) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public final Status removeNodeConfig(final String nodeId) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public final Status removeSubnet(final SubnetConfig configObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public final List getSubnetsConfigList() { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public final SwitchConfig getSwitchConfig(final String nodeId) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public Status modifySubnet(final SubnetConfig configObject) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.xtend deleted file mode 100644 index faa4b8d5cd..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/switchmanager/ConfigurableSwitchManager.xtend +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2014 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.md.compatibility.switchmanager - -import org.opendaylight.controller.switchmanager.ISwitchManager -import org.opendaylight.controller.switchmanager.SpanConfig -import org.opendaylight.controller.switchmanager.SwitchConfig -import org.opendaylight.controller.switchmanager.SubnetConfig - -/** - * - * THis methods should be backed by config subsystem. - * - */ -abstract class ConfigurableSwitchManager implements ISwitchManager { - - override saveSwitchConfig() { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override removeSpanConfig(SpanConfig cfgObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override addSubnet(SubnetConfig configObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - - } - - final override addSpanConfig(SpanConfig configObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - - } - - final override getSpanConfigList() { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - - } - - final override updateSwitchConfig(SwitchConfig cfgObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - - } - - final override updateNodeConfig(SwitchConfig switchConfig) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - - } - - final override getSubnetConfig(String subnet) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - final override removeNodeConfig(String nodeId) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - final override removeSubnet(SubnetConfig configObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - final override getSubnetsConfigList() { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - final override getSwitchConfig(String nodeId) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override modifySubnet(SubnetConfig configObject) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.java new file mode 100644 index 0000000000..8e50bd881e --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.java @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2014 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.md.compatibility.topology; + +import java.util.Iterator; + +import org.opendaylight.controller.sal.compatibility.InventoryMapping; +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.core.Edge; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; + +import com.google.common.base.Splitter; + +public class TopologyMapping { + private static final String HEAD_TAIL_STRING = "::::"; + private static final Splitter HEAD_TAIL_SPLITTER = Splitter.on(HEAD_TAIL_STRING); + + public TopologyMapping(final TopologyKey path, final InstanceIdentifier key) { + // No-op for now. Multi-instance will require fixing InventoryMapping first. + } + + public Edge toAdTopologyEdge(final InstanceIdentifier identifier) throws ConstructionException { + @SuppressWarnings("unchecked") + final LinkKey linkKey = ((KeyedInstanceIdentifier)identifier).getKey(); + + final Iterator it = HEAD_TAIL_SPLITTER.split(linkKey.getLinkId().getValue()).iterator(); + final NodeConnector tail = InventoryMapping.nodeConnectorFromId(it.next()); + final NodeConnector head = InventoryMapping.nodeConnectorFromId(it.next()); + return new Edge(tail, head); + } + + public NodeConnector toAdTopologyNodeConnector(final InstanceIdentifier identifier) { + @SuppressWarnings("unchecked") + final TerminationPointKey tpKey = ((KeyedInstanceIdentifier)identifier).getKey(); + + return InventoryMapping.nodeConnectorFromId(tpKey.getTpId().getValue()); + } + + public org.opendaylight.controller.sal.core.Node toAdTopologyNode(final InstanceIdentifier identifier) { + @SuppressWarnings("unchecked") + final NodeKey nodeKey = ((KeyedInstanceIdentifier)identifier).getKey(); + + return InventoryMapping.nodeFromNodeId(nodeKey.getNodeId().getValue()); + } + + public NodeKey toTopologyNodeKey(final org.opendaylight.controller.sal.core.Node node) { + return new NodeKey(new NodeId(InventoryMapping.toNodeId(node))); + } + + public TerminationPointKey toTopologyTerminationPointKey(final NodeConnector nc) { + return new TerminationPointKey(new TpId(InventoryMapping.toNodeConnectorId(nc))); + } + + public LinkKey toTopologyLinkKey(final Edge edge) { + final TerminationPointKey sourceTp = toTopologyTerminationPointKey(edge.getTailNodeConnector()); + final TerminationPointKey destTp = toTopologyTerminationPointKey(edge.getHeadNodeConnector()); + + final StringBuilder sb = new StringBuilder(); + sb.append(sourceTp.getTpId().toString()); + sb.append(HEAD_TAIL_STRING); + sb.append(destTp.getTpId().toString()); + return new LinkKey(new LinkId(sb.toString())); + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.xtend deleted file mode 100644 index 0889de17b6..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyMapping.xtend +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2014 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.md.compatibility.topology - -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology -import org.opendaylight.controller.sal.core.Edge -import java.util.Set -import org.opendaylight.controller.sal.core.Property -import org.opendaylight.controller.sal.core.NodeConnector - -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node -import org.opendaylight.controller.sal.compatibility.InventoryMapping -class TopologyMapping { - - new(TopologyKey path, InstanceIdentifier key) { - // NOOP - } - - def Edge toAdTopologyEdge(InstanceIdentifier identifier) { - val linkKey = (identifier.path.last as IdentifiableItem).key; - val components = linkKey.linkId.value.split("::::"); - val tail = InventoryMapping.nodeConnectorFromId(components.get(0)); - val head = InventoryMapping.nodeConnectorFromId(components.get(1)); - return new Edge(tail, head); - } - - def NodeConnector toAdTopologyNodeConnector(InstanceIdentifier identifier) { - val tpKey = (identifier.path.last as IdentifiableItem).key; - return InventoryMapping.nodeConnectorFromId(tpKey.tpId.value); - } - - def org.opendaylight.controller.sal.core.Node toAdTopologyNode( - InstanceIdentifier identifier) { - val tpKey = (identifier.path.last as IdentifiableItem).key; - return InventoryMapping.nodeFromNodeId(tpKey.nodeId.value); - } - - - - def NodeKey toTopologyNodeKey(org.opendaylight.controller.sal.core.Node node) { - val nodeId = new NodeId(InventoryMapping.toNodeId(node)); - return new NodeKey(nodeId); - } - - def TerminationPointKey toTopologyTerminationPointKey(NodeConnector nc) { - val node = nc.node; - val nodeId = new TpId(InventoryMapping.toNodeConnectorId(nc)) - return new TerminationPointKey(nodeId); - } - - def LinkKey toTopologyLinkKey(Edge edge) { - val sourceTp = edge.tailNodeConnector.toTopologyTerminationPointKey; - val destTp = edge.headNodeConnector.toTopologyTerminationPointKey; - val linkId = new LinkId('''«sourceTp.tpId»::::«destTp.tpId»''') - return new LinkKey(linkId); - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.java new file mode 100644 index 0000000000..a4ac6f94ee --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.java @@ -0,0 +1,199 @@ +/** + * Copyright (c) 2014 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.md.compatibility.topology; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.core.Edge; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.controller.switchmanager.ISwitchManager; +import org.opendaylight.controller.topologymanager.ITopologyManager; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TopologyReader implements RuntimeDataProvider { + private static final Logger LOG = LoggerFactory.getLogger(TopologyReader.class); + private final InstanceIdentifier topologyPath; + private final TopologyKey topologyKey; + private final TopologyMapping mapping; + private ITopologyManager topologyManager; + private ISwitchManager switchManager; + + public ISwitchManager getSwitchManager() { + return this.switchManager; + } + + public void setSwitchManager(final ISwitchManager switchManager) { + this.switchManager = switchManager; + } + + public ITopologyManager getTopologyManager() { + return this.topologyManager; + } + + public void setTopologyManager(final ITopologyManager topologyManager) { + this.topologyManager = topologyManager; + } + + public TopologyKey getTopologyKey() { + return this.topologyKey; + } + + public TopologyMapping getMapping() { + return this.mapping; + } + + public TopologyReader() { + this.topologyKey = new TopologyKey(new TopologyId("compatibility:ad-sal")); + this.topologyPath = InstanceIdentifier.builder(NetworkTopology.class) + .child(Topology.class, topologyKey) + .toInstance(); + this.mapping = new TopologyMapping(topologyKey, topologyPath); + } + + @Override + public DataObject readConfigurationData(final InstanceIdentifier path) { + // Topology and Inventory are operational only + return null; + } + + @SuppressWarnings("unchecked") + @Override + public DataObject readOperationalData(final InstanceIdentifier path) { + if (!topologyPath.contains(path)) { + return null; + } + + final Class type = path.getTargetType(); + if (Link.class.equals(type)) { + return readLink((InstanceIdentifier) path); + } + if (Node.class.equals(type)) { + return readNode((InstanceIdentifier) path); + } + if (TerminationPoint.class.equals(type)) { + return readTerminationPoint((InstanceIdentifier) path); + + } + if (Topology.class.equals(type)) { + return readTopology((InstanceIdentifier) path); + } + + LOG.debug("Unsupported type {}", type); + return null; + } + + private Link readLink(final InstanceIdentifier identifier) { + final Edge edge; + try { + edge = this.mapping.toAdTopologyEdge(identifier); + } catch (ConstructionException e) { + throw new IllegalStateException(String.format("Failed to construct edge for link %s", identifier), e); + } + + final Map> edges; + if (topologyManager != null) { + edges = topologyManager.getEdges(); + } else { + edges = null; + } + + final Set properties; + if (edges != null) { + properties = edges.get(edge); + } else { + properties = null; + } + + return constructLink(edge); + } + + private TerminationPoint readTerminationPoint(final InstanceIdentifier identifier) { + return constructTerminationPoint(mapping.toAdTopologyNodeConnector(identifier)); + } + + private Node readNode(final InstanceIdentifier identifier) { + return constructNode(mapping.toAdTopologyNode(identifier)); + } + + private Topology readTopology(final InstanceIdentifier identifier) { + final Set nodes = getSwitchManager().getNodes(); + final ArrayList nodeList = new ArrayList(nodes.size()); + for (final org.opendaylight.controller.sal.core.Node node : nodes) { + nodeList.add(constructNode(node)); + } + + final Map> edges = getTopologyManager().getEdges(); + final ArrayList linkList = new ArrayList(edges.size()); + for (final Edge edge : edges.keySet()) { + linkList.add(constructLink(edge)); + } + + return new TopologyBuilder() + .setKey(topologyKey) + .setNode(nodeList) + .setLink(linkList) + .build(); + } + + private Link constructLink(final Edge edge) { + final NodeConnector sourceNc = edge.getTailNodeConnector(); + final NodeConnector destNc = edge.getHeadNodeConnector(); + + final LinkBuilder it = new LinkBuilder().setKey(mapping.toTopologyLinkKey(edge)); + + it.setSource(new SourceBuilder() + .setSourceNode(mapping.toTopologyNodeKey(sourceNc.getNode()).getNodeId()) + .setSourceTp(mapping.toTopologyTerminationPointKey(sourceNc).getTpId()) + .build()); + + it.setDestination(new DestinationBuilder() + .setDestNode(mapping.toTopologyNodeKey(destNc.getNode()).getNodeId()) + .setDestTp(mapping.toTopologyTerminationPointKey(destNc).getTpId()) + .build()); + + return it.build(); + } + + private Node constructNode(final org.opendaylight.controller.sal.core.Node node) { + final Set connectors = getSwitchManager().getNodeConnectors(node); + final ArrayList tpList = new ArrayList(connectors.size()); + for (final NodeConnector connector : connectors) { + tpList.add(constructTerminationPoint(connector)); + } + + return new NodeBuilder() + .setKey(mapping.toTopologyNodeKey(node)) + .setTerminationPoint(tpList) + .build(); + } + + private TerminationPoint constructTerminationPoint(final NodeConnector connector) { + return new TerminationPointBuilder().setKey(mapping.toTopologyTerminationPointKey(connector)).build(); + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend deleted file mode 100644 index 6ebe20b84a..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topology/TopologyReader.xtend +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2014 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.md.compatibility.topology - -import java.util.ArrayList -import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider -import org.opendaylight.controller.sal.core.Edge -import org.opendaylight.controller.sal.core.NodeConnector -import org.opendaylight.controller.switchmanager.ISwitchManager -import org.opendaylight.controller.topologymanager.ITopologyManager -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder -import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier - -class TopologyReader implements RuntimeDataProvider { - - @Property - var ISwitchManager switchManager; - - @Property - var ITopologyManager topologyManager; - - @Property - val TopologyKey topologyKey; - - @Property - val InstanceIdentifier topologyPath; - - @Property - val extension TopologyMapping mapping; - - new() { - _topologyKey = new TopologyKey(new TopologyId("compatibility:ad-sal")); - _topologyPath = InstanceIdentifier.builder(NetworkTopology).child(Topology, topologyKey).toInstance; - _mapping = new TopologyMapping(topologyKey, topologyPath); - } - - override readConfigurationData(InstanceIdentifier path) { - - // Topology and Inventory are operational only - return null; - } - - override readOperationalData(InstanceIdentifier path) { - val type = path.targetType; - var DataObject data = null; - if (false == topologyPath.contains(path)) { - return null; - } - switch (type) { - case Topology: - data = readTopology(path as InstanceIdentifier) - case Node: - data = readNode(path as InstanceIdentifier) - case TerminationPoint: - data = readTerminationPoint(path as InstanceIdentifier) - case Link: - data = readLink(path as InstanceIdentifier) - } - return data; - } - - def DataObject readLink(InstanceIdentifier identifier) { - val edge = identifier.toAdTopologyEdge(); - val properties = topologyManager?.edges?.get(edge); - - return constructLink(edge); - } - - def DataObject readTerminationPoint(InstanceIdentifier identifier) { - val nodeConnector = identifier.toAdTopologyNodeConnector(); - return constructTerminationPoint(nodeConnector) - } - - def DataObject readNode(InstanceIdentifier identifier) { - val node = identifier.toAdTopologyNode(); - return constructNode(node); - } - - def DataObject readTopology(InstanceIdentifier identifier) { - - //val nodeConnectors = switchManager. - val nodes = switchManager.nodes - val edges = topologyManager.edges - - val nodeList = new ArrayList(nodes.size) - for (node : nodes) { - nodeList.add(constructNode(node)) - } - - val linkList = new ArrayList(edges.size) - for (edge : edges.keySet) { - linkList.add(constructLink(edge)) - } - - val it = new TopologyBuilder(); - key = topologyKey - node = nodeList - link = linkList - return build() - } - - def constructLink(Edge edge) { - val sourceNc = edge.tailNodeConnector - val destNc = edge.headNodeConnector - - val it = new LinkBuilder() - key = edge.toTopologyLinkKey(); - source = new SourceBuilder().setSourceNode(sourceNc.node.toTopologyNodeKey.nodeId).setSourceTp( - sourceNc.toTopologyTerminationPointKey.tpId).build() - destination = new DestinationBuilder().setDestNode(destNc.node.toTopologyNodeKey.nodeId).setDestTp( - destNc.toTopologyTerminationPointKey.tpId).build - return build() - } - - def Node constructNode(org.opendaylight.controller.sal.core.Node node) { - val connectors = switchManager.getNodeConnectors(node) - - val tpList = new ArrayList(connectors.size) - for (connector : connectors) { - tpList.add(constructTerminationPoint(connector)); - } - - val it = new NodeBuilder() - key = node.toTopologyNodeKey(); - terminationPoint = tpList - return build(); - } - - def TerminationPoint constructTerminationPoint(NodeConnector connector) { - val it = new TerminationPointBuilder() - key = connector.toTopologyTerminationPointKey - return build(); - } - -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.java new file mode 100644 index 0000000000..a7a7a9ac3a --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2014 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.md.compatibility.topologymanager; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.sal.compatibility.NodeMapping; +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.core.Edge; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class AdSalTopologyMapping { + private final InstanceIdentifier topologyPath; + + public AdSalTopologyMapping(final TopologyKey topology) { + this.topologyPath = InstanceIdentifier.builder(NetworkTopology.class) + .child(Topology.class, topology).toInstance(); + } + + public InstanceIdentifier getTopologyPath() { + return topologyPath; + } + + public InstanceIdentifier toTerminationPoint(final NodeConnector connector) { + return getTopologyPath().builder() + .child(Node.class) + .child(TerminationPoint.class, toTerminationPointKey(connector)) + .toInstance(); + } + + public Map> toEdgePropertiesMap(final Iterable links) { + final HashMap> ret = new HashMap<>(); + for (final Link link : links) { + try { + ret.put(toEdge(link), toProperties(link)); + } catch (ConstructionException e) { + throw new IllegalStateException(String.format("Failed to create edge properties for {}", link), e); + } + } + return ret; + } + + public static Set toEdges(final Iterable links) throws ConstructionException { + final HashSet ret = new HashSet(); + for (final Link link : links) { + ret.add(toEdge(link)); + } + return ret; + } + + public static Edge toEdge(final Link link) throws ConstructionException { + final NodeConnector tail = toNodeConnector(link.getSource()); + final NodeConnector head = toNodeConnector(link.getDestination()); + return new Edge(tail, head); + } + + public static org.opendaylight.controller.sal.core.Node toAdNode(final Node node) throws ConstructionException { + return toAdNode(node.getNodeId()); + } + + public static org.opendaylight.controller.sal.core.Node toAdNode(final NodeId node) throws ConstructionException { + final NodeKey key = new NodeKey( + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId(node)); + return new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, key); + } + + public static NodeConnector toNodeConnector(final Source ref) throws ConstructionException { + final org.opendaylight.controller.sal.core.Node adNode = toAdNode(ref.getSourceNode()); + final NodeConnectorKey key = new NodeConnectorKey(new NodeConnectorId(ref.getSourceTp())); + return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, adNode); + } + + public static NodeConnector toNodeConnector(final Destination ref) throws ConstructionException { + final org.opendaylight.controller.sal.core.Node adNode = toAdNode(ref.getDestNode()); + final NodeConnectorKey key = new NodeConnectorKey(new NodeConnectorId(ref.getDestTp())); + return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, adNode); + } + + public TerminationPointKey toTerminationPointKey(final NodeConnector connector) { + return null; + } + + public Set toProperties(final Link link) { + return null; + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend deleted file mode 100644 index aa238a8a8e..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/AdSalTopologyMapping.xtend +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2014 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.md.compatibility.topologymanager - -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint -import org.opendaylight.controller.sal.core.NodeConnector -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology -import java.util.Map -import org.opendaylight.controller.sal.core.Edge -import java.util.Set -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node -import java.util.HashSet -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId -import org.opendaylight.controller.sal.compatibility.NodeMapping -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey -import java.util.HashMap - -class AdSalTopologyMapping { - - val TopologyKey topologyMapping; - @Property - val InstanceIdentifier topologyPath; - - new(TopologyKey topology) { - topologyMapping = topology; - _topologyPath = InstanceIdentifier.builder(NetworkTopology).child(Topology, topology).toInstance; - } - - def InstanceIdentifier toTerminationPoint(NodeConnector connector) { - InstanceIdentifier.builder(topologyPath).child(Node).child(TerminationPoint, connector.toTerminationPointKey()).toInstance; - } - - def Map> toEdgePropertiesMap(Iterable links) { - val ret = new HashMap> - for (link : links) { - ret.put(link.toEdge(), link.toProperties()) - } - return ret; - } - - def Set toEdges(Iterable links) { - val ret = new HashSet - for (link : links) { - ret.add(link.toEdge) - } - return ret; - } - - def Edge toEdge(Link link) { - val tail = link.source.toNodeConnector(); - val head = link.destination.toNodeConnector(); - return new Edge(tail, head); - } - - def org.opendaylight.controller.sal.core.Node toAdNode(Node node) { - return node.nodeId.toAdNode; - } - - def org.opendaylight.controller.sal.core.Node toAdNode( - org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId node) { - val key = new NodeKey(new NodeId(node)) - return new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, key); - } - - def NodeConnector toNodeConnector(Source ref) { - val adNode = ref.sourceNode.toAdNode(); - val key = new NodeConnectorKey(new NodeConnectorId(ref.sourceTp)) - return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, adNode); - } - - def NodeConnector toNodeConnector(Destination ref) { - val adNode = ref.destNode.toAdNode(); - val key = new NodeConnectorKey(new NodeConnectorId(ref.destTp)) - return new NodeConnector(NodeMapping.MD_SAL_TYPE, key, adNode); - } - - def TerminationPointKey toTerminationPointKey(NodeConnector connector) { - } - - def Set toProperties(Link link) { - } -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.java b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.java new file mode 100644 index 0000000000..11320a12cd --- /dev/null +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2014 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.md.compatibility.topologymanager; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader; +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.core.Edge; +import org.opendaylight.controller.sal.core.Host; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.controller.sal.core.UpdateType; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.topologymanager.ITopologyManager; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; + +@SuppressWarnings("all") +public class CompatibleTopologyManager extends ConfigurableLinkManager implements ITopologyManager { + private AdSalTopologyMapping topologyMapping; + private TypeSafeDataReader dataReader; + + public TypeSafeDataReader getDataReader() { + return dataReader; + } + + public void setDataReader(final TypeSafeDataReader dataReader) { + this.dataReader = dataReader; + } + + public AdSalTopologyMapping getTopologyMapping() { + return topologyMapping; + } + + public void setTopologyMapping(final AdSalTopologyMapping topologyMapping) { + this.topologyMapping = topologyMapping; + } + + @Override + public Map> getEdges() { + final Topology topology = getDataReader().readOperationalData(topologyMapping.getTopologyPath()); + return this.topologyMapping.toEdgePropertiesMap(topology.getLink()); + } + + @Override + public Map> getNodeEdges() { + final Topology topology = getDataReader().readOperationalData(topologyMapping.getTopologyPath()); + final HashMap> ret = new HashMap<>(); + for (final Node node : topology.getNode()) { + try { + ret.put(topologyMapping.toAdNode(node), topologyMapping.toEdges( + FluentIterable.from(topology.getLink()).filter(new Predicate() { + @Override + public boolean apply(final Link input) { + final NodeId nodeId = node.getNodeId(); + if (nodeId.equals(input.getSource().getSourceNode())) { + return true; + } + if (nodeId.equals(input.getDestination().getDestNode())) { + return true; + } + + return false; + } + }))); + } catch (ConstructionException e) { + throw new IllegalStateException(String.format("Failed to construct node for {}", node), e); + } + } + return ret; + } + + /** + * Returns true if point is connected to link + */ + private boolean isInternal(final TerminationPoint point) { + final Topology topology = getDataReader().readConfigurationData(topologyMapping.getTopologyPath()); + final TpId tpId = point.getKey().getTpId(); + return FluentIterable.from(topology.getLink()).anyMatch(new Predicate() { + @Override + public boolean apply(final Link input) { + if (tpId.equals(input.getSource().getSourceTp())) { + return true; + } + if (tpId.equals(input.getDestination().getDestTp())) { + return true; + } + return false; + } + }); + } + + @Override + public Set getNodeConnectorWithHost() { + return null; + } + + @Override + public Host getHostAttachedToNodeConnector(final NodeConnector p) { + final InstanceIdentifier tpPath = topologyMapping.toTerminationPoint(p); + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public List getHostsAttachedToNodeConnector(final NodeConnector p) { + final Topology topology = getDataReader().readOperationalData(topologyMapping.getTopologyPath()); + throw new UnsupportedOperationException("Hosts not mapped yet"); + } + + @Override + public Map> getNodesWithNodeConnectorHost() { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); + } + + @Override + public boolean isInternal(final NodeConnector p) { + final TerminationPoint connector = getDataReader() + .readConfigurationData(topologyMapping.toTerminationPoint(p)); + return this.isInternal(connector); + } + + @Override + public void updateHostLink(final NodeConnector p, final Host h, final UpdateType t, final Set props) { + // Update app defined topology + } + + @Override + public Status saveConfig() { + // FIXME: commit configuration + return null; + } +} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.xtend deleted file mode 100644 index 4fdea4b4c2..0000000000 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/CompatibleTopologyManager.xtend +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2014 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.md.compatibility.topologymanager - -import org.opendaylight.controller.topologymanager.ITopologyManager -import org.opendaylight.controller.sal.core.NodeConnector -import org.opendaylight.controller.sal.core.Host -import org.opendaylight.controller.sal.core.UpdateType -import java.util.Set -import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader -import java.util.HashMap -import org.opendaylight.controller.sal.core.Edge -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint -import com.google.common.collect.FluentIterable - -class CompatibleTopologyManager extends ConfigurableLinkManager implements ITopologyManager { - - @Property - var TypeSafeDataReader dataReader; - - @Property - var extension AdSalTopologyMapping topologyMapping; - - override getEdges() { - val topology = dataReader.readOperationalData(topologyPath); - return topology.link.toEdgePropertiesMap(); - } - - override getNodeEdges() { - val topology = dataReader.readOperationalData(topologyPath); - val ret = new HashMap>; - for (node : topology.node) { - val adNode = node.toAdNode(); - val adEdges = FluentIterable.from(topology.link).filter[ - source.sourceNode == node.nodeId || destination.destNode == node.nodeId].toEdges(); - ret.put(adNode, adEdges) - } - return ret; - } - - /** - * Returns true if point is connected to link - */ - def isInternal(TerminationPoint point) { - val topology = dataReader.readConfigurationData(topologyPath); - val tpId = point.key.tpId; - return FluentIterable.from(topology.link).anyMatch( - [ - source.sourceTp == tpId || destination.destTp == tpId - ]) - } - - override getNodeConnectorWithHost() { - } - - override getHostAttachedToNodeConnector(NodeConnector p) { - val tpPath = p.toTerminationPoint(); - throw new UnsupportedOperationException("TODO: auto-generated method stub") - } - - override getHostsAttachedToNodeConnector(NodeConnector p) { - val topology = dataReader.readOperationalData(topologyPath); - - throw new UnsupportedOperationException("Hosts not mapped yet") - } - - override getNodesWithNodeConnectorHost() { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - - } - - override isInternal(NodeConnector p) { - val tpPath = p.toTerminationPoint(); - val connector = dataReader.readConfigurationData(tpPath); - return connector.isInternal(); - } - - override updateHostLink(NodeConnector p, Host h, UpdateType t, - Set props) { - // Update app defined topology - } - - override saveConfig() { - // FIXME: commit configuration - } - -} diff --git a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.xtend b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.java similarity index 57% rename from opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.xtend rename to opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.java index b5f6cecd34..2d85f76278 100644 --- a/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.xtend +++ b/opendaylight/md-sal/compatibility/inventory-topology-compatibility/src/main/java/org/opendaylight/controller/md/compatibility/topologymanager/ConfigurableLinkManager.java @@ -1,31 +1,31 @@ -/* +/** * Copyright (c) 2014 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.md.compatibility.topologymanager +package org.opendaylight.controller.md.compatibility.topologymanager; -import org.opendaylight.controller.topologymanager.ITopologyManager -import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig +import java.util.concurrent.ConcurrentMap; -abstract class ConfigurableLinkManager implements ITopologyManager { - - final override addUserLink(TopologyUserLinkConfig link) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.topologymanager.ITopologyManager; +import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig; + +public abstract class ConfigurableLinkManager implements ITopologyManager { + @Override + public final Status addUserLink(final TopologyUserLinkConfig link) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); } - - - final override deleteUserLink(String linkName) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - + + @Override + public final Status deleteUserLink(final String linkName) { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); } - - - final override getUserLinks() { - throw new UnsupportedOperationException("TODO: auto-generated method stub") - + + @Override + public final ConcurrentMap getUserLinks() { + throw new UnsupportedOperationException("TODO: auto-generated method stub"); } } diff --git a/opendaylight/md-sal/compatibility/pom.xml b/opendaylight/md-sal/compatibility/pom.xml index 3ed1edf7d6..688e6ac09b 100644 --- a/opendaylight/md-sal/compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/pom.xml @@ -21,10 +21,6 @@ com.google.guava guava - - org.eclipse.xtend - org.eclipse.xtend.lib - org.opendaylight.controller sal @@ -60,10 +56,6 @@ - - org.eclipse.xtend - xtend-maven-plugin - org.jacoco jacoco-maven-plugin diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml b/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml index a145a3b4e1..6c79e053e1 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml +++ b/opendaylight/md-sal/compatibility/sal-compatibility/pom.xml @@ -42,10 +42,6 @@ - - org.eclipse.xtend - xtend-maven-plugin - org.jacoco jacoco-maven-plugin diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java index 53257f8c83..a879a36f8c 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/FromSalConversionsUtils.java @@ -261,11 +261,11 @@ public class FromSalConversionsUtils { .setType(etherType); targetEthMatchBuild.setEthernetType(ethType.build()); } - if((sourceMatch.getField(DL_SRC) != null && sourceMatch.getField(DL_SRC).getValue() != null) || - (sourceMatch.getField(DL_DST) != null && sourceMatch.getField(DL_DST).getValue() != null)|| + if((sourceMatch.getField(DL_SRC) != null && sourceMatch.getField(DL_SRC).getValue() != null) || + (sourceMatch.getField(DL_DST) != null && sourceMatch.getField(DL_DST).getValue() != null)|| dataLinkType != null ) { - return targetEthMatchBuild.build(); - } + return targetEthMatchBuild.build(); + } return null; } @@ -372,7 +372,7 @@ public class FromSalConversionsUtils { .toAddrString(inetDestAddress); layer4MatchBuild .setIpv4Destination(new Ipv4Prefix(inetDstAddressString)); - } + } return layer4MatchBuild.build(); } @@ -388,13 +388,13 @@ public class FromSalConversionsUtils { } if(inetDestAddress != null) { String inetDstAddressString = InetAddresses - .toAddrString(inetDestAddress); + .toAddrString(inetDestAddress); layer6MatchBuild .setIpv6Destination(new Ipv6Prefix(inetDstAddressString)); } return layer6MatchBuild.build(); } - + public static boolean flowEquals(Flow statsFlow, Flow storedFlow) { if (statsFlow.getClass() != storedFlow.getClass()) { return false; diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.java new file mode 100644 index 0000000000..2830165425 --- /dev/null +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.java @@ -0,0 +1,770 @@ +/** + * Copyright (c) 2014 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.sal.compatibility; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.controller.sal.core.ConstructionException; +import org.opendaylight.controller.sal.core.Edge; +import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.NodeTable; +import org.opendaylight.controller.sal.core.Property; +import org.opendaylight.controller.sal.core.UpdateType; +import org.opendaylight.controller.sal.inventory.IPluginInInventoryService; +import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService; +import org.opendaylight.controller.sal.reader.FlowOnNode; +import org.opendaylight.controller.sal.reader.IPluginInReadService; +import org.opendaylight.controller.sal.reader.IPluginOutReadService; +import org.opendaylight.controller.sal.reader.NodeConnectorStatistics; +import org.opendaylight.controller.sal.reader.NodeDescription; +import org.opendaylight.controller.sal.reader.NodeTableStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.Link; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.Bytes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.Packets; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetNodeConnectorStatisticsInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInInventoryService, OpendaylightInventoryListener, OpendaylightFlowStatisticsListener, OpendaylightFlowTableStatisticsListener, OpendaylightPortStatisticsListener { + private static final Logger LOG = LoggerFactory.getLogger(InventoryAndReadAdapter.class); + private static final short OPENFLOWV10_TABLE_ID = 0; + + private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider(); + private final Map> nodeToNodeConnectorsMap = new ConcurrentHashMap<>(); + private List inventoryPublisher = new CopyOnWriteArrayList<>(); + private List statisticsPublisher = new CopyOnWriteArrayList<>(); + + private OpendaylightFlowTableStatisticsService flowTableStatisticsService; + private OpendaylightPortStatisticsService nodeConnectorStatisticsService; + private OpendaylightFlowStatisticsService flowStatisticsService; + private FlowTopologyDiscoveryService topologyDiscovery; + private DataProviderService dataProviderService; + private DataBrokerService dataService; + + public DataBrokerService getDataService() { + return dataService; + } + + public void setDataService(final DataBrokerService dataService) { + this.dataService = dataService; + } + + public DataProviderService getDataProviderService() { + return dataProviderService; + } + + public void setDataProviderService(final DataProviderService dataProviderService) { + this.dataProviderService = dataProviderService; + } + + public OpendaylightFlowStatisticsService getFlowStatisticsService() { + return flowStatisticsService; + } + + public void setFlowStatisticsService(final OpendaylightFlowStatisticsService flowStatisticsService) { + this.flowStatisticsService = flowStatisticsService; + } + + public OpendaylightPortStatisticsService getNodeConnectorStatisticsService() { + return nodeConnectorStatisticsService; + } + + public void setNodeConnectorStatisticsService(final OpendaylightPortStatisticsService nodeConnectorStatisticsService) { + this.nodeConnectorStatisticsService = nodeConnectorStatisticsService; + } + + public OpendaylightFlowTableStatisticsService getFlowTableStatisticsService() { + return flowTableStatisticsService; + } + + public void setFlowTableStatisticsService(final OpendaylightFlowTableStatisticsService flowTableStatisticsService) { + this.flowTableStatisticsService = flowTableStatisticsService; + } + + public FlowTopologyDiscoveryService getTopologyDiscovery() { + return topologyDiscovery; + } + + public void setTopologyDiscovery(final FlowTopologyDiscoveryService topologyDiscovery) { + this.topologyDiscovery = topologyDiscovery; + } + + public List getStatisticsPublisher() { + return statisticsPublisher; + } + + public void setStatisticsPublisher(final List statisticsPublisher) { + this.statisticsPublisher = statisticsPublisher; + } + + public List getInventoryPublisher() { + return inventoryPublisher; + } + + public void setInventoryPublisher(final List inventoryPublisher) { + this.inventoryPublisher = inventoryPublisher; + } + + public void startAdapter() { + inventoryNotificationProvider.setDataProviderService(getDataProviderService()); + inventoryNotificationProvider.setInventoryPublisher(getInventoryPublisher()); + // inventoryNotificationProvider.start(); + } + + public boolean setInventoryPublisher(final IPluginOutInventoryService listener) { + return getInventoryPublisher().add(listener); + } + + public boolean unsetInventoryPublisher(final IPluginOutInventoryService listener) { + return getInventoryPublisher().remove(listener); + } + + public boolean setReadPublisher(final IPluginOutReadService listener) { + return getStatisticsPublisher().add(listener); + } + + public Boolean unsetReadPublisher(final IPluginOutReadService listener) { + if (listener != null) { + return getStatisticsPublisher().remove(listener); + } + return false; + } + + protected DataModificationTransaction startChange() { + return getDataProviderService().beginTransaction(); + } + + @Override + public long getTransmitRate(final NodeConnector connector) { + final FlowCapableNodeConnector nodeConnector = this.readOperFlowCapableNodeConnector(NodeMapping.toNodeConnectorRef(connector)); + return nodeConnector.getCurrentSpeed().longValue(); + } + + private FlowCapableNode readOperFlowCapableNode(final NodeRef ref) { + final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node = + (org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node)getDataService().readOperationalData(ref.getValue()); + if (node == null) { + return null; + } + + return node.getAugmentation(FlowCapableNode.class); + } + + private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node readConfigNode(final Node node) { + final InstanceIdentifier nodeRef = + InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, InventoryMapping.toNodeKey(node)) + .build(); + + return (org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node) startChange().readConfigurationData(nodeRef); + } + + private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector readConfigNodeConnector(final NodeConnector connector) { + final InstanceIdentifier nodeConnectorRef = + InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, InventoryMapping.toNodeKey(connector.getNode())) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector.class, InventoryMapping.toNodeConnectorKey(connector)) + .toInstance(); + + return((org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector) startChange().readConfigurationData(nodeConnectorRef)); + } + + /** + * Read a table of a node from configuration data store. + * + * @param node Node id + * @param id Table id + * @return Table contents, or null if not present + */ + private Table readConfigTable(final Node node, final short id) { + final InstanceIdentifier tableRef = InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, InventoryMapping.toNodeKey(node)) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(id)) + .build(); + + return (Table) startChange().readConfigurationData(tableRef); + } + + @Override + public List readAllFlow(final Node node, final boolean cached) { + final ArrayList output = new ArrayList<>(); + final Table table = readConfigTable(node, OPENFLOWV10_TABLE_ID); + if (table != null) { + final List flows = table.getFlow(); + LOG.trace("Number of flows installed in table 0 of node {} : {}", node, flows.size()); + + for (final Flow flow : flows) { + final FlowStatisticsData statsFromDataStore = flow.getAugmentation(FlowStatisticsData.class); + if (statsFromDataStore != null) { + final FlowOnNode it = new FlowOnNode(ToSalConversionsUtils.toFlow(flow, node)); + output.add(addFlowStats(it, statsFromDataStore.getFlowStatistics())); + } + } + } + + // TODO (main): Shall we send request to the switch? It will make async request to the switch. + // Once the plugin receives a response, it will let the adaptor know through onFlowStatisticsUpdate() + // If we assume that md-sal statistics manager will always be running, then it is not required + // But if not, then sending request will collect the latest data for adaptor at least. + getFlowStatisticsService().getAllFlowsStatisticsFromAllFlowTables( + new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder().setNode(NodeMapping.toNodeRef(node)).build()); + return output; + } + + @Override + public List readAllNodeConnector(final Node node, final boolean cached) { + final ArrayList ret = new ArrayList<>(); + + final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node dsNode = readConfigNode(node); + if (dsNode != null) { + for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector dsNodeConnector : dsNode.getNodeConnector()) { + final FlowCapableNodeConnectorStatistics stats = (dsNodeConnector.getAugmentation(FlowCapableNodeConnectorStatisticsData.class)); + if (stats != null) { + try { + ret.add(toNodeConnectorStatistics(stats.getFlowCapableNodeConnectorStatistics(), dsNode.getId(), dsNodeConnector.getId())); + } catch (ConstructionException e) { + LOG.warn("Failed to instantiate node connector statistics for node {} connector {}, ignoring it", + dsNode.getId(), dsNodeConnector.getId(), e); + } + } + } + } + + //TODO: Refer TODO (main) + getNodeConnectorStatisticsService().getAllNodeConnectorsStatistics( + new GetAllNodeConnectorsStatisticsInputBuilder().setNode(NodeMapping.toNodeRef(node)).build()); + return ret; + } + + @Override + public List readAllNodeTable(final Node node, final boolean cached) { + final NodeRef nodeRef = NodeMapping.toNodeRef(node); + + final ArrayList ret = new ArrayList<>(); + final FlowCapableNode dsFlowCapableNode = this.readOperFlowCapableNode(nodeRef); + if (dsFlowCapableNode != null) { + for (final Table table : dsFlowCapableNode.getTable()) { + final FlowTableStatisticsData tableStats = table.getAugmentation(FlowTableStatisticsData.class); + if (tableStats != null) { + try { + ret.add(toNodeTableStatistics(tableStats.getFlowTableStatistics(), table.getId(), node)); + } catch (ConstructionException e) { + LOG.warn("Failed to instantiate table statistics for node {} table {}, ignoring it", node, table.getId(), e); + } + } + } + } + + //TODO: Refer TODO (main) + getFlowTableStatisticsService().getFlowTablesStatistics(new GetFlowTablesStatisticsInputBuilder().setNode(nodeRef).build()); + return ret; + } + + @Override + public NodeDescription readDescription(final Node node, final boolean cached) { + return this.toNodeDescription(NodeMapping.toNodeRef(node)); + } + + @Override + public FlowOnNode readFlow(final Node node, final org.opendaylight.controller.sal.flowprogrammer.Flow targetFlow, final boolean cached) { + FlowOnNode ret = null; + final Table table = readConfigTable(node, OPENFLOWV10_TABLE_ID); + if (table != null) { + final List flows = table.getFlow(); + InventoryAndReadAdapter.LOG.trace("Number of flows installed in table 0 of node {} : {}", node, flows.size()); + + for (final Flow mdsalFlow : flows) { + if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))) { + final FlowStatisticsData statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData.class); + if (statsFromDataStore != null) { + InventoryAndReadAdapter.LOG.debug("Found matching flow in the data store flow table "); + ret = addFlowStats(new FlowOnNode(targetFlow), statsFromDataStore.getFlowStatistics()); + + // FIXME: break; ? + } + } + } + } + + //TODO: Refer TODO (main) + final GetFlowStatisticsFromFlowTableInputBuilder input = new GetFlowStatisticsFromFlowTableInputBuilder().setNode(NodeMapping.toNodeRef(node)); + input.fieldsFrom(MDFlowMapping.toMDSalflow(targetFlow)); + getFlowStatisticsService().getFlowStatisticsFromFlowTable(input.build()); + return ret; + } + + @Override + public NodeConnectorStatistics readNodeConnector(final NodeConnector connector, final boolean cached) { + final NodeConnectorId ncId = InventoryMapping.toNodeConnectorKey(connector).getId(); + + NodeConnectorStatistics ret = null; + final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nodeConnectorFromDS = readConfigNodeConnector(connector); + if (nodeConnectorFromDS != null) { + final FlowCapableNodeConnectorStatistics stats = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData.class); + if (stats != null) { + try { + ret = toNodeConnectorStatistics(stats.getFlowCapableNodeConnectorStatistics(), + InventoryMapping.toNodeKey(connector.getNode()).getId(), ncId); + } catch (ConstructionException e) { + LOG.warn("Failed to instantiate node connector statistics for connector {}, ignoring it", + connector, e); + } + } + } + + getNodeConnectorStatisticsService().getNodeConnectorStatistics( + new GetNodeConnectorStatisticsInputBuilder().setNode(NodeMapping.toNodeRef(connector.getNode())).setNodeConnectorId(ncId).build()); + return ret; + } + + @Override + public NodeTableStatistics readNodeTable(final NodeTable nodeTable, final boolean cached) { + NodeTableStatistics nodeStats = null; + final Table table = readConfigTable(nodeTable.getNode(), (short) nodeTable.getID()); + if (table != null) { + final FlowTableStatisticsData tableStats = table.getAugmentation(FlowTableStatisticsData.class); + if (tableStats != null) { + try { + nodeStats = toNodeTableStatistics(tableStats.getFlowTableStatistics(), table.getId(), nodeTable.getNode()); + } catch (ConstructionException e) { + LOG.warn("Failed to instantiate table statistics for node {} table {}, ignoring it", + nodeTable.getNode(), table.getId(), e); + } + } + } + + //TODO: Refer TODO (main) + getFlowTableStatisticsService().getFlowTablesStatistics( + new GetFlowTablesStatisticsInputBuilder().setNode(NodeMapping.toNodeRef(nodeTable.getNode())).build()); + return nodeStats; + } + + @Override + public void onNodeConnectorRemoved(final NodeConnectorRemoved update) { + // Never received + } + + @Override + public void onNodeRemoved(final NodeRemoved notification) { + this.removeNodeConnectors(notification.getNodeRef().getValue()); + try { + final Node aDNode = NodeMapping.toADNode(notification.getNodeRef()); + this.publishNodeUpdate(aDNode, UpdateType.REMOVED, Collections.emptySet()); + } catch (ConstructionException e) { + LOG.warn("Failed to construct node for {}, not propagating update", notification.getNodeRef(), e); + } + } + + @Override + public void onNodeConnectorUpdated(final NodeConnectorUpdated update) { + final NodeConnectorRef ref = update.getNodeConnectorRef(); + final UpdateType updateType; + if (!this.isKnownNodeConnector(ref.getValue())) { + this.recordNodeConnector(ref.getValue()); + updateType = UpdateType.ADDED; + } else { + updateType = UpdateType.CHANGED; + } + + try { + final NodeConnector nodeConnector; + nodeConnector = NodeMapping.toADNodeConnector(ref); + this.publishNodeConnectorUpdate(nodeConnector, updateType, NodeMapping.toADNodeConnectorProperties(update)); + } catch (ConstructionException e) { + LOG.warn("Failed to construct node connector for {}, not reporting the update", ref, e); + } + } + + @Override + public void onNodeUpdated(final NodeUpdated notification) { + final NodeRef ref = notification.getNodeRef(); + + final UpdateType updateType; + if (dataService.readOperationalData(ref.getValue()) == null) { + updateType = UpdateType.ADDED; + } else { + updateType = UpdateType.CHANGED; + } + + final Node aDNode; + try { + aDNode = NodeMapping.toADNode(ref); + } catch (ConstructionException e) { + LOG.warn("Failed to construct node for {}, not reporting the update", ref, e); + return; + } + + this.publishNodeUpdate(aDNode, updateType, NodeMapping.toADNodeProperties(notification)); + for (final IPluginOutReadService statsPublisher : getStatisticsPublisher()) { + final NodeDescription description = this.toNodeDescription(ref); + if (description != null) { + final InstanceIdentifier nodeRef = + InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(notification.getId())) + .toInstance(); + try { + statsPublisher.descriptionStatisticsUpdated(NodeMapping.toADNode(nodeRef), description); + } catch (ConstructionException e) { + LOG.warn("Failed to construct node for {}, not reporting the update to publisher {}", nodeRef, statsPublisher, e); + } + } + } + } + + @Override + public ConcurrentMap> getNodeProps() { + final ConcurrentHashMap> props = new ConcurrentHashMap<>(); + final Nodes nodes = this.readOperAllMDNodes(); + for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node : nodes.getNode()) { + final FlowCapableNode fcn = node.getAugmentation(FlowCapableNode.class); + if (fcn != null) { + final ConcurrentHashMap perNodePropMap = new ConcurrentHashMap(); + final HashSet perNodeProps = NodeMapping.toADNodeProperties(fcn, node.getId()); + if (perNodeProps != null) { + for (final Property perNodeProp : perNodeProps) { + perNodePropMap.put(perNodeProp.getName(), perNodeProp); + } + } + + try { + final Node adNode = new Node(NodeMapping.MD_SAL_TYPE, NodeMapping.toADNodeId(node.getId())); + props.put(adNode, perNodePropMap); + } catch (ConstructionException e) { + LOG.warn("Failed to construct node for {}, skipping it", node, e); + } + } + } + return props; + } + + private Nodes readOperAllMDNodes() { + final TypeSafeDataReader reader = TypeSafeDataReader.forReader(getDataService()); + return reader.readOperationalData(InstanceIdentifier.builder(Nodes.class).build()); + } + + @Override + public ConcurrentMap> getNodeConnectorProps(final Boolean refresh) { + final ConcurrentHashMap> props = new ConcurrentHashMap<>(); + for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node : this.readOperAllMDNodes().getNode()) { + for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc : node.getNodeConnector()) { + final FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class); + if (fcnc != null) { + final ConcurrentHashMap ncpsm = new ConcurrentHashMap<>(); + final HashSet ncps = NodeMapping.toADNodeConnectorProperties(fcnc); + if (ncps != null) { + for (final Property p : ncps) { + ncpsm.put(p.getName(), p); + } + } + + try { + props.put(NodeMapping.toADNodeConnector(nc.getId(), node.getId()), ncpsm); + } catch (ConstructionException e) { + LOG.warn("Failed to instantiate node {} connector {}, not reporting it", node.getId(), nc.getId(), e); + } + } + } + } + return props; + } + + private FlowCapableNodeConnector readOperFlowCapableNodeConnector(final NodeConnectorRef ref) { + final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc = + (org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector) + getDataService().readOperationalData(ref.getValue()); + return nc.getAugmentation(FlowCapableNodeConnector.class); + } + + private static NodeConnectorStatistics toNodeConnectorStatistics(final org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics nodeConnectorStatistics, final NodeId nodeId, final NodeConnectorId nodeConnectorId) throws ConstructionException { + final NodeConnectorStatistics it = new NodeConnectorStatistics(); + + final Packets packets = nodeConnectorStatistics.getPackets(); + it.setReceivePacketCount(packets.getReceived().longValue()); + it.setTransmitPacketCount(packets.getTransmitted().longValue()); + + final Bytes bytes = nodeConnectorStatistics.getBytes(); + it.setReceiveByteCount(bytes.getReceived().longValue()); + it.setTransmitByteCount(bytes.getTransmitted().longValue()); + + it.setReceiveDropCount(nodeConnectorStatistics.getReceiveDrops().longValue()); + it.setTransmitDropCount(nodeConnectorStatistics.getTransmitDrops().longValue()); + it.setReceiveErrorCount(nodeConnectorStatistics.getReceiveErrors().longValue()); + it.setTransmitErrorCount(nodeConnectorStatistics.getTransmitErrors().longValue()); + it.setReceiveFrameErrorCount(nodeConnectorStatistics.getReceiveFrameError().longValue()); + it.setReceiveOverRunErrorCount(nodeConnectorStatistics.getReceiveOverRunError().longValue()); + it.setReceiveCRCErrorCount(nodeConnectorStatistics.getReceiveCrcError().longValue()); + it.setCollisionCount(nodeConnectorStatistics.getCollisionCount().longValue()); + + final InstanceIdentifier nodeConnectorRef = + InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(nodeId)) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector.class, new NodeConnectorKey(nodeConnectorId)) + .build(); + it.setNodeConnector(NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef))); + return it; + } + + private static NodeTableStatistics toNodeTableStatistics(final FlowTableStatistics tableStats, final Short tableId, final Node node) throws ConstructionException { + final NodeTableStatistics it = new NodeTableStatistics(); + it.setActiveCount(tableStats.getActiveFlows().getValue().intValue()); + it.setLookupCount(tableStats.getPacketsLookedUp().getValue().longValue()); + it.setMatchedCount(tableStats.getPacketsMatched().getValue().longValue()); + it.setName(tableId.toString()); + it.setNodeTable(new NodeTable(NodeMapping.MD_SAL_TYPE, tableId, node)); + return it; + } + + private NodeDescription toNodeDescription(final NodeRef nodeRef) { + final FlowCapableNode capableNode = this.readOperFlowCapableNode(nodeRef); + if (capableNode == null) { + return null; + } + + final NodeDescription it = new NodeDescription(); + it.setManufacturer(capableNode.getManufacturer()); + it.setSerialNumber(capableNode.getSerialNumber()); + it.setSoftware(capableNode.getSoftware()); + it.setDescription(capableNode.getDescription()); + return it; + } + + public Edge toADEdge(final Link link) throws ConstructionException { + NodeConnectorRef _source = link.getSource(); + NodeConnector _aDNodeConnector = NodeMapping.toADNodeConnector(_source); + NodeConnectorRef _destination = link.getDestination(); + NodeConnector _aDNodeConnector_1 = NodeMapping.toADNodeConnector(_destination); + Edge _edge = new Edge(_aDNodeConnector, _aDNodeConnector_1); + return _edge; + } + + /** + * OpendaylightFlowStatisticsListener interface implementation + */ + @Override + public void onAggregateFlowStatisticsUpdate(final AggregateFlowStatisticsUpdate notification) { + // Ignoring this notification as there does not seem to be a way to bubble this up to AD-SAL + } + + @Override + public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) { + final ArrayList adsalFlowsStatistics = new ArrayList<>(); + final InstanceIdentifier nodeRef = + InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(notification.getId())) + .build(); + + final Node aDNode; + try { + aDNode = NodeMapping.toADNode(nodeRef); + } catch (ConstructionException e) { + LOG.warn("Failed to construct node for {}, ignoring it", notification.getId(), e); + return; + } + + for (final FlowAndStatisticsMapList flowStats : notification.getFlowAndStatisticsMapList()) { + if (flowStats.getTableId() == 0) { + adsalFlowsStatistics.add(InventoryAndReadAdapter.toFlowOnNode(flowStats, aDNode)); + } + } + for (final IPluginOutReadService statsPublisher : getStatisticsPublisher()) { + statsPublisher.nodeFlowStatisticsUpdated(aDNode, adsalFlowsStatistics); + } + } + + /** + * OpendaylightFlowTableStatisticsListener interface implementation + */ + @Override + public void onFlowTableStatisticsUpdate(final FlowTableStatisticsUpdate notification) { + ArrayList adsalFlowTableStatistics = new ArrayList<>(); + for (final FlowTableAndStatisticsMap stats : notification.getFlowTableAndStatisticsMap()) { + if (stats.getTableId().getValue() == 0) { + final NodeTableStatistics it = new NodeTableStatistics(); + it.setActiveCount(stats.getActiveFlows().getValue().intValue()); + it.setLookupCount(stats.getPacketsLookedUp().getValue().longValue()); + it.setMatchedCount(stats.getPacketsMatched().getValue().longValue()); + adsalFlowTableStatistics.add(it); + } + } + + final InstanceIdentifier nodeRef = + InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(notification.getId())) + .build(); + + final Node aDNode; + try { + aDNode = NodeMapping.toADNode(nodeRef); + } catch (ConstructionException e) { + LOG.warn("Failed to construct node for {}, ignoring it", notification.getId(), e); + return; + } + + for (final IPluginOutReadService statsPublisher : getStatisticsPublisher()) { + statsPublisher.nodeTableStatisticsUpdated(aDNode, adsalFlowTableStatistics); + } + } + + /** + * OpendaylightPortStatisticsUpdate interface implementation + */ + @Override + public void onNodeConnectorStatisticsUpdate(final NodeConnectorStatisticsUpdate notification) { + final ArrayList adsalPortStatistics = new ArrayList(); + for (final NodeConnectorStatisticsAndPortNumberMap nodeConnectorStatistics : notification.getNodeConnectorStatisticsAndPortNumberMap()) { + try { + adsalPortStatistics.add(toNodeConnectorStatistics( + nodeConnectorStatistics, notification.getId(), nodeConnectorStatistics.getNodeConnectorId())); + } catch (ConstructionException e) { + LOG.warn("Failed to create statistics for node {} connector {}, not updating them", + notification.getId(), nodeConnectorStatistics.getNodeConnectorId(), e); + } + } + + final InstanceIdentifier nodeRef = + InstanceIdentifier.builder(Nodes.class) + .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(notification.getId())) + .build(); + + final Node aDNode; + try { + aDNode = NodeMapping.toADNode(nodeRef); + } catch (ConstructionException e) { + LOG.warn("Failed to construct node for {}, ignoring it", notification.getId(), e); + return; + } + + for (final IPluginOutReadService statsPublisher : getStatisticsPublisher()) { + statsPublisher.nodeConnectorStatisticsUpdated(aDNode, adsalPortStatistics); + } + } + + private static FlowOnNode toFlowOnNode(final FlowAndStatisticsMapList flowAndStatsMap, final Node node) { + final FlowOnNode it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap, node)); + return addFlowStats(it, flowAndStatsMap); + } + + private static FlowOnNode addFlowStats(final FlowOnNode node, final GenericStatistics stats) { + node.setByteCount(stats.getByteCount().getValue().longValue()); + node.setPacketCount(stats.getPacketCount().getValue().longValue()); + node.setDurationSeconds(stats.getDuration().getSecond().getValue().intValue()); + node.setDurationNanoseconds(stats.getDuration().getNanosecond().getValue().intValue()); + return node; + } + + @Override + public Set getConfiguredNotConnectedNodes() { + return Collections.emptySet(); + } + + private void publishNodeUpdate(final Node node, final UpdateType updateType, final Set properties) { + for (final IPluginOutInventoryService publisher : getInventoryPublisher()) { + publisher.updateNode(node, updateType, properties); + } + } + + private void publishNodeConnectorUpdate(final NodeConnector nodeConnector, final UpdateType updateType, final Set properties) { + for (final IPluginOutInventoryService publisher : getInventoryPublisher()) { + publisher.updateNodeConnector(nodeConnector, updateType, properties); + } + } + + private boolean isKnownNodeConnector(final InstanceIdentifier nodeConnectorIdentifier) { + final List path = nodeConnectorIdentifier.getPath(); + if (path.size() >= 3) { + final PathArgument nodePath = path.get(1); + final PathArgument nodeConnectorPath = path.get(2); + final List nodeConnectors = nodeToNodeConnectorsMap.get(nodePath); + if (nodeConnectors != null) { + return nodeConnectors.contains(nodeConnectorPath); + } + } + return false; + } + + private boolean recordNodeConnector(final InstanceIdentifier nodeConnectorIdentifier) { + final List path = nodeConnectorIdentifier.getPath(); + if (path.size() < 3) { + return false; + } + + final PathArgument nodePath = path.get(1); + final PathArgument nodeConnectorPath = path.get(2); + + synchronized (this) { + List nodeConnectors = this.nodeToNodeConnectorsMap.get(nodePath); + if (nodeConnectors == null) { + nodeConnectors = new ArrayList<>(); + this.nodeToNodeConnectorsMap.put(nodePath, nodeConnectors); + } + + return nodeConnectors.add(nodeConnectorPath); + } + } + + private List removeNodeConnectors(final InstanceIdentifier nodeIdentifier) { + return this.nodeToNodeConnectorsMap.remove(nodeIdentifier.getPath().get(1)); + } +} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend deleted file mode 100644 index 8908504f15..0000000000 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryAndReadAdapter.xtend +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Copyright (c) 2014 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.sal.compatibility - -import java.util.ArrayList -import java.util.Collections -import java.util.List -import java.util.Map -import java.util.Set -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.CopyOnWriteArrayList -import java.util.concurrent.locks.Lock -import java.util.concurrent.locks.ReentrantLock -import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService -import org.opendaylight.controller.sal.binding.api.data.DataProviderService -import org.opendaylight.controller.sal.core.Edge -import org.opendaylight.controller.sal.core.Node -import org.opendaylight.controller.sal.core.NodeTable -import org.opendaylight.controller.sal.core.UpdateType -import org.opendaylight.controller.sal.flowprogrammer.Flow -import org.opendaylight.controller.sal.inventory.IPluginInInventoryService -import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService -import org.opendaylight.controller.sal.reader.FlowOnNode -import org.opendaylight.controller.sal.reader.IPluginInReadService -import org.opendaylight.controller.sal.reader.IPluginOutReadService -import org.opendaylight.controller.sal.reader.NodeConnectorStatistics -import org.opendaylight.controller.sal.reader.NodeDescription -import org.opendaylight.controller.sal.reader.NodeTableStatistics -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryService -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.Link -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatistics -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetNodeConnectorStatisticsInputBuilder -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService -import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.slf4j.LoggerFactory - -import static extension org.opendaylight.controller.sal.common.util.Arguments.* -import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.* - -class InventoryAndReadAdapter implements IPluginInReadService, - IPluginInInventoryService, - OpendaylightInventoryListener, - OpendaylightFlowStatisticsListener, - OpendaylightFlowTableStatisticsListener, - OpendaylightPortStatisticsListener { - - private static val LOG = LoggerFactory.getLogger(InventoryAndReadAdapter); - - private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue; - @Property - DataBrokerService dataService; - - @Property - DataProviderService dataProviderService; - - @Property - OpendaylightFlowStatisticsService flowStatisticsService; - - @Property - OpendaylightPortStatisticsService nodeConnectorStatisticsService; - - @Property - OpendaylightFlowTableStatisticsService flowTableStatisticsService; - - @Property - FlowTopologyDiscoveryService topologyDiscovery; - - @Property - List statisticsPublisher = new CopyOnWriteArrayList(); - - @Property - List inventoryPublisher = new CopyOnWriteArrayList(); - - private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider(); - - private final Map> nodeToNodeConnectorsMap = new ConcurrentHashMap>(); - - private final Lock nodeToNodeConnectorsLock = new ReentrantLock(); - - - def startAdapter(){ - inventoryNotificationProvider.dataProviderService = dataProviderService; - inventoryNotificationProvider.inventoryPublisher = inventoryPublisher; - // inventoryNotificationProvider.start(); - } - - def start(){ - } - - def setInventoryPublisher(IPluginOutInventoryService listener){ - inventoryPublisher.add(listener); - } - - def unsetInventoryPublisher(IPluginOutInventoryService listener){ - inventoryPublisher.remove(listener); - } - - def setReadPublisher(IPluginOutReadService listener) { - statisticsPublisher.add(listener); - } - - def unsetReadPublisher (IPluginOutReadService listener) { - if( listener != null) - statisticsPublisher.remove(listener); - } - - protected def startChange() { - return dataProviderService.beginTransaction; - } - - override getTransmitRate(org.opendaylight.controller.sal.core.NodeConnector connector) { - val nodeConnector = readFlowCapableNodeConnector(connector.toNodeConnectorRef); - return nodeConnector.currentSpeed - } - - override readAllFlow(Node node, boolean cached) { - - val output = new ArrayList(); - val tableRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) - .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance(); - - val it = this.startChange(); - - val table= it.readConfigurationData(tableRef) as Table; - - if(table != null){ - LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size); - - for(flow : table.flow){ - - val adsalFlow = ToSalConversionsUtils.toFlow(flow,node); - val statsFromDataStore = flow.getAugmentation(FlowStatisticsData); - - if(statsFromDataStore != null){ - val it = new FlowOnNode(adsalFlow); - byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue; - packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue; - durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue; - durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue; - - output.add(it); - } - } - } - - //TODO (main): Shell we send request to the switch? It will make async request to the switch. - // Once plugin receive response, it will let adaptor know through onFlowStatisticsUpdate() - // If we assume that md-sal statistics manager will always be running, then its not required - // But if not, then sending request will collect the latest data for adaptor atleast. - val input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder; - input.setNode(node.toNodeRef); - flowStatisticsService.getAllFlowsStatisticsFromAllFlowTables(input.build) - - return output; - } - - override readAllNodeConnector(Node node, boolean cached) { - - val ret = new ArrayList(); - val nodeRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) - .toInstance(); - - val provider = this.startChange(); - - val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; - - if(dsNode != null){ - - for (dsNodeConnector : dsNode.nodeConnector){ - val nodeConnectorRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) - .child(NodeConnector, dsNodeConnector.key) - .toInstance(); - - val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector; - - if(nodeConnectorFromDS != null){ - val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics; - - ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id)); - } - } - } - - //TODO: Refer TODO (main) - val input = new GetAllNodeConnectorsStatisticsInputBuilder(); - input.setNode(node.toNodeRef); - nodeConnectorStatisticsService.getAllNodeConnectorsStatistics(input.build()); - return ret; - } - - override readAllNodeTable(Node node, boolean cached) { - val ret = new ArrayList(); - - val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef) - - if(dsFlowCapableNode != null){ - - for (table : dsFlowCapableNode.table){ - - val tableStats = table.getAugmentation(FlowTableStatisticsData); - - if(tableStats != null){ - ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node)); - } - } - } - - //TODO: Refer TODO (main) - val input = new GetFlowTablesStatisticsInputBuilder(); - input.setNode(node.toNodeRef); - flowTableStatisticsService.getFlowTablesStatistics(input.build); - return ret; - } - - override readDescription(Node node, boolean cached) { - return toNodeDescription(node.toNodeRef); - } - - override readFlow(Node node, Flow targetFlow, boolean cached) { - var FlowOnNode ret= null; - - val tableRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node)) - .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance(); - - val it = this.startChange(); - - val table= it.readConfigurationData(tableRef) as Table; - - if(table != null){ - LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size); - - for(mdsalFlow : table.flow){ - if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){ - val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData); - - if(statsFromDataStore != null){ - LOG.debug("Found matching flow in the data store flow table "); - val it = new FlowOnNode(targetFlow); - byteCount = statsFromDataStore.flowStatistics.byteCount.value.longValue; - packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue; - durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue; - durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue; - - ret = it; - } - } - } - } - - //TODO: Refer TODO (main) - val input = new GetFlowStatisticsFromFlowTableInputBuilder; - input.setNode(node.toNodeRef); - input.fieldsFrom(MDFlowMapping.toMDSalflow(targetFlow)); - flowStatisticsService.getFlowStatisticsFromFlowTable(input.build) - - return ret; - - } - - override readNodeConnector(org.opendaylight.controller.sal.core.NodeConnector connector, boolean cached) { - var NodeConnectorStatistics nodeConnectorStatistics = null; - - val nodeConnectorRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node)) - .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector)) - .toInstance(); - val provider = this.startChange(); - - val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector; - - if(nodeConnectorFromDS != null){ - val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics; - if(nodeConnectorStatsFromDs != null) { - nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics, - InventoryMapping.toNodeKey(connector.node).id, - InventoryMapping.toNodeConnectorKey(connector).id); - } - } - - //TODO: Refer TODO (main) - val input = new GetNodeConnectorStatisticsInputBuilder(); - input.setNode(connector.node.toNodeRef); - input.setNodeConnectorId(InventoryMapping.toNodeConnectorKey(connector).id); - nodeConnectorStatisticsService.getNodeConnectorStatistics(input.build()); - return nodeConnectorStatistics; - } - - override readNodeTable(NodeTable nodeTable, boolean cached) { - var NodeTableStatistics nodeStats = null - - val tableRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node)) - .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance(); - - val it = this.startChange(); - - val table= it.readConfigurationData(tableRef) as Table; - - if(table != null){ - val tableStats = table.getAugmentation(FlowTableStatisticsData); - - if(tableStats != null){ - nodeStats = toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node); - } - } - - //TODO: Refer TODO (main) - val input = new GetFlowTablesStatisticsInputBuilder(); - input.setNode(nodeTable.node.toNodeRef); - flowTableStatisticsService.getFlowTablesStatistics(input.build); - - return nodeStats; - } - - override onNodeConnectorRemoved(NodeConnectorRemoved update) { - // Never received - } - - override onNodeRemoved(NodeRemoved notification) { - val properties = Collections.emptySet(); - - removeNodeConnectors(notification.nodeRef.value); - - publishNodeUpdate(notification.nodeRef.toADNode, UpdateType.REMOVED, properties); - } - - override onNodeConnectorUpdated(NodeConnectorUpdated update) { - var updateType = UpdateType.CHANGED; - if(!isKnownNodeConnector(update.nodeConnectorRef.value)){ - updateType = UpdateType.ADDED; - recordNodeConnector(update.nodeConnectorRef.value); - } - - var nodeConnector = update.nodeConnectorRef.toADNodeConnector - - publishNodeConnectorUpdate(nodeConnector , updateType , update.toADNodeConnectorProperties); - } - - override onNodeUpdated(NodeUpdated notification) { - val InstanceIdentifier identifier = notification.nodeRef.value as InstanceIdentifier; - - var updateType = UpdateType.CHANGED; - if ( this._dataService.readOperationalData(identifier) == null ){ - updateType = UpdateType.ADDED; - } - publishNodeUpdate(notification.nodeRef.toADNode, updateType, notification.toADNodeProperties); - - //Notify the listeners of IPluginOutReadService - - for (statsPublisher : statisticsPublisher){ - val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; - val description = notification.nodeRef.toNodeDescription - if(description != null) { - statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description); - } - } - } - - override getNodeProps() { - val props = new ConcurrentHashMap>() - - val nodes = readAllMDNodes() - for (node : nodes.node ) { - val fcn = node.getAugmentation(FlowCapableNode) - if(fcn != null) { - val perNodeProps = fcn.toADNodeProperties(node.id) - val perNodePropMap = new ConcurrentHashMap - if(perNodeProps != null ) { - for(perNodeProp : perNodeProps) { - perNodePropMap.put(perNodeProp.name,perNodeProp) - } - } - props.put(new Node(MD_SAL_TYPE, node.id.toADNodeId),perNodePropMap) - } - } - return props; - } - - private def readAllMDNodes() { - val nodesRef = InstanceIdentifier.builder(Nodes) - .toInstance - val reader = TypeSafeDataReader.forReader(dataService) - return reader.readOperationalData(nodesRef) - } - - private def readAllMDNodeConnectors(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node) { - val nodeRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(node.id)) - .toInstance - val reader = TypeSafeDataReader.forReader(dataService) - return reader.readOperationalData(nodeRef).nodeConnector - } - - override getNodeConnectorProps(Boolean refresh) { - // Note, because the MD-SAL has a unified data store, we can ignore the Boolean refresh, as we have no secondary - // data store to refresh from - val props = new ConcurrentHashMap>() - val nodes = readAllMDNodes() - for (node : nodes.node) { - val ncs = node.readAllMDNodeConnectors - if(ncs != null) { - for( nc : ncs ) { - val fcnc = nc.getAugmentation(FlowCapableNodeConnector) - if(fcnc != null) { - val ncps = fcnc.toADNodeConnectorProperties - val ncpsm = new ConcurrentHashMap - if(ncps != null) { - for(p : ncps) { - ncpsm.put(p.name,p) - } - } - props.put(nc.id.toADNodeConnector(node.id),ncpsm) - } - } - } - } - return props - } - - private def FlowCapableNode readFlowCapableNode(NodeRef ref) { - val dataObject = dataService.readOperationalData(ref.value as InstanceIdentifier); - if(dataObject != null) { - val node = dataObject.checkInstanceOf( - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node); - return node.getAugmentation(FlowCapableNode); - } - return null; - } - - private def FlowCapableNodeConnector readFlowCapableNodeConnector(NodeConnectorRef ref) { - val dataObject = dataService.readOperationalData(ref.value as InstanceIdentifier); - val node = dataObject.checkInstanceOf( - NodeConnector); - return node.getAugmentation(FlowCapableNodeConnector); - } - - private def toNodeConnectorStatistics( - org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics nodeConnectorStatistics, NodeId nodeId, NodeConnectorId nodeConnectorId) { - - val it = new NodeConnectorStatistics(); - - receivePacketCount = nodeConnectorStatistics.packets.received.longValue; - transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue; - - receiveByteCount = nodeConnectorStatistics.bytes.received.longValue; - transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue; - - receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue; - transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue; - - receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue; - transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue; - - receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue; - receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue; - receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue; - collisionCount = nodeConnectorStatistics.collisionCount.longValue; - - val nodeConnectorRef = InstanceIdentifier.builder(Nodes) - .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId)) - .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance; - - nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef)); - - return it; - } - - private def toNodeTableStatistics( - FlowTableStatistics tableStats, - Short tableId,Node node){ - var it = new NodeTableStatistics(); - - activeCount = tableStats.activeFlows.value.intValue; - lookupCount = tableStats.packetsLookedUp.value.intValue; - matchedCount = tableStats.packetsMatched.value.intValue; - name = tableId.toString; - nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node); - return it; - } - - private def toNodeDescription(NodeRef nodeRef){ - val capableNode = readFlowCapableNode(nodeRef); - if(capableNode !=null) { - val it = new NodeDescription() - manufacturer = capableNode.manufacturer - serialNumber = capableNode.serialNumber - software = capableNode.software - description = capableNode.description - - return it; - } - return null; - } - - - def Edge toADEdge(Link link) { - new Edge(link.source.toADNodeConnector,link.destination.toADNodeConnector) - } - - /* - * OpendaylightFlowStatisticsListener interface implementation - */ - override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { - //Ignoring this notification as there does not seem to be a way to bubble this up to AD-SAL - } - - override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) { - - val adsalFlowsStatistics = new ArrayList(); - val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; - - for(flowStats : notification.flowAndStatisticsMapList){ - if(flowStats.tableId == 0) - adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode)); - } - - for (statsPublisher : statisticsPublisher){ - statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics); - } - - } - /* - * OpendaylightFlowTableStatisticsListener interface implementation - */ - override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { - var adsalFlowTableStatistics = new ArrayList(); - - for(stats : notification.flowTableAndStatisticsMap){ - if (stats.tableId.value == 0){ - val it = new NodeTableStatistics(); - activeCount = stats.activeFlows.value.intValue; - lookupCount = stats.packetsLookedUp.value.longValue; - matchedCount = stats.packetsMatched.value.longValue; - - adsalFlowTableStatistics.add(it); - } - } - for (statsPublisher : statisticsPublisher){ - val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; - statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics); - } - } - - /* - * OpendaylightPortStatisticsUpdate interface implementation - */ - override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { - - val adsalPortStatistics = new ArrayList(); - - for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){ - adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId)); - } - - for (statsPublisher : statisticsPublisher){ - val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance; - statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics); - } - - } - - private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){ - - val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node)); - - byteCount = flowAndStatsMap.byteCount.value.longValue; - packetCount = flowAndStatsMap.packetCount.value.longValue; - durationSeconds = flowAndStatsMap.duration.second.value.intValue; - durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue; - - return it; - } - - override getConfiguredNotConnectedNodes() { - return Collections.emptySet(); - } - - - private def publishNodeUpdate(Node node, UpdateType updateType, Set properties){ - for( publisher : inventoryPublisher){ - publisher.updateNode(node, updateType, properties); - } - } - - private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set properties){ - for( publisher : inventoryPublisher){ - publisher.updateNodeConnector(nodeConnector, updateType, properties); - } - } - - private def isKnownNodeConnector(InstanceIdentifier nodeConnectorIdentifier){ - if(nodeConnectorIdentifier.path.size() < 3) { - return false; - } - - val nodePath = nodeConnectorIdentifier.path.get(1); - val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2); - - val nodeConnectors = nodeToNodeConnectorsMap.get(nodePath); - - if(nodeConnectors == null){ - return false; - } - return nodeConnectors.contains(nodeConnectorPath); - } - - - private def recordNodeConnector(InstanceIdentifier nodeConnectorIdentifier){ - if(nodeConnectorIdentifier.path.size() < 3) { - return false; - } - - val nodePath = nodeConnectorIdentifier.path.get(1); - val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2); - - nodeToNodeConnectorsLock.lock(); - - try { - var nodeConnectors = nodeToNodeConnectorsMap.get(nodePath); - - if(nodeConnectors == null){ - nodeConnectors = new ArrayList(); - nodeToNodeConnectorsMap.put(nodePath, nodeConnectors); - } - - nodeConnectors.add(nodeConnectorPath); - } finally { - nodeToNodeConnectorsLock.unlock(); - } - } - - private def removeNodeConnectors(InstanceIdentifier nodeIdentifier){ - val nodePath = nodeIdentifier.path.get(1); - - nodeToNodeConnectorsMap.remove(nodePath); - } -} diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.java index 29904220d7..1e4d97446f 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/InventoryMapping.java @@ -1,104 +1,99 @@ /** * 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.sal.compatibility; -import org.eclipse.xtend2.lib.StringConcatenation; -import org.eclipse.xtext.xbase.lib.Conversions; -import org.eclipse.xtext.xbase.lib.IterableExtensions; -import org.opendaylight.controller.sal.core.Node; -import org.opendaylight.controller.sal.core.NodeConnector; +import java.util.Iterator; + import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; - -import java.util.List; - -@SuppressWarnings("all") -public class InventoryMapping { - public static NodeConnector toAdNodeConnector(final InstanceIdentifier identifier) { - final List path = identifier.getPath(); - final PathArgument lastPathArgument = IterableExtensions.last(path); - final NodeConnectorKey tpKey = ((IdentifiableItem) lastPathArgument).getKey(); - return InventoryMapping.nodeConnectorFromId(tpKey.getId().getValue()); - } - - public static Node toAdNode(final InstanceIdentifier identifier) { - final List path = identifier.getPath(); - final PathArgument lastPathArgument = IterableExtensions.last(path); - final NodeKey tpKey = ((IdentifiableItem) lastPathArgument).getKey(); - return InventoryMapping.nodeFromNodeId(tpKey.getId().getValue()); - } - - public static NodeRef toNodeRef(final Node node) { - final NodeId nodeId = new NodeId(InventoryMapping.toNodeId(node)); - final NodeKey nodeKey = new NodeKey(nodeId); - final InstanceIdentifierBuilder nodes = InstanceIdentifier.builder(Nodes.class); - final InstanceIdentifierBuilder child = - nodes.child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeKey); - final InstanceIdentifier path = child.toInstance(); - return new NodeRef(path); - } - - public static NodeKey toNodeKey(final Node node) { - final NodeId nodeId = new NodeId(InventoryMapping.toNodeId(node)); - return new NodeKey(nodeId); - } - - public static NodeConnectorKey toNodeConnectorKey(final NodeConnector nc) { - final NodeConnectorId nodeConnectorId = new NodeConnectorId(InventoryMapping.toNodeConnectorId(nc)); - return new NodeConnectorKey(nodeConnectorId); - } - - public static String toNodeId(final Node node) { - final StringConcatenation builder = new StringConcatenation(); - builder.append("ad-sal:"); - builder.append(node.getType(), ""); - builder.append("::"); - builder.append(node.getNodeIDString(), ""); - return builder.toString(); - } - - public static String toNodeConnectorId(final NodeConnector nc) { - final StringConcatenation builder = new StringConcatenation(); - builder.append(InventoryMapping.toNodeId(nc.getNode()), ""); - builder.append("::"); - builder.append(nc.getNodeConnectorIDString(), ""); - return builder.toString(); - } - - public static Node nodeFromNodeId(final String nodeId) { - final String[] split = nodeId.split("::"); - return InventoryMapping.nodeFromString(split); - } - - public static NodeConnector nodeConnectorFromId(final String invId) { - final String[] split = invId.split("::"); - return InventoryMapping.nodeConnectorFromString(split); - } - - private static NodeConnector nodeConnectorFromString(final String[] string) { - final List subList = ((List)Conversions.doWrapArray(string)).subList(0, 1); - final Node node = InventoryMapping.nodeFromString(((String[])Conversions.unwrapArray(subList, String.class))); - final String index3 = string[2]; - return NodeConnector.fromStringNoNode(index3, node); - } - - private static Node nodeFromString(final String[] strings) { - String index0 = strings[0]; - final String type = index0.substring(6); - String id = strings[1]; - return Node.fromString(type, id); - } +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; + +import com.google.common.base.Splitter; + +public final class InventoryMapping { + private static final String NODE_TYPE_STRING = "::"; + private static final Splitter NODE_TYPE_SPLITTER = Splitter.on(NODE_TYPE_STRING); + + private InventoryMapping() { + throw new UnsupportedOperationException("Utility class"); + } + + public static org.opendaylight.controller.sal.core.NodeConnector toAdNodeConnector(final InstanceIdentifier identifier) { + @SuppressWarnings("unchecked") + final NodeConnectorKey tpKey = ((KeyedInstanceIdentifier) identifier).getKey(); + return InventoryMapping.nodeConnectorFromId(tpKey.getId().getValue()); + } + + public static org.opendaylight.controller.sal.core.Node toAdNode(final InstanceIdentifier identifier) { + @SuppressWarnings("unchecked") + final NodeKey tpKey = ((KeyedInstanceIdentifier)identifier).getKey(); + return InventoryMapping.nodeFromNodeId(tpKey.getId().getValue()); + } + + public static NodeRef toNodeRef(final org.opendaylight.controller.sal.core.Node node) { + final NodeKey nodeKey = new NodeKey(new NodeId(InventoryMapping.toNodeId(node))); + final InstanceIdentifier path = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, nodeKey).toInstance(); + return new NodeRef(path); + } + + public static NodeKey toNodeKey(final org.opendaylight.controller.sal.core.Node node) { + final NodeId nodeId = new NodeId(InventoryMapping.toNodeId(node)); + return new NodeKey(nodeId); + } + + public static NodeConnectorKey toNodeConnectorKey(final org.opendaylight.controller.sal.core.NodeConnector nc) { + final NodeConnectorId nodeConnectorId = new NodeConnectorId(InventoryMapping.toNodeConnectorId(nc)); + return new NodeConnectorKey(nodeConnectorId); + } + + private static StringBuilder nodeIdBulder(final org.opendaylight.controller.sal.core.Node node) { + final StringBuilder sb = new StringBuilder(); + sb.append("ad-sal:"); + sb.append(node.getType()); + sb.append(NODE_TYPE_STRING); + sb.append(node.getNodeIDString()); + return sb; + } + + public static String toNodeId(final org.opendaylight.controller.sal.core.Node node) { + return nodeIdBulder(node).toString(); + } + + public static String toNodeConnectorId(final org.opendaylight.controller.sal.core.NodeConnector nc) { + final StringBuilder sb = nodeIdBulder(nc.getNode()); + sb.append(NODE_TYPE_STRING); + sb.append(nc.getNodeConnectorIDString()); + return sb.toString(); + } + + public static org.opendaylight.controller.sal.core.Node nodeFromNodeId(final String nodeId) { + return InventoryMapping.nodeFromStrings(NODE_TYPE_SPLITTER.split(nodeId).iterator()); + } + + public static org.opendaylight.controller.sal.core.NodeConnector nodeConnectorFromId(final String invId) { + return InventoryMapping.nodeConnectorFromString(NODE_TYPE_SPLITTER.split(invId).iterator()); + } + + private static org.opendaylight.controller.sal.core.NodeConnector nodeConnectorFromString(final Iterator it) { + final org.opendaylight.controller.sal.core.Node node = InventoryMapping.nodeFromStrings(it); + return org.opendaylight.controller.sal.core.NodeConnector.fromStringNoNode(it.next(), node); + } + + private static org.opendaylight.controller.sal.core.Node nodeFromStrings(final Iterator it) { + final String type = it.next().substring(6); + return org.opendaylight.controller.sal.core.Node.fromString(type, it.next()); + } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java index 2c95252ac7..ba86ad99fb 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/NodeMapping.java @@ -61,314 +61,314 @@ import com.google.common.base.Objects; import com.google.common.base.Preconditions; public final class NodeMapping { - public final static String MD_SAL_TYPE = "MD_SAL"; - - private final static Class NODE_CLASS = Node.class; - - private final static Class NODECONNECTOR_CLASS = NodeConnector.class; - - private NodeMapping() { - throw new UnsupportedOperationException("Utility class. Instantiation is not allowed."); - } - - public static org.opendaylight.controller.sal.core.Node toADNode(final InstanceIdentifier node) throws ConstructionException { - NodeId nodeId = NodeMapping.toNodeId(node); - return NodeMapping.toADNode(nodeId); - } - - public static org.opendaylight.controller.sal.core.Node toADNode(final NodeId id) throws ConstructionException { - String aDNodeId = NodeMapping.toADNodeId(id); - return new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, aDNodeId); - } - - public static NodeId toNodeId(final InstanceIdentifier id) { - final NodeKey key = id.firstKeyOf(Node.class, NodeKey.class); - Preconditions.checkArgument(key != null, "No node identifier found in %s", id); - return key.getId(); - } - - public static String toADNodeId(final NodeId nodeId) { - return nodeId.getValue(); - } - - public static org.opendaylight.controller.sal.core.NodeConnector toADNodeConnector(final NodeConnectorRef source) throws ConstructionException { - final InstanceIdentifier id = Preconditions.checkNotNull(source.getValue()); - final NodeConnectorKey key = id.firstKeyOf(NodeConnector.class, NodeConnectorKey.class); - return NodeMapping.toADNodeConnector(key.getId(), NodeMapping.toNodeId(id)); - } - - public static org.opendaylight.controller.sal.core.NodeConnector toADNodeConnector(final NodeConnectorId ncid, final NodeId nid) throws ConstructionException { - String nodeConnectorType = NodeMapping.toNodeConnectorType(ncid, nid); - Object aDNodeConnectorId = NodeMapping.toADNodeConnectorId(ncid, nid); - org.opendaylight.controller.sal.core.Node aDNode = NodeMapping.toADNode(nid); - return new org.opendaylight.controller.sal.core.NodeConnector(nodeConnectorType, aDNodeConnectorId, aDNode); - } - - public static String toNodeConnectorType(final NodeConnectorId ncId, final NodeId nodeId) { - if (ncId.equals(toLocalNodeConnectorId(nodeId))) { - return NodeConnectorIDType.SWSTACK; - } else if (ncId.equals(toNormalNodeConnectorId(nodeId))) { - return NodeConnectorIDType.HWPATH; - } else if (ncId.equals(toControllerNodeConnectorId(nodeId))) { - return NodeConnectorIDType.CONTROLLER; - } - return MD_SAL_TYPE; - } - - public static Object toADNodeConnectorId(final NodeConnectorId nodeConnectorId, final NodeId nodeId) { - if (nodeConnectorId.equals(toLocalNodeConnectorId(nodeId)) || - nodeConnectorId.equals(toNormalNodeConnectorId(nodeId)) || - nodeConnectorId.equals(toControllerNodeConnectorId(nodeId))) { - return org.opendaylight.controller.sal.core.NodeConnector.SPECIALNODECONNECTORID; - } - return nodeConnectorId.getValue(); - } - - public static NodeConnectorId toControllerNodeConnectorId(final NodeId node) { - return new NodeConnectorId(node.getValue() + ":" + 4294967293L); - } - - public static NodeConnectorId toLocalNodeConnectorId(final NodeId node) { - return new NodeConnectorId(node.getValue() + ":" + 4294967294L); - } - - public static NodeConnectorId toNormalNodeConnectorId(final NodeId node) { - return new NodeConnectorId(node.getValue() + ":" + 4294967290L); - } - - public static NodeRef toNodeRef(final org.opendaylight.controller.sal.core.Node node) { - Preconditions.checkArgument(MD_SAL_TYPE.equals(node.getType())); - final String nodeId = Arguments.checkInstanceOf(node.getID(), String.class); - final NodeKey nodeKey = new NodeKey(new NodeId(nodeId)); - final InstanceIdentifier nodePath = InstanceIdentifier.builder(Nodes.class).child(NODE_CLASS, nodeKey).toInstance(); - return new NodeRef(nodePath); - } - - public static NodeConnectorRef toNodeConnectorRef(final org.opendaylight.controller.sal.core.NodeConnector nodeConnector) { - - final NodeRef node = NodeMapping.toNodeRef(nodeConnector.getNode()); - @SuppressWarnings("unchecked") - final InstanceIdentifier nodePath = ((InstanceIdentifier) node.getValue()); - NodeConnectorId nodeConnectorId = null; - - if (nodeConnector.getID().equals(org.opendaylight.controller.sal.core.NodeConnector.SPECIALNODECONNECTORID)) { - final NodeId nodeId = toNodeId(nodePath); - final String nodeConnectorType = nodeConnector.getType(); - if (nodeConnectorType.equals(NodeConnectorIDType.SWSTACK)) { - nodeConnectorId = toLocalNodeConnectorId(nodeId); - } else if (nodeConnectorType.equals(NodeConnectorIDType.HWPATH)) { - nodeConnectorId = toNormalNodeConnectorId(nodeId); - } else if (nodeConnectorType.equals(NodeConnectorIDType.CONTROLLER)) { - nodeConnectorId = toControllerNodeConnectorId(nodeId); + public final static String MD_SAL_TYPE = "MD_SAL"; + + private final static Class NODE_CLASS = Node.class; + + private final static Class NODECONNECTOR_CLASS = NodeConnector.class; + + private NodeMapping() { + throw new UnsupportedOperationException("Utility class. Instantiation is not allowed."); + } + + public static org.opendaylight.controller.sal.core.Node toADNode(final InstanceIdentifier node) throws ConstructionException { + NodeId nodeId = NodeMapping.toNodeId(node); + return NodeMapping.toADNode(nodeId); + } + + public static org.opendaylight.controller.sal.core.Node toADNode(final NodeId id) throws ConstructionException { + String aDNodeId = NodeMapping.toADNodeId(id); + return new org.opendaylight.controller.sal.core.Node(NodeMapping.MD_SAL_TYPE, aDNodeId); + } + + public static NodeId toNodeId(final InstanceIdentifier id) { + final NodeKey key = id.firstKeyOf(Node.class, NodeKey.class); + Preconditions.checkArgument(key != null, "No node identifier found in %s", id); + return key.getId(); + } + + public static String toADNodeId(final NodeId nodeId) { + return nodeId.getValue(); + } + + public static org.opendaylight.controller.sal.core.NodeConnector toADNodeConnector(final NodeConnectorRef source) throws ConstructionException { + final InstanceIdentifier id = Preconditions.checkNotNull(source.getValue()); + final NodeConnectorKey key = id.firstKeyOf(NodeConnector.class, NodeConnectorKey.class); + return NodeMapping.toADNodeConnector(key.getId(), NodeMapping.toNodeId(id)); + } + + public static org.opendaylight.controller.sal.core.NodeConnector toADNodeConnector(final NodeConnectorId ncid, final NodeId nid) throws ConstructionException { + String nodeConnectorType = NodeMapping.toNodeConnectorType(ncid, nid); + Object aDNodeConnectorId = NodeMapping.toADNodeConnectorId(ncid, nid); + org.opendaylight.controller.sal.core.Node aDNode = NodeMapping.toADNode(nid); + return new org.opendaylight.controller.sal.core.NodeConnector(nodeConnectorType, aDNodeConnectorId, aDNode); + } + + public static String toNodeConnectorType(final NodeConnectorId ncId, final NodeId nodeId) { + if (ncId.equals(toLocalNodeConnectorId(nodeId))) { + return NodeConnectorIDType.SWSTACK; + } else if (ncId.equals(toNormalNodeConnectorId(nodeId))) { + return NodeConnectorIDType.HWPATH; + } else if (ncId.equals(toControllerNodeConnectorId(nodeId))) { + return NodeConnectorIDType.CONTROLLER; } - } else { - nodeConnectorId = new NodeConnectorId(Arguments.checkInstanceOf(nodeConnector.getID(), String.class)); + return MD_SAL_TYPE; } - final NodeConnectorKey connectorKey = new NodeConnectorKey(nodeConnectorId); - final InstanceIdentifier path = nodePath.child(NODECONNECTOR_CLASS, connectorKey); - return new NodeConnectorRef(path); - } - public static org.opendaylight.controller.sal.core.Node toADNode(final NodeRef node) throws ConstructionException { - return NodeMapping.toADNode(node.getValue()); - } + public static Object toADNodeConnectorId(final NodeConnectorId nodeConnectorId, final NodeId nodeId) { + if (nodeConnectorId.equals(toLocalNodeConnectorId(nodeId)) || + nodeConnectorId.equals(toNormalNodeConnectorId(nodeId)) || + nodeConnectorId.equals(toControllerNodeConnectorId(nodeId))) { + return org.opendaylight.controller.sal.core.NodeConnector.SPECIALNODECONNECTORID; + } + return nodeConnectorId.getValue(); + } - public static HashSet toADNodeConnectorProperties(final NodeConnectorUpdated nc) { - final FlowCapableNodeConnectorUpdated fcncu = nc.getAugmentation(FlowCapableNodeConnectorUpdated.class); - if (!Objects.equal(fcncu, null)) { - return NodeMapping.toADNodeConnectorProperties(fcncu); + public static NodeConnectorId toControllerNodeConnectorId(final NodeId node) { + return new NodeConnectorId(node.getValue() + ":" + 4294967293L); } - return new HashSet(); - } - public static HashSet toADNodeConnectorProperties(final NodeConnector nc) { - final FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class); - if (!Objects.equal(fcnc, null)) { - return NodeMapping.toADNodeConnectorProperties(fcnc); + public static NodeConnectorId toLocalNodeConnectorId(final NodeId node) { + return new NodeConnectorId(node.getValue() + ":" + 4294967294L); } - return new HashSet(); - } - public static HashSet toADNodeConnectorProperties(final FlowNodeConnector fcncu) { + public static NodeConnectorId toNormalNodeConnectorId(final NodeId node) { + return new NodeConnectorId(node.getValue() + ":" + 4294967290L); + } + + public static NodeRef toNodeRef(final org.opendaylight.controller.sal.core.Node node) { + Preconditions.checkArgument(MD_SAL_TYPE.equals(node.getType())); + final String nodeId = Arguments.checkInstanceOf(node.getID(), String.class); + final NodeKey nodeKey = new NodeKey(new NodeId(nodeId)); + final InstanceIdentifier nodePath = InstanceIdentifier.builder(Nodes.class).child(NODE_CLASS, nodeKey).toInstance(); + return new NodeRef(nodePath); + } - final HashSet props = new HashSet<>(); - if (fcncu != null) { - if (fcncu.getCurrentFeature() != null && toAdBandwidth(fcncu.getCurrentFeature()) != null) { - props.add(toAdBandwidth(fcncu.getCurrentFeature())); + public static NodeConnectorRef toNodeConnectorRef(final org.opendaylight.controller.sal.core.NodeConnector nodeConnector) { + + final NodeRef node = NodeMapping.toNodeRef(nodeConnector.getNode()); + @SuppressWarnings("unchecked") + final InstanceIdentifier nodePath = ((InstanceIdentifier) node.getValue()); + NodeConnectorId nodeConnectorId = null; + + if (nodeConnector.getID().equals(org.opendaylight.controller.sal.core.NodeConnector.SPECIALNODECONNECTORID)) { + final NodeId nodeId = toNodeId(nodePath); + final String nodeConnectorType = nodeConnector.getType(); + if (nodeConnectorType.equals(NodeConnectorIDType.SWSTACK)) { + nodeConnectorId = toLocalNodeConnectorId(nodeId); + } else if (nodeConnectorType.equals(NodeConnectorIDType.HWPATH)) { + nodeConnectorId = toNormalNodeConnectorId(nodeId); + } else if (nodeConnectorType.equals(NodeConnectorIDType.CONTROLLER)) { + nodeConnectorId = toControllerNodeConnectorId(nodeId); + } + } else { + nodeConnectorId = new NodeConnectorId(Arguments.checkInstanceOf(nodeConnector.getID(), String.class)); } - if (fcncu.getAdvertisedFeatures() != null && toAdAdvertizedBandwidth(fcncu.getAdvertisedFeatures()) != null) { - props.add(toAdAdvertizedBandwidth(fcncu.getAdvertisedFeatures())); + final NodeConnectorKey connectorKey = new NodeConnectorKey(nodeConnectorId); + final InstanceIdentifier path = nodePath.child(NODECONNECTOR_CLASS, connectorKey); + return new NodeConnectorRef(path); + } + + public static org.opendaylight.controller.sal.core.Node toADNode(final NodeRef node) throws ConstructionException { + return NodeMapping.toADNode(node.getValue()); + } + + public static HashSet toADNodeConnectorProperties(final NodeConnectorUpdated nc) { + final FlowCapableNodeConnectorUpdated fcncu = nc.getAugmentation(FlowCapableNodeConnectorUpdated.class); + if (!Objects.equal(fcncu, null)) { + return NodeMapping.toADNodeConnectorProperties(fcncu); } - if (fcncu.getSupported() != null && toAdSupportedBandwidth(fcncu.getSupported()) != null) { - props.add(toAdSupportedBandwidth(fcncu.getSupported())); + return new HashSet(); + } + + public static HashSet toADNodeConnectorProperties(final NodeConnector nc) { + final FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class); + if (!Objects.equal(fcnc, null)) { + return NodeMapping.toADNodeConnectorProperties(fcnc); } - if (fcncu.getPeerFeatures() != null && toAdPeerBandwidth(fcncu.getPeerFeatures()) != null) { - props.add(toAdPeerBandwidth(fcncu.getPeerFeatures())); + return new HashSet(); + } + + public static HashSet toADNodeConnectorProperties(final FlowNodeConnector fcncu) { + + final HashSet props = new HashSet<>(); + if (fcncu != null) { + if (fcncu.getCurrentFeature() != null && toAdBandwidth(fcncu.getCurrentFeature()) != null) { + props.add(toAdBandwidth(fcncu.getCurrentFeature())); + } + if (fcncu.getAdvertisedFeatures() != null && toAdAdvertizedBandwidth(fcncu.getAdvertisedFeatures()) != null) { + props.add(toAdAdvertizedBandwidth(fcncu.getAdvertisedFeatures())); + } + if (fcncu.getSupported() != null && toAdSupportedBandwidth(fcncu.getSupported()) != null) { + props.add(toAdSupportedBandwidth(fcncu.getSupported())); + } + if (fcncu.getPeerFeatures() != null && toAdPeerBandwidth(fcncu.getPeerFeatures()) != null) { + props.add(toAdPeerBandwidth(fcncu.getPeerFeatures())); + } + if (fcncu.getName() != null && toAdName(fcncu.getName()) != null) { + props.add(toAdName(fcncu.getName())); + } + if (fcncu.getConfiguration() != null && toAdConfig(fcncu.getConfiguration()) != null) { + props.add(toAdConfig(fcncu.getConfiguration())); + } + if (fcncu.getState() != null && toAdState(fcncu.getState()) != null) { + props.add(toAdState(fcncu.getState())); + } } - if (fcncu.getName() != null && toAdName(fcncu.getName()) != null) { - props.add(toAdName(fcncu.getName())); + return props; + } + + public static Name toAdName(final String name) { + return new Name(name); + } + + public static Config toAdConfig(final PortConfig pc) { + Config config = null; + if (pc.isPORTDOWN()) { + config = new Config(Config.ADMIN_DOWN); + } else { + config = new Config(Config.ADMIN_UP); + } + return config; + } + + public static org.opendaylight.controller.sal.core.State toAdState(final State s) { + + org.opendaylight.controller.sal.core.State state = null; + if (s.isLinkDown()) { + state = new org.opendaylight.controller.sal.core.State(org.opendaylight.controller.sal.core.State.EDGE_DOWN); + } else { + state = new org.opendaylight.controller.sal.core.State(org.opendaylight.controller.sal.core.State.EDGE_UP); } - if (fcncu.getConfiguration() != null && toAdConfig(fcncu.getConfiguration()) != null) { - props.add(toAdConfig(fcncu.getConfiguration())); + return state; + } + + public static Bandwidth toAdBandwidth(final PortFeatures pf) { + Bandwidth bw = null; + if (pf.isTenMbHd() || pf.isTenMbFd()) { + bw = new Bandwidth(Bandwidth.BW10Mbps); + } else if (pf.isHundredMbHd() || pf.isHundredMbFd()) { + bw = new Bandwidth(Bandwidth.BW100Mbps); + } else if (pf.isOneGbHd() || pf.isOneGbFd()) { + bw = new Bandwidth(Bandwidth.BW1Gbps); + } else if (pf.isOneGbFd()) { + bw = new Bandwidth(Bandwidth.BW10Gbps); + } else if (pf.isTenGbFd()) { + bw = new Bandwidth(Bandwidth.BW10Gbps); + } else if (pf.isFortyGbFd()) { + bw = new Bandwidth(Bandwidth.BW40Gbps); + } else if (pf.isHundredGbFd()) { + bw = new Bandwidth(Bandwidth.BW100Gbps); + } else if (pf.isOneTbFd()) { + bw = new Bandwidth(Bandwidth.BW1Tbps); } - if (fcncu.getState() != null && toAdState(fcncu.getState()) != null) { - props.add(toAdState(fcncu.getState())); + return bw; + } + + public static AdvertisedBandwidth toAdAdvertizedBandwidth(final PortFeatures pf) { + AdvertisedBandwidth abw = null; + final Bandwidth bw = toAdBandwidth(pf); + if (bw != null) { + abw = new AdvertisedBandwidth(bw.getValue()); } + return abw; } - return props; - } - - public static Name toAdName(final String name) { - return new Name(name); - } - - public static Config toAdConfig(final PortConfig pc) { - Config config = null; - if (pc.isPORTDOWN()) { - config = new Config(Config.ADMIN_DOWN); - } else { - config = new Config(Config.ADMIN_UP); - } - return config; - } - - public static org.opendaylight.controller.sal.core.State toAdState(final State s) { - - org.opendaylight.controller.sal.core.State state = null; - if (s.isLinkDown()) { - state = new org.opendaylight.controller.sal.core.State(org.opendaylight.controller.sal.core.State.EDGE_DOWN); - } else { - state = new org.opendaylight.controller.sal.core.State(org.opendaylight.controller.sal.core.State.EDGE_UP); - } - return state; - } - - public static Bandwidth toAdBandwidth(final PortFeatures pf) { - Bandwidth bw = null; - if (pf.isTenMbHd() || pf.isTenMbFd()) { - bw = new Bandwidth(Bandwidth.BW10Mbps); - } else if (pf.isHundredMbHd() || pf.isHundredMbFd()) { - bw = new Bandwidth(Bandwidth.BW100Mbps); - } else if (pf.isOneGbHd() || pf.isOneGbFd()) { - bw = new Bandwidth(Bandwidth.BW1Gbps); - } else if (pf.isOneGbFd()) { - bw = new Bandwidth(Bandwidth.BW10Gbps); - } else if (pf.isTenGbFd()) { - bw = new Bandwidth(Bandwidth.BW10Gbps); - } else if (pf.isFortyGbFd()) { - bw = new Bandwidth(Bandwidth.BW40Gbps); - } else if (pf.isHundredGbFd()) { - bw = new Bandwidth(Bandwidth.BW100Gbps); - } else if (pf.isOneTbFd()) { - bw = new Bandwidth(Bandwidth.BW1Tbps); - } - return bw; - } - - public static AdvertisedBandwidth toAdAdvertizedBandwidth(final PortFeatures pf) { - AdvertisedBandwidth abw = null; - final Bandwidth bw = toAdBandwidth(pf); - if (bw != null) { - abw = new AdvertisedBandwidth(bw.getValue()); - } - return abw; - } - - public static SupportedBandwidth toAdSupportedBandwidth(final PortFeatures pf) { - SupportedBandwidth sbw = null; - final Bandwidth bw = toAdBandwidth(pf); - if (bw != null) { - sbw = new SupportedBandwidth(bw.getValue()); - } - return sbw; - } - - public static PeerBandwidth toAdPeerBandwidth(final PortFeatures pf) { - PeerBandwidth pbw = null; - final Bandwidth bw = toAdBandwidth(pf); - if (bw != null) { - pbw = new PeerBandwidth(bw.getValue()); - } - return pbw; - } - - public static HashSet toADNodeProperties(final NodeUpdated nu) { - final FlowCapableNodeUpdated fcnu = nu.getAugmentation(FlowCapableNodeUpdated.class); - if (fcnu != null) { - return toADNodeProperties(fcnu, nu.getId()); - } - return new HashSet(); - } - - public static HashSet toADNodeProperties(final FlowNode fcnu, final NodeId id) { - - final HashSet props = new HashSet<>(); - - if (fcnu != null) { - props.add(toADTimestamp()); - - // props.add(fcnu.supportedActions.toADActions) - TODO - if (id != null) { - props.add(toADMacAddress(id)); + + public static SupportedBandwidth toAdSupportedBandwidth(final PortFeatures pf) { + SupportedBandwidth sbw = null; + final Bandwidth bw = toAdBandwidth(pf); + if (bw != null) { + sbw = new SupportedBandwidth(bw.getValue()); } - SwitchFeatures switchFeatures = fcnu.getSwitchFeatures(); - if (switchFeatures != null) { - if (switchFeatures.getMaxTables() != null) { - props.add(toADTables(switchFeatures.getMaxTables())); - } - if (switchFeatures.getCapabilities() != null) { - props.add(toADCapabiliities(switchFeatures.getCapabilities())); + return sbw; + } + + public static PeerBandwidth toAdPeerBandwidth(final PortFeatures pf) { + PeerBandwidth pbw = null; + final Bandwidth bw = toAdBandwidth(pf); + if (bw != null) { + pbw = new PeerBandwidth(bw.getValue()); + } + return pbw; + } + + public static HashSet toADNodeProperties(final NodeUpdated nu) { + final FlowCapableNodeUpdated fcnu = nu.getAugmentation(FlowCapableNodeUpdated.class); + if (fcnu != null) { + return toADNodeProperties(fcnu, nu.getId()); + } + return new HashSet(); + } + + public static HashSet toADNodeProperties(final FlowNode fcnu, final NodeId id) { + + final HashSet props = new HashSet<>(); + + if (fcnu != null) { + props.add(toADTimestamp()); + + // props.add(fcnu.supportedActions.toADActions) - TODO + if (id != null) { + props.add(toADMacAddress(id)); } - if (switchFeatures.getMaxBuffers() != null) { - props.add(toADBuffers(switchFeatures.getMaxBuffers())); + SwitchFeatures switchFeatures = fcnu.getSwitchFeatures(); + if (switchFeatures != null) { + if (switchFeatures.getMaxTables() != null) { + props.add(toADTables(switchFeatures.getMaxTables())); + } + if (switchFeatures.getCapabilities() != null) { + props.add(toADCapabiliities(switchFeatures.getCapabilities())); + } + if (switchFeatures.getMaxBuffers() != null) { + props.add(toADBuffers(switchFeatures.getMaxBuffers())); + } } } + return props; } - return props; - } - - public static TimeStamp toADTimestamp() { - final Date date = new Date(); - final TimeStamp timestamp = new TimeStamp(date.getTime(), "connectedSince"); - return timestamp; - } - - public static MacAddress toADMacAddress(final NodeId id) { - final String nodeId = id.getValue().replaceAll("openflow:", ""); - BigInteger nodeIdRaw = new BigInteger(nodeId); - long lNodeId = nodeIdRaw.longValue(); - byte[] bytesFromDpid = ToSalConversionsUtils.bytesFromDpid(lNodeId); - return new MacAddress(bytesFromDpid); - } - - public static Tables toADTables(final Short tables) { - return new Tables(tables.byteValue()); - } - - public static Capabilities toADCapabiliities(final List> capabilities) { - - int b = 0; - for (Class capability : capabilities) { - if (capability.equals(FlowFeatureCapabilityFlowStats.class)) { - b = Capabilities.CapabilitiesType.FLOW_STATS_CAPABILITY.getValue() | b; - } else if (capability.equals(FlowFeatureCapabilityTableStats.class)) { - b = Capabilities.CapabilitiesType.TABLE_STATS_CAPABILITY.getValue() | b; - } else if (capability.equals(FlowFeatureCapabilityPortStats.class)) { - b = Capabilities.CapabilitiesType.PORT_STATS_CAPABILITY.getValue() | b; - } else if (capability.equals(FlowFeatureCapabilityStp.class)) { - b = Capabilities.CapabilitiesType.STP_CAPABILITY.getValue() | b; - } else if (capability.equals(FlowFeatureCapabilityIpReasm.class)) { - b = Capabilities.CapabilitiesType.IP_REASSEM_CAPABILITY.getValue() | b; - } else if (capability.equals(FlowFeatureCapabilityQueueStats.class)) { - b = Capabilities.CapabilitiesType.QUEUE_STATS_CAPABILITY.getValue() | b; - } else if (capability.equals(FlowFeatureCapabilityArpMatchIp.class)) { - b = Capabilities.CapabilitiesType.ARP_MATCH_IP_CAPABILITY.getValue() | b; + + public static TimeStamp toADTimestamp() { + final Date date = new Date(); + final TimeStamp timestamp = new TimeStamp(date.getTime(), "connectedSince"); + return timestamp; + } + + public static MacAddress toADMacAddress(final NodeId id) { + final String nodeId = id.getValue().replaceAll("openflow:", ""); + BigInteger nodeIdRaw = new BigInteger(nodeId); + long lNodeId = nodeIdRaw.longValue(); + byte[] bytesFromDpid = ToSalConversionsUtils.bytesFromDpid(lNodeId); + return new MacAddress(bytesFromDpid); + } + + public static Tables toADTables(final Short tables) { + return new Tables(tables.byteValue()); + } + + public static Capabilities toADCapabiliities(final List> capabilities) { + + int b = 0; + for (Class capability : capabilities) { + if (capability.equals(FlowFeatureCapabilityFlowStats.class)) { + b = Capabilities.CapabilitiesType.FLOW_STATS_CAPABILITY.getValue() | b; + } else if (capability.equals(FlowFeatureCapabilityTableStats.class)) { + b = Capabilities.CapabilitiesType.TABLE_STATS_CAPABILITY.getValue() | b; + } else if (capability.equals(FlowFeatureCapabilityPortStats.class)) { + b = Capabilities.CapabilitiesType.PORT_STATS_CAPABILITY.getValue() | b; + } else if (capability.equals(FlowFeatureCapabilityStp.class)) { + b = Capabilities.CapabilitiesType.STP_CAPABILITY.getValue() | b; + } else if (capability.equals(FlowFeatureCapabilityIpReasm.class)) { + b = Capabilities.CapabilitiesType.IP_REASSEM_CAPABILITY.getValue() | b; + } else if (capability.equals(FlowFeatureCapabilityQueueStats.class)) { + b = Capabilities.CapabilitiesType.QUEUE_STATS_CAPABILITY.getValue() | b; + } else if (capability.equals(FlowFeatureCapabilityArpMatchIp.class)) { + b = Capabilities.CapabilitiesType.ARP_MATCH_IP_CAPABILITY.getValue() | b; + } } + return new Capabilities(b); } - return new Capabilities(b); - } - public static Buffers toADBuffers(final Long buffers) { - return new Buffers(buffers.intValue()); - } + public static Buffers toADBuffers(final Long buffers) { + return new Buffers(buffers.intValue()); + } } diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java index 74b94c7cba..da3477ee45 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/main/java/org/opendaylight/controller/sal/compatibility/ToSalConversionsUtils.java @@ -168,7 +168,7 @@ public class ToSalConversionsUtils { public static List actionFrom(List actions, Node node) { List targetAction = new ArrayList<>(); for (Action action : actions) { - org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action sourceAction = action + org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action sourceAction = action .getAction(); if (sourceAction instanceof ControllerActionCase) { @@ -585,7 +585,7 @@ public class ToSalConversionsUtils { } return macAddress; } - + public static byte[] bytesFromDpid(long dpid) { byte[] mac = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/NodeMappingTest.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/NodeMappingTest.java index b9a2f5bff0..041924af33 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/NodeMappingTest.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/NodeMappingTest.java @@ -45,7 +45,7 @@ public class NodeMappingTest { {(byte) 0x7f, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}, {(byte) 0x76, (byte) 0x4a, (byte) 0xe9, (byte) 0xac, (byte) 0xe6, (byte) 0x5a} }; - + Assert.assertEquals(expectedMacs.length, nodeIds.length); for (int i = 0; i < expectedMacs.length; i++) { diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java index 81ccb35cd9..5d5a409445 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestFromSalConversionsUtils.java @@ -249,7 +249,7 @@ public class TestFromSalConversionsUtils { boolean b) { int numOfFoundActions = 0; for (org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action action : actions) { - org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action innerAction = action + org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action innerAction = action .getAction(); if (cl.isInstance(innerAction)) { numOfFoundActions++; diff --git a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java index 71f2e94805..4d3509769c 100644 --- a/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java +++ b/opendaylight/md-sal/compatibility/sal-compatibility/src/test/java/org/opendaylight/controller/sal/compatibility/test/TestToSalConversionsUtils.java @@ -155,9 +155,9 @@ public class TestToSalConversionsUtils { public void testToSalConversion() throws ConstructionException { FlowAddedBuilder odNodeFlowBuilder = new FlowAddedBuilder(); odNodeFlowBuilder = prepareOdFlowCommon(); - + Node node = new Node(NodeIDType.OPENFLOW,(long)1); - + Flow salFlow = ToSalConversionsUtils.toFlow(prepareOdFlow(odNodeFlowBuilder, MtchType.other), node); checkSalMatch(salFlow.getMatch(), MtchType.other); @@ -185,7 +185,7 @@ public class TestToSalConversionsUtils { private void checkSalMatch(org.opendaylight.controller.sal.match.Match match, MtchType mt) { switch (mt) { case other: - /*assertNotNull("DL_DST isn't equal.", "3C:A9:F4:00:E0:C8", + /*assertNotNull("DL_DST isn't equal.", "3C:A9:F4:00:E0:C8", new String((byte[]) match.getField(MatchType.DL_DST).getValue())); assertEquals("DL_SRC isn't equal.", "24:77:03:7C:C5:F1", new String((byte[]) match.getField(MatchType.DL_SRC).getValue())); @@ -312,7 +312,7 @@ public class TestToSalConversionsUtils { //assertEquals("Wrong value for action SetDlSrc for MAC address.", "24:77:03:7C:C5:F1", new String( // ((SetDlSrc) action).getDlAddress())); } else if (action instanceof SetDlType) { - assertEquals("Wrong value for action SetDlType for.", 513l, ((SetDlType) action).getDlType()); + assertEquals("Wrong value for action SetDlType for.", 513L, ((SetDlType) action).getDlType()); } else if (action instanceof SetNextHop) { InetAddress inetAddress = ((SetNextHop) action).getAddress(); checkIpAddresses(inetAddress, "192.168.100.100", "2001:db8:85a3::8a2e:370:7334"); @@ -431,14 +431,14 @@ public class TestToSalConversionsUtils { odActions.add(new ActionBuilder().setAction(setVlanPcpActionBuilder.build()).build()); odActions.add(new ActionBuilder().setAction(swPathActionBuilder.build()).build()); - + ApplyActionsCase innerInst = new ApplyActionsCaseBuilder().setApplyActions(new ApplyActionsBuilder().setAction(odActions).build()).build(); Instruction applyActions = new InstructionBuilder().setInstruction(innerInst).build(); List instructions = Collections.singletonList(applyActions ); InstructionsBuilder instBuilder = new InstructionsBuilder(); - + instBuilder.setInstruction(instructions); - + return instBuilder.build(); } @@ -492,7 +492,7 @@ public class TestToSalConversionsUtils { private void prepareActionSetNwDst(List odActions) { // test case for IPv4 - + SetNwDstActionBuilder setNwDstActionBuilderIpv4 = new SetNwDstActionBuilder(); setNwDstActionBuilderIpv4.setAddress(prapareIpv4Address("192.168.100.101")); odActions.add(new ActionBuilder().setAction(new SetNwDstActionCaseBuilder().setSetNwDstAction(setNwDstActionBuilderIpv4.build()).build()).build()); @@ -529,7 +529,7 @@ public class TestToSalConversionsUtils { private void prepareActionSetDlType(SetDlTypeActionCaseBuilder wrapper) { SetDlTypeActionBuilder setDlTypeActionBuilder = new SetDlTypeActionBuilder(); - setDlTypeActionBuilder.setDlType(new EtherType(513l)); + setDlTypeActionBuilder.setDlType(new EtherType(513L)); wrapper.setSetDlTypeAction(setDlTypeActionBuilder.build()); } @@ -674,7 +674,7 @@ public class TestToSalConversionsUtils { private EthernetType prepEthType() { EthernetTypeBuilder ethTypeBuild = new EthernetTypeBuilder(); - ethTypeBuild.setType(new EtherType(0xffffl)); + ethTypeBuild.setType(new EtherType(0xffffL)); return ethTypeBuild.build(); } diff --git a/opendaylight/md-sal/feature/src/main/resources/features.xml b/opendaylight/md-sal/feature/src/main/resources/features.xml index f816018519..16b4574037 100644 --- a/opendaylight/md-sal/feature/src/main/resources/features.xml +++ b/opendaylight/md-sal/feature/src/main/resources/features.xml @@ -3,7 +3,7 @@ - + odl-mdsal-commons odl-mdsal-broker odl-mdsal-restconf @@ -46,4 +46,4 @@ wrap:mvn:io.netty/netty-handler/${netty.version} wrap:mvn:io.netty/netty-transport/${netty.version} - \ No newline at end of file + diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java index 426f4ba2d5..c8a7f01e13 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2014 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 @@ -19,7 +19,7 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** - * + * * @author Vaclav Demcak * */ @@ -32,17 +32,17 @@ public abstract class AbstractChangeListener implements DataChangeListener { public void onDataChanged(DataChangeEvent, DataObject> changeEvent) { this.transactionId = this.newTransactionIdentifier().toString(); - final Set, DataObject>> createdEntries = + final Set, DataObject>> createdEntries = changeEvent.getCreatedConfigurationData().entrySet(); - final Set, DataObject>> updatedEntries = + final Set, DataObject>> updatedEntries = new HashSet, DataObject>>(); - Set, DataObject>> updateConfigEntrySet = + Set, DataObject>> updateConfigEntrySet = changeEvent.getUpdatedConfigurationData().entrySet(); updatedEntries.addAll(updateConfigEntrySet); updatedEntries.removeAll(createdEntries); - final Set> removeEntriesInstanceIdentifiers = + final Set> removeEntriesInstanceIdentifiers = changeEvent.getRemovedConfigurationData(); for (final Entry, DataObject> createdEntry : createdEntries) { @@ -52,7 +52,7 @@ public abstract class AbstractChangeListener implements DataChangeListener { } for (final Entry, DataObject> updatedEntrie : updatedEntries) { - Map, DataObject> origConfigData = + Map, DataObject> origConfigData = changeEvent.getOriginalConfigurationData(); InstanceIdentifier u_key = updatedEntrie.getKey(); @@ -62,7 +62,7 @@ public abstract class AbstractChangeListener implements DataChangeListener { } for (final InstanceIdentifier instanceId : removeEntriesInstanceIdentifiers) { - Map, DataObject> origConfigData = + Map, DataObject> origConfigData = changeEvent.getOriginalConfigurationData(); final DataObject removeValue = origConfigData.get(instanceId); diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java index 929c489eaf..2f986ea5bc 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2014 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 @@ -24,10 +24,10 @@ public class FRMActivator extends AbstractBindingAwareProvider { private final static Logger LOG = LoggerFactory.getLogger(FRMActivator.class); - private static FlowProvider flowProvider = new FlowProvider(); + private static FlowProvider flowProvider = new FlowProvider(); private static GroupProvider groupProvider = new GroupProvider(); private static MeterProvider meterProvider = new MeterProvider(); - + @Override public void onSessionInitiated(final ProviderContext session) { DataProviderService flowSalService = session.getSALService(DataProviderService.class); @@ -46,7 +46,7 @@ public class FRMActivator extends AbstractBindingAwareProvider { FRMActivator.meterProvider.setSalMeterService(rpcMeterSalService); FRMActivator.meterProvider.start(); } - + @Override protected void stopImpl(final BundleContext context) { try { diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java index df086c7acc..b60424513f 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2014 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 @@ -32,7 +32,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * + * * @author Vaclav Demcak * */ @@ -45,7 +45,7 @@ public class FlowChangeListener extends AbstractChangeListener { public SalFlowService getSalFlowService() { return this.salFlowService; } - + public FlowChangeListener(final SalFlowService manager) { this.salFlowService = manager; } @@ -58,16 +58,16 @@ public class FlowChangeListener extends AbstractChangeListener { @Override protected void remove(InstanceIdentifier identifier, DataObject removeDataObj) { if ((removeDataObj instanceof Flow)) { - + final Flow flow = ((Flow) removeDataObj); final InstanceIdentifier
tableInstanceId = identifier.
firstIdentifierOf(Table.class); final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow); - + builder.setFlowRef(new FlowRef(identifier)); builder.setNode(new NodeRef(nodeInstanceId)); builder.setFlowTable(new FlowTableRef(tableInstanceId)); - + Uri uri = new Uri(this.getTransactionId()); builder.setTransactionUri(uri); this.salFlowService.removeFlow((RemoveFlowInput) builder.build()); @@ -78,21 +78,21 @@ public class FlowChangeListener extends AbstractChangeListener { @Override protected void update(InstanceIdentifier identifier, DataObject original, DataObject update) { if (original instanceof Flow && update instanceof Flow) { - + final Flow originalFlow = ((Flow) original); final Flow updatedFlow = ((Flow) update); final InstanceIdentifier nodeInstanceId = identifier.firstIdentifierOf(Node.class); final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder(); - + builder.setNode(new NodeRef(nodeInstanceId)); builder.setFlowRef(new FlowRef(identifier)); - + Uri uri = new Uri(this.getTransactionId()); builder.setTransactionUri(uri); - + builder.setUpdatedFlow((UpdatedFlow) (new UpdatedFlowBuilder(updatedFlow)).build()); builder.setOriginalFlow((OriginalFlow) (new OriginalFlowBuilder(originalFlow)).build()); - + this.salFlowService.updateFlow((UpdateFlowInput) builder.build()); LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update}); } @@ -101,16 +101,16 @@ public class FlowChangeListener extends AbstractChangeListener { @Override protected void add(InstanceIdentifier identifier, DataObject addDataObj) { if ((addDataObj instanceof Flow)) { - + final Flow flow = ((Flow) addDataObj); final InstanceIdentifier
tableInstanceId = identifier.
firstIdentifierOf(Table.class); final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow); - + builder.setNode(new NodeRef(nodeInstanceId)); builder.setFlowRef(new FlowRef(identifier)); builder.setFlowTable(new FlowTableRef(tableInstanceId)); - + Uri uri = new Uri(this.getTransactionId()); builder.setTransactionUri(uri); this.salFlowService.addFlow((AddFlowInput) builder.build()); diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java index afdd628bbb..33db529598 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2014 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 @@ -42,7 +42,7 @@ public class FlowProvider implements AutoCloseable { InstanceIdentifierBuilder
tableChild = augmentFlowCapNode.
child(Table.class); InstanceIdentifierBuilder flowChild = tableChild. child(Flow.class); final InstanceIdentifier flowDataObjectPath = flowChild.toInstance(); - + /* DataChangeListener registration */ this.flowDataChangeListener = new FlowChangeListener(this.salFlowService); this.flowDataChangeListenerRegistration = this.dataService.registerDataChangeListener(flowDataObjectPath, flowDataChangeListener); diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java index 4ef93a55e9..9cd42466a6 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2014 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 diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java index 1260f0ec53..54f12bfdcf 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2014 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 @@ -30,7 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * + * * @author Vaclav Demcak * */ @@ -43,7 +43,7 @@ public class GroupChangeListener extends AbstractChangeListener { public SalGroupService getSalGroupService() { return this.salGroupService; } - + public GroupChangeListener(final SalGroupService manager) { this.salGroupService = manager; } @@ -56,14 +56,14 @@ public class GroupChangeListener extends AbstractChangeListener { @Override protected void remove(InstanceIdentifier identifier, DataObject removeDataObj) { if ((removeDataObj instanceof Group)) { - + final Group group = ((Group) removeDataObj); final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group); - + builder.setNode(new NodeRef(nodeInstanceId)); builder.setGroupRef(new GroupRef(identifier)); - + Uri uri = new Uri(this.getTransactionId()); builder.setTransactionUri(uri); this.salGroupService.removeGroup((RemoveGroupInput) builder.build()); @@ -74,21 +74,21 @@ public class GroupChangeListener extends AbstractChangeListener { @Override protected void update(InstanceIdentifier identifier, DataObject original, DataObject update) { if (original instanceof Group && update instanceof Group) { - + final Group originalGroup = ((Group) original); final Group updatedGroup = ((Group) update); final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder(); - + builder.setNode(new NodeRef(nodeInstanceId)); builder.setGroupRef(new GroupRef(identifier)); - + Uri uri = new Uri(this.getTransactionId()); builder.setTransactionUri(uri); - + builder.setUpdatedGroup((UpdatedGroup) (new UpdatedGroupBuilder(updatedGroup)).build()); builder.setOriginalGroup((OriginalGroup) (new OriginalGroupBuilder(originalGroup)).build()); - + this.salGroupService.updateGroup((UpdateGroupInput) builder.build()); LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update}); } @@ -100,10 +100,10 @@ public class GroupChangeListener extends AbstractChangeListener { final Group group = ((Group) addDataObj); final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); final AddGroupInputBuilder builder = new AddGroupInputBuilder(group); - + builder.setNode(new NodeRef(nodeInstanceId)); builder.setGroupRef(new GroupRef(identifier)); - + Uri uri = new Uri(this.getTransactionId()); builder.setTransactionUri(uri); this.salGroupService.addGroup((AddGroupInput) builder.build()); diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java index 14b1b6f2fd..9f2806e929 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2014 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 @@ -46,11 +46,11 @@ public class GroupProvider implements AutoCloseable { this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener(groupDataObjectPath, groupDataChangeListener); LOG.info("Group Config Provider started."); } - + protected DataModificationTransaction startChange() { return this.dataService.beginTransaction(); } - + public void close() throws Exception { if(groupDataChangeListenerRegistration != null){ groupDataChangeListenerRegistration.close(); diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java index 839e556fbc..48d5257978 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2014 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 @@ -30,7 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * + * * @author Vaclav Demcak * */ @@ -43,7 +43,7 @@ public class MeterChangeListener extends AbstractChangeListener { public SalMeterService getSalMeterService() { return this.salMeterService; } - + public MeterChangeListener(final SalMeterService manager) { this.salMeterService = manager; } @@ -56,14 +56,14 @@ public class MeterChangeListener extends AbstractChangeListener { @Override protected void remove(InstanceIdentifier identifier, DataObject removeDataObj) { if ((removeDataObj instanceof Meter)) { - + final Meter meter = ((Meter) removeDataObj); final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter); - + builder.setNode(new NodeRef(nodeInstanceId)); builder.setMeterRef(new MeterRef(identifier)); - + Uri uri = new Uri(this.getTransactionId()); builder.setTransactionUri(uri); this.salMeterService.removeMeter((RemoveMeterInput) builder.build()); @@ -74,21 +74,21 @@ public class MeterChangeListener extends AbstractChangeListener { @Override protected void update(InstanceIdentifier identifier, DataObject original, DataObject update) { if (original instanceof Meter && update instanceof Meter) { - + final Meter originalMeter = ((Meter) original); final Meter updatedMeter = ((Meter) update); final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder(); - + builder.setNode(new NodeRef(nodeInstanceId)); builder.setMeterRef(new MeterRef(identifier)); - + Uri uri = new Uri(this.getTransactionId()); builder.setTransactionUri(uri); - + builder.setUpdatedMeter((UpdatedMeter) (new UpdatedMeterBuilder(updatedMeter)).build()); builder.setOriginalMeter((OriginalMeter) (new OriginalMeterBuilder(originalMeter)).build()); - + this.salMeterService.updateMeter((UpdateMeterInput) builder.build()); LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update}); } @@ -97,14 +97,14 @@ public class MeterChangeListener extends AbstractChangeListener { @Override protected void add(InstanceIdentifier identifier, DataObject addDataObj) { if ((addDataObj instanceof Meter)) { - + final Meter meter = ((Meter) addDataObj); final InstanceIdentifier nodeInstanceId = identifier. firstIdentifierOf(Node.class); final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter); - + builder.setNode(new NodeRef(nodeInstanceId)); builder.setMeterRef(new MeterRef(identifier)); - + Uri uri = new Uri(this.getTransactionId()); builder.setTransactionUri(uri); this.salMeterService.addMeter((AddMeterInput) builder.build()); diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java index 620801fba5..8596c3fec6 100644 --- a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java +++ b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java @@ -1,6 +1,6 @@ /** * Copyright (c) 2014 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 @@ -46,7 +46,7 @@ public class MeterProvider implements AutoCloseable { this.meterDataChangeListenerRegistration = this.dataService.registerDataChangeListener(meterDataObjectPath, meterDataChangeListener); LOG.info("Meter Config Provider started."); } - + protected DataModificationTransaction startChange() { return this.dataService.beginTransaction(); } diff --git a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java index 2a3d8fd37e..674ae398d3 100644 --- a/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java +++ b/opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java @@ -126,7 +126,7 @@ public class NodeChangeCommiter implements OpendaylightInventoryListener { Future> commitResult = it.commit(); listenOnTransactionState(it.getIdentifier(), commitResult, "node update", ref.getValue()); } - + /** * @param txId transaction identificator * @param future transaction result @@ -136,13 +136,13 @@ public class NodeChangeCommiter implements OpendaylightInventoryListener { private static void listenOnTransactionState(final Object txId, Future> future, final String action, final InstanceIdentifier nodeConnectorPath) { Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future),new FutureCallback>() { - + @Override public void onFailure(Throwable t) { LOG.error("Action {} [{}] failed for Tx:{}", action, nodeConnectorPath, txId, t); - + } - + @Override public void onSuccess(RpcResult result) { if(!result.isSuccessful()) { diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 94bd0731aa..9222734360 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -143,12 +143,32 @@ + org.apache.maven.plugins maven-checkstyle-plugin - ${checkstyle.version} + 2.12 + + false + false + checkstyle-logging.xml + true + true + ${project.basedir} + **\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat,**\/*.yang + **\/target\/,**\/bin\/,**\/target-ide\/,**\/${jmxGeneratorPath}\/,**\/${salGeneratorPath}\/ + + + + org.opendaylight.yangtools + checkstyle-logging + ${yangtools.version} + + - none + + check + diff --git a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java index d6b42faccf..e242b0a393 100644 --- a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java +++ b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImpl.java @@ -8,430 +8,457 @@ package org.opendaylight.controller.sal.connector.remoterpc.impl; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; + +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.NotSupportedException; +import javax.transaction.RollbackException; + import org.apache.felix.dm.Component; -import org.opendaylight.controller.clustering.services.*; +import org.opendaylight.controller.clustering.services.CacheConfigException; +import org.opendaylight.controller.clustering.services.CacheExistException; +import org.opendaylight.controller.clustering.services.CacheListenerAddException; +import org.opendaylight.controller.clustering.services.ICacheUpdateAware; +import org.opendaylight.controller.clustering.services.IClusterGlobalServices; +import org.opendaylight.controller.clustering.services.IClusterServices; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException; import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.transaction.HeuristicMixedException; -import javax.transaction.HeuristicRollbackException; -import javax.transaction.NotSupportedException; -import javax.transaction.RollbackException; -import java.util.*; -import java.util.concurrent.ConcurrentMap; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; public class RoutingTableImpl implements RoutingTable, ICacheUpdateAware { - private Logger log = LoggerFactory.getLogger(RoutingTableImpl.class); + private final Logger log = LoggerFactory.getLogger(RoutingTableImpl.class); - private IClusterGlobalServices clusterGlobalServices = null; + private IClusterGlobalServices clusterGlobalServices = null; - private ConcurrentMap globalRpcCache = null; - private ConcurrentMap> rpcCache = null; //need routes to ordered by insert-order + private ConcurrentMap globalRpcCache = null; + private ConcurrentMap> rpcCache = null; //need routes to ordered by insert-order - public static final String GLOBALRPC_CACHE = "remoterpc_routingtable.globalrpc_cache"; - public static final String RPC_CACHE = "remoterpc_routingtable.rpc_cache"; + public static final String GLOBALRPC_CACHE = "remoterpc_routingtable.globalrpc_cache"; + public static final String RPC_CACHE = "remoterpc_routingtable.rpc_cache"; - public RoutingTableImpl() { - } - - @Override - public R getGlobalRoute(I routeId) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeId, "getGlobalRoute: routeId cannot be null!"); - return globalRpcCache.get(routeId); - } - - @Override - public void addGlobalRoute(I routeId, R route) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!"); - Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!"); - try { - - log.debug("addGlobalRoute: adding a new route with id[{}] and value [{}]", routeId, route); - clusterGlobalServices.tbegin(); - if (globalRpcCache.putIfAbsent(routeId, route) != null) { - throw new DuplicateRouteException(" There is already existing route " + routeId); - } - clusterGlobalServices.tcommit(); - - } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { - throw new RoutingTableException("Transaction error - while trying to create route id=" - + routeId + "with route" + route, e); - } catch (javax.transaction.SystemException e) { - throw new SystemException("System error occurred - while trying to create with value", e); + public RoutingTableImpl() { } - } + @Override + public R getGlobalRoute(final I routeId) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "getGlobalRoute: routeId cannot be null!"); + return globalRpcCache.get(routeId); + } - @Override - public void removeGlobalRoute(I routeId) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!"); - try { - log.debug("removeGlobalRoute: removing a new route with id [{}]", routeId); + @Override + public void addGlobalRoute(final I routeId, final R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!"); + Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!"); + try { + + log.debug("addGlobalRoute: adding a new route with id[{}] and value [{}]", routeId, route); + clusterGlobalServices.tbegin(); + if (globalRpcCache.putIfAbsent(routeId, route) != null) { + throw new DuplicateRouteException(" There is already existing route " + routeId); + } + clusterGlobalServices.tcommit(); + + } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to create route id=" + + routeId + "with route" + route, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to create with value", e); + } - clusterGlobalServices.tbegin(); - globalRpcCache.remove(routeId); - clusterGlobalServices.tcommit(); + } - } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { - throw new RoutingTableException("Transaction error - while trying to remove route id=" - + routeId, e); - } catch (javax.transaction.SystemException e) { - throw new SystemException("System error occurred - while trying to remove with value", e); + @Override + public void removeGlobalRoute(final I routeId) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!"); + try { + log.debug("removeGlobalRoute: removing a new route with id [{}]", routeId); + + clusterGlobalServices.tbegin(); + globalRpcCache.remove(routeId); + clusterGlobalServices.tcommit(); + + } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to remove with value", e); + } } - } - @Override - public Set getRoutes(I routeId) { - Preconditions.checkNotNull(routeId, "getRoutes: routeId cannot be null!"); - Set routes = rpcCache.get(routeId); + @Override + public Set getRoutes(final I routeId) { + Preconditions.checkNotNull(routeId, "getRoutes: routeId cannot be null!"); + Set routes = rpcCache.get(routeId); - if (routes == null) return Collections.emptySet(); + if (routes == null) { + return Collections.emptySet(); + } - return ImmutableSet.copyOf(routes); - } + return ImmutableSet.copyOf(routes); + } - public R getLastAddedRoute(I routeId) { + @Override + public R getLastAddedRoute(final I routeId) { - Set routes = getRoutes(routeId); + Set routes = getRoutes(routeId); - if (routes.isEmpty()) return null; + if (routes.isEmpty()) { + return null; + } - R route = null; - Iterator iter = routes.iterator(); - while (iter.hasNext()) - route = iter.next(); + R route = null; + Iterator iter = routes.iterator(); + while (iter.hasNext()) { + route = iter.next(); + } - return route; - } + return route; + } - @Override - public void addRoute(I routeId, R route) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeId, "addRoute: routeId cannot be null"); - Preconditions.checkNotNull(route, "addRoute: route cannot be null"); + @Override + public void addRoute(final I routeId, final R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "addRoute: routeId cannot be null"); + Preconditions.checkNotNull(route, "addRoute: route cannot be null"); + + try{ + clusterGlobalServices.tbegin(); + log.debug("addRoute: adding a route with k/v [{}/{}]", routeId, route); + threadSafeAdd(routeId, route); + clusterGlobalServices.tcommit(); + + } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to remove with value", e); + } + } - try{ - clusterGlobalServices.tbegin(); - log.debug("addRoute: adding a route with k/v [{}/{}]", routeId, route); - threadSafeAdd(routeId, route); - clusterGlobalServices.tcommit(); + @Override + public void addRoutes(final Set routeIds, final R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeIds, "addRoutes: routeIds must not be null"); + for (I routeId : routeIds){ + addRoute(routeId, route); + } + } - } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { - throw new RoutingTableException("Transaction error - while trying to remove route id=" - + routeId, e); - } catch (javax.transaction.SystemException e) { - throw new SystemException("System error occurred - while trying to remove with value", e); + @Override + public void removeRoute(final I routeId, final R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeId, "removeRoute: routeId cannot be null!"); + Preconditions.checkNotNull(route, "removeRoute: route cannot be null!"); + + LinkedHashSet routes = rpcCache.get(routeId); + if (routes == null) { + return; + } + + try { + log.debug("removeRoute: removing a new route with k/v [{}/{}]", routeId, route); + + clusterGlobalServices.tbegin(); + threadSafeRemove(routeId, route); + clusterGlobalServices.tcommit(); + + } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { + throw new RoutingTableException("Transaction error - while trying to remove route id=" + + routeId, e); + } catch (javax.transaction.SystemException e) { + throw new SystemException("System error occurred - while trying to remove with value", e); + } } - } - @Override - public void addRoutes(Set routeIds, R route) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeIds, "addRoutes: routeIds must not be null"); - for (I routeId : routeIds){ - addRoute(routeId, route); + @Override + public void removeRoutes(final Set routeIds, final R route) throws RoutingTableException, SystemException { + Preconditions.checkNotNull(routeIds, "removeRoutes: routeIds must not be null"); + for (I routeId : routeIds){ + removeRoute(routeId, route); + } } - } - @Override - public void removeRoute(I routeId, R route) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeId, "removeRoute: routeId cannot be null!"); - Preconditions.checkNotNull(route, "removeRoute: route cannot be null!"); + /** + * This method guarantees that no 2 thread over write each other's changes. + * Just so that we dont end up in infinite loop, it tries for 100 times then throw + */ + private void threadSafeAdd(final I routeId, final R route) { + + for (int i=0;i<100;i++){ + + LinkedHashSet updatedRoutes = new LinkedHashSet<>(); + updatedRoutes.add(route); + LinkedHashSet oldRoutes = rpcCache.putIfAbsent(routeId, updatedRoutes); + if (oldRoutes == null) { + return; + } + + updatedRoutes = new LinkedHashSet<>(oldRoutes); + updatedRoutes.add(route); + + if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) { + return; + } + } + //the method did not already return means it failed to add route in 10 attempts + throw new IllegalStateException("Failed to add route [" + routeId + "]"); + } - LinkedHashSet routes = rpcCache.get(routeId); - if (routes == null) return; + /** + * This method guarantees that no 2 thread over write each other's changes. + * Just so that we dont end up in infinite loop, it tries for 10 times then throw + */ + private void threadSafeRemove(final I routeId, final R route) { + LinkedHashSet updatedRoutes = null; + for (int i=0;i<10;i++){ + LinkedHashSet oldRoutes = rpcCache.get(routeId); + + // if route to be deleted is the only entry in the set then remove routeId from the cache + if ((oldRoutes.size() == 1) && oldRoutes.contains(route)){ + rpcCache.remove(routeId); + return; + } + + // if there are multiple routes for this routeId, remove the route to be deleted only from the set. + updatedRoutes = new LinkedHashSet<>(oldRoutes); + updatedRoutes.remove(route); + if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) { + return; + } + + } + //the method did not already return means it failed to remove route in 10 attempts + throw new IllegalStateException("Failed to remove route [" + routeId + "]"); + } - try { - log.debug("removeRoute: removing a new route with k/v [{}/{}]", routeId, route); - clusterGlobalServices.tbegin(); - threadSafeRemove(routeId, route); - clusterGlobalServices.tcommit(); + // /** + // * @deprecated doesn't do anything will be removed once listeners used + // * whiteboard pattern Registers listener for sending any change + // * notification + // * @param listener + // */ + // @Override + // public void registerRouteChangeListener(RouteChangeListener listener) { + // + // } + + // public void setRouteChangeListener(RouteChangeListener rcl) { + // if(rcl != null){ + // routeChangeListeners.add(rcl); + // }else{ + // log.warn("setRouteChangeListener called with null listener"); + // } + // } + // + // public void unSetRouteChangeListener(RouteChangeListener rcl) { + // if(rcl != null){ + // routeChangeListeners.remove(rcl); + // }else{ + // log.warn("unSetRouteChangeListener called with null listener"); + // } + // } + + /** + * Returning the set of route change listeners for Unit testing Note: the + * package scope is default + * + * @return List of registered RouteChangeListener listeners + */ + // Set getRegisteredRouteChangeListeners() { + // return routeChangeListeners; + // } + public void setClusterGlobalServices(final IClusterGlobalServices clusterGlobalServices) { + this.clusterGlobalServices = clusterGlobalServices; + } - } catch (NotSupportedException | HeuristicRollbackException | RollbackException | HeuristicMixedException e) { - throw new RoutingTableException("Transaction error - while trying to remove route id=" - + routeId, e); - } catch (javax.transaction.SystemException e) { - throw new SystemException("System error occurred - while trying to remove with value", e); + public void unsetClusterGlobalServices(final IClusterGlobalServices clusterGlobalServices) { + if ((clusterGlobalServices != null) && (this.clusterGlobalServices.equals(clusterGlobalServices))) { + this.clusterGlobalServices = null; + } } - } - @Override - public void removeRoutes(Set routeIds, R route) throws RoutingTableException, SystemException { - Preconditions.checkNotNull(routeIds, "removeRoutes: routeIds must not be null"); - for (I routeId : routeIds){ - removeRoute(routeId, route); + /** + * Finds OR Creates clustered cache for Global RPCs + * + * @throws CacheExistException -- cluster global services exception when cache exist + * @throws CacheConfigException -- cluster global services exception during cache config + * @throws CacheListenerAddException -- cluster global services exception during adding of listener + */ + + @SuppressWarnings("unchecked") + void findOrCreateGlobalRpcCache() throws CacheExistException, CacheConfigException, + CacheListenerAddException { + // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it + // should be caching? + + // let us check here if the cache already exists -- if so don't create + if (!clusterGlobalServices.existCache(GLOBALRPC_CACHE)) { + + globalRpcCache = (ConcurrentMap) clusterGlobalServices.createCache(GLOBALRPC_CACHE, + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); + log.debug("Cache created [{}] ", GLOBALRPC_CACHE); + + } else { + globalRpcCache = (ConcurrentMap) clusterGlobalServices.getCache(GLOBALRPC_CACHE); + log.debug("Cache exists [{}] ", GLOBALRPC_CACHE); + } } - } - /** - * This method guarantees that no 2 thread over write each other's changes. - * Just so that we dont end up in infinite loop, it tries for 100 times then throw - */ - private void threadSafeAdd(I routeId, R route) { + /** + * Finds OR Creates clustered cache for Routed RPCs + * + * @throws CacheExistException -- cluster global services exception when cache exist + * @throws CacheConfigException -- cluster global services exception during cache config + * @throws CacheListenerAddException -- cluster global services exception during adding of listener + */ + + @SuppressWarnings("unchecked") + void findOrCreateRpcCache() throws CacheExistException, CacheConfigException, + CacheListenerAddException { + // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it + // should be caching? + + if (clusterGlobalServices.existCache(RPC_CACHE)){ + rpcCache = (ConcurrentMap>) clusterGlobalServices.getCache(RPC_CACHE); + log.debug("Cache exists [{}] ", RPC_CACHE); + return; + } + + //cache doesnt exist, create one + rpcCache = (ConcurrentMap>) clusterGlobalServices.createCache(RPC_CACHE, + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); + log.debug("Cache created [{}] ", RPC_CACHE); + } - for (int i=0;i<100;i++){ - LinkedHashSet updatedRoutes = new LinkedHashSet<>(); - updatedRoutes.add(route); - LinkedHashSet oldRoutes = rpcCache.putIfAbsent(routeId, updatedRoutes); - if (oldRoutes == null) return; + /** + * Function called by the dependency manager when all the required + * dependencies are satisfied + */ + void init(final Component c) { + try { - updatedRoutes = new LinkedHashSet<>(oldRoutes); - updatedRoutes.add(route); + findOrCreateGlobalRpcCache(); + findOrCreateRpcCache(); - if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) return; + } catch (CacheExistException|CacheConfigException|CacheListenerAddException e) { + throw new IllegalStateException("could not construct routing table cache"); + } } - //the method did not already return means it failed to add route in 10 attempts - throw new IllegalStateException("Failed to add route [" + routeId + "]"); - } - - /** - * This method guarantees that no 2 thread over write each other's changes. - * Just so that we dont end up in infinite loop, it tries for 10 times then throw - */ - private void threadSafeRemove(I routeId, R route) { - LinkedHashSet updatedRoutes = null; - for (int i=0;i<10;i++){ - LinkedHashSet oldRoutes = rpcCache.get(routeId); - - // if route to be deleted is the only entry in the set then remove routeId from the cache - if ((oldRoutes.size() == 1) && oldRoutes.contains(route)){ - rpcCache.remove(routeId); - return; - } - - // if there are multiple routes for this routeId, remove the route to be deleted only from the set. - updatedRoutes = new LinkedHashSet<>(oldRoutes); - updatedRoutes.remove(route); - if (rpcCache.replace(routeId, oldRoutes, updatedRoutes)) return; + /** + * Useful for unit testing It has package + * scope + */ + ConcurrentMap getGlobalRpcCache() { + return this.globalRpcCache; } - //the method did not already return means it failed to remove route in 10 attempts - throw new IllegalStateException("Failed to remove route [" + routeId + "]"); - } - - -// /** -// * @deprecated doesn't do anything will be removed once listeners used -// * whiteboard pattern Registers listener for sending any change -// * notification -// * @param listener -// */ -// @Override -// public void registerRouteChangeListener(RouteChangeListener listener) { -// -// } - -// public void setRouteChangeListener(RouteChangeListener rcl) { -// if(rcl != null){ -// routeChangeListeners.add(rcl); -// }else{ -// log.warn("setRouteChangeListener called with null listener"); -// } -// } -// -// public void unSetRouteChangeListener(RouteChangeListener rcl) { -// if(rcl != null){ -// routeChangeListeners.remove(rcl); -// }else{ -// log.warn("unSetRouteChangeListener called with null listener"); -// } -// } - - /** - * Returning the set of route change listeners for Unit testing Note: the - * package scope is default - * - * @return List of registered RouteChangeListener listeners - */ -// Set getRegisteredRouteChangeListeners() { -// return routeChangeListeners; -// } - public void setClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { - this.clusterGlobalServices = clusterGlobalServices; - } - - public void unsetClusterGlobalServices(IClusterGlobalServices clusterGlobalServices) { - if ((clusterGlobalServices != null) && (this.clusterGlobalServices.equals(clusterGlobalServices))) { - this.clusterGlobalServices = null; - } - } - - /** - * Finds OR Creates clustered cache for Global RPCs - * - * @throws CacheExistException -- cluster global services exception when cache exist - * @throws CacheConfigException -- cluster global services exception during cache config - * @throws CacheListenerAddException -- cluster global services exception during adding of listener - */ - - void findOrCreateGlobalRpcCache() throws CacheExistException, CacheConfigException, - CacheListenerAddException { - // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it - // should be caching? - - // let us check here if the cache already exists -- if so don't create - if (!clusterGlobalServices.existCache(GLOBALRPC_CACHE)) { - - globalRpcCache = (ConcurrentMap) clusterGlobalServices.createCache(GLOBALRPC_CACHE, - EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - log.debug("Cache created [{}] ", GLOBALRPC_CACHE); - - } else { - globalRpcCache = (ConcurrentMap) clusterGlobalServices.getCache(GLOBALRPC_CACHE); - log.debug("Cache exists [{}] ", GLOBALRPC_CACHE); - } - } - - /** - * Finds OR Creates clustered cache for Routed RPCs - * - * @throws CacheExistException -- cluster global services exception when cache exist - * @throws CacheConfigException -- cluster global services exception during cache config - * @throws CacheListenerAddException -- cluster global services exception during adding of listener - */ - - void findOrCreateRpcCache() throws CacheExistException, CacheConfigException, - CacheListenerAddException { - // TBD: HOW DO WE DECIDE ON PROPERTIES OF THE CACHE i.e. what duration it - // should be caching? - - if (clusterGlobalServices.existCache(RPC_CACHE)){ - rpcCache = (ConcurrentMap>) clusterGlobalServices.getCache(RPC_CACHE); - log.debug("Cache exists [{}] ", RPC_CACHE); - return; - } - - //cache doesnt exist, create one - rpcCache = (ConcurrentMap>) clusterGlobalServices.createCache(RPC_CACHE, - EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL)); - log.debug("Cache created [{}] ", RPC_CACHE); - } - - - /** - * Function called by the dependency manager when all the required - * dependencies are satisfied - */ - void init(Component c) { - try { - findOrCreateGlobalRpcCache(); - findOrCreateRpcCache(); - - } catch (CacheExistException|CacheConfigException|CacheListenerAddException e) { - throw new IllegalStateException("could not construct routing table cache"); + /** + * Useful for unit testing It has package + * scope + */ + ConcurrentMap> getRpcCache() { + return this.rpcCache; } - } - - /** - * Useful for unit testing It has package - * scope - */ - ConcurrentMap getGlobalRpcCache() { - return this.globalRpcCache; - } - - /** - * Useful for unit testing It has package - * scope - */ - ConcurrentMap getRpcCache() { - return this.rpcCache; - } - - /** - * This is used from integration test NP rest API to check out the result of the - * cache population - * For testing purpose only-- use it wisely - * - * @return - */ - public String dumpGlobalRpcCache() { - Set> cacheEntrySet = this.globalRpcCache.entrySet(); - StringBuilder sb = new StringBuilder(); - for (Map.Entry entry : cacheEntrySet) { - sb.append("Key:").append(entry.getKey()).append("---->Value:") - .append((entry.getValue() != null) ? entry.getValue() : "null") - .append("\n"); + + /** + * This is used from integration test NP rest API to check out the result of the + * cache population + * For testing purpose only-- use it wisely + * + * @return + */ + public String dumpGlobalRpcCache() { + Set> cacheEntrySet = this.globalRpcCache.entrySet(); + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : cacheEntrySet) { + sb.append("Key:").append(entry.getKey()).append("---->Value:") + .append((entry.getValue() != null) ? entry.getValue() : "null") + .append("\n"); + } + return sb.toString(); } - return sb.toString(); - } - - public String dumpRpcCache() { - Set>> cacheEntrySet = this.rpcCache.entrySet(); - StringBuilder sb = new StringBuilder(); - for (Map.Entry> entry : cacheEntrySet) { - sb.append("Key:").append(entry.getKey()).append("---->Value:") - .append((entry.getValue() != null) ? entry.getValue() : "null") - .append("\n"); + + public String dumpRpcCache() { + Set>> cacheEntrySet = this.rpcCache.entrySet(); + StringBuilder sb = new StringBuilder(); + for (Map.Entry> entry : cacheEntrySet) { + sb.append("Key:").append(entry.getKey()).append("---->Value:") + .append((entry.getValue() != null) ? entry.getValue() : "null") + .append("\n"); + } + return sb.toString(); } - return sb.toString(); - } - /** - * Invoked when a new entry is available in the cache, the key is only - * provided, the value will come as an entryUpdate invocation - * - * @param key Key for the entry just created - * @param cacheName name of the cache for which update has been received - * @param originLocal true if the event is generated from this node - */ - @Override - public void entryCreated(I key, String cacheName, boolean originLocal) { - // TBD: do we require this. - if (log.isDebugEnabled()) { - log.debug("RoutingTableUpdates: entryCreated routeId = " + key + " cacheName=" + cacheName); + /** + * Invoked when a new entry is available in the cache, the key is only + * provided, the value will come as an entryUpdate invocation + * + * @param key Key for the entry just created + * @param cacheName name of the cache for which update has been received + * @param originLocal true if the event is generated from this node + */ + @Override + public void entryCreated(final I key, final String cacheName, final boolean originLocal) { + // TBD: do we require this. + if (log.isDebugEnabled()) { + log.debug("RoutingTableUpdates: entryCreated routeId = " + key + " cacheName=" + cacheName); + } } - } - - /** - * Called anytime a given entry is updated - * - * @param key Key for the entry modified - * @param new_value the new value the key will have - * @param cacheName name of the cache for which update has been received - * @param originLocal true if the event is generated from this node - */ - @Override - public void entryUpdated(I key, R new_value, String cacheName, boolean originLocal) { - if (log.isDebugEnabled()) { - log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + ",value = " + new_value - + " ,cacheName=" + cacheName + " originLocal=" + originLocal); + + /** + * Called anytime a given entry is updated + * + * @param key Key for the entry modified + * @param new_value the new value the key will have + * @param cacheName name of the cache for which update has been received + * @param originLocal true if the event is generated from this node + */ + @Override + public void entryUpdated(final I key, final R new_value, final String cacheName, final boolean originLocal) { + if (log.isDebugEnabled()) { + log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + ",value = " + new_value + + " ,cacheName=" + cacheName + " originLocal=" + originLocal); + } + // if (!originLocal) { + // for (RouteChangeListener rcl : routeChangeListeners) { + // rcl.onRouteUpdated(key, new_value); + // } + // } } -// if (!originLocal) { -// for (RouteChangeListener rcl : routeChangeListeners) { -// rcl.onRouteUpdated(key, new_value); -// } -// } - } - - /** - * Called anytime a given key is removed from the ConcurrentHashMap we are - * listening to. - * - * @param key Key of the entry removed - * @param cacheName name of the cache for which update has been received - * @param originLocal true if the event is generated from this node - */ - @Override - public void entryDeleted(I key, String cacheName, boolean originLocal) { - if (log.isDebugEnabled()) { - log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + " local = " + originLocal - + " cacheName=" + cacheName + " originLocal=" + originLocal); + + /** + * Called anytime a given key is removed from the ConcurrentHashMap we are + * listening to. + * + * @param key Key of the entry removed + * @param cacheName name of the cache for which update has been received + * @param originLocal true if the event is generated from this node + */ + @Override + public void entryDeleted(final I key, final String cacheName, final boolean originLocal) { + if (log.isDebugEnabled()) { + log.debug("RoutingTableUpdates: entryUpdated routeId = " + key + " local = " + originLocal + + " cacheName=" + cacheName + " originLocal=" + originLocal); + } + // if (!originLocal) { + // for (RouteChangeListener rcl : routeChangeListeners) { + // rcl.onRouteDeleted(key); + // } + // } } -// if (!originLocal) { -// for (RouteChangeListener rcl : routeChangeListeners) { -// rcl.onRouteDeleted(key); -// } -// } - } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java index 0987df5956..1ff49c1543 100644 --- a/opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java +++ b/opendaylight/md-sal/remoterpc-routingtable/implementation/src/test/java/org/opendaylight/controller/sal/connector/remoterpc/impl/RoutingTableImplTest.java @@ -8,7 +8,22 @@ package org.opendaylight.controller.sal.connector.remoterpc.impl; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; + +import java.net.URI; +import java.util.EnumSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + import junit.framework.Assert; + import org.apache.felix.dm.Component; import org.junit.After; import org.junit.Before; @@ -17,314 +32,303 @@ import org.opendaylight.controller.clustering.services.IClusterGlobalServices; import org.opendaylight.controller.clustering.services.IClusterServices; import org.opendaylight.controller.sal.connector.api.RpcRouter; import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable; -import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException; -import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import java.net.URI; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.concurrent.*; - -import static org.mockito.Mockito.*; - public class RoutingTableImplTest { - private final URI namespace = URI.create("http://cisco.com/example"); - private final QName QNAME = new QName(namespace, "global"); - - private IClusterGlobalServices clusterService; - private RoutingTableImpl, String> routingTable; - ConcurrentMap mockGlobalRpcCache; - ConcurrentMap mockRpcCache; - - @Before - public void setUp() throws Exception{ - clusterService = mock(IClusterGlobalServices.class); - routingTable = new RoutingTableImpl, String>(); - mockGlobalRpcCache = new ConcurrentHashMap<>(); - mockRpcCache = new ConcurrentHashMap<>(); - createRoutingTableCache(); - } - - @After - public void tearDown(){ - reset(clusterService); - mockGlobalRpcCache = null; - mockRpcCache = null; - } + private final URI namespace = URI.create("http://cisco.com/example"); + private final QName QNAME = new QName(namespace, "global"); + + private IClusterGlobalServices clusterService; + private RoutingTableImpl, String> routingTable; + ConcurrentMap mockGlobalRpcCache; + ConcurrentMap mockRpcCache; + + @Before + public void setUp() throws Exception{ + clusterService = mock(IClusterGlobalServices.class); + routingTable = new RoutingTableImpl, String>(); + mockGlobalRpcCache = new ConcurrentHashMap<>(); + mockRpcCache = new ConcurrentHashMap<>(); + createRoutingTableCache(); + } - @Test - public void addGlobalRoute_ValidArguments_ShouldAdd() throws Exception { + @After + public void tearDown(){ + reset(clusterService); + mockGlobalRpcCache = null; + mockRpcCache = null; + } - Assert.assertNotNull(mockGlobalRpcCache); - RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); + @Test + public void addGlobalRoute_ValidArguments_ShouldAdd() throws Exception { - final String expectedRoute = "172.27.12.1:5000"; - routingTable.addGlobalRoute(routeIdentifier, expectedRoute); + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); - ConcurrentMap latestCache = routingTable.getGlobalRpcCache(); - Assert.assertEquals(mockGlobalRpcCache, latestCache); - Assert.assertEquals(expectedRoute, latestCache.get(routeIdentifier)); - } + final String expectedRoute = "172.27.12.1:5000"; + routingTable.addGlobalRoute(routeIdentifier, expectedRoute); - @Test (expected = RoutingTable.DuplicateRouteException.class) - public void addGlobalRoute_DuplicateRoute_ShouldThrow() throws Exception{ + ConcurrentMap latestCache = routingTable.getGlobalRpcCache(); + Assert.assertEquals(mockGlobalRpcCache, latestCache); + Assert.assertEquals(expectedRoute, latestCache.get(routeIdentifier)); + } - Assert.assertNotNull(mockGlobalRpcCache); + @Test (expected = RoutingTable.DuplicateRouteException.class) + public void addGlobalRoute_DuplicateRoute_ShouldThrow() throws Exception{ - RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); - routingTable.addGlobalRoute(routeIdentifier, new String()); - routingTable.addGlobalRoute(routeIdentifier, new String()); - } + Assert.assertNotNull(mockGlobalRpcCache); - @Test - public void getGlobalRoute_ExistingRouteId_ShouldReturnRoute() throws Exception { + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); + routingTable.addGlobalRoute(routeIdentifier, new String()); + routingTable.addGlobalRoute(routeIdentifier, new String()); + } - Assert.assertNotNull(mockGlobalRpcCache); - RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); - String expectedRoute = "172.27.12.1:5000"; + @Test + public void getGlobalRoute_ExistingRouteId_ShouldReturnRoute() throws Exception { - routingTable.addGlobalRoute(routeIdentifier, expectedRoute); + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); + String expectedRoute = "172.27.12.1:5000"; - String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier); - Assert.assertEquals(expectedRoute, actualRoute); - } + routingTable.addGlobalRoute(routeIdentifier, expectedRoute); - @Test - public void getGlobalRoute_NonExistentRouteId_ShouldReturnNull() throws Exception { + String actualRoute = routingTable.getGlobalRoute(routeIdentifier); + Assert.assertEquals(expectedRoute, actualRoute); + } - Assert.assertNotNull(mockGlobalRpcCache); - RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); + @Test + public void getGlobalRoute_NonExistentRouteId_ShouldReturnNull() throws Exception { - String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier); - Assert.assertNull(actualRoute); - } + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); - @Test - public void removeGlobalRoute_ExistingRouteId_ShouldRemove() throws Exception { + String actualRoute = routingTable.getGlobalRoute(routeIdentifier); + Assert.assertNull(actualRoute); + } - Assert.assertNotNull(mockGlobalRpcCache); - RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); + @Test + public void removeGlobalRoute_ExistingRouteId_ShouldRemove() throws Exception { - ConcurrentMap cache = routingTable.getGlobalRpcCache(); - Assert.assertTrue(cache.size() == 0); - routingTable.addGlobalRoute(routeIdentifier, "172.27.12.1:5000"); - Assert.assertTrue(cache.size() == 1); + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); - routingTable.removeGlobalRoute(routeIdentifier); - Assert.assertTrue(cache.size() == 0); + ConcurrentMap cache = routingTable.getGlobalRpcCache(); + Assert.assertTrue(cache.size() == 0); + routingTable.addGlobalRoute(routeIdentifier, "172.27.12.1:5000"); + Assert.assertTrue(cache.size() == 1); - } + routingTable.removeGlobalRoute(routeIdentifier); + Assert.assertTrue(cache.size() == 0); - @Test - public void removeGlobalRoute_NonExistentRouteId_ShouldDoNothing() throws Exception { + } - Assert.assertNotNull(mockGlobalRpcCache); - RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); + @Test + public void removeGlobalRoute_NonExistentRouteId_ShouldDoNothing() throws Exception { - ConcurrentMap cache = routingTable.getGlobalRpcCache(); - Assert.assertTrue(cache.size() == 0); + Assert.assertNotNull(mockGlobalRpcCache); + RpcRouter.RouteIdentifier routeIdentifier = getRouteIdentifier(); - routingTable.removeGlobalRoute(routeIdentifier); - Assert.assertTrue(cache.size() == 0); + ConcurrentMap cache = routingTable.getGlobalRpcCache(); + Assert.assertTrue(cache.size() == 0); - } + routingTable.removeGlobalRoute(routeIdentifier); + Assert.assertTrue(cache.size() == 0); - @Test - public void addRoute_ForNewRouteId_ShouldAddRoute() throws Exception { - Assert.assertTrue(mockRpcCache.size() == 0); + } - RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + @Test + public void addRoute_ForNewRouteId_ShouldAddRoute() throws Exception { + Assert.assertTrue(mockRpcCache.size() == 0); - routingTable.addRoute(routeId, new String()); - Assert.assertTrue(mockRpcCache.size() == 1); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); - Set routes = routingTable.getRoutes(routeId); - Assert.assertEquals(1, routes.size()); - } + routingTable.addRoute(routeId, new String()); + Assert.assertTrue(mockRpcCache.size() == 1); - @Test - public void addRoute_ForExistingRouteId_ShouldAppendRoute() throws Exception { + Set routes = routingTable.getRoutes(routeId); + Assert.assertEquals(1, routes.size()); + } - Assert.assertTrue(mockRpcCache.size() == 0); + @Test + public void addRoute_ForExistingRouteId_ShouldAppendRoute() throws Exception { - RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + Assert.assertTrue(mockRpcCache.size() == 0); - String route_1 = "10.0.0.1:5955"; - String route_2 = "10.0.0.2:5955"; + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); - routingTable.addRoute(routeId, route_1); - routingTable.addRoute(routeId, route_2); + String route_1 = "10.0.0.1:5955"; + String route_2 = "10.0.0.2:5955"; - Assert.assertTrue(mockRpcCache.size() == 1); + routingTable.addRoute(routeId, route_1); + routingTable.addRoute(routeId, route_2); - Set routes = routingTable.getRoutes(routeId); - Assert.assertEquals(2, routes.size()); - Assert.assertTrue(routes.contains(route_1)); - Assert.assertTrue(routes.contains(route_2)); - } + Assert.assertTrue(mockRpcCache.size() == 1); - @Test - public void addRoute_UsingMultipleThreads_ShouldNotOverwrite(){ - ExecutorService threadPool = Executors.newCachedThreadPool(); + Set routes = routingTable.getRoutes(routeId); + Assert.assertEquals(2, routes.size()); + Assert.assertTrue(routes.contains(route_1)); + Assert.assertTrue(routes.contains(route_2)); + } - int numOfRoutesToAdd = 100; - String routePrefix_1 = "10.0.0.1:555"; - RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); - threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_1, routeId)); - String routePrefix_2 = "10.0.0.1:556"; - threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_2, routeId)); + @Test + public void addRoute_UsingMultipleThreads_ShouldNotOverwrite(){ + ExecutorService threadPool = Executors.newCachedThreadPool(); + + int numOfRoutesToAdd = 100; + String routePrefix_1 = "10.0.0.1:555"; + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_1, routeId)); + String routePrefix_2 = "10.0.0.1:556"; + threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_2, routeId)); + + // wait for all tasks to complete; timeout in 10 sec + threadPool.shutdown(); + try { + threadPool.awaitTermination(10, TimeUnit.SECONDS); // + } catch (InterruptedException e) { + e.printStackTrace(); + } - // wait for all tasks to complete; timeout in 10 sec - threadPool.shutdown(); - try { - threadPool.awaitTermination(10, TimeUnit.SECONDS); // - } catch (InterruptedException e) { - e.printStackTrace(); + Assert.assertEquals(2*numOfRoutesToAdd, routingTable.getRoutes(routeId).size()); } - Assert.assertEquals(2*numOfRoutesToAdd, routingTable.getRoutes(routeId).size()); - } - - @Test(expected = NullPointerException.class) - public void addRoute_NullRouteId_shouldThrowNpe() throws Exception { + @Test(expected = NullPointerException.class) + public void addRoute_NullRouteId_shouldThrowNpe() throws Exception { - routingTable.addRoute(null, new String()); - } + routingTable.addRoute(null, new String()); + } - @Test(expected = NullPointerException.class) - public void addRoute_NullRoute_shouldThrowNpe() throws Exception{ + @Test(expected = NullPointerException.class) + public void addRoute_NullRoute_shouldThrowNpe() throws Exception{ - routingTable.addRoute(getRouteIdentifier(), null); - } + routingTable.addRoute(getRouteIdentifier(), null); + } - @Test (expected = UnsupportedOperationException.class) - public void getRoutes_Call_ShouldReturnImmutableCopy() throws Exception{ - Assert.assertNotNull(routingTable); - RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); - routingTable.addRoute(routeId, new String()); + @Test (expected = UnsupportedOperationException.class) + public void getRoutes_Call_ShouldReturnImmutableCopy() throws Exception{ + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + routingTable.addRoute(routeId, new String()); - Set routes = routingTable.getRoutes(routeId); //returns Immutable Set + Set routes = routingTable.getRoutes(routeId); //returns Immutable Set - routes.add(new String()); //can not be modified; should throw - } + routes.add(new String()); //can not be modified; should throw + } - @Test - public void getRoutes_With2RoutesFor1RouteId_ShouldReturnASetWithSize2() throws Exception{ - Assert.assertNotNull(routingTable); - RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); - routingTable.addRoute(routeId, "10.0.0.1:5555"); - routingTable.addRoute(routeId, "10.0.0.2:5555"); + @Test + public void getRoutes_With2RoutesFor1RouteId_ShouldReturnASetWithSize2() throws Exception{ + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + routingTable.addRoute(routeId, "10.0.0.1:5555"); + routingTable.addRoute(routeId, "10.0.0.2:5555"); - Set routes = routingTable.getRoutes(routeId); //returns Immutable Set + Set routes = routingTable.getRoutes(routeId); //returns Immutable Set - Assert.assertEquals(2, routes.size()); - } + Assert.assertEquals(2, routes.size()); + } - @Test - public void getLastAddedRoute_WhenMultipleRoutesExists_ShouldReturnLatestRoute() - throws Exception { + @Test + public void getLastAddedRoute_WhenMultipleRoutesExists_ShouldReturnLatestRoute() + throws Exception { - Assert.assertNotNull(routingTable); - RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); - String route_1 = "10.0.0.1:5555"; - String route_2 = "10.0.0.2:5555"; - routingTable.addRoute(routeId, route_1); - routingTable.addRoute(routeId, route_2); + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + String route_1 = "10.0.0.1:5555"; + String route_2 = "10.0.0.2:5555"; + routingTable.addRoute(routeId, route_1); + routingTable.addRoute(routeId, route_2); - Assert.assertEquals(route_2, routingTable.getLastAddedRoute(routeId)); - } + Assert.assertEquals(route_2, routingTable.getLastAddedRoute(routeId)); + } - @Test - public void removeRoute_WhenMultipleRoutesExist_RemovesGivenRoute() throws Exception{ - Assert.assertNotNull(routingTable); - RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); - String route_1 = "10.0.0.1:5555"; - String route_2 = "10.0.0.2:5555"; + @Test + public void removeRoute_WhenMultipleRoutesExist_RemovesGivenRoute() throws Exception{ + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + String route_1 = "10.0.0.1:5555"; + String route_2 = "10.0.0.2:5555"; - routingTable.addRoute(routeId, route_1); - routingTable.addRoute(routeId, route_2); + routingTable.addRoute(routeId, route_1); + routingTable.addRoute(routeId, route_2); - Assert.assertEquals(2, routingTable.getRoutes(routeId).size()); + Assert.assertEquals(2, routingTable.getRoutes(routeId).size()); - routingTable.removeRoute(routeId, route_1); - Assert.assertEquals(1, routingTable.getRoutes(routeId).size()); + routingTable.removeRoute(routeId, route_1); + Assert.assertEquals(1, routingTable.getRoutes(routeId).size()); - } + } - @Test - public void removeRoute_WhenOnlyOneRouteExists_RemovesRouteId() throws Exception{ - Assert.assertNotNull(routingTable); - RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); - String route_1 = "10.0.0.1:5555"; + @Test + public void removeRoute_WhenOnlyOneRouteExists_RemovesRouteId() throws Exception{ + Assert.assertNotNull(routingTable); + RpcRouter.RouteIdentifier routeId = getRouteIdentifier(); + String route_1 = "10.0.0.1:5555"; - routingTable.addRoute(routeId, route_1); - Assert.assertEquals(1, routingTable.getRoutes(routeId).size()); + routingTable.addRoute(routeId, route_1); + Assert.assertEquals(1, routingTable.getRoutes(routeId).size()); - routingTable.removeRoute(routeId, route_1); - ConcurrentMap cache = routingTable.getRpcCache(); - Assert.assertFalse(cache.containsKey(routeId)); + routingTable.removeRoute(routeId, route_1); + ConcurrentMap cache = routingTable.getRpcCache(); + Assert.assertFalse(cache.containsKey(routeId)); - } + } - /* - * Private helper methods - */ - private void createRoutingTableCache() throws Exception { + /* + * Private helper methods + */ + private void createRoutingTableCache() throws Exception { - //here init - Component c = mock(Component.class); + //here init + Component c = mock(Component.class); - when(clusterService.existCache( - RoutingTableImpl.GLOBALRPC_CACHE)).thenReturn(false); + when(clusterService.existCache( + RoutingTableImpl.GLOBALRPC_CACHE)).thenReturn(false); - when(clusterService.createCache(RoutingTableImpl.GLOBALRPC_CACHE, - EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))). - thenReturn(mockGlobalRpcCache); + when(clusterService.createCache(RoutingTableImpl.GLOBALRPC_CACHE, + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))). + thenReturn(mockGlobalRpcCache); - when(clusterService.existCache( - RoutingTableImpl.RPC_CACHE)).thenReturn(false); + when(clusterService.existCache( + RoutingTableImpl.RPC_CACHE)).thenReturn(false); - when(clusterService.createCache(RoutingTableImpl.RPC_CACHE, - EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))). - thenReturn(mockRpcCache); + when(clusterService.createCache(RoutingTableImpl.RPC_CACHE, + EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))). + thenReturn(mockRpcCache); - doNothing().when(clusterService).tbegin(); - doNothing().when(clusterService).tcommit(); + doNothing().when(clusterService).tbegin(); + doNothing().when(clusterService).tcommit(); - routingTable.setClusterGlobalServices(this.clusterService); - routingTable.init(c); + routingTable.setClusterGlobalServices(this.clusterService); + routingTable.init(c); - Assert.assertEquals(mockGlobalRpcCache, routingTable.getGlobalRpcCache()); - Assert.assertEquals(mockRpcCache, routingTable.getRpcCache()); - } + Assert.assertEquals(mockGlobalRpcCache, routingTable.getGlobalRpcCache()); + Assert.assertEquals(mockRpcCache, routingTable.getRpcCache()); + } - private RpcRouter.RouteIdentifier getRouteIdentifier(){ - RpcRouter.RouteIdentifier routeIdentifier = mock(RpcRouter.RouteIdentifier.class); - InstanceIdentifier identifier = mock(InstanceIdentifier.class); - when(routeIdentifier.getType()).thenReturn(QNAME); - when(routeIdentifier.getRoute()).thenReturn(identifier); + private RpcRouter.RouteIdentifier getRouteIdentifier(){ + RpcRouter.RouteIdentifier routeIdentifier = mock(RpcRouter.RouteIdentifier.class); + InstanceIdentifier identifier = mock(InstanceIdentifier.class); + when(routeIdentifier.getType()).thenReturn(QNAME); + when(routeIdentifier.getRoute()).thenReturn(identifier); - return routeIdentifier; - } + return routeIdentifier; + } - private Runnable addRoutes(final int numRoutes, final String routePrefix, final RpcRouter.RouteIdentifier routeId){ - return new Runnable() { - @Override - public void run() { - for (int i=0;i tracker; private BindingAwareBroker broker; private ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer() { - + @Override public BindingAwareBroker addingService(ServiceReference reference) { broker = context.getService(reference); mdActivationPool.execute(new Runnable() { - + @Override public void run() { - onBrokerAvailable(broker, context);; + onBrokerAvailable(broker, context); } }); return broker; } - + @Override public void modifiedService(ServiceReference reference, BindingAwareBroker service) { // TODO Auto-generated method stub - + } @Override public void removedService(ServiceReference reference, BindingAwareBroker service) { // TODO Auto-generated method stub - + } }; - - + + @Override public final void start(BundleContext context) throws Exception { this.context = context; startImpl(context); tracker = new ServiceTracker<>(context, BindingAwareBroker.class, customizer); tracker.open(); - + } - + @Override public final void stop(BundleContext context) throws Exception { tracker.close(); stopImpl(context); } - - + + /** * Called when this bundle is started (before * {@link #onSessionInitiated(ProviderContext)} so the Framework can perform * the bundle-specific activities necessary to start this bundle. This * method can be used to register services or to allocate any resources that * this bundle needs. - * + * *

* This method must complete and return to its caller in a timely manner. - * + * * @param context * The execution context of the bundle being started. * @throws Exception @@ -99,10 +99,10 @@ public abstract class AbstractBrokerAwareActivator implements BundleActivator { * started. There should be no active threads that were started by this * bundle when this bundle returns. A stopped bundle must not call any * Framework objects. - * + * *

* This method must complete and return to its caller in a timely manner. - * + * * @param context The execution context of the bundle being stopped. * @throws Exception If this method throws an exception, the bundle is still * marked as stopped, and the Framework will remove the bundle's @@ -112,11 +112,11 @@ public abstract class AbstractBrokerAwareActivator implements BundleActivator { protected void stopImpl(BundleContext context) { // NOOP } - + protected abstract void onBrokerAvailable(BindingAwareBroker broker, BundleContext context); - + protected void onBrokerRemoved(BindingAwareBroker broker, BundleContext context) { - + } } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareBroker.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareBroker.java index 5b700703bc..453ff44911 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareBroker.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareBroker.java @@ -9,8 +9,6 @@ package org.opendaylight.controller.sal.binding.api; import org.opendaylight.controller.md.sal.common.api.routing.RoutedRegistration; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality; -import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.yangtools.concepts.ObjectRegistration; import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -39,8 +37,8 @@ import org.osgi.framework.BundleContext; *

  • Notification Service - see {@link NotificationService} and * {@link NotificationProviderService} *
  • Functionality and Data model - *
  • Data Store access and modification - see {@link DataBrokerService} and - * {@link DataProviderService} + *
  • Data Store access and modification - see {@link org.opendaylight.controller.sal.binding.api.data.DataBrokerService} and + * {@link org.opendaylight.controller.sal.binding.api.data.DataProviderService} * * * The services are exposed via session. @@ -52,9 +50,6 @@ import org.osgi.framework.BundleContext; * * For more information about session-based access see {@link ConsumerContext} * and {@link ProviderContext} - * - * - * */ public interface BindingAwareBroker { /** @@ -122,9 +117,6 @@ public interface BindingAwareBroker { * functionality) for the consumer and provides access to the SAL * infrastructure services and other functionality provided by * {@link Provider}s. - * - * - * */ public interface ConsumerContext extends RpcConsumerRegistry { @@ -137,8 +129,6 @@ public interface BindingAwareBroker { * @return Session specific implementation of service */ T getSALService(Class service); - - } /** diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareConsumer.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareConsumer.java index 871abb2117..4327451d21 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareConsumer.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareConsumer.java @@ -10,28 +10,28 @@ package org.opendaylight.controller.sal.binding.api; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; /** - * + * * Defines the component of controller and supplies additional metadata. A * component of the controller or application supplies a concrete implementation * of this interface. - * + * * A user-implemented component (application) which facilitates the SAL and SAL * services to access infrastructure services or providers' functionality. - * - * - * + * + * + * */ public interface BindingAwareConsumer { /** * Callback signaling initialization of the consumer session to the SAL. - * + * * The consumer MUST use the session for all communication with SAL or * retrieving SAL infrastructure services. - * + * * This method is invoked by * {@link BindingAwareBroker#registerConsumer(BindingAwareConsumer)} - * + * * @param session * Unique session between consumer and SAL. */ diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareProvider.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareProvider.java index 120674fa0d..0812e5f53c 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareProvider.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareProvider.java @@ -14,24 +14,24 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderCo import org.opendaylight.yangtools.yang.binding.RpcService; /** - * + * * Defines the component of controller and supplies additional metadata. A * component of the controller or application supplies a concrete implementation * of this interface. - * + * *

    * A user-implemented component (application) which facilitates the SAL and SAL * services to access infrastructure services and to provide functionality to * {@link Consumer}s and other providers. - * - * + * + * */ public interface BindingAwareProvider { /** * Returns a set of provided implementations of YANG modules and their rpcs. - * - * + * + * * @return Set of provided implementation of YANG modules and their Rpcs */ Collection getImplementations(); @@ -39,24 +39,24 @@ public interface BindingAwareProvider { /** * Gets a set of implementations of provider functionality to be registered * into system during the provider registration to the SAL. - * + * *

    * This method is invoked by {@link Broker#registerProvider(Provider)} to * learn the initial provided functionality - * + * * @return Set of provider's functionality. */ Collection getFunctionality(); /** * Functionality provided by the {@link BindingAwareProvider} - * + * *

    * Marker interface used to mark the interfaces describing specific * functionality which could be exposed by providers to other components. - * - * - * + * + * + * */ public interface ProviderFunctionality { diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareService.java index b3680568bb..adaa27f3e6 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareService.java @@ -7,33 +7,26 @@ */ package org.opendaylight.controller.sal.binding.api; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; - /** - * * Session-specific instance of the broker functionality. - * + * *

    * BindingAwareService is marker interface for infrastructure services provided * by the SAL. These services are session-specific, each * {@link BindingAwareConsumer} and {@link BindingAwareProvider} usually has own * instance of the service with it's own context. - * + * *

    * The consumer's (or provider's) instance of specific service could be obtained - * by invoking {@link ConsumerContext#getSALService(Class)} method on session + * by invoking {@link org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext#getSALService(Class)} method on session * assigned to the consumer. - * + * *

    - * {@link BindingAwareService} and {@link BindingAwareProvider} may seem + * {@link org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext} and {@link BindingAwareProvider} may seem * similar, but provider provides YANG model-based functionality and * {@link BindingAwareProvider} exposes the necessary supporting functionality * to implement specific functionality of YANG and to reuse it in the - * development of {@link BindingAwareConsumer}s and {@link BindingAwareProvider} - * s. - * - * - * + * development of {@link BindingAwareConsumer}s and {@link BindingAwareProvider}s. */ public interface BindingAwareService { diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationListener.java index dd454c6620..9429d3f8fa 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationListener.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationListener.java @@ -19,13 +19,13 @@ import org.opendaylight.yangtools.yang.binding.Notification; * @param Notification type */ public interface NotificationListener extends EventListener { - /** - * Invoked to deliver the notification. Note that this method may be invoked - * from a shared thread pool, so implementations SHOULD NOT perform CPU-intensive - * operations and they definitely MUST NOT invoke any potentially blocking - * operations. - * - * @param notification Notification being delivered. - */ + /** + * Invoked to deliver the notification. Note that this method may be invoked + * from a shared thread pool, so implementations SHOULD NOT perform CPU-intensive + * operations and they definitely MUST NOT invoke any potentially blocking + * operations. + * + * @param notification Notification being delivered. + */ void onNotification(T notification); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java index f71d69b860..7da0a48517 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java @@ -12,13 +12,13 @@ import org.opendaylight.yangtools.yang.binding.RpcService; /** * Base interface defining contract for retrieving MD-SAL * version of RpcServices - * + * */ public interface RpcConsumerRegistry extends BindingAwareService { /** * Returns a session specific instance (implementation) of requested * YANG module implementation / service provided by consumer. - * + * * @return Session specific implementation of service */ T getRpcService(Class module); diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java index 65f1ff2fe3..d0225768b4 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java @@ -33,7 +33,7 @@ public interface DataBrokerService extends // * @return new blank data modification transaction. */ @Override - DataModificationTransaction beginTransaction(); + DataModificationTransaction beginTransaction(); /** * Reads data subtree from configurational store. diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java index 7190638323..5fafabbd1b 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java @@ -11,7 +11,6 @@ import java.util.EventListener; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataModification; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -19,13 +18,12 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; public interface DataModificationTransaction extends DataModification, DataObject> { - /** * Returns an unique identifier for transaction * */ @Override - public Object getIdentifier(); + Object getIdentifier(); /** * Initiates a two-phase commit of candidate data. @@ -44,7 +42,7 @@ public interface DataModificationTransaction extends DataModification> commit(); - - + Future> commit(); /** * Register a listener for transaction @@ -64,12 +60,8 @@ public interface DataModificationTransaction extends DataModification registerListener(DataTransactionListener listener); - - /** * Listener for transaction state changes - * - * */ public interface DataTransactionListener extends EventListener { /** diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java index 7d662cfcf2..b496d1dfb4 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java @@ -7,22 +7,17 @@ */ package org.opendaylight.controller.sal.binding.api.data; - import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService; import org.opendaylight.controller.md.sal.common.api.data.DataReader; -import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** - * DataProviderService is common access point for {@link BindingAwareProvider} providers + * DataProviderService is common access point for {@link org.opendaylight.controller.sal.binding.api.BindingAwareProvider} providers * to access data trees described by the YANG model. - * */ public interface DataProviderService extends DataBrokerService, DataProvisionService, DataObject> { - - /** * Registers a data reader for particular subtree of overal YANG data tree. * diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderInstance.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderInstance.java index dec44f364f..0d9a90286e 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderInstance.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderInstance.java @@ -15,9 +15,9 @@ import org.opendaylight.controller.sal.binding.api.data.DataProviderService; * Provider's version of Mount Point, this version allows access to MD-SAL * services specific for this mountpoint and registration / provision of * interfaces for mount point. - * + * * @author ttkacik - * + * */ public interface MountProviderInstance // extends // diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcContextIdentifier.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcContextIdentifier.java index d6374fff90..e3bedd33f9 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcContextIdentifier.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcContextIdentifier.java @@ -15,7 +15,7 @@ public final class RpcContextIdentifier implements Immutable{ public final Class rpcService; public final Class routingContext; - + private RpcContextIdentifier(Class rpcService, Class routingContext) { super(); this.rpcService = rpcService; @@ -29,11 +29,11 @@ public final class RpcContextIdentifier implements Immutable{ public Class getRoutingContext() { return routingContext; } - + public static final RpcContextIdentifier contextForGlobalRpc(Class serviceType) { return new RpcContextIdentifier(serviceType, null); } - + public static final RpcContextIdentifier contextFor(Class serviceType,Class routingContext) { return new RpcContextIdentifier(serviceType, routingContext); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcRoutingTable.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcRoutingTable.java index cc800b6bbb..61c7cfc953 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcRoutingTable.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/rpc/RpcRoutingTable.java @@ -22,7 +22,7 @@ public interface RpcRoutingTable e /** * Updates route for particular path to specified instance of * {@link RpcService}. - * + * * @param path * Path for which RpcService routing is to be updated * @param service @@ -33,19 +33,19 @@ public interface RpcRoutingTable e /** * Deletes a route for particular path - * + * * @param path * Path for which */ void removeRoute(InstanceIdentifier path); /** - * + * */ S getRoute(InstanceIdentifier nodeInstance); /** - * + * * @return */ Map, S> getRoutes(); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModuleFactory.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModuleFactory.java index df3b7ece5d..a11a7d67f5 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModuleFactory.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingBrokerImplModuleFactory.java @@ -26,14 +26,14 @@ import org.osgi.framework.BundleContext; */ public class BindingBrokerImplModuleFactory extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractBindingBrokerImplModuleFactory { - + @Override public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) { BindingBrokerImplModule module = (BindingBrokerImplModule) super.createModule(instanceName, dependencyResolver, bundleContext); module.setBundleContext(bundleContext); return module; } - + @Override public Module createModule(String instanceName, DependencyResolver dependencyResolver, DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java index 8aff12b44a..9b7b8e28c9 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java @@ -9,56 +9,54 @@ package org.opendaylight.controller.sal.binding.codegen; import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; -import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext; public interface RuntimeCodeGenerator { /** * Returns an instance of provided RpcService type which delegates all calls * to the delegate. - * + * *

    * Returned instance: *

      *
    • implements provided subclass of RpcService type and - * {@link DelegateProxy} interface. + * {@link org.opendaylight.controller.sal.binding.spi.DelegateProxy} interface. *
    • *

      * delegates all invocations of methods, which are defined in RpcService * subtype to delegate which is defined by - * {@link DelegateProxy#setDelegate(Object)}. + * {@link org.opendaylight.controller.sal.binding.spi.DelegateProxy#setDelegate(Object)}. *

      * If delegate is not defined (getDelegate() == null) * implementation throws {@link IllegalStateException} - *

    • {@link DelegateProxy#getDelegate()} - returns the delegate to which + *
    • {@link org.opendaylight.controller.sal.binding.spi.DelegateProxy#getDelegate()} - returns the delegate to which * all calls are delegated. - *
    • {@link DelegateProxy#setDelegate(Object)} - sets the delegate for + *
    • {@link org.opendaylight.controller.sal.binding.spi.DelegateProxy#setDelegate(Object)} - sets the delegate for * particular instance - * + * *
    - * + * * @param serviceType * - Subclass of RpcService for which direct proxy is to be * generated. * @return Instance of RpcService of provided serviceType which implements - * and {@link DelegateProxy} + * and {@link org.opendaylight.controller.sal.binding.spi.DelegateProxy} * @throws IllegalArgumentException - * + * */ T getDirectProxyFor(Class serviceType) throws IllegalArgumentException; /** * Returns an instance of provided RpcService type which routes all calls to * other instances selected on particular input field. - * + * *

    * Returned instance: *

      *
    • Implements: *
        - *
      • {@link DelegateProxy} + *
      • {@link org.opendaylight.controller.sal.binding.spi.DelegateProxy} *
      • {@link RpcRouter} *
      *
    • @@ -69,22 +67,23 @@ public interface RuntimeCodeGenerator { *
        *
      • * Implementation uses - * {@link RpcRouter#getService(Class, InstanceIdentifier)} method to + * {@link RpcRouter#getService(Class, org.opendaylight.yangtools.yang.binding.InstanceIdentifier)} method to * retrieve particular instance to which call will be routed. *
      • - * Instance of {@link InstanceIdentifier} is determined by first argument of + * Instance of {@link org.opendaylight.yangtools.yang.binding.InstanceIdentifier} is determined by first argument of * method and is retrieved via method which is annotated with - * {@link RoutingContext}. Class representing Routing Context Identifier is - * retrieved by {@link RoutingContext}. - *
      • If first argument is not defined / {@link RoutingContext} annotation + * {@link org.opendaylight.yangtools.yang.binding.annotations.RoutingContext}. + * Class representing Routing Context Identifier is retrieved by a + * {@link org.opendaylight.yangtools.yang.binding.annotations.RoutingContext}. + *
      • If first argument is not defined / {@link org.opendaylight.yangtools.yang.binding.annotations.RoutingContext} annotation * is not present on any field invocation will be delegated to default * service {@link RpcRouter#getDefaultService()}. *
      - * + * * @param serviceType * - Subclass of RpcService for which Router is to be generated. * @return Instance of RpcService of provided serviceType which implements - * also {@link RpcRouter} and {@link DelegateProxy} + * also {@link RpcRouter} and {@link org.opendaylight.controller.sal.binding.spi.DelegateProxy} */ RpcRouter getRouterFor(Class serviceType,String name) throws IllegalArgumentException; diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/YangtoolsMappingHelper.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/YangtoolsMappingHelper.java deleted file mode 100644 index 4ad0bb0558..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/YangtoolsMappingHelper.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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.sal.binding.codegen; - -import java.lang.reflect.Method; - -import org.opendaylight.yangtools.yang.binding.Notification; - -public final class YangtoolsMappingHelper { - private YangtoolsMappingHelper() { - throw new UnsupportedOperationException("Utility class"); - } - - public static boolean isNotificationCallback(final Method it) { - return it.getName().startsWith("on") && (it.getParameterTypes().length == 1) && - Notification.class.isAssignableFrom(it.getParameterTypes()[0]); - } -} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/AbstractRuntimeCodeGenerator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/AbstractRuntimeCodeGenerator.java new file mode 100644 index 0000000000..9605a4d372 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/AbstractRuntimeCodeGenerator.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2014 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.sal.binding.codegen.impl; + +import java.util.Map; +import java.util.WeakHashMap; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtMethod; +import javassist.NotFoundException; + +import javax.annotation.concurrent.GuardedBy; + +import org.eclipse.xtext.xbase.lib.Extension; +import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; +import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.NotificationListener; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext; +import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils; + +import com.google.common.base.Supplier; + +abstract class AbstractRuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory { + @GuardedBy("this") + private final Map, RuntimeGeneratedInvokerPrototype> invokerClasses = new WeakHashMap<>(); + private final CtClass brokerNotificationListener; + + @Extension + protected final JavassistUtils utils; + + protected AbstractRuntimeCodeGenerator(final ClassPool pool) { + utils = JavassistUtils.forClassPool(pool); + + /* + * Make sure Javassist ClassPool sees the classloader of RpcService + */ + utils.ensureClassLoader(RpcService.class); + + brokerNotificationListener = utils.asCtClass(org.opendaylight.controller.sal.binding.api.NotificationListener.class); + } + + protected final CtClass getBrokerNotificationListener() { + return brokerNotificationListener; + } + + protected abstract RuntimeGeneratedInvokerPrototype generateListenerInvoker(Class cls); + protected abstract Supplier directProxySupplier(final Class serviceType); + protected abstract Supplier routerSupplier(final Class serviceType, RpcServiceMetadata metadata); + + private RpcServiceMetadata getRpcMetadata(final CtClass iface) throws ClassNotFoundException, NotFoundException { + final RpcServiceMetadata metadata = new RpcServiceMetadata(); + + for (CtMethod method : iface.getMethods()) { + if (iface.equals(method.getDeclaringClass()) && method.getParameterTypes().length == 1) { + final RpcMetadata routingPair = getRpcMetadata(method); + if (routingPair != null) { + metadata.addContext(routingPair.getContext()); + metadata.addRpcMethod(method.getName(), routingPair); + + /* + * Force-load the RPC class representing the "input" of this RPC. + * + * FIXME: this is pre-existing side-effect of the original code, which + * kept a reference to the loaded class, but it did not use it. + * + * There was no explanation as to why forcing this load was + * necessary. As far as I can tell now is that it forces the + * resolution of method arguments, which would (according to + * my reading of JLS) occur only when the method is invoked via + * binding-aware class action, not when coming from + * binding-independent world. Whether that makes sense or not, + * remains to be investigated. + */ + Thread.currentThread().getContextClassLoader().loadClass(routingPair.getInputType().getName()); + } + } + } + + return metadata; + } + + private RpcMetadata getRpcMetadata(final CtMethod method) throws NotFoundException { + final CtClass inputClass = method.getParameterTypes()[0]; + return rpcMethodMetadata(inputClass, inputClass, method.getName()); + } + + private RpcMetadata rpcMethodMetadata(final CtClass dataClass, final CtClass inputClass, final String rpcMethod) throws NotFoundException { + for (CtMethod method : dataClass.getMethods()) { + if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { + for (Object annotation : method.getAvailableAnnotations()) { + if (annotation instanceof RoutingContext) { + boolean encapsulated = !method.getReturnType().equals(utils.asCtClass(InstanceIdentifier.class)); + return new RpcMetadata(rpcMethod, ((RoutingContext)annotation).value(), method, encapsulated, inputClass); + } + } + } + } + + for (CtClass iface : dataClass.getInterfaces()) { + final RpcMetadata ret = rpcMethodMetadata(iface, inputClass, rpcMethod); + if(ret != null) { + return ret; + } + } + return null; + } + + private synchronized RuntimeGeneratedInvokerPrototype resolveInvokerClass(final Class cls) { + RuntimeGeneratedInvokerPrototype invoker = invokerClasses.get(cls); + if (invoker != null) { + return invoker; + } + + utils.getLock().lock(); + try { + invoker = ClassLoaderUtils.withClassLoader(cls.getClassLoader(), new Supplier() { + @Override + public RuntimeGeneratedInvokerPrototype get() { + return generateListenerInvoker(cls); + } + }); + + invokerClasses.put(cls, invoker); + return invoker; + } finally { + utils.getLock().unlock(); + } + } + + @Override + public final NotificationInvokerFactory getInvokerFactory() { + return this; + } + + @Override + public final T getDirectProxyFor(final Class serviceType) { + utils.getLock().lock(); + try { + return ClassLoaderUtils.withClassLoader(serviceType.getClassLoader(), directProxySupplier(serviceType)); + } finally { + utils.getLock().unlock(); + } + } + + @Override + public final RpcRouter getRouterFor(final Class serviceType, final String name) { + final RpcServiceMetadata metadata = ClassLoaderUtils.withClassLoader(serviceType.getClassLoader(), new Supplier() { + @Override + public RpcServiceMetadata get() { + try { + return getRpcMetadata(utils.asCtClass(serviceType)); + } catch (ClassNotFoundException | NotFoundException e) { + throw new IllegalStateException(String.format("Failed to load metadata for class {}", serviceType), e); + } + } + }); + + utils.getLock().lock(); + try { + final T instance = ClassLoaderUtils.withClassLoader(serviceType.getClassLoader(), routerSupplier(serviceType, metadata)); + return new RpcRouterCodegenInstance(name, serviceType, instance, metadata.getContexts()); + } finally { + utils.getLock().unlock(); + } + } + + @Override + public NotificationInvoker invokerFor(final NotificationListener instance) { + final Class cls = instance.getClass(); + final RuntimeGeneratedInvokerPrototype prototype = resolveInvokerClass(cls); + + try { + return RuntimeGeneratedInvoker.create(instance, prototype); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException(String.format("Failed to create invoker for %s", instance), e); + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/BrokerImplClassLoader.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/BrokerImplClassLoader.java index cab4fe90e0..fdd9350680 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/BrokerImplClassLoader.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/BrokerImplClassLoader.java @@ -6,25 +6,22 @@ * and is available at http://www.eclipse.org/legal/epl-v10.html */ - package org.opendaylight.controller.sal.binding.codegen.impl; -import org.eclipse.xtext.xbase.lib.Exceptions; - -@SuppressWarnings("all") public class BrokerImplClassLoader extends ClassLoader { - private final ClassLoader spiClassLoader; + private final ClassLoader spiClassLoader; - public BrokerImplClassLoader(final ClassLoader model, final ClassLoader spi) { - super(model); - this.spiClassLoader = spi; - } + public BrokerImplClassLoader(final ClassLoader model, final ClassLoader spi) { + super(model); + this.spiClassLoader = spi; + } - public Class loadClass(final String name) throws ClassNotFoundException { - try { - return super.loadClass(name); - } catch (ClassNotFoundException e) { - return this.spiClassLoader.loadClass(name); + @Override + public Class loadClass(final String name) throws ClassNotFoundException { + try { + return super.loadClass(name); + } catch (ClassNotFoundException e) { + return this.spiClassLoader.loadClass(name); + } } - } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcMetadata.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcMetadata.java new file mode 100644 index 0000000000..6f9f85f58a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcMetadata.java @@ -0,0 +1,95 @@ +/** + * 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.sal.binding.codegen.impl; + +import javassist.CtClass; +import javassist.CtMethod; + +import org.opendaylight.yangtools.yang.binding.BaseIdentity; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; + +final class RpcMetadata { + private final Class context; + private final CtMethod inputRouteGetter; + private final Boolean routeEncapsulated; + private final CtClass inputType; + private final String methodName; + + public Class getContext() { + return context; + } + + public CtMethod getInputRouteGetter() { + return inputRouteGetter; + } + + public CtClass getInputType() { + return inputType; + } + + public boolean isRouteEncapsulated() { + return routeEncapsulated; + } + + public RpcMetadata(final String methodName, final Class context, final CtMethod inputRouteGetter, final boolean routeEncapsulated, final CtClass inputType) { + this.inputRouteGetter = Preconditions.checkNotNull(inputRouteGetter); + this.methodName = Preconditions.checkNotNull(methodName); + this.inputType = Preconditions.checkNotNull(inputType); + this.context = Preconditions.checkNotNull(context); + this.routeEncapsulated = routeEncapsulated; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + methodName.hashCode(); + result = prime * result + context.hashCode(); + result = prime * result + inputRouteGetter.hashCode(); + result = prime * result + routeEncapsulated.hashCode(); + result = prime * result + inputType.hashCode(); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof RpcMetadata)) { + return false; + } + final RpcMetadata other = (RpcMetadata) obj; + if (!methodName.equals(other.methodName)) { + return false; + } + if (!context.equals(other.context)) { + return false; + } + if (!inputRouteGetter.equals(other.inputRouteGetter)) { + return false; + } + if (!routeEncapsulated.equals(other.routeEncapsulated)) { + return false; + } + return inputType.equals(other.inputType); + } + + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("context", context) + .add("inputRouteGetter", inputRouteGetter) + .add("inputType", inputType) + .add("methodName", methodName) + .add("routeEncapsulated", routeEncapsulated) + .toString(); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java index 5578f75ae2..052fd2169a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java @@ -24,7 +24,6 @@ import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.yangtools.yang.binding.BaseIdentity; -import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; import org.slf4j.Logger; @@ -34,7 +33,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; public class RpcRouterCodegenInstance implements // - RpcRouter, RouteChangeListener, InstanceIdentifier> { +RpcRouter, RouteChangeListener, InstanceIdentifier> { private static final Logger LOG = LoggerFactory.getLogger(RpcRouterCodegenInstance.class); @@ -53,8 +52,7 @@ public class RpcRouterCodegenInstance implements // private final String name; @SuppressWarnings("unchecked") - public RpcRouterCodegenInstance(String name,Class type, T routerImpl, Set> contexts, - Set> inputs) { + public RpcRouterCodegenInstance(final String name,final Class type, final T routerImpl, final Iterable> contexts) { this.name = name; this.listeners = ListenerRegistry.create(); this.serviceType = type; @@ -86,7 +84,7 @@ public class RpcRouterCodegenInstance implements // @Override @SuppressWarnings("unchecked") - public RpcRoutingTable getRoutingTable(Class routeContext) { + public RpcRoutingTable getRoutingTable(final Class routeContext) { return (RpcRoutingTable) routingTables.get(routeContext); } @@ -102,12 +100,12 @@ public class RpcRouterCodegenInstance implements // @Override public , InstanceIdentifier>> ListenerRegistration registerRouteChangeListener( - L listener) { + final L listener) { return listeners.registerWithType(listener); } @Override - public void onRouteChange(RouteChange, InstanceIdentifier> change) { + public void onRouteChange(final RouteChange, InstanceIdentifier> change) { for (ListenerRegistration, InstanceIdentifier>> listener : listeners) { try { listener.getInstance().onRouteChange(change); @@ -118,17 +116,17 @@ public class RpcRouterCodegenInstance implements // } @Override - public T getService(Class context, InstanceIdentifier path) { + public T getService(final Class context, final InstanceIdentifier path) { return routingTables.get(context).getRoute(path); } @Override - public RoutedRpcRegistration addRoutedRpcImplementation(T service) { + public RoutedRpcRegistration addRoutedRpcImplementation(final T service) { return new RoutedRpcRegistrationImpl(service); } @Override - public RpcRegistration registerDefaultService(T service) { + public RpcRegistration registerDefaultService(final T service) { // TODO Auto-generated method stub RuntimeCodeHelper.setDelegate(invocationProxy, service); return null; @@ -136,7 +134,7 @@ public class RpcRouterCodegenInstance implements // private class RoutedRpcRegistrationImpl extends AbstractObjectRegistration implements RoutedRpcRegistration { - public RoutedRpcRegistrationImpl(T instance) { + public RoutedRpcRegistrationImpl(final T instance) { super(instance); } @@ -146,22 +144,22 @@ public class RpcRouterCodegenInstance implements // } @Override - public void registerPath(Class context, InstanceIdentifier path) { + public void registerPath(final Class context, final InstanceIdentifier path) { routingTables.get(context).updateRoute(path, getInstance()); } @Override - public void unregisterPath(Class context, InstanceIdentifier path) { + public void unregisterPath(final Class context, final InstanceIdentifier path) { routingTables.get(context).removeRoute(path, getInstance()); } @Override - public void registerInstance(Class context, InstanceIdentifier instance) { + public void registerInstance(final Class context, final InstanceIdentifier instance) { registerPath(context, instance); } @Override - public void unregisterInstance(Class context, InstanceIdentifier instance) { + public void unregisterInstance(final Class context, final InstanceIdentifier instance) { unregisterPath(context, instance); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcServiceMetadata.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcServiceMetadata.java new file mode 100644 index 0000000000..430b7a7e31 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcServiceMetadata.java @@ -0,0 +1,39 @@ +/** + * 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.sal.binding.codegen.impl; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.yangtools.yang.binding.BaseIdentity; + +import com.google.common.collect.Iterables; + +final class RpcServiceMetadata { + private final Set> contexts = new HashSet<>(); + private final Map rpcMethods = new HashMap<>(); + private final Iterable> roContexts = Iterables.unmodifiableIterable(contexts); + + public Iterable> getContexts() { + return roContexts; + } + + public RpcMetadata getRpcMethod(final String name) { + return rpcMethods.get(name); + } + + public void addContext(final Class context) { + contexts.add(context); + } + + public void addRpcMethod(final String name, final RpcMetadata routingPair) { + rpcMethods.put(name, routingPair); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend index 465a1f7d9d..3fef544f81 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend @@ -7,59 +7,28 @@ */ package org.opendaylight.controller.sal.binding.codegen.impl +import java.util.Map import javassist.ClassPool -import org.opendaylight.yangtools.yang.binding.RpcService - -import javassist.CtClass -import javassist.CtMethod import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext -import org.opendaylight.yangtools.yang.binding.BaseIdentity - -import java.util.Map -import java.util.HashMap - - -import org.opendaylight.yangtools.yang.binding.NotificationListener import org.opendaylight.yangtools.yang.binding.Notification - - -import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.* -import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.* -import java.util.HashSet -import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.* -import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory -import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker -import java.util.Set -import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper -import java.util.WeakHashMap -import org.opendaylight.yangtools.yang.binding.annotations.QName -import org.opendaylight.yangtools.yang.binding.DataContainer import org.opendaylight.yangtools.yang.binding.RpcImplementation -import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils -import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils -import javassist.LoaderClassPath +import org.opendaylight.yangtools.yang.binding.util.BindingReflections +import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils -class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory { - - val CtClass BROKER_NOTIFICATION_LISTENER; - val extension JavassistUtils utils; - val Map, RuntimeGeneratedInvokerPrototype> invokerClasses; +import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.* +class RuntimeCodeGenerator extends AbstractRuntimeCodeGenerator { new(ClassPool pool) { - utils = new JavassistUtils(pool); - invokerClasses = new WeakHashMap(); - BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass; - pool.appendClassPath(new LoaderClassPath(RpcService.classLoader)); + super(pool) } - override getDirectProxyFor(Class iface) { - val T instance = withClassLoaderAndLock(iface.classLoader,lock) [| + override directProxySupplier(Class iface) { + return [| val proxyName = iface.directProxyName; val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName) if(potentialClass != null) { - return potentialClass.newInstance as T; + return potentialClass.newInstance; } val supertype = iface.asCtClass val createdCls = createClass(iface.directProxyName, supertype) [ @@ -84,23 +53,17 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co ''' ] ] - return createdCls.toClass(iface.classLoader).newInstance as T + return createdCls.toClass(iface.classLoader).newInstance ] - return instance; } - override getRouterFor(Class iface,String routerInstanceName) { - val metadata = withClassLoader(iface.classLoader) [| - val supertype = iface.asCtClass - return supertype.rpcMetadata; - ] - - val instance = withClassLoaderAndLock(iface.classLoader,lock) [ | + override routerSupplier(Class iface, RpcServiceMetadata metadata) { + return [ | val supertype = iface.asCtClass val routerName = iface.routerName; val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName) if(potentialClass != null) { - return potentialClass.newInstance as T; + return potentialClass.newInstance; } val targetCls = createClass(iface.routerName, supertype) [ @@ -115,7 +78,7 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co } implementMethodsFrom(supertype) [ if (parameterTypes.size === 1) { - val rpcMeta = metadata.rpcMethods.get(name); + val rpcMeta = metadata.getRpcMethod(name); val bodyTmp = ''' { final «InstanceIdentifier.name» identifier = $1.«rpcMeta.inputRouteGetter.name»()«IF rpcMeta. @@ -143,74 +106,18 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co ''' ] ] - return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T - + return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance ]; - return new RpcRouterCodegenInstance(routerInstanceName,iface, instance, metadata.contexts,metadata.supportedInputs); - } - - private def RpcServiceMetadata getRpcMetadata(CtClass iface) { - val metadata = new RpcServiceMetadata; - - iface.methods.filter[declaringClass == iface && parameterTypes.size === 1].forEach [ method | - val routingPair = method.rpcMetadata; - if (routingPair !== null) { - metadata.contexts.add(routingPair.context) - metadata.rpcMethods.put(method.name,routingPair) - val input = routingPair.inputType.javaClass as Class; - metadata.supportedInputs.add(input); - metadata.rpcInputs.put(input,routingPair); - } - ] - return metadata; - } - - private def getRpcMetadata(CtMethod method) { - val inputClass = method.parameterTypes.get(0); - return inputClass.rpcMethodMetadata(inputClass,method.name); - } - - private def RpcMetadata rpcMethodMetadata(CtClass dataClass,CtClass inputClass,String rpcMethod) { - for (method : dataClass.methods) { - if (method.name.startsWith("get") && method.parameterTypes.size === 0) { - for (annotation : method.availableAnnotations) { - if (annotation instanceof RoutingContext) { - val encapsulated = !method.returnType.equals(InstanceIdentifier.asCtClass); - return new RpcMetadata(null,rpcMethod,(annotation as RoutingContext).value, method, encapsulated,inputClass); - } - } - } - } - for (iface : dataClass.interfaces) { - val ret = rpcMethodMetadata(iface,inputClass,rpcMethod); - if(ret != null) return ret; - } - return null; } - private def getJavaClass(CtClass cls) { - Thread.currentThread.contextClassLoader.loadClass(cls.name) - } - - override getInvokerFactory() { - return this; - } - - override invokerFor(NotificationListener instance) { - val cls = instance.class - val prototype = resolveInvokerClass(cls); - - return new RuntimeGeneratedInvoker(instance, prototype) - } - - protected def generateListenerInvoker(Class iface) { - val callbacks = iface.methods.filter[notificationCallback] + override generateListenerInvoker(Class iface) { + val callbacks = iface.methods.filter[BindingReflections.isNotificationCallback(it)] val supportedNotification = callbacks.map[parameterTypes.get(0) as Class].toSet; - val targetCls = createClass(iface.invokerName, BROKER_NOTIFICATION_LISTENER) [ + val targetCls = createClass(iface.invokerName, brokerNotificationListener) [ field(DELEGATE_FIELD, iface) - implementMethodsFrom(BROKER_NOTIFICATION_LISTENER) [ + implementMethodsFrom(brokerNotificationListener) [ body = ''' { «FOR callback : callbacks SEPARATOR " else "» @@ -229,95 +136,4 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co return new RuntimeGeneratedInvokerPrototype(supportedNotification, finalClass as Class>); } - - - - - - protected def resolveInvokerClass(Class class1) { - return withClassLoaderAndLock(class1.classLoader,lock) [| - val invoker = invokerClasses.get(class1); - if (invoker !== null) { - return invoker; - } - val newInvoker = generateListenerInvoker(class1); - invokerClasses.put(class1, newInvoker); - return newInvoker - - ] - } -} - -@Data -package class RuntimeGeneratedInvoker implements NotificationInvoker { - - @Property - val NotificationListener delegate; - - @Property - var org.opendaylight.controller.sal.binding.api.NotificationListener invocationProxy; - - @Property - var RuntimeGeneratedInvokerPrototype prototype; - - new(NotificationListener delegate, RuntimeGeneratedInvokerPrototype prototype) { - _delegate = delegate; - _prototype = prototype; - _invocationProxy = prototype.protoClass.newInstance as org.opendaylight.controller.sal.binding.api.NotificationListener; - RuntimeCodeHelper.setDelegate(_invocationProxy, delegate); - } - - override getSupportedNotifications() { - prototype.supportedNotifications; - } - - override close() { - } -} - -@Data -package class RuntimeGeneratedInvokerPrototype { - - @Property - val Set> supportedNotifications; - - @Property - val Class> protoClass; -} - -package class RpcServiceMetadata { - - @Property - val contexts = new HashSet>(); - - @Property - val rpcMethods = new HashMap(); - - @Property - val rpcInputs = new HashMap, RpcMetadata>(); - - - @Property - val supportedInputs = new HashSet>(); -} - -@Data -package class RpcMetadata { - - @Property - val QName qname; - - @Property - val String methodName; - - @Property - val Class context; - @Property - val CtMethod inputRouteGetter; - - @Property - val boolean routeEncapsulated; - - @Property - val CtClass inputType; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeGeneratedInvoker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeGeneratedInvoker.java new file mode 100644 index 0000000000..8762562ad1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeGeneratedInvoker.java @@ -0,0 +1,91 @@ +/** + * 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.sal.binding.codegen.impl; + +import java.util.Set; + +import org.eclipse.xtext.xbase.lib.util.ToStringHelper; +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper; +import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.opendaylight.yangtools.yang.binding.NotificationListener; + +import com.google.common.base.Preconditions; + +final class RuntimeGeneratedInvoker implements NotificationInvoker { + private final org.opendaylight.controller.sal.binding.api.NotificationListener invocationProxy; + private final RuntimeGeneratedInvokerPrototype prototype; + private final NotificationListener delegate; + + @SuppressWarnings("unchecked") + private RuntimeGeneratedInvoker(final NotificationListener delegate, final RuntimeGeneratedInvokerPrototype prototype, final org.opendaylight.controller.sal.binding.api.NotificationListener proxy) { + this.invocationProxy = (org.opendaylight.controller.sal.binding.api.NotificationListener) proxy; + this.delegate = Preconditions.checkNotNull(delegate); + this.prototype = prototype; + } + + public static RuntimeGeneratedInvoker create(final NotificationListener delegate, final RuntimeGeneratedInvokerPrototype prototype) throws InstantiationException, IllegalAccessException { + final org.opendaylight.controller.sal.binding.api.NotificationListener proxy = Preconditions.checkNotNull(prototype.getProtoClass().newInstance()); + RuntimeCodeHelper.setDelegate(proxy, delegate); + return new RuntimeGeneratedInvoker(delegate, prototype, proxy); + } + + @Override + public NotificationListener getDelegate() { + return delegate; + } + + @Override + public org.opendaylight.controller.sal.binding.api.NotificationListener getInvocationProxy() { + return invocationProxy; + } + + @Override + public Set> getSupportedNotifications() { + return prototype.getSupportedNotifications(); + } + + @Override + public void close() { + // Nothing to do + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + delegate.hashCode(); + result = prime * result + invocationProxy.hashCode(); + result = prime * result + prototype.hashCode(); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof RuntimeGeneratedInvoker)) { + return false; + } + final RuntimeGeneratedInvoker other = (RuntimeGeneratedInvoker) obj; + if (!delegate.equals(other.delegate)) { + return false; + } + if (!invocationProxy.equals(other.invocationProxy)) { + return false; + } + return prototype.equals(other.prototype); + } + + @Override + public String toString() { + String result = new ToStringHelper().toString(this); + return result; + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeGeneratedInvokerPrototype.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeGeneratedInvokerPrototype.java new file mode 100644 index 0000000000..317268420f --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeGeneratedInvokerPrototype.java @@ -0,0 +1,66 @@ +/** + * 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.sal.binding.codegen.impl; + +import java.util.Set; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.yangtools.yang.binding.Notification; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; + +final class RuntimeGeneratedInvokerPrototype { + private final Set> supportedNotifications; + private final Class> protoClass; + + public RuntimeGeneratedInvokerPrototype(final Set> supportedNotifications, final Class> protoClass) { + this.supportedNotifications = Preconditions.checkNotNull(supportedNotifications); + this.protoClass = Preconditions.checkNotNull(protoClass); + } + + public Set> getSupportedNotifications() { + return supportedNotifications; + } + + public Class> getProtoClass() { + return protoClass; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + supportedNotifications.hashCode(); + result = prime * result + protoClass.hashCode(); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof RuntimeGeneratedInvokerPrototype)) { + return false; + } + final RuntimeGeneratedInvokerPrototype other = (RuntimeGeneratedInvokerPrototype) obj; + if (!protoClass.equals(other.protoClass)) { + return false; + } + return supportedNotifications.equals(other.supportedNotifications); + } + + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("protoClass", protoClass) + .add("supportedNotifications", supportedNotifications) + .toString(); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java index 3ad1dabffe..75d44db9d1 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootBindingAwareBroker.java @@ -112,7 +112,7 @@ public class RootBindingAwareBroker implements // LOG.info("Starting Binding Aware Broker: {}", identifier); controllerRoot = new RootSalInstance(getRpcProviderRegistry(), getNotificationBroker(), getDataBroker()); - + supportedConsumerServices = ImmutableClassToInstanceMap. builder() .put(NotificationService.class, getRoot()) // @@ -144,19 +144,19 @@ public class RootBindingAwareBroker implements // public void close() throws Exception { // FIXME: Close all sessions } - + @Override public RoutedRpcRegistration addRoutedRpcImplementation(Class type, T implementation) throws IllegalStateException { return getRoot().addRoutedRpcImplementation(type, implementation); } - + @Override public RpcRegistration addRpcImplementation(Class type, T implementation) throws IllegalStateException { return getRoot().addRpcImplementation(type, implementation); } - + @Override public T getRpcService(Class module) { return getRoot().getRpcService(module); @@ -166,7 +166,7 @@ public class RootBindingAwareBroker implements // L arg0) { return getRoot().registerRouteChangeListener(arg0); } - + public class RootSalInstance extends AbstractBindingSalProviderInstance { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java index 978c79ea02..bfafc1f9b7 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java @@ -80,7 +80,7 @@ public class BindingDomConnectorDeployer { connector.startDataForwarding(); } - public static void startNotificationForwarding(BindingIndependentConnector connector, + public static void startNotificationForwarding(BindingIndependentConnector connector, NotificationProviderService baService, NotificationPublishService domService) { if(connector.isNotificationForwarding()) { return; diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java index 5bbebe6f1b..d2472669fa 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java @@ -83,7 +83,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Function; -import com.google.common.base.Optional; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardingUtils.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardingUtils.java index e455bea19c..d28b3b5c91 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardingUtils.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardingUtils.java @@ -21,7 +21,7 @@ public class DomForwardingUtils { DomForwardedBroker forwardedSource = (DomForwardedBroker) source; DomForwardedBroker forwardedTarget = (DomForwardedBroker) target; reuseForwardingFrom(forwardedTarget, forwardedSource); - + } private static void reuseForwardingFrom(DomForwardedBroker target, DomForwardedBroker source) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/BindingAwareDataReaderRouter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/BindingAwareDataReaderRouter.java index b0316635e2..97f74ff6f3 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/BindingAwareDataReaderRouter.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/BindingAwareDataReaderRouter.java @@ -7,14 +7,13 @@ */ package org.opendaylight.controller.sal.binding.impl.util; -import java.util.Iterator; import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -@SuppressWarnings("all") public class BindingAwareDataReaderRouter extends AbstractDataReadRouter,DataObject> { - protected DataObject merge(final InstanceIdentifier path, final Iterable data) { - return data.iterator().next(); - } + @Override + protected DataObject merge(final InstanceIdentifier path, final Iterable data) { + return data.iterator().next(); + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/DelegateProxy.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/DelegateProxy.java index e34ee28a31..d22335e66e 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/DelegateProxy.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/DelegateProxy.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.sal.binding.spi; public interface DelegateProxy { - + void setDelegate(T delegate); T getDelegate(); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RemoteRpcRouter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RemoteRpcRouter.java index 526ca40595..068c68a81f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RemoteRpcRouter.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RemoteRpcRouter.java @@ -12,13 +12,13 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; public interface RemoteRpcRouter { - - - - + + + + ListenerRegistration registerRouteChangeListener(RouteChangeListener listener); - - + + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/MultipleAugmentationPutsTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/MultipleAugmentationPutsTest.java index 02870c4ef7..25c57ccd5f 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/MultipleAugmentationPutsTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/MultipleAugmentationPutsTest.java @@ -89,7 +89,6 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem Nodes nodes = checkForNodes(); verifyNode(nodes, flowCapableNode).assertHasAugmentation(FlowCapableNode.class); - ; assertBindingIndependentVersion(NODE_INSTANCE_ID_BI); // Node meterStatsNode = createTestNode(NodeMeterStatistics.class, nodeMeterStatistics()); // commitNodeAndVerifyTransaction(meterStatsNode); diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java index 36a172d09c..9f8a443bbf 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/UnionSerializationTest.java @@ -19,22 +19,22 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp import org.opendaylight.yangtools.yang.data.api.CompositeNode; public class UnionSerializationTest extends AbstractDataServiceTest { - + public static final String PREFIX_STRING = "192.168.0.1/32"; - - + + @Test public void testPrefixSerialization() throws Exception { - + Ipv4Prefix ipv4prefix = new Ipv4Prefix(PREFIX_STRING); IpPrefix ipPrefix = new IpPrefix(ipv4prefix); Prefix prefix = new PrefixBuilder().setPrefix(ipPrefix).build(); - + CompositeNode serialized = testContext.getBindingToDomMappingService().toDataDom(prefix); assertNotNull(serialized); assertNotNull(serialized.getFirstSimpleByName(Prefix.QNAME)); assertEquals(PREFIX_STRING, serialized.getFirstSimpleByName(Prefix.QNAME).getValue()); - + Prefix deserialized = (Prefix) testContext.getBindingToDomMappingService().dataObjectFromDataDom(Prefix.class, serialized); assertNotNull(deserialized); assertNotNull(deserialized.getPrefix()); diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarListener.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarListener.java index f7c19ba1c3..6c133728b6 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarListener.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/BarListener.java @@ -12,7 +12,7 @@ import org.opendaylight.yangtools.yang.binding.NotificationListener; public interface BarListener extends NotificationListener { void onBarUpdate(BarUpdate notification); - + void onFlowDelete(FlowDelete notification); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java index 3b872d0149..cb8020e3fd 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooListener.java @@ -12,5 +12,5 @@ import org.opendaylight.yangtools.yang.binding.NotificationListener; public interface FooListener extends NotificationListener { void onFooUpdate(FooUpdate notification); - + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java index e844809662..2bd211995d 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java @@ -13,11 +13,11 @@ import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.common.RpcResult; public interface FooService extends RpcService { - + Future> foo(); - + Future> simple(SimpleInput obj); - + Future> inheritedContext(InheritedContextInput obj); } diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/RpcRegistrationNullPointer.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/RpcRegistrationNullPointer.java index 23ae4cd532..b54461c7c1 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/RpcRegistrationNullPointer.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/bugfix/RpcRegistrationNullPointer.java @@ -9,7 +9,7 @@ package org.opendaylight.controller.sal.binding.test.bugfix; public class RpcRegistrationNullPointer { - - - + + + } diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java index 1480f0c610..6d0226849f 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/BrokerIntegrationTest.java @@ -78,14 +78,14 @@ public class BrokerIntegrationTest extends AbstractDataServiceTest { /** * We create transaction no 2 - * + * */ DataModificationTransaction removalTransaction = baDataService.beginTransaction(); assertNotNull(transaction); /** * We remove node 1 - * + * */ removalTransaction.removeConfigurationData(node1.getValue()); diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java index cfdab37651..df287791ef 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java @@ -114,16 +114,16 @@ public class MessageCapturingFlowService implements SalFlowService, AutoCloseabl registration.unregisterPath(context, path); return this; } - + public static MessageCapturingFlowService create() { return new MessageCapturingFlowService(); } - + public static MessageCapturingFlowService create(RpcProviderRegistry registry) { MessageCapturingFlowService ret = new MessageCapturingFlowService(); ret.registerTo(registry); return ret; } - - + + } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/RegistrationListener.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/RegistrationListener.java index b4f51f5771..f088c0a0bd 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/RegistrationListener.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/RegistrationListener.java @@ -14,6 +14,6 @@ import org.opendaylight.yangtools.concepts.Registration; public interface RegistrationListener> extends EventListener { void onRegister(T registration); - + void onUnregister(T registration); } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java index 1d1d9101ec..7744f71888 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncReadTransaction.java @@ -7,8 +7,6 @@ */ package org.opendaylight.controller.md.sal.common.api.data; -import java.util.concurrent.Future; - import org.opendaylight.yangtools.concepts.Path; import com.google.common.base.Optional; diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java index 2ce43b5f7c..82c48d2ddb 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java @@ -110,8 +110,10 @@ public interface AsyncWriteTransaction

      , D> extends AsyncTrans * @param store Identifier of the store, where commit should occur. * @return Result of the Commit, containing success information or list of * encountered errors, if commit was not successful. The Future - * blocks until {@link TransactionStatus#COMMITED} or - * {@link TransactionStatus#FAILED} is reached. + * blocks until {@link TransactionStatus#COMMITED} is reached. + * Future will fail with {@link TransactionCommitFailedException} + * if Commit of this transaction failed. + * * @throws IllegalStateException if the transaction is not {@link TransactionStatus#NEW} */ public ListenableFuture> commit(); diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java index 7d78fd283d..da7efebdfe 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java @@ -16,8 +16,8 @@ import org.opendaylight.yangtools.concepts.Registration; public interface DataProvisionService

      , D> { public Registration> registerCommitHandler(P path, DataCommitHandler commitHandler); - - public ListenerRegistration>> + + public ListenerRegistration>> registerCommitHandlerListener(RegistrationListener> commitHandlerListener); } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java new file mode 100644 index 0000000000..f3c2e1093c --- /dev/null +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 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.md.sal.common.api.data; + +/** + * + * Failed commit of asynchronous transaction + * + * This exception is raised and returned when transaction commit + * failed. + * + */ +public class TransactionCommitFailedException extends Exception { + + private static final long serialVersionUID = -6138306275373237068L; + + protected TransactionCommitFailedException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public TransactionCommitFailedException(final String message, final Throwable cause) { + super(message, cause); + } + + public TransactionCommitFailedException(final String message) { + super(message); + } + +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/notify/NotificationPublishService.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/notify/NotificationPublishService.java index 6a906c5b88..f5f03a106b 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/notify/NotificationPublishService.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/notify/NotificationPublishService.java @@ -12,6 +12,6 @@ import java.util.concurrent.ExecutorService; public interface NotificationPublishService { void publish(N notification); - + void publish(N notification,ExecutorService executor); } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/MutableRoutingTable.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/MutableRoutingTable.java index f99c13ecf5..0ecb2c5768 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/MutableRoutingTable.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/MutableRoutingTable.java @@ -11,7 +11,7 @@ import org.opendaylight.yangtools.concepts.Mutable; import org.opendaylight.yangtools.concepts.Path; public interface MutableRoutingTable, T> extends RoutingTable, Mutable { - + void setDefaultRoute(T target); void updateRoute(P path,T target); void removeRoute(P path); diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Route.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Route.java index fbf735fa75..4bfb30f828 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Route.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/Route.java @@ -12,6 +12,6 @@ import org.opendaylight.yangtools.concepts.Immutable; public interface Route extends Immutable { C getType(); - + P getPath(); } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RoutingTable.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RoutingTable.java index 4402f69a5f..9e72b68cd6 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RoutingTable.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RoutingTable.java @@ -14,10 +14,10 @@ import org.opendaylight.yangtools.concepts.Path; public interface RoutingTable, T> { C getIdentifier(); - + T getDefaultRoute(); - + Map getRoutes(); - + T getRoute(P path); } diff --git a/opendaylight/md-sal/sal-common-impl/pom.xml b/opendaylight/md-sal/sal-common-impl/pom.xml index 9fd9bc8042..6b387b5a61 100644 --- a/opendaylight/md-sal/sal-common-impl/pom.xml +++ b/opendaylight/md-sal/sal-common-impl/pom.xml @@ -14,10 +14,6 @@ com.google.guava guava - - org.eclipse.xtend - org.eclipse.xtend.lib - org.opendaylight.controller sal-common-api @@ -58,10 +54,6 @@ - - org.eclipse.xtend - xtend-maven-plugin - diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/AbstractDataReadRouter.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/AbstractDataReadRouter.java index 4d395267dd..ee9af6cb80 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/AbstractDataReadRouter.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/AbstractDataReadRouter.java @@ -24,7 +24,7 @@ import com.google.common.collect.Multimaps; /** * Base abstract implementation of DataReadRouter, which performs * a read operation on multiple data readers and then merges result. - * + * * @param

      * @param */ @@ -50,7 +50,7 @@ public abstract class AbstractDataReadRouter

      , D> implements Da /** * Merges data readed by reader instances from specified path - * + * * @param path Path on which read was performed * @param data Data which was returned by read operation. * @return Merged result. @@ -59,11 +59,11 @@ public abstract class AbstractDataReadRouter

      , D> implements Da /** * Returns a function which performs configuration read for supplied path - * + * * @param path * @return function which performs configuration read for supplied path */ - + private Function, D> configurationRead(final P path) { return new Function, D>() { @Override @@ -75,7 +75,7 @@ public abstract class AbstractDataReadRouter

      , D> implements Da /** * Returns a function which performs operational read for supplied path - * + * * @param path * @return function which performs operational read for supplied path */ @@ -92,10 +92,10 @@ public abstract class AbstractDataReadRouter

      , D> implements Da /** * Register's a reader for operational data. - * + * * @param path Path which is served by this reader * @param reader Reader instance which is responsible for reading particular subpath. - * @return + * @return */ public Registration> registerOperationalReader(P path, DataReader reader) { OperationalDataReaderRegistration ret = new OperationalDataReaderRegistration<>(path, reader); @@ -142,15 +142,15 @@ public abstract class AbstractDataReadRouter

      , D> implements Da } private Predicate>> affects(final P path) { - + return new Predicate>>() { - + @Override public boolean apply(Entry> input) { final P key = input.getKey(); return key.contains(path) || ((P) path).contains(key); } - + }; } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java index 691c303688..c86aec96d1 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java @@ -24,9 +24,9 @@ public class DataChangeEventImpl

      , D> implements DataChangeEven private final D updatedOperationalSubtree; private final D updatedConfigurationSubtree; - - - + + + public DataChangeEventImpl(DataChange dataChange, D originalConfigurationSubtree, D originalOperationalSubtree, D updatedOperationalSubtree, D updatedConfigurationSubtree) { super(); diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java index d904427502..f35d6dc6af 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java @@ -28,24 +28,24 @@ public class InitialDataChangeEventImpl

      ,D> implements DataChan updatedConfigurationData = Collections.emptyMap(); updatedOperationalData = Collections.emptyMap(); } - + public InitialDataChangeEventImpl(D configTree, D operTree, Map updatedCfgData, Map updatedOperData) { updatedConfigurationTree = configTree; updatedOperationalTree = operTree; updatedConfigurationData = updatedCfgData; updatedOperationalData = updatedOperData; } - + @Override public Map getCreatedConfigurationData() { return Collections.emptyMap(); } - + @Override public Map getCreatedOperationalData() { return Collections.emptyMap(); } - + @Override public Map getOriginalConfigurationData() { return Collections.emptyMap(); @@ -66,7 +66,7 @@ public class InitialDataChangeEventImpl

      ,D> implements DataChan public Map getUpdatedConfigurationData() { return updatedConfigurationData; } - + @Override public D getUpdatedConfigurationSubtree() { return updatedConfigurationTree; @@ -75,21 +75,21 @@ public class InitialDataChangeEventImpl

      ,D> implements DataChan public D getUpdatedOperationalSubtree() { return updatedOperationalTree; } - + @Override public D getOriginalConfigurationSubtree() { return updatedConfigurationTree; } - + @Override public D getOriginalOperationalSubtree() { return updatedOperationalTree; } - + @Override public Map getUpdatedOperationalData() { return updatedOperationalData; } - + } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationException.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationException.java index f7a15b614e..daecfdb59b 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationException.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/compat/DataNormalizationException.java @@ -8,13 +8,13 @@ package org.opendaylight.controller.md.sal.common.impl.util.compat; public class DataNormalizationException extends Exception { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - public DataNormalizationException(String message) { - super(message); - } + public DataNormalizationException(String message) { + super(message); + } - public DataNormalizationException(String message, Throwable cause) { - super(message, cause); - } + public DataNormalizationException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/CommitHandlerTransactions.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/CommitHandlerTransactions.java index 5d73b1eefb..1af7ccc79a 100644 --- a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/CommitHandlerTransactions.java +++ b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/CommitHandlerTransactions.java @@ -18,7 +18,7 @@ import org.opendaylight.yangtools.yang.common.RpcResult; public class CommitHandlerTransactions { private static class AllwaysSuccessfulTransaction

      ,D> implements DataCommitTransaction { - + private final DataModification modification; public AllwaysSuccessfulTransaction(DataModification modification) { @@ -32,13 +32,13 @@ public class CommitHandlerTransactions { public RpcResult finish() throws IllegalStateException { return Rpcs.getRpcResult(true, null, Collections.emptyList()); } - + @Override public DataModification getModification() { return modification; } } - + public static final

      ,D> AllwaysSuccessfulTransaction allwaysSuccessfulTransaction(DataModification modification) { return new AllwaysSuccessfulTransaction<>(modification); } diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/RpcErrors.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/RpcErrors.java index 86dcba9596..4d41249b4d 100644 --- a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/RpcErrors.java +++ b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/RpcErrors.java @@ -16,20 +16,20 @@ import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; * */ public class RpcErrors { - + /** * @param applicationTag * @param tag * @param info * @param severity * @param message - * @param errorType - * @param cause + * @param errorType + * @param cause * @return {@link RpcError} implementation */ public static RpcError getRpcError(String applicationTag, String tag, String info, ErrorSeverity severity, String message, ErrorType errorType, Throwable cause) { - RpcErrorTO ret = new RpcErrorTO(applicationTag, tag, info, severity, message, + RpcErrorTO ret = new RpcErrorTO(applicationTag, tag, info, severity, message, errorType, cause); return ret; } @@ -94,7 +94,7 @@ public class RpcErrors { public Throwable getCause() { return cause; } - + @Override public ErrorType getErrorType() { return errorType; diff --git a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalPropertyClassUtils.java b/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalPropertyClassUtils.java index ff9f037f5a..3894fbe200 100644 --- a/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalPropertyClassUtils.java +++ b/opendaylight/md-sal/sal-compability/src/main/java/org/opendaylight/controller/sal/compability/ToSalPropertyClassUtils.java @@ -7,43 +7,42 @@ */ package org.opendaylight.controller.sal.compability; -import org.opendaylight.controller.sal.core.*; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortFeatures; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; public class ToSalPropertyClassUtils { public static Bandwidth salAdvertisedBandwidthFrom(NodeConnector nodeConnector) { - FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); PortFeatures portFeatures = flowCapNodeConn.getAdvertisedFeatures(); return new AdvertisedBandwidth(resolveBandwidth(portFeatures)); } public static Bandwidth salPeerBandwidthFrom(NodeConnector nodeConnector) { - FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); PortFeatures portFeatures = flowCapNodeConn.getPeerFeatures(); return new PeerBandwidth(resolveBandwidth(portFeatures)); } public static Bandwidth salSupportedBandwidthFrom(NodeConnector nodeConnector) { - FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); PortFeatures portFeatures = flowCapNodeConn.getSupported(); return new SupportedBandwidth(resolveBandwidth(portFeatures)); } public static MacAddress salMacAddressFrom(NodeConnector nodeConnector) { - FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); String hwAddress = flowCapNodeConn.getHardwareAddress().getValue(); - return new MacAddress(bytesFrom(hwAddress)); + return new MacAddress(bytesFrom(hwAddress)); } - - + + public static Name salNameFrom(NodeConnector nodeConnector) { - FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); + FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); return new Name(flowCapNodeConn.getName()); } - - + + private static byte[] bytesFrom(String hwAddress) { String[] mac = hwAddress.split(":"); diff --git a/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/BindingAwareRpcRouter.java b/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/BindingAwareRpcRouter.java index a1d573db08..cf59eb4a90 100644 --- a/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/BindingAwareRpcRouter.java +++ b/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/BindingAwareRpcRouter.java @@ -53,8 +53,8 @@ public interface BindingAwareRpcRouter extends RpcRouter> receivedRequest(RpcRequest input) { - + return mdSalRouter.sendRpc(input); } diff --git a/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/Connector.java b/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/Connector.java index efa24d099f..519d21bf4f 100644 --- a/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/Connector.java +++ b/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/Connector.java @@ -15,11 +15,11 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; public interface Connector extends RpcImplementation, NotificationListener { - - + + Set getConfigurationPrefixes(); Set getRuntimePrefixes(); - + void registerListener(ConnectorListener listener); void unregisterListener(ConnectorListener listener); } diff --git a/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/RpcRouter.java b/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/RpcRouter.java index f161644f6d..fa4c8048fa 100644 --- a/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/RpcRouter.java +++ b/opendaylight/md-sal/sal-connector-api/src/main/java/org/opendaylight/controller/sal/connector/api/RpcRouter.java @@ -10,7 +10,7 @@ package org.opendaylight.controller.sal.connector.api; import java.util.concurrent.Future; /** - * + * * @author ttkacik * * @param Routing Context Identifier @@ -20,14 +20,14 @@ import java.util.concurrent.Future; */ public interface RpcRouter { - - + + Future> sendRpc(RpcRequest input); - - + + /** - * - * @author + * + * @author * * @param Routing Context Identifier * @param Route Type @@ -39,14 +39,14 @@ public interface RpcRouter { RouteIdentifier getRoutingInformation(); D getPayload(); } - + public interface RouteIdentifier { - + C getContext(); // defines a routing table (e.g. NodeContext) T getType(); // rpc type R getRoute(); // e.g. (node identity) } - + public interface RpcReply { D getPayload(); } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractConsumer.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractConsumer.java index 99a38ca43a..c14d5a679c 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractConsumer.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/AbstractConsumer.java @@ -18,9 +18,9 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; public abstract class AbstractConsumer implements Consumer, BundleActivator,ServiceTrackerCustomizer { - - - + + + private BundleContext context; private ServiceTracker tracker; private Broker broker; @@ -54,7 +54,7 @@ public abstract class AbstractConsumer implements Consumer, BundleActivator,Serv return Collections.emptySet(); } - + @Override public Broker addingService(ServiceReference reference) { if(broker == null) { @@ -62,15 +62,15 @@ public abstract class AbstractConsumer implements Consumer, BundleActivator,Serv broker.registerConsumer(this, context); return broker; } - + return null; } - + @Override public void modifiedService(ServiceReference reference, Broker service) { // NOOP } - + @Override public void removedService(ServiceReference reference, Broker service) { stopImpl(context); diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Broker.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Broker.java index 72df8cb553..724cbe75f4 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Broker.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Broker.java @@ -11,10 +11,6 @@ import java.util.Set; import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.common.api.routing.RoutedRegistration; -import org.opendaylight.controller.sal.core.api.data.DataBrokerService; -import org.opendaylight.controller.sal.core.api.data.DataProviderService; -import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService; -import org.opendaylight.controller.sal.core.api.notify.NotificationService; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.ObjectRegistration; import org.opendaylight.yangtools.yang.common.QName; @@ -39,11 +35,11 @@ import org.osgi.framework.BundleContext; *

    • RPC Invocation - see {@link ConsumerSession#rpc(QName, CompositeNode)}, * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} and * {@link RpcImplementation} - *
    • Notification Service - see {@link NotificationService} and - * {@link NotificationPublishService} + *
    • Notification Service - see {@link org.opendaylight.controller.sal.core.api.notify.NotificationService} and + * {@link org.opendaylight.controller.sal.core.api.notify.NotificationPublishService} *
    • Functionality and Data model - *
    • Data Store access and modification - see {@link DataBrokerService} and - * {@link DataProviderService} + *
    • Data Store access and modification - see {@link org.opendaylight.controller.sal.core.api.data.DataBrokerService} and + * {@link org.opendaylight.controller.sal.core.api.data.DataProviderService} *
    * * The services are exposed via session. @@ -227,7 +223,7 @@ public interface Broker { * functionality of the provider from the system. */ @Override - public void close(); + void close(); @Override boolean isClosed(); @@ -244,7 +240,6 @@ public interface Broker { void close(); } - public interface RoutedRpcRegistration extends RpcRegistration, - RoutedRegistration { + public interface RoutedRpcRegistration extends RpcRegistration, RoutedRegistration { } } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/BrokerService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/BrokerService.java index c1518b1ec6..7c00c9c2bb 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/BrokerService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/BrokerService.java @@ -7,31 +7,29 @@ */ package org.opendaylight.controller.sal.core.api; -import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; - /** - * + * * Session-specific instance of the broker functionality. - * + * *

    * BrokerService is marker interface for infrastructure services provided by the * SAL. These services are session-specific, each {@link Provider} and * {@link Consumer} usually has own instance of the service with it's own * context. - * + * *

    * The consumer's (or provider's) instance of specific service could be obtained - * by invoking {@link ConsumerSession#getService(Class)} method on session + * by invoking {@link org.opendaylight.controller.sal.core.api.Broker.ConsumerSession#getService(Class)} method on session * assigned to the consumer. - * + * *

    * {@link BrokerService} and {@link Provider} may seem similar, but provider * provides YANG model-based functionality and {@link BrokerService} exposes the * necessary supporting functionality to implement specific functionality of * YANG and to reuse it in the development of {@link Consumer}s and * {@link Provider}s. - * - * + * + * */ public interface BrokerService { diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Consumer.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Consumer.java index 3127df521f..a693cd6c49 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Consumer.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Consumer.java @@ -12,26 +12,26 @@ import java.util.Collection; import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; /** - * + * * Defines the component of controller and supplies additional metadata. A * component of the controller or application supplies a concrete implementation * of this interface. - * + * * A user-implemented component (application) which facilitates the SAL and SAL * services to access infrastructure services or providers' functionality. - * - * + * + * */ public interface Consumer { /** * Callback signaling initialization of the consumer session to the SAL. - * + * * The consumer MUST use the session for all communication with SAL or * retrieving SAL infrastructure services. - * + * * This method is invoked by {@link Broker#registerConsumer(Consumer)} - * + * * @param session * Unique session between consumer and SAL. */ @@ -40,9 +40,9 @@ public interface Consumer { /** * Get a set of implementations of consumer functionality to be registered * into system during the consumer registration to the SAL. - * + * * This method is invoked by {@link Broker#registerConsumer(Consumer)}. - * + * * @return Set of consumer functionality. */ public Collection getConsumerFunctionality(); @@ -50,8 +50,8 @@ public interface Consumer { /** * The marker interface for the interfaces describing the consumer * functionality contracts. - * - * + * + * */ public interface ConsumerFunctionality { diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Provider.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Provider.java index fef8618b2c..0a57d12579 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Provider.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/Provider.java @@ -12,30 +12,30 @@ import java.util.Collection; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; /** - * + * * Defines the component of controller and supplies additional metadata. A * component of the controller or application supplies a concrete implementation * of this interface. - * + * *

    * A user-implemented component (application) which facilitates the SAL and SAL * services to access infrastructure services and to provide functionality to * {@link Consumer}s and other providers. - * - * + * + * */ public interface Provider { /** * Callback signaling initialization of the provider session to the SAL. - * + * *

    * The provider MUST use the session for all communication with SAL * or retrieving SAL infrastructure services. - * + * *

    * This method is invoked by {@link Broker#registerConsumer(Consumer)} - * + * * @param session * Unique session between provider and SAL. */ @@ -44,24 +44,24 @@ public interface Provider { /** * Gets a set of implementations of provider functionality to be registered * into system during the provider registration to the SAL. - * + * *

    * This method is invoked by {@link Broker#registerProvider(Provider)} to * learn the initial provided functionality - * + * * @return Set of provider's functionality. */ public Collection getProviderFunctionality(); /** * Functionality provided by the {@link Provider} - * + * *

    * Marker interface used to mark the interfaces describing specific * functionality which could be exposed by providers to other components. - * + * - * + * */ public interface ProviderFunctionality { diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcConsumptionRegistry.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcConsumptionRegistry.java index 665a50f9ca..da592e9b22 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcConsumptionRegistry.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcConsumptionRegistry.java @@ -16,7 +16,7 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; public interface RpcConsumptionRegistry { /** * Sends an RPC to other components registered to the broker. - * + * * @see RpcImplementation * @param rpc * Name of RPC diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java index 38b33d5d2a..d14910055b 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcImplementation.java @@ -9,8 +9,6 @@ package org.opendaylight.controller.sal.core.api; import java.util.Set; -import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; -import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; @@ -29,14 +27,14 @@ import com.google.common.util.concurrent.ListenableFuture; * {@link Provider#getProviderFunctionality()} *

  • passing an instance of implementation and {@link QName} of rpc as * arguments to the - * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} + * {@link org.opendaylight.controller.sal.core.api.Broker.ProviderSession#addRpcImplementation(QName, RpcImplementation)} * * * The simplified process of the invocation of rpc is following: * *
      *
    1. {@link Consumer} invokes - * {@link ConsumerSession#rpc(QName, CompositeNode)} + * {@link org.opendaylight.controller.sal.core.api.Broker.ConsumerSession#rpc(QName, CompositeNode)} *
    2. {@link Broker} finds registered {@link RpcImplementation}s *
    3. {@link Broker} invokes * {@link RpcImplementation#invokeRpc(QName, CompositeNode)} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java index f43dcd6b43..a22a6ef75e 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java @@ -18,17 +18,17 @@ public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, /** * Registers an implementation of the rpc. - * + * *

      * The registered rpc functionality will be available to all other * consumers and providers registered to the broker, which are aware of * the {@link QName} assigned to the rpc. - * + * *

      * There is no assumption that rpc type is in the set returned by * invoking {@link RpcImplementation#getSupportedRpcs()}. This allows * for dynamic rpc implementations. - * + * * @param rpcType * Name of Rpc * @param implementation @@ -38,7 +38,7 @@ public interface RpcProvisionRegistry extends RpcImplementation, BrokerService, */ RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException; - + ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener); RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation); diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java index 2ba5c4ba20..a0be886b24 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java @@ -12,8 +12,8 @@ import java.util.EventListener; import org.opendaylight.yangtools.yang.common.QName; public interface RpcRegistrationListener extends EventListener { - + public void onRpcImplementationAdded(QName name); - + public void onRpcImplementationRemoved(QName name); } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRoutingContext.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRoutingContext.java index 64195303e8..66d290f531 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRoutingContext.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRoutingContext.java @@ -15,20 +15,20 @@ import org.opendaylight.yangtools.yang.common.QName; public class RpcRoutingContext implements Immutable, Serializable { /** - * + * */ private static final long serialVersionUID = -9079324728075883325L; - + private final QName context; private final QName rpc; - - + + private RpcRoutingContext(QName context, QName rpc) { super(); this.context = context; this.rpc = rpc; } - + public static final RpcRoutingContext create(QName context, QName rpc) { return new RpcRoutingContext(context, rpc); } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java index 2d5f4b2a55..266b6976af 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java @@ -18,12 +18,12 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; /** * DataBrokerService provides unified access to the data stores available in the * system. - * - * + * + * * @see DataProviderService - * + * */ -public interface DataBrokerService extends +public interface DataBrokerService extends BrokerService, // DataReader, // DataModificationTransactionFactory, // diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java index 20fa29dceb..0538660fd7 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java @@ -15,14 +15,14 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.controller.md.sal.common.api.data.DataReader;; -public interface DataProviderService extends +public interface DataProviderService extends DataBrokerService, // DataProvisionService { /** * Adds {@link DataValidator} for specified Data Store - * + * * @param store * Data Store * @param validator @@ -32,7 +32,7 @@ public interface DataProviderService extends /** * Removes {@link DataValidator} from specified Data Store - * + * * @param store * @param validator * Validator @@ -42,7 +42,7 @@ public interface DataProviderService extends /** * Adds {@link DataRefresher} for specified data store - * + * * @param store * @param refresher */ @@ -50,22 +50,22 @@ public interface DataProviderService extends /** * Removes {@link DataRefresher} from specified data store - * + * * @param store * @param refresher */ void removeRefresher(DataStoreIdentifier store, DataRefresher refresher); - + Registration> registerConfigurationReader(InstanceIdentifier path, DataReader reader); Registration> registerOperationalReader(InstanceIdentifier path, DataReader reader); - + public interface DataRefresher extends Provider.ProviderFunctionality { /** * Fired when some component explicitly requested the data refresh. - * + * * The provider which exposed the {@link DataRefresher} should republish * its provided data by editing the data in all affected data stores. */ diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java index 8bdd061871..58ffb38365 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java @@ -15,11 +15,11 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; public interface DataStore extends // DataReader, DataCommitHandler { - - + + Iterable getStoredConfigurationPaths(); Iterable getStoredOperationalPaths(); - + boolean containsConfigurationPath(InstanceIdentifier path); boolean containsOperationalPath(InstanceIdentifier path); diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataValidator.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataValidator.java index 2bcb84be34..286770b048 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataValidator.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataValidator.java @@ -17,7 +17,7 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; /** * {@link Provider}-supplied Validator of the data. - * + * *

      * The registration could be done by : *

        @@ -27,25 +27,25 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; * as arguments to the * {@link DataProviderService#addValidator(DataStoreIdentifier, DataValidator)} *
      - * + * **/ public interface DataValidator extends Provider.ProviderFunctionality { /** * A set of Data Stores supported by implementation. - * + * * The set of {@link DataStoreIdentifier}s which identifies target data * stores which are supported by this implementation. This set is used, when * {@link Provider} is registered to the SAL, to register and expose the * validation functionality to affected data stores. - * + * * @return Set of Data Store identifiers */ Set getSupportedDataStores(); /** * Performs validation on supplied data. - * + * * @param toValidate * Data to validate * @return Validation result. The diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationListener.java index f87fee5bce..7dc8cb36c5 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationListener.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationListener.java @@ -21,21 +21,21 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; public interface NotificationListener extends Consumer.ConsumerFunctionality, EventListener { /** * A set of notification types supported by listeners. - * + * * The set of notification {@link QName}s which are supported by this * listener. This set is used, when {@link Consumer} is registered to the * SAL, to automatically register the listener. - * + * * @return Set of QNames identifying supported notifications. */ Set getSupportedNotifications(); /** * Fired when the notification occurs. - * + * * The type of the notification could be learned by * QName type = notification.getNodeType(); - * + * * @param notification * Notification content */ diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationPublishService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationPublishService.java index aa22b90f65..f1156c3964 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationPublishService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationPublishService.java @@ -7,32 +7,30 @@ */ package org.opendaylight.controller.sal.core.api.notify; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.yangtools.yang.data.api.CompositeNode; /** * Notification Publishing Service - * + * * The simplified process of the notification publishing is following: - * + * *
        - *
      1. {@link Provider} invokes {@link #sendNotification(CompositeNode)} - *
      2. {@link Broker} finds {@link NotificationListener}s which subscribed for + *
      3. {@link org.opendaylight.controller.sal.core.api.Provider} invokes {@link #sendNotification(CompositeNode)} + *
      4. {@link org.opendaylight.controller.sal.core.api.Broker} finds {@link NotificationListener}s which subscribed for * the notification type. - * - *
      5. For each subscriber {@link Broker} invokes + * + *
      6. For each subscriber {@link org.opendaylight.controller.sal.core.api.Broker} invokes * {@link NotificationListener#onNotification(CompositeNode)} *
      */ public interface NotificationPublishService extends NotificationService { /** * Publishes a notification. - * + * * Notification type is determined by the * {@link CompositeNode#getNodeType()} of the * notification parameter. - * + * * @param notification * Notification to publish */ diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationService.java index f654ca9ad6..1d67ca0824 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/notify/NotificationService.java @@ -8,9 +8,6 @@ package org.opendaylight.controller.sal.core.api.notify; import org.opendaylight.controller.sal.core.api.BrokerService; -import org.opendaylight.controller.sal.core.api.Provider; -import org.opendaylight.controller.sal.core.api.RpcImplementation; -import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.common.QName; @@ -18,26 +15,26 @@ import org.opendaylight.yangtools.yang.common.QName; /** * NotificationService provides access to the notification functionality of the * SAL. - * + * * NotificationService allows for consumption of notifications by registering * implementations of NotificationListener. - * + * * The registration of notification listeners could be done by: *
        *
      • returning an instance of implementation in the return value of - * {@link Provider#getProviderFunctionality()} - *
      • passing an instance of implementation and {@link QName} of rpc as an - * arguments to the - * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} + * {@link org.opendaylight.controller.sal.core.api.Provider#getProviderFunctionality()} + *
      • passing an instance of implementation and {@link QName} of an RPC as an + * argument to + * {@link org.opendaylight.controller.sal.core.api.Broker.ProviderSession#addRpcImplementation(QName, org.opendaylight.controller.sal.core.api.RpcImplementation)} *
      - * - * + * + * */ public interface NotificationService extends BrokerService { /** * Registers a notification listener for supplied notification type. - * + * * @param notification * @param listener */ diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/statistics/DomBrokerRuntimeMXBeanImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/statistics/DomBrokerRuntimeMXBeanImpl.java index 692a0babdf..8e2a11184c 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/statistics/DomBrokerRuntimeMXBeanImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/statistics/DomBrokerRuntimeMXBeanImpl.java @@ -14,13 +14,13 @@ import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl; public class DomBrokerRuntimeMXBeanImpl implements DomBrokerImplRuntimeMXBean { - + private final DataBrokerImpl dataService; private final Transactions transactions = new Transactions(); private final Data data = new Data(); - + public DomBrokerRuntimeMXBeanImpl(DataBrokerImpl dataService) { - this.dataService = dataService; + this.dataService = dataService; } public Transactions getTransactions() { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java index 2495146aa6..10b838a2c6 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java @@ -13,6 +13,8 @@ import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicLong; +import javax.annotation.concurrent.GuardedBy; + import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype; @@ -41,6 +43,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; @@ -48,13 +51,14 @@ import com.google.common.util.concurrent.ListeningExecutorService; /** * In-memory DOM Data Store * - * Implementation of {@link DOMStore} which uses {@link DataTree} - * and other classes such as {@link SnapshotBackedWriteTransaction}. + * Implementation of {@link DOMStore} which uses {@link DataTree} and other + * classes such as {@link SnapshotBackedWriteTransaction}. * {@link SnapshotBackedReadTransaction} and {@link ResolveDataChangeEventsTask} * to implement {@link DOMStore} contract. * */ -public class InMemoryDOMDataStore implements DOMStore, Identifiable, SchemaContextListener, TransactionReadyPrototype { +public class InMemoryDOMDataStore implements DOMStore, Identifiable, SchemaContextListener, + TransactionReadyPrototype { private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class); private final DataTree dataTree = InMemoryDataTreeFactory.getInstance().create(); private final ListenerTree listenerTree = ListenerTree.create(); @@ -148,14 +152,22 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch private class DOMStoreTransactionChainImpl implements DOMStoreTransactionChain, TransactionReadyPrototype { - private SnapshotBackedWriteTransaction previousOutstandingTx; + @GuardedBy("this") + private SnapshotBackedWriteTransaction latestOutstandingTx; + + private boolean chainFailed = false; + + private void checkFailed() { + Preconditions.checkState(!chainFailed, "Transaction chain is failed."); + } @Override public synchronized DOMStoreReadTransaction newReadOnlyTransaction() { final DataTreeSnapshot snapshot; - if(previousOutstandingTx != null) { - checkState(previousOutstandingTx.isReady(), "Previous transaction in chain must be ready."); - snapshot = previousOutstandingTx.getMutatedView(); + checkFailed(); + if (latestOutstandingTx != null) { + checkState(latestOutstandingTx.isReady(), "Previous transaction in chain must be ready."); + snapshot = latestOutstandingTx.getMutatedView(); } else { snapshot = dataTree.takeSnapshot(); } @@ -165,42 +177,112 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch @Override public synchronized DOMStoreReadWriteTransaction newReadWriteTransaction() { final DataTreeSnapshot snapshot; - if(previousOutstandingTx != null) { - checkState(previousOutstandingTx.isReady(), "Previous transaction in chain must be ready."); - snapshot = previousOutstandingTx.getMutatedView(); + checkFailed(); + if (latestOutstandingTx != null) { + checkState(latestOutstandingTx.isReady(), "Previous transaction in chain must be ready."); + snapshot = latestOutstandingTx.getMutatedView(); } else { - snapshot = dataTree.takeSnapshot().newModification(); + snapshot = dataTree.takeSnapshot(); } - SnapshotBackedReadWriteTransaction ret = new SnapshotBackedReadWriteTransaction(nextIdentifier(), snapshot,this); + final SnapshotBackedReadWriteTransaction ret = new SnapshotBackedReadWriteTransaction(nextIdentifier(), + snapshot, this); + latestOutstandingTx = ret; return ret; } @Override public synchronized DOMStoreWriteTransaction newWriteOnlyTransaction() { final DataTreeSnapshot snapshot; - if(previousOutstandingTx != null) { - checkState(previousOutstandingTx.isReady(), "Previous transaction in chain must be ready."); - snapshot = previousOutstandingTx.getMutatedView(); + checkFailed(); + if (latestOutstandingTx != null) { + checkState(latestOutstandingTx.isReady(), "Previous transaction in chain must be ready."); + snapshot = latestOutstandingTx.getMutatedView(); } else { - snapshot = dataTree.takeSnapshot().newModification(); + snapshot = dataTree.takeSnapshot(); } - SnapshotBackedWriteTransaction ret =new SnapshotBackedWriteTransaction(nextIdentifier(), snapshot,this); + final SnapshotBackedWriteTransaction ret = new SnapshotBackedWriteTransaction(nextIdentifier(), snapshot, + this); + latestOutstandingTx = ret; return ret; } @Override public DOMStoreThreePhaseCommitCohort ready(final SnapshotBackedWriteTransaction tx) { DOMStoreThreePhaseCommitCohort storeCohort = InMemoryDOMDataStore.this.ready(tx); - // FIXME: We probably want to add Transaction Chain cohort - return storeCohort; + return new ChainedTransactionCommitImpl(tx, storeCohort, this); } @Override public void close() { - // TODO Auto-generated method stub } + protected synchronized void onTransactionFailed(final SnapshotBackedWriteTransaction transaction, + final Throwable t) { + chainFailed = true; + + } + + public synchronized void onTransactionCommited(final SnapshotBackedWriteTransaction transaction) { + // If commited transaction is latestOutstandingTx we clear + // latestOutstandingTx + // field in order to base new transactions on Datastore Data Tree + // directly. + if (transaction.equals(latestOutstandingTx)) { + latestOutstandingTx = null; + } + } + + } + + private static class ChainedTransactionCommitImpl implements DOMStoreThreePhaseCommitCohort { + + private final SnapshotBackedWriteTransaction transaction; + private final DOMStoreThreePhaseCommitCohort delegate; + + private final DOMStoreTransactionChainImpl txChain; + + protected ChainedTransactionCommitImpl(final SnapshotBackedWriteTransaction transaction, + final DOMStoreThreePhaseCommitCohort delegate, final DOMStoreTransactionChainImpl txChain) { + super(); + this.transaction = transaction; + this.delegate = delegate; + this.txChain = txChain; + } + + @Override + public ListenableFuture canCommit() { + return delegate.canCommit(); + } + + @Override + public ListenableFuture preCommit() { + return delegate.preCommit(); + } + + @Override + public ListenableFuture abort() { + return delegate.abort(); + } + + @Override + public ListenableFuture commit() { + ListenableFuture commitFuture = delegate.commit(); + Futures.addCallback(commitFuture, new FutureCallback() { + @Override + public void onFailure(final Throwable t) { + txChain.onTransactionFailed(transaction, t); + } + + @Override + public void onSuccess(final Void result) { + txChain.onTransactionCommited(transaction); + } + + }); + return commitFuture; + } + } private class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort { @@ -226,7 +308,8 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch LOG.debug("Store Transaction: {} can be committed", transaction.getIdentifier()); return true; } catch (DataPreconditionFailedException e) { - LOG.warn("Store Tx: {} Data Precondition failed for {}.",transaction.getIdentifier(),e.getPath(),e); + LOG.warn("Store Tx: {} Data Precondition failed for {}.", transaction.getIdentifier(), + e.getPath(), e); return false; } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java index 717fb11987..534ee64b8a 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java @@ -26,7 +26,7 @@ import com.google.common.base.Throwables; * Implementation of Write transaction which is backed by * {@link DataTreeSnapshot} and executed according to * {@link TransactionReadyPrototype}. - * + * */ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction implements DOMStoreWriteTransaction { @@ -37,7 +37,7 @@ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction impleme /** * Creates new write-only transaction. - * + * * @param identifier * transaction Identifier * @param snapshot @@ -140,19 +140,19 @@ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction impleme /** * Prototype implementation of * {@link #ready(SnapshotBackedWriteTransaction)} - * + * * This class is intended to be implemented by Transaction factories * responsible for allocation of {@link SnapshotBackedWriteTransaction} and * providing underlying logic for applying implementation. - * + * */ public static interface TransactionReadyPrototype { /** * Returns a commit coordinator associated with supplied transactions. - * + * * This call must not fail. - * + * * @param tx * Transaction on which ready was invoked. * @return DOMStoreThreePhaseCommitCohort associated with transaction diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeFactory.java index 7422c116ef..c6dd25c76b 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeFactory.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/DataTreeFactory.java @@ -11,10 +11,10 @@ package org.opendaylight.controller.md.sal.dom.store.impl.tree; * Factory interface for creating data trees. */ public interface DataTreeFactory { - /** - * Create a new data tree. - * - * @return A data tree instance. - */ - DataTree create(); + /** + * Create a new data tree. + * + * @return A data tree instance. + */ + DataTree create(); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/TreeNodeUtils.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/TreeNodeUtils.java index 99982d318c..fe98468b5c 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/TreeNodeUtils.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/TreeNodeUtils.java @@ -13,7 +13,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; @@ -23,7 +22,7 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; /** - * A set of utility methods for interacting with {@link TreeNode} objects. + * A set of utility methods for interacting with {@link org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode} objects. */ public final class TreeNodeUtils { private TreeNodeUtils() { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java index f7e95b84bd..39ff4f0aa0 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/data/InMemoryDataTreeModification.java @@ -12,6 +12,7 @@ import java.util.Map.Entry; import javax.annotation.concurrent.GuardedBy; import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType; import org.opendaylight.controller.md.sal.dom.store.impl.tree.TreeNodeUtils; import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; @@ -151,7 +152,27 @@ final class InMemoryDataTreeModification implements DataTreeModification { public synchronized DataTreeModification newModification() { Preconditions.checkState(sealed, "Attempted to chain on an unsealed modification"); - // FIXME: transaction chaining - throw new UnsupportedOperationException("Implement this as part of transaction chaining"); + if(rootNode.getType() == ModificationType.UNMODIFIED) { + return snapshot.newModification(); + } + + /* + * FIXME: Add advanced transaction chaining for modification of not rebased + * modification. + * + * Current computation of tempRoot may yeld incorrect subtree versions + * if there are multiple concurrent transactions, which may break + * versioning preconditions for modification of previously occured write, + * directly nested under parent node, since node version is derived from + * subtree version. + * + * For deeper nodes subtree version is derived from their respective metadata + * nodes, so this incorrect root subtree version is not affecting us. + */ + TreeNode originalSnapshotRoot = snapshot.getRootNode(); + Optional tempRoot = strategyTree.apply(rootNode, Optional.of(originalSnapshotRoot), originalSnapshotRoot.getSubtreeVersion().next()); + + InMemoryDataTreeSnapshot tempTree = new InMemoryDataTreeSnapshot(snapshot.getSchemaContext(), tempRoot.get(), strategyTree); + return tempTree.newModification(); } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.java index 7f834351d3..3291afa061 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.java @@ -1,6 +1,6 @@ /** * 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 diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java index ba3dcc8c86..69f518bb32 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java @@ -27,16 +27,16 @@ public class DataBrokerImpl extends AbstractDataBroker +public class DataTransactionImpl extends AbstractDataTransaction implements DataModificationTransaction { private final ListenerRegistry listeners = new ListenerRegistry(); - - - + + + public DataTransactionImpl(Object identifier,DataBrokerImpl dataBroker) { super(identifier,dataBroker); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java index a2c43d0c73..8fc6fe2295 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java @@ -229,7 +229,6 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable, Ro if (CONTEXT_REFERENCE.equals(extension.getNodeType())) { return Optional.fromNullable(extension.getQName()); } - ; } return Optional.absent(); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/AbstractBrokerServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/AbstractBrokerServiceProxy.java index cfaf481e72..853e3e391f 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/AbstractBrokerServiceProxy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/AbstractBrokerServiceProxy.java @@ -7,6 +7,9 @@ */ package org.opendaylight.controller.sal.dom.broker.osgi; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -14,14 +17,13 @@ import java.util.Set; import org.opendaylight.controller.sal.core.api.BrokerService; import org.opendaylight.yangtools.concepts.Registration; import org.osgi.framework.ServiceReference; -import static com.google.common.base.Preconditions.*; public abstract class AbstractBrokerServiceProxy implements AutoCloseable, BrokerService { private T delegate; private final ServiceReference reference; - public AbstractBrokerServiceProxy(ServiceReference ref, T delegate) { + public AbstractBrokerServiceProxy(final ServiceReference ref, final T delegate) { this.delegate = checkNotNull(delegate, "Delegate should not be null."); this.reference = checkNotNull(ref, "Reference should not be null."); } @@ -35,9 +37,9 @@ public abstract class AbstractBrokerServiceProxy implem return reference; } - private Set> registrations = Collections.synchronizedSet(new HashSet>()); + private final Set> registrations = Collections.synchronizedSet(new HashSet>()); - protected > R addRegistration(R registration) { + protected > R addRegistration(final R registration) { if (registration != null) { registrations.add(registration); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataBrokerServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataBrokerServiceProxy.java index 5839db46ca..30027ec929 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataBrokerServiceProxy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DataBrokerServiceProxy.java @@ -37,6 +37,6 @@ public class DataBrokerServiceProxy extends AbstractBrokerServiceProxy>> registerCommitHandlerListener( RegistrationListener> commitHandlerListener) { diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java index 6e44cba494..7193a53177 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/RpcProvisionRegistryProxy.java @@ -11,7 +11,12 @@ package org.opendaylight.controller.sal.dom.broker.osgi; import java.util.Set; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; -import org.opendaylight.controller.sal.core.api.*; +import org.opendaylight.controller.sal.core.api.Broker; +import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; +import org.opendaylight.controller.sal.core.api.RpcRoutingContext; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; @@ -21,35 +26,34 @@ import org.osgi.framework.ServiceReference; import com.google.common.util.concurrent.ListenableFuture; -public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy - implements RpcProvisionRegistry { +public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy implements RpcProvisionRegistry { - public RpcProvisionRegistryProxy(ServiceReference ref, RpcProvisionRegistry delegate) { + public RpcProvisionRegistryProxy(final ServiceReference ref, final RpcProvisionRegistry delegate) { super(ref, delegate); } @Override - public Broker.RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { + public Broker.RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation) throws IllegalArgumentException { return getDelegate().addRpcImplementation(rpcType, implementation); } @Override - public ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener) { + public ListenerRegistration addRpcRegistrationListener(final RpcRegistrationListener listener) { return getDelegate().addRpcRegistrationListener(listener); } @Override - public Broker.RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + public Broker.RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) { return getDelegate().addRoutedRpcImplementation(rpcType, implementation); } @Override - public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) { + public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) { getDelegate().setRoutedRpcDefaultDelegate(defaultImplementation); } @Override - public > ListenerRegistration registerRouteChangeListener(L listener) { + public > ListenerRegistration registerRouteChangeListener(final L listener) { return getDelegate().registerRouteChangeListener(listener); } @@ -59,7 +63,7 @@ public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy> invokeRpc(QName rpc, CompositeNode input) { + public ListenableFuture> invokeRpc(final QName rpc, final CompositeNode input) { return getDelegate().invokeRpc(rpc, input); } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/NotificationRouter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/NotificationRouter.java index 74923dd8b8..ebe95d6eb5 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/NotificationRouter.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/NotificationRouter.java @@ -18,7 +18,7 @@ public interface NotificationRouter { /** * Registers a notification listener for supplied notification type. - * + * * @param notification * @param listener */ diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangDataUtils.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangDataUtils.java index 8b78b83e2f..0444fad65c 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangDataUtils.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangDataUtils.java @@ -7,6 +7,8 @@ */ package org.opendaylight.controller.sal.dom.broker.util; +import static com.google.common.base.Preconditions.checkArgument; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -16,17 +18,13 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.SimpleNode; -import static com.google.common.base.Preconditions.*; - -public class YangDataUtils { +public final class YangDataUtils { - public YangDataUtils() { - // TODO Auto-generated constructor stub + private YangDataUtils() { + throw new UnsupportedOperationException("Utility class"); } - - - public static Map,CompositeNode> toIndexMap(List nodes,List keys) { + public static Map,CompositeNode> toIndexMap(final List nodes,final List keys) { ConcurrentHashMap,CompositeNode> ret = new ConcurrentHashMap<>(); for(CompositeNode node : nodes) { Map key = getKeyMap(node,keys); @@ -35,16 +33,14 @@ public class YangDataUtils { return ret; } - - - public static Map getKeyMap(CompositeNode node, List keys) { + public static Map getKeyMap(final CompositeNode node, final List keys) { Map map = new HashMap<>(); for(QName key : keys) { SimpleNode keyNode = node.getFirstSimpleByName(QName.create(node.getNodeType(), key.getLocalName())); checkArgument(keyNode != null,"Node must contains all keys."); Object value = keyNode.getValue(); map.put(key, value); - + } return map; } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangSchemaUtils.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangSchemaUtils.java index 7f6918f2a1..306cd34a69 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangSchemaUtils.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/YangSchemaUtils.java @@ -7,6 +7,8 @@ */ package org.opendaylight.controller.sal.dom.broker.util; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; import java.util.Iterator; import java.util.List; @@ -32,17 +34,15 @@ import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; import org.opendaylight.yangtools.yang.model.api.UsesNode; -import static com.google.common.base.Preconditions.*; - import com.google.common.base.Function; import com.google.common.collect.FluentIterable; -public class YangSchemaUtils { +public final class YangSchemaUtils { private static final Function QNAME_FROM_PATH_ARGUMENT = new Function(){ - + @Override - public QName apply(PathArgument input) { + public QName apply(final PathArgument input) { if(input == null) { return null; } @@ -50,29 +50,28 @@ public class YangSchemaUtils { } }; - private YangSchemaUtils() { + private YangSchemaUtils() { throw new UnsupportedOperationException("Utility class."); } - - - public static DataSchemaNode getSchemaNode(SchemaContext schema,InstanceIdentifier path) { + + public static DataSchemaNode getSchemaNode(final SchemaContext schema,final InstanceIdentifier path) { checkArgument(schema != null,"YANG Schema must not be null."); checkArgument(path != null,"Path must not be null."); return getSchemaNode(schema, FluentIterable.from(path.getPath()).transform(QNAME_FROM_PATH_ARGUMENT)); } - - public static DataSchemaNode getSchemaNode(SchemaContext schema,Iterable path) { + + public static DataSchemaNode getSchemaNode(final SchemaContext schema,final Iterable path) { checkArgument(schema != null,"YANG Schema must not be null."); checkArgument(path != null,"Path must not be null."); if(!path.iterator().hasNext()){ return toRootDataNode(schema); } - + QName firstNode = path.iterator().next(); DataNodeContainer previous = schema.findModuleByNamespaceAndRevision(firstNode.getNamespace(), firstNode.getRevision()); Iterator iterator = path.iterator(); - + while (iterator.hasNext()) { checkArgument(previous!= null, "Supplied path does not resolve into valid schema node."); QName arg = iterator.next(); @@ -92,7 +91,7 @@ public class YangSchemaUtils { return (DataSchemaNode) previous; } - private static DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) { + private static DataSchemaNode searchInChoices(final DataNodeContainer node, final QName arg) { Set children = node.getChildNodes(); for (DataSchemaNode child : children) { if (child instanceof ChoiceNode) { @@ -106,7 +105,7 @@ public class YangSchemaUtils { return null; } - private static DataSchemaNode searchInCases(ChoiceNode choiceNode, QName arg) { + private static DataSchemaNode searchInCases(final ChoiceNode choiceNode, final QName arg) { Set cases = choiceNode.getCases(); for (ChoiceCaseNode caseNode : cases) { DataSchemaNode node = caseNode.getDataChildByName(arg); @@ -117,124 +116,124 @@ public class YangSchemaUtils { return null; } - private static ContainerSchemaNode toRootDataNode(SchemaContext schema) { + private static ContainerSchemaNode toRootDataNode(final SchemaContext schema) { return new NetconfDataRootNode(schema); } private static final class NetconfDataRootNode implements ContainerSchemaNode { - - public NetconfDataRootNode(SchemaContext schema) { + + public NetconfDataRootNode(final SchemaContext schema) { // TODO Auto-generated constructor stub } - + @Override public Set> getTypeDefinitions() { // TODO Auto-generated method stub return null; } - + @Override public Set getChildNodes() { // TODO Auto-generated method stub return null; } - + @Override public Set getGroupings() { // TODO Auto-generated method stub return null; } - + @Override - public DataSchemaNode getDataChildByName(QName name) { + public DataSchemaNode getDataChildByName(final QName name) { // TODO Auto-generated method stub return null; } - + @Override - public DataSchemaNode getDataChildByName(String name) { + public DataSchemaNode getDataChildByName(final String name) { // TODO Auto-generated method stub return null; } - + @Override public Set getUses() { // TODO Auto-generated method stub return null; } - + @Override public Set getAvailableAugmentations() { // TODO Auto-generated method stub return null; } - + @Override public boolean isAugmenting() { // TODO Auto-generated method stub return false; } - + @Override public boolean isAddedByUses() { // TODO Auto-generated method stub return false; } - + @Override public boolean isConfiguration() { // TODO Auto-generated method stub return false; } - + @Override public ConstraintDefinition getConstraints() { // TODO Auto-generated method stub return null; } - + @Override public QName getQName() { // TODO Auto-generated method stub return null; } - + @Override public SchemaPath getPath() { // TODO Auto-generated method stub return null; } - + @Override public String getDescription() { // TODO Auto-generated method stub return null; } - + @Override public String getReference() { // TODO Auto-generated method stub return null; } - + @Override public Status getStatus() { // TODO Auto-generated method stub return null; } - + @Override public List getUnknownSchemaNodes() { // TODO Auto-generated method stub return null; } - + @Override public boolean isPresenceContainer() { // TODO Auto-generated method stub return false; } - + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDataStoreTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDataStoreTest.java index c0f0a35565..413d81d029 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDataStoreTest.java +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDataStoreTest.java @@ -12,6 +12,7 @@ import org.junit.Test; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -25,7 +26,6 @@ public class InMemoryDataStoreTest { private SchemaContext schemaContext; private InMemoryDOMDataStore domStore; - @Before public void setupStore() { domStore = new InMemoryDOMDataStore("TEST", MoreExecutors.sameThreadExecutor()); @@ -34,13 +34,11 @@ public class InMemoryDataStoreTest { } - @Test public void testTransactionIsolation() throws InterruptedException, ExecutionException { assertNotNull(domStore); - DOMStoreReadTransaction readTx = domStore.newReadOnlyTransaction(); assertNotNull(readTx); @@ -55,19 +53,17 @@ public class InMemoryDataStoreTest { /** * - * Reads /test from writeTx - * Read should return container. + * Reads /test from writeTx Read should return container. * */ ListenableFuture>> writeTxContainer = writeTx.read(TestModel.TEST_PATH); assertTrue(writeTxContainer.get().isPresent()); /** - * - * Reads /test from readTx - * Read should return Absent. - * - */ + * + * Reads /test from readTx Read should return Absent. + * + */ ListenableFuture>> readTxContainer = readTx.read(TestModel.TEST_PATH); assertFalse(readTxContainer.get().isPresent()); } @@ -86,8 +82,7 @@ public class InMemoryDataStoreTest { /** * - * Reads /test from writeTx - * Read should return container. + * Reads /test from writeTx Read should return container. * */ ListenableFuture>> writeTxContainer = writeTx.read(TestModel.TEST_PATH); @@ -97,7 +92,8 @@ public class InMemoryDataStoreTest { assertThreePhaseCommit(cohort); - Optional> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH).get(); + Optional> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH) + .get(); assertTrue(afterCommitRead.isPresent()); } @@ -115,10 +111,91 @@ public class InMemoryDataStoreTest { cohort.preCommit().get(); cohort.abort().get(); - Optional> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH).get(); + Optional> afterCommitRead = domStore.newReadOnlyTransaction().read(TestModel.TEST_PATH) + .get(); assertFalse(afterCommitRead.isPresent()); } + @Test + public void testTransactionChain() throws InterruptedException, ExecutionException { + DOMStoreTransactionChain txChain = domStore.createTransactionChain(); + assertNotNull(txChain); + + /** + * We alocate new read-write transaction and write /test + * + * + */ + DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction(); + assertTestContainerWrite(firstTx); + + /** + * First transaction is marked as ready, we are able to allocate chained + * transactions + */ + DOMStoreThreePhaseCommitCohort firstWriteTxCohort = firstTx.ready(); + + /** + * We alocate chained transaction - read transaction, note first one is + * still not commited to datastore. + */ + DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction(); + + /** + * + * We test if we are able to read data from tx, read should not fail + * since we are using chained transaction. + * + * + */ + assertTestContainerExists(secondReadTx); + + /** + * + * We alocate next transaction, which is still based on first one, but + * is read-write. + * + */ + DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction(); + + /** + * We test existence of /test in third transaction container should + * still be visible from first one (which is still uncommmited). + * + * + */ + assertTestContainerExists(thirdDeleteTx); + + /** + * We delete node in third transaction + */ + thirdDeleteTx.delete(TestModel.TEST_PATH); + + /** + * third transaction is sealed. + */ + DOMStoreThreePhaseCommitCohort thirdDeleteTxCohort = thirdDeleteTx.ready(); + + /** + * We commit first transaction + * + */ + assertThreePhaseCommit(firstWriteTxCohort); + + // Alocates store transacion + DOMStoreReadTransaction storeReadTx = domStore.newReadOnlyTransaction(); + /** + * We verify transaction is commited to store, container should exists + * in datastore. + */ + assertTestContainerExists(storeReadTx); + /** + * We commit third transaction + * + */ + assertThreePhaseCommit(thirdDeleteTxCohort); + } + @Test @Ignore public void testTransactionConflict() throws InterruptedException, ExecutionException { @@ -138,32 +215,36 @@ public class InMemoryDataStoreTest { assertFalse(txTwo.ready().canCommit().get()); } - - - private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort) throws InterruptedException, ExecutionException { + private static void assertThreePhaseCommit(final DOMStoreThreePhaseCommitCohort cohort) + throws InterruptedException, ExecutionException { assertTrue(cohort.canCommit().get().booleanValue()); cohort.preCommit().get(); cohort.commit().get(); } - - private static Optional> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx) throws InterruptedException, ExecutionException { + private static Optional> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx) + throws InterruptedException, ExecutionException { /** - * - * Writes /test in writeTx - * - */ - writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); + * + * Writes /test in writeTx + * + */ + writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)); - /** - * - * Reads /test from writeTx - * Read should return container. - * - */ - ListenableFuture>> writeTxContainer = writeTx.read(TestModel.TEST_PATH); - assertTrue(writeTxContainer.get().isPresent()); - return writeTxContainer.get(); + return assertTestContainerExists(writeTx); + } + + /** + * + * Reads /test from readTx Read should return container. + * + */ + private static Optional> assertTestContainerExists(DOMStoreReadTransaction readTx) + throws InterruptedException, ExecutionException { + + ListenableFuture>> writeTxContainer = readTx.read(TestModel.TEST_PATH); + assertTrue(writeTxContainer.get().isPresent()); + return writeTxContainer.get(); } } diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java index 138b726edb..ab47d1034f 100644 --- a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java +++ b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStore.java @@ -9,8 +9,6 @@ package org.opendaylight.controller.sal.core.spi.data; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; -import org.opendaylight.controller.md.sal.common.api.data.DataChangeListener; -import org.opendaylight.controller.md.sal.common.api.data.TransactionChain; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -25,13 +23,13 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; * Read and write access to stored data is provided only via transactions * created using {@link #newReadOnlyTransaction()}, * {@link #newWriteOnlyTransaction()} and {@link #newReadWriteTransaction()}, or - * by creating {@link TransactionChain}. + * by creating {@link org.opendaylight.controller.md.sal.common.api.data.TransactionChain}. * */ public interface DOMStore extends DOMStoreTransactionFactory { /** - * Registers {@link DataChangeListener} for Data Change callbacks which will + * Registers {@link org.opendaylight.controller.md.sal.common.api.data.DataChangeListener} for Data Change callbacks which will * be triggered on the change of provided subpath. What constitutes a change * depends on the @scope parameter. * diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java index 733c10926c..b546f2e77d 100644 --- a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java +++ b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreReadTransaction.java @@ -7,8 +7,6 @@ */ package org.opendaylight.controller.sal.core.spi.data; -import java.util.concurrent.Future; - import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -27,10 +25,10 @@ public interface DOMStoreReadTransaction extends DOMStoreTransaction { * read * @return Listenable Future which contains read result *
        - *
      • If data at supplied path exists the {@link Future#get()} + *
      • If data at supplied path exists the {@link java.util.concurrent.Future#get()} * returns Optional object containing data *
      • If data at supplied path does not exists the - * {@link Future#get()} returns {@link Optional#absent()}. + * {@link java.util.concurrent.Future#get()} returns {@link Optional#absent()}. *
      */ ListenableFuture>> read(InstanceIdentifier path); diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java index ddabbc6c03..19bb0538c2 100644 --- a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java +++ b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/sal/core/spi/data/DOMStoreWriteTransaction.java @@ -7,8 +7,6 @@ */ package org.opendaylight.controller.sal.core.spi.data; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.yangtools.concepts.Path; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -20,7 +18,7 @@ public interface DOMStoreWriteTransaction extends DOMStoreTransaction { * specified path. * * If you need add or merge of current object with specified use - * {@link #merge(LogicalDatastoreType, Path, Object)} + * {@link #merge(org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType, org.opendaylight.yangtools.concepts.Path, Object)} * * * @param path @@ -39,7 +37,7 @@ public interface DOMStoreWriteTransaction extends DOMStoreTransaction { * specified path. * * If you need add or merge of current object with specified use - * {@link #merge(LogicalDatastoreType, Path, Object)} + * {@link #merge(org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType, org.opendaylight.yangtools.concepts.Path, Object)} * * * @param path diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/api/SchemaSourceProviderFactory.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/api/SchemaSourceProviderFactory.java index 7037231c5f..04c5c54184 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/api/SchemaSourceProviderFactory.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/api/SchemaSourceProviderFactory.java @@ -7,7 +7,6 @@ */ package org.opendaylight.controller.sal.connect.api; -import org.opendaylight.controller.sal.connect.netconf.sal.NetconfDeviceRpc; import org.opendaylight.controller.sal.core.api.RpcImplementation; import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider; diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicator.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicator.java index fa6e252293..e78f2b32df 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicator.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfDeviceCommunicator.java @@ -18,7 +18,6 @@ import org.opendaylight.controller.netconf.api.NetconfTerminationReason; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; import org.opendaylight.controller.netconf.client.NetconfClientSession; import org.opendaylight.controller.netconf.client.NetconfClientSessionListener; -import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration; import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceRpc.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceRpc.java index 927d41861a..6a62b1e20b 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceRpc.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceRpc.java @@ -11,10 +11,6 @@ import com.google.common.base.Function; import com.google.common.util.concurrent.Futures; import java.util.Collections; import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import javax.annotation.Nullable; import org.opendaylight.controller.netconf.api.NetconfMessage; diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/NetconfDeviceSchemaProviderFactory.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/NetconfDeviceSchemaProviderFactory.java index 9f844fde3f..e7d64646ea 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/NetconfDeviceSchemaProviderFactory.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/NetconfDeviceSchemaProviderFactory.java @@ -12,11 +12,8 @@ import java.util.Collection; import java.util.List; import java.util.Set; -import javax.annotation.concurrent.ThreadSafe; - import org.opendaylight.controller.sal.connect.api.SchemaContextProviderFactory; import org.opendaylight.controller.sal.connect.util.RemoteDeviceId; -import org.opendaylight.controller.sal.core.api.RpcImplementation; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/NetconfRemoteSchemaSourceProvider.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/NetconfRemoteSchemaSourceProvider.java index b43e03bef7..44ff2ef985 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/NetconfRemoteSchemaSourceProvider.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/NetconfRemoteSchemaSourceProvider.java @@ -69,13 +69,11 @@ public final class NetconfRemoteSchemaSourceProvider implements SchemaSourceProv private ImmutableCompositeNode createGetSchemaRequest(final String moduleName, final Optional revision) { final CompositeNodeBuilder request = ImmutableCompositeNode.builder(); - request.setQName(GET_SCHEMA_QNAME) - .addLeaf("format", "yang") - .addLeaf("identifier", moduleName); - + request.setQName(GET_SCHEMA_QNAME).addLeaf("identifier", moduleName); if (revision.isPresent()) { request.addLeaf("version", revision.get()); } + request.addLeaf("format", "yang"); return request.toInstance(); } diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java index c85a52909d..2adc1be79e 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java @@ -7,12 +7,11 @@ */ package org.opendaylight.controller.sal.connect.netconf.schema.mapping; +import com.google.common.base.Optional; import java.util.Collections; import java.util.List; import java.util.Set; - import javax.activation.UnsupportedDataTypeException; - import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.connect.api.MessageTransformer; @@ -24,15 +23,15 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; +import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider; import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils; import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.w3c.dom.Document; import org.w3c.dom.Element; -import com.google.common.base.Optional; - public class NetconfMessageTransformer implements MessageTransformer { public static final String MESSAGE_ID_PREFIX = "m"; @@ -65,7 +64,17 @@ public class NetconfMessageTransformer implements MessageTransformer + * {@code + * rpc + * edit-config + * config + * // All schema nodes from remote schema + * config + * edit-config + * rpc + * } + * + * + * This makes the translation of rpc edit-config request(especially the config node) + * to xml use schema which is crucial for some types of nodes e.g. identity-ref. + */ + public static DataNodeContainer createSchemaForEdit(final SchemaContext schemaContext) { + final QName config = QName.create(NETCONF_EDIT_CONFIG_QNAME, "config"); + final QName editConfig = QName.create(NETCONF_EDIT_CONFIG_QNAME, "edit-config"); + final NodeContainerProxy configProxy = new NodeContainerProxy(config, schemaContext.getChildNodes()); + final NodeContainerProxy editConfigProxy = new NodeContainerProxy(editConfig, Sets.newHashSet(configProxy)); + return new NodeContainerProxy(NETCONF_RPC_QNAME, Sets.newHashSet(editConfigProxy)); + } + public static CompositeNodeTOImpl wrap(final QName name, final Node node) { if (node != null) { return new CompositeNodeTOImpl(name, null, Collections.> singletonList(node)); diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NodeContainerProxy.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NodeContainerProxy.java new file mode 100644 index 0000000000..bd075d0606 --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/util/NodeContainerProxy.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014 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.sal.connect.netconf.util; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.Status; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; +import org.opendaylight.yangtools.yang.model.api.UsesNode; + +class NodeContainerProxy implements ContainerSchemaNode { + + private final Map childNodes; + private final QName qName; + + public NodeContainerProxy(final QName qName, final Map childNodes) { + this.childNodes = Preconditions.checkNotNull(childNodes, "childNodes"); + this.qName = Preconditions.checkNotNull(qName, "qName"); + } + + public NodeContainerProxy(final QName qName, final Set childNodes) { + this(qName, asMap(childNodes)); + } + + private static Map asMap(final Set childNodes) { + final Map mapped = Maps.newHashMap(); + for (final DataSchemaNode childNode : childNodes) { + mapped.put(childNode.getQName(), childNode); + } + return mapped; + } + + @Override + public Set> getTypeDefinitions() { + return Collections.emptySet(); + } + + @Override + public Set getChildNodes() { + return Sets.newHashSet(childNodes.values()); + } + + @Override + public Set getGroupings() { + return Collections.emptySet(); + } + + @Override + public DataSchemaNode getDataChildByName(final QName qName) { + return childNodes.get(qName); + } + + @Override + public DataSchemaNode getDataChildByName(final String s) { + throw new UnsupportedOperationException(); + } + + @Override + public Set getUses() { + return Collections.emptySet(); + } + + @Override + public boolean isPresenceContainer() { + throw new UnsupportedOperationException(); + } + + @Override + public Set getAvailableAugmentations() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isAugmenting() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isAddedByUses() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isConfiguration() { + throw new UnsupportedOperationException(); + } + + @Override + public ConstraintDefinition getConstraints() { + throw new UnsupportedOperationException(); + } + + @Override + public QName getQName() { + return qName; + } + + @Override + public SchemaPath getPath() { + throw new UnsupportedOperationException(); + } + + @Override + public String getDescription() { + throw new UnsupportedOperationException(); + } + + @Override + public String getReference() { + throw new UnsupportedOperationException(); + } + + @Override + public Status getStatus() { + throw new UnsupportedOperationException(); + } + + @Override + public List getUnknownSchemaNodes() { + return Collections.emptyList(); + } +} diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java index f55566acc3..e3ac9bab30 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModule.java @@ -7,7 +7,10 @@ */ package org.opendaylight.controller.config.yang.md.sal.remote.rpc; -import org.opendaylight.controller.sal.connector.remoterpc.*; +import org.opendaylight.controller.sal.connector.remoterpc.ClientImpl; +import org.opendaylight.controller.sal.connector.remoterpc.RemoteRpcProvider; +import org.opendaylight.controller.sal.connector.remoterpc.RoutingTableProvider; +import org.opendaylight.controller.sal.connector.remoterpc.ServerImpl; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.osgi.framework.BundleContext; @@ -16,51 +19,51 @@ import org.osgi.framework.BundleContext; * */ public final class ZeroMQServerModule - extends org.opendaylight.controller.config.yang.md.sal.remote.rpc.AbstractZeroMQServerModule { +extends org.opendaylight.controller.config.yang.md.sal.remote.rpc.AbstractZeroMQServerModule { - private static final Integer ZEROMQ_ROUTER_PORT = 5554; - private BundleContext bundleContext; + private static final Integer ZEROMQ_ROUTER_PORT = 5554; + private BundleContext bundleContext; - public ZeroMQServerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, - org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { - super(identifier, dependencyResolver); - } + public ZeroMQServerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, + final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } - public ZeroMQServerModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, - org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, - ZeroMQServerModule oldModule, java.lang.AutoCloseable oldInstance) { + public ZeroMQServerModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, + final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + final ZeroMQServerModule oldModule, final java.lang.AutoCloseable oldInstance) { - super(identifier, dependencyResolver, oldModule, oldInstance); - } + super(identifier, dependencyResolver, oldModule, oldInstance); + } - @Override - protected void customValidation() { - // Add custom validation for module attributes here. - } + @Override + protected void customValidation() { + // Add custom validation for module attributes here. + } - @Override - public java.lang.AutoCloseable createInstance() { + @Override + public java.lang.AutoCloseable createInstance() { - Broker broker = getDomBrokerDependency(); + Broker broker = getDomBrokerDependency(); - final int port = getPort() != null ? getPort() : ZEROMQ_ROUTER_PORT; + final int port = getPort() != null ? getPort() : ZEROMQ_ROUTER_PORT; - ServerImpl serverImpl = new ServerImpl(port); + ServerImpl serverImpl = new ServerImpl(port); - ClientImpl clientImpl = new ClientImpl(); + ClientImpl clientImpl = new ClientImpl(); - RoutingTableProvider provider = new RoutingTableProvider(bundleContext);//,serverImpl); + RoutingTableProvider provider = new RoutingTableProvider(bundleContext);//,serverImpl); - RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl); - facade.setRoutingTableProvider(provider); - facade.setContext(bundleContext); - facade.setRpcProvisionRegistry((RpcProvisionRegistry) broker); + RemoteRpcProvider facade = new RemoteRpcProvider(serverImpl, clientImpl); + facade.setRoutingTableProvider(provider); + facade.setContext(bundleContext); + facade.setRpcProvisionRegistry((RpcProvisionRegistry) broker); - broker.registerProvider(facade, bundleContext); - return facade; - } + broker.registerProvider(facade, bundleContext); + return facade; + } - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } + public void setBundleContext(final BundleContext bundleContext) { + this.bundleContext = bundleContext; + } } diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModuleFactory.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModuleFactory.java index c8d6806344..0c2a370e06 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModuleFactory.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/config/yang/md/sal/remote/rpc/ZeroMQServerModuleFactory.java @@ -24,7 +24,7 @@ public class ZeroMQServerModuleFactory extends org.opendaylight.controller.confi module.setBundleContext(bundleContext); return module; } - + @Override public Module createModule(String instanceName, DependencyResolver dependencyResolver, DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception { diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java index e721084763..200ebaee6a 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/ClientImpl.java @@ -26,7 +26,6 @@ import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException; import org.opendaylight.controller.sal.connector.remoterpc.dto.Message; import org.opendaylight.controller.sal.connector.remoterpc.dto.RouteIdentifierImpl; import org.opendaylight.controller.sal.connector.remoterpc.util.XmlUtils; -import org.opendaylight.controller.sal.core.api.RpcImplementation; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; @@ -41,7 +40,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; /** - * An implementation of {@link RpcImplementation} that makes + * An implementation of {@link org.opendaylight.controller.sal.core.api.RpcImplementation} that makes * remote RPC calls */ public class ClientImpl implements RemoteRpcClient { diff --git a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/MessageWrapper.java b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/MessageWrapper.java index 8d2198c365..85f4113663 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/MessageWrapper.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/implementation/src/main/java/org/opendaylight/controller/sal/connector/remoterpc/dto/MessageWrapper.java @@ -16,7 +16,7 @@ public class MessageWrapper { private Message _message; private ZMQ.Socket _receiveSocket; - + public MessageWrapper(Message message, ZMQ.Socket receiveSocket) { this._message = message; this._receiveSocket = receiveSocket; diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/pom.xml index dd216c0881..89695c124a 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/pom.xml @@ -1,85 +1,83 @@ - - 4.0.0 - - sal-remoterpc-connector-test-parent - org.opendaylight.controller.tests - 1.0-SNAPSHOT - - sal-remoterpc-connector-test-consumer - bundle - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - + + + 4.0.0 + + org.opendaylight.controller.tests + sal-remoterpc-connector-test-parent + 1.1-SNAPSHOT + + sal-remoterpc-connector-test-consumer + bundle + - - - - org.apache.felix - maven-bundle-plugin - - - org.opendaylight.controller.sample.zeromq.consumer.ExampleConsumer - - - - - + + org.opendaylight.controller + containermanager + 0.5.2-SNAPSHOT + - - - org.opendaylight.controller - sal-binding-api - 1.0-SNAPSHOT - - - org.opendaylight.controller - sal-common-util - 1.0-SNAPSHOT - - - org.opendaylight.controller - sal-core-api - 1.0-SNAPSHOT - + + org.opendaylight.controller + sal + 0.8.1-SNAPSHOT + + + org.opendaylight.controller + sal-binding-api + 1.1-SNAPSHOT + + + org.opendaylight.controller + sal-common-util + 1.1-SNAPSHOT + + + org.opendaylight.controller + sal-common-util + 1.1-SNAPSHOT + + + org.opendaylight.controller + sal-core-api + 1.1-SNAPSHOT + + + org.opendaylight.yangtools + yang-binding + + + org.opendaylight.yangtools + yang-common + + + org.opendaylight.yangtools + yang-data-api + + + org.opendaylight.yangtools + yang-data-impl + ${yangtools.version} + + - - org.opendaylight.controller - containermanager - 0.5.1-SNAPSHOT - - - - org.opendaylight.controller - sal - 0.5.1-SNAPSHOT - - - org.opendaylight.yangtools - yang-binding - - - org.opendaylight.yangtools - yang-common - - - org.opendaylight.yangtools - yang-data-api - - - org.opendaylight.yangtools - yang-data-impl - ${yangtools.version} - - - - org.opendaylight.controller - sal-common-util - 1.0-SNAPSHOT - - + + + + org.apache.felix + maven-bundle-plugin + + + org.opendaylight.controller.sample.zeromq.consumer.ExampleConsumer + + + + + + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java index 7119a66113..aac6da47ba 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/consumer-service/src/main/java/org/opendaylight/controller/sample/zeromq/consumer/ExampleConsumer.java @@ -11,7 +11,7 @@ import java.io.FileNotFoundException; import java.io.InputStream; import java.net.URI; import java.util.Hashtable; -import java.util.concurrent.*; +import java.util.concurrent.Future; import org.opendaylight.controller.sal.core.api.AbstractConsumer; import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; @@ -25,7 +25,6 @@ import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.opendaylight.yangtools.yang.data.impl.XmlTreeBuilder; -import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; import javax.xml.stream.XMLStreamException; diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/pom.xml index 5bfbcba5f8..3f47700f8d 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/pom.xml @@ -1,20 +1,15 @@ - + + 4.0.0 org.opendaylight.controller sal-parent - 1.0-SNAPSHOT + 1.1-SNAPSHOT ../.. - pom org.opendaylight.controller.tests sal-remoterpc-connector-test-parent - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - + pom consumer-service @@ -22,5 +17,10 @@ test-it test-nb + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/pom.xml index a13a5aeba0..bd0e43bada 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/pom.xml @@ -4,7 +4,7 @@ sal-remoterpc-connector-test-parent org.opendaylight.controller.tests - 1.0-SNAPSHOT + 1.1-SNAPSHOT sal-remoterpc-connector-test-provider bundle @@ -33,30 +33,30 @@ org.opendaylight.controller sal-binding-api - 1.0-SNAPSHOT + 1.1-SNAPSHOT org.opendaylight.controller sal-common-util - 1.0-SNAPSHOT + 1.1-SNAPSHOT org.opendaylight.controller sal-core-api - 1.0-SNAPSHOT + 1.1-SNAPSHOT org.opendaylight.controller containermanager - 0.5.1-SNAPSHOT + 0.5.2-SNAPSHOT org.opendaylight.controller sal - 0.5.1-SNAPSHOT + 0.8.1-SNAPSHOT org.opendaylight.yangtools @@ -77,12 +77,12 @@ org.opendaylight.controller sal-common-util - 1.0-SNAPSHOT + 1.1-SNAPSHOT org.opendaylight.controller sal-remoterpc-connector - 1.0-SNAPSHOT + 1.1-SNAPSHOT diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java index e33011b92b..ff930db6fd 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/provider-service/src/main/java/org/opendaylight/controller/sample/zeromq/provider/ExampleProvider.java @@ -26,7 +26,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URI; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class ExampleProvider extends AbstractProvider implements RpcImplementation { @@ -91,7 +95,7 @@ public class ExampleProvider extends AbstractProvider implements RpcImplementati } return false; } - + // Adds a child SimpleNode containing the value "success" to the input CompositeNode private CompositeNode addSuccessNode(CompositeNode input) { List> list = new ArrayList>(input.getChildren()); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml index 4c7e15dbb0..84e9d29c72 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/pom.xml @@ -4,7 +4,7 @@ sal-remoterpc-connector-test-parent org.opendaylight.controller.tests - 1.0-SNAPSHOT + 1.1-SNAPSHOT sal-remoterpc-connector-test-it @@ -95,17 +95,17 @@ org.opendaylight.controller.tests sal-remoterpc-connector-test-provider - 1.0-SNAPSHOT + 1.1-SNAPSHOT org.opendaylight.controller.tests sal-remoterpc-connector-test-consumer - 1.0-SNAPSHOT + 1.1-SNAPSHOT org.opendaylight.controller sal-broker-impl - 1.0-SNAPSHOT + 1.1-SNAPSHOT org.ops4j.pax.exam @@ -318,6 +318,7 @@ org.opendaylight.controller ietf-netconf-monitoring + 0.2.5-SNAPSHOT org.opendaylight.yangtools diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/RouterTest.java b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/RouterTest.java index 5ee982009e..e02e290a29 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/RouterTest.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-it/src/test/java/org/opendaylight/controller/sample/zeromq/test/it/RouterTest.java @@ -9,8 +9,6 @@ package org.opendaylight.controller.sample.zeromq.test.it; import junit.framework.Assert; -import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,12 +40,11 @@ import javax.inject.Inject; import java.io.IOException; import java.net.URI; -import java.util.Hashtable; import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles; import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles; -import static org.ops4j.pax.exam.CoreOptions.*; +//import static org.ops4j.pax.exam.CoreOptions.*; @RunWith(PaxExam.class) public class RouterTest { @@ -67,7 +64,7 @@ public class RouterTest { @Inject @Filter(timeout=60*1000) Broker broker; - + private ZMQ.Context zmqCtx = ZMQ.context(1); //private Server router; //private ExampleProvider provider; @@ -336,7 +333,7 @@ public class RouterTest { return msg; } - + private void printState(){ Bundle[] b = ctx.getBundles(); _logger.debug("\n\nNumber of bundles [{}]\n\n]", b.length); diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml index a6bbe31684..b041cb430a 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/pom.xml @@ -5,7 +5,7 @@ sal-remoterpc-connector-test-parent org.opendaylight.controller.tests - 1.0-SNAPSHOT + 1.1-SNAPSHOT sal-remoterpc-connector-test-nb diff --git a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqrouter/rest/Router.java b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqrouter/rest/Router.java index edd49485af..e97be52f3d 100644 --- a/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqrouter/rest/Router.java +++ b/opendaylight/md-sal/sal-remoterpc-connector/integrationtest/test-nb/src/main/java/org/opendaylight/controller/tests/zmqrouter/rest/Router.java @@ -19,7 +19,8 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.osgi.framework.*; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java index 067b7d96ec..4d9b198795 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java @@ -31,12 +31,12 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; *
        *
      • /restconf - {@link #getRoot()} *
          - *
        • /config - {@link #readConfigurationData(String)} + *
        • /config - {@link #readConfigurationData(String)} * {@link #updateConfigurationData(String, CompositeNode)} * {@link #createConfigurationData(CompositeNode)} * {@link #createConfigurationData(String, CompositeNode)} * {@link #deleteConfigurationData(String)} - *
        • /operational - {@link #readOperationalData(String)} + *
        • /operational - {@link #readOperationalData(String)} *
        • /modules - {@link #getModules()} *
            *
          • /module @@ -95,41 +95,41 @@ public interface RestconfService { Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); - + @POST @Path("/operations/{identifier:.+}") @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML, Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, @DefaultValue("") String noPayload); - + @GET @Path("/config/{identifier:.+}") - @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public StructuredData readConfigurationData(@Encoded @PathParam("identifier") String identifier); @GET @Path("/operational/{identifier:.+}") - @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public StructuredData readOperationalData(@Encoded @PathParam("identifier") String identifier); @PUT @Path("/config/{identifier:.+}") - @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); @POST @Path("/config/{identifier:.+}") - @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); @POST @Path("/config") - @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, + @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) public Response createConfigurationData(CompositeNode payload); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java index ba3e315e72..290d976b28 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java @@ -20,7 +20,7 @@ import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO.Predicate import org.opendaylight.yangtools.yang.model.api.TypeDefinition; public final class RestUtil { - + public static final String SQUOTE = "'"; public static final String DQUOTE = "\""; private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]"); @@ -45,29 +45,29 @@ public final class RestUtil { IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(value); for (int i = 1; i < xPathParts.length; i++) { String xPathPartTrimmed = xPathParts[i].trim(); - + String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed); IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap); if (identityValue == null) { return null; } - + List predicates = toPredicates(xPathPartTrimmed, prefixMap); if (predicates == null) { return null; } identityValue.setPredicates(predicates); - + identityValuesDTO.add(identityValue); } return identityValuesDTO.getValuesWithNamespaces().isEmpty() ? null : identityValuesDTO; } - + private static String getIdAndPrefixAsStr(String pathPart) { int predicateStartIndex = pathPart.indexOf("["); return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex); } - + private static IdentityValue toIdentity(String xPathPart, PrefixesMaping prefixMap) { String xPathPartTrimmed = xPathPart.trim(); if (xPathPartTrimmed.isEmpty()) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfDocumentedExceptionMapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfDocumentedExceptionMapper.java index c13d593a8e..5f6909cea8 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfDocumentedExceptionMapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfDocumentedExceptionMapper.java @@ -8,6 +8,15 @@ package org.opendaylight.controller.sal.rest.impl; +import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERRORS_CONTAINER_QNAME; +import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERROR_APP_TAG_QNAME; +import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERROR_INFO_QNAME; +import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERROR_LIST_QNAME; +import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERROR_MESSAGE_QNAME; +import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERROR_TAG_QNAME; +import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERROR_TYPE_QNAME; +import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.NAMESPACE; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; @@ -33,8 +42,6 @@ import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.*; - import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfError; @@ -70,7 +77,7 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper> errorNodes = ImmutableList.> builder(); @@ -116,7 +123,7 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper toDomNode( RestconfError error ) { + private Node toDomNode( final RestconfError error ) { CompositeNodeBuilder builder = ImmutableCompositeNode.builder(); builder.setQName( ERROR_LIST_QNAME ); @@ -209,7 +216,7 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper parseErrorInfo( String errorInfo ) { + private Node parseErrorInfo( final String errorInfo ) { if( Strings.isNullOrEmpty( errorInfo ) ) { return null; } @@ -226,19 +233,19 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper" ) - .append( errorInfo ).append( "" ).toString(); + .append( errorInfo ).append( "" ).toString(); Document doc = null; try { doc = factory.newDocumentBuilder().parse( - new InputSource( new StringReader( errorInfoWithRoot ) ) ); + new InputSource( new StringReader( errorInfoWithRoot ) ) ); } catch( Exception e ) { // TODO: what if the content is text that happens to contain invalid markup? Could // wrap in CDATA and try again. LOG.warn( "Error parsing restconf error-info, \"" + errorInfo + "\", as XML: " + - e.toString() ); + e.toString() ); return null; } @@ -263,8 +270,8 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper builder, QName qname, - String value ) { + private void addLeaf( final CompositeNodeBuilder builder, final QName qname, + final String value ) { if( !Strings.isNullOrEmpty( value ) ) { builder.addLeaf( qname, value ); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java index 86ed13a280..b0916f4500 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java @@ -7,19 +7,6 @@ */ package org.opendaylight.controller.sal.restconf.impl; -import com.google.common.base.Function; -import com.google.common.base.Objects; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.base.Splitter; -import com.google.common.base.Strings; -import com.google.common.collect.BiMap; -import com.google.common.collect.FluentIterable; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; @@ -40,8 +27,6 @@ import org.opendaylight.controller.sal.core.api.mount.MountInstance; import org.opendaylight.controller.sal.core.api.mount.MountService; import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.impl.RestUtil; -import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; -import org.opendaylight.controller.sal.restconf.impl.RestCodec; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.yangtools.concepts.Codec; @@ -69,6 +54,19 @@ import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.collect.BiMap; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + public class ControllerContext implements SchemaContextListener { private final static Logger LOG = LoggerFactory.getLogger( ControllerContext.class ); @@ -127,7 +125,7 @@ public class ControllerContext implements SchemaContextListener { } private InstanceIdWithSchemaNode toIdentifier( final String restconfInstance, - final boolean toMountPointIdentifier ) { + final boolean toMountPointIdentifier ) { this.checkPreconditions(); Iterable split = Splitter.on( "/" ).split( restconfInstance ); @@ -149,7 +147,7 @@ public class ControllerContext implements SchemaContextListener { InstanceIdentifierBuilder builder = InstanceIdentifier.builder(); Module latestModule = this.getLatestModule( globalSchema, startModule ); InstanceIdWithSchemaNode iiWithSchemaNode = this.collectPathArguments( builder, pathArgs, - latestModule, null, toMountPointIdentifier ); + latestModule, null, toMountPointIdentifier ); if( iiWithSchemaNode == null ) { throw new RestconfDocumentedException( @@ -187,7 +185,7 @@ public class ControllerContext implements SchemaContextListener { Predicate filter = new Predicate() { @Override - public boolean apply( Module m ) { + public boolean apply( final Module m ) { return Objects.equal( m.getName(), moduleName ); } }; @@ -232,14 +230,14 @@ public class ControllerContext implements SchemaContextListener { final SchemaContext mountPointSchema = mountPoint.getSchemaContext(); Set moduleSchemas = mountPointSchema == null ? null : - mountPointSchema.findModuleByNamespace( namespace ); + mountPointSchema.findModuleByNamespace( namespace ); return moduleSchemas == null ? null : this.filterLatestModule( moduleSchemas ); } public Module findModuleByNameAndRevision( final QName module ) { this.checkPreconditions(); Preconditions.checkArgument( module != null && module.getLocalName() != null && - module.getRevision() != null ); + module.getRevision() != null ); return globalSchema.findModuleByName( module.getLocalName(), module.getRevision() ); } @@ -247,11 +245,11 @@ public class ControllerContext implements SchemaContextListener { public Module findModuleByNameAndRevision( final MountInstance mountPoint, final QName module ) { this.checkPreconditions(); Preconditions.checkArgument( module != null && module.getLocalName() != null && - module.getRevision() != null && mountPoint != null ); + module.getRevision() != null && mountPoint != null ); SchemaContext schemaContext = mountPoint.getSchemaContext(); return schemaContext == null ? null : - schemaContext.findModuleByName( module.getLocalName(), module.getRevision() ); + schemaContext.findModuleByName( module.getLocalName(), module.getRevision() ); } public DataNodeContainer getDataNodeContainerFor( final InstanceIdentifier path ) { @@ -354,7 +352,7 @@ public class ControllerContext implements SchemaContextListener { String module = this.uriToModuleName.get( qname.getNamespace() ); if( module == null ) { final Module moduleSchema = globalSchema.findModuleByNamespaceAndRevision( - qname.getNamespace(), qname.getRevision() ); + qname.getNamespace(), qname.getRevision() ); if( moduleSchema == null ) { return null; } @@ -378,7 +376,7 @@ public class ControllerContext implements SchemaContextListener { SchemaContext schemaContext = mountPoint.getSchemaContext(); final Module moduleSchema = schemaContext.findModuleByNamespaceAndRevision( - qname.getNamespace(), qname.getRevision() ); + qname.getNamespace(), qname.getRevision() ); if( moduleSchema == null ) { return null; } @@ -406,7 +404,7 @@ public class ControllerContext implements SchemaContextListener { @Override public boolean apply(final GroupingDefinition g) { return Objects.equal(g.getQName().getLocalName(), - Draft02.RestConfModule.ERRORS_GROUPING_SCHEMA_NODE); + Draft02.RestConfModule.ERRORS_GROUPING_SCHEMA_NODE); } }; @@ -416,12 +414,12 @@ public class ControllerContext implements SchemaContextListener { List instanceDataChildrenByName = this.findInstanceDataChildrenByName(restconfGrouping, - Draft02.RestConfModule.ERRORS_CONTAINER_SCHEMA_NODE); + Draft02.RestConfModule.ERRORS_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instanceDataChildrenByName, null); } - public DataSchemaNode getRestconfModuleRestConfSchemaNode( Module inRestconfModule, - String schemaNodeName ) { + public DataSchemaNode getRestconfModuleRestConfSchemaNode( final Module inRestconfModule, + final String schemaNodeName ) { Module restconfModule = inRestconfModule; if( restconfModule == null ) { restconfModule = getRestconfModule(); @@ -437,7 +435,7 @@ public class ControllerContext implements SchemaContextListener { @Override public boolean apply(final GroupingDefinition g) { return Objects.equal(g.getQName().getLocalName(), - Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE); + Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE); } }; @@ -447,49 +445,49 @@ public class ControllerContext implements SchemaContextListener { List instanceDataChildrenByName = this.findInstanceDataChildrenByName(restconfGrouping, - Draft02.RestConfModule.RESTCONF_CONTAINER_SCHEMA_NODE); + Draft02.RestConfModule.RESTCONF_CONTAINER_SCHEMA_NODE); final DataSchemaNode restconfContainer = Iterables.getFirst(instanceDataChildrenByName, null); if (Objects.equal(schemaNodeName, Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE)) { List instances = this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer), - Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE); + Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE)) { List instances = this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer), - Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); + Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE)) { List instances = this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer), - Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); + Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); final DataSchemaNode modules = Iterables.getFirst(instances, null); instances = this.findInstanceDataChildrenByName(((DataNodeContainer) modules), - Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE); + Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE)) { List instances = this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer), - Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE); + Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE)) { List instances = this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer), - Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE); + Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE); final DataSchemaNode modules = Iterables.getFirst(instances, null); instances = this.findInstanceDataChildrenByName(((DataNodeContainer) modules), - Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE); + Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE); return Iterables.getFirst(instances, null); } else if(Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE)) { List instances = this.findInstanceDataChildrenByName(((DataNodeContainer) restconfContainer), - Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); + Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); return Iterables.getFirst(instances, null); } @@ -545,7 +543,7 @@ public class ControllerContext implements SchemaContextListener { private String toUriString( final Object object ) throws UnsupportedEncodingException { return object == null ? "" : - URLEncoder.encode( object.toString(), ControllerContext.URI_ENCODING_CHAR_SET ); + URLEncoder.encode( object.toString(), ControllerContext.URI_ENCODING_CHAR_SET ); } private InstanceIdWithSchemaNode collectPathArguments( final InstanceIdentifierBuilder builder, @@ -559,7 +557,7 @@ public class ControllerContext implements SchemaContextListener { if( strings.isEmpty() ) { return new InstanceIdWithSchemaNode( builder.toInstance(), - ((DataSchemaNode) parentNode), mountPoint ); + ((DataSchemaNode) parentNode), mountPoint ); } String head = strings.iterator().next(); @@ -569,7 +567,7 @@ public class ControllerContext implements SchemaContextListener { DataSchemaNode targetNode = null; if( !Strings.isNullOrEmpty( moduleName ) ) { if( Objects.equal( moduleName, ControllerContext.MOUNT_MODULE ) && - Objects.equal( nodeName, ControllerContext.MOUNT_NODE ) ) { + Objects.equal( nodeName, ControllerContext.MOUNT_NODE ) ) { if( mountPoint != null ) { throw new RestconfDocumentedException( "Restconf supports just one mount point in URI.", @@ -587,7 +585,7 @@ public class ControllerContext implements SchemaContextListener { if( mount == null ) { LOG.debug( "Instance identifier to missing mount point: {}", partialPath ); throw new RestconfDocumentedException( - "Mount point does not exist.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT ); + "Mount point does not exist.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT ); } final SchemaContext mountPointSchema = mount.getSchemaContext(); @@ -610,12 +608,12 @@ public class ControllerContext implements SchemaContextListener { final String moduleNameBehindMountPoint = toModuleName( strings.get( 1 ) ); if( moduleNameBehindMountPoint == null ) { throw new RestconfDocumentedException( - "First node after mount point in URI has to be in format \"moduleName:nodeName\"", - ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE ); + "First node after mount point in URI has to be in format \"moduleName:nodeName\"", + ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE ); } final Module moduleBehindMountPoint = this.getLatestModule( mountPointSchema, - moduleNameBehindMountPoint ); + moduleNameBehindMountPoint ); if( moduleBehindMountPoint == null ) { throw new RestconfDocumentedException( "\"" +moduleName + "\" module does not exist in mount point.", @@ -624,7 +622,7 @@ public class ControllerContext implements SchemaContextListener { List subList = strings.subList( 1, strings.size() ); return this.collectPathArguments( InstanceIdentifier.builder(), subList, moduleBehindMountPoint, - mount, returnJustMountPoint ); + mount, returnJustMountPoint ); } Module module = null; @@ -639,7 +637,7 @@ public class ControllerContext implements SchemaContextListener { else { SchemaContext schemaContext = mountPoint.getSchemaContext(); module = schemaContext == null ? null : - this.getLatestModule( schemaContext, moduleName ); + this.getLatestModule( schemaContext, moduleName ); if( module == null ) { throw new RestconfDocumentedException( "\"" + moduleName + "\" module does not exist in mount point.", @@ -648,23 +646,23 @@ public class ControllerContext implements SchemaContextListener { } targetNode = this.findInstanceDataChildByNameAndNamespace( - parentNode, nodeName, module.getNamespace() );; + parentNode, nodeName, module.getNamespace() ); if( targetNode == null ) { throw new RestconfDocumentedException( "URI has bad format. Possible reasons:\n" + - " 1. \"" + head + "\" was not found in parent data node.\n" + - " 2. \"" + head + "\" is behind mount point. Then it should be in format \"/" + - MOUNT + "/" + head + "\".", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE ); + " 1. \"" + head + "\" was not found in parent data node.\n" + + " 2. \"" + head + "\" is behind mount point. Then it should be in format \"/" + + MOUNT + "/" + head + "\".", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE ); } } else { final List potentialSchemaNodes = - this.findInstanceDataChildrenByName( parentNode, nodeName ); + this.findInstanceDataChildrenByName( parentNode, nodeName ); if( potentialSchemaNodes.size() > 1 ) { final StringBuilder strBuilder = new StringBuilder(); for( final DataSchemaNode potentialNodeSchema : potentialSchemaNodes ) { strBuilder.append( " " ) - .append( potentialNodeSchema.getQName().getNamespace() ) - .append( "\n" ); + .append( potentialNodeSchema.getQName().getNamespace() ) + .append( "\n" ); } throw new RestconfDocumentedException( @@ -714,7 +712,7 @@ public class ControllerContext implements SchemaContextListener { } this.addKeyValue( keyValues, listNode.getDataChildByName( key ), - uriKeyValue, mountPoint ); + uriKeyValue, mountPoint ); i++; } } @@ -729,7 +727,7 @@ public class ControllerContext implements SchemaContextListener { if( (targetNode instanceof DataNodeContainer) ) { final List remaining = strings.subList( consumed, strings.size() ); return this.collectPathArguments( builder, remaining, - ((DataNodeContainer) targetNode), mountPoint, returnJustMountPoint ); + ((DataNodeContainer) targetNode), mountPoint, returnJustMountPoint ); } return new InstanceIdWithSchemaNode( builder.toInstance(), targetNode, mountPoint ); @@ -743,7 +741,7 @@ public class ControllerContext implements SchemaContextListener { Predicate filter = new Predicate() { @Override - public boolean apply( DataSchemaNode node ) { + public boolean apply( final DataSchemaNode node ) { return Objects.equal( node.getQName().getNamespace(), namespace ); } }; @@ -753,7 +751,7 @@ public class ControllerContext implements SchemaContextListener { } public List findInstanceDataChildrenByName( final DataNodeContainer container, - final String name ) { + final String name ) { Preconditions. checkNotNull( container ); Preconditions. checkNotNull( name ); @@ -769,7 +767,7 @@ public class ControllerContext implements SchemaContextListener { Predicate filter = new Predicate() { @Override - public boolean apply( DataSchemaNode node ) { + public boolean apply( final DataSchemaNode node ) { return Objects.equal( node.getQName().getLocalName(), name ); } }; @@ -785,7 +783,7 @@ public class ControllerContext implements SchemaContextListener { } Iterable choiceNodes = Iterables. filter( container.getChildNodes(), - ChoiceNode.class ); + ChoiceNode.class ); final Function> choiceFunction = new Function>() { @@ -796,7 +794,7 @@ public class ControllerContext implements SchemaContextListener { }; Iterable> map = Iterables.> transform( - choiceNodes, choiceFunction ); + choiceNodes, choiceFunction ); final Iterable allCases = Iterables. concat( map ); for( final ChoiceCaseNode caze : allCases ) { @@ -806,11 +804,11 @@ public class ControllerContext implements SchemaContextListener { public boolean isInstantiatedDataSchema( final DataSchemaNode node ) { return node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode || - node instanceof ContainerSchemaNode || node instanceof ListSchemaNode; + node instanceof ContainerSchemaNode || node instanceof ListSchemaNode; } private void addKeyValue( final HashMap map, final DataSchemaNode node, - final String uriValue, final MountInstance mountPoint ) { + final String uriValue, final MountInstance mountPoint ) { Preconditions. checkNotNull( uriValue ); Preconditions.checkArgument( (node instanceof LeafSchemaNode) ); @@ -830,8 +828,8 @@ public class ControllerContext implements SchemaContextListener { if( decoded == null ) { throw new RestconfDocumentedException( - uriValue + " from URI can't be resolved. " + additionalInfo, - ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE ); + uriValue + " from URI can't be resolved. " + additionalInfo, + ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE ); } map.put( node.getQName(), decoded ); @@ -888,8 +886,8 @@ public class ControllerContext implements SchemaContextListener { }; Optional namespace = FluentIterable.from( sorted ) - .transform( transform ) - .firstMatch( findFirst ); + .transform( transform ) + .firstMatch( findFirst ); return namespace.isPresent() ? QName.create( namespace.get(), node ) : null; } @@ -948,7 +946,7 @@ public class ControllerContext implements SchemaContextListener { } private CharSequence convertToRestconfIdentifier( final PathArgument argument, - final DataNodeContainer node ) { + final DataNodeContainer node ) { if( argument instanceof NodeIdentifier && node instanceof ContainerSchemaNode ) { return convertToRestconfIdentifier( (NodeIdentifier) argument, (ContainerSchemaNode) node ); } @@ -957,7 +955,7 @@ public class ControllerContext implements SchemaContextListener { } else if( argument != null && node != null ) { throw new IllegalArgumentException( - "Conversion of generic path argument is not supported" ); + "Conversion of generic path argument is not supported" ); } else { throw new IllegalArgumentException( "Unhandled parameter types: " @@ -966,7 +964,7 @@ public class ControllerContext implements SchemaContextListener { } private CharSequence convertToRestconfIdentifier( final NodeIdentifier argument, - final ContainerSchemaNode node ) { + final ContainerSchemaNode node ) { StringBuilder builder = new StringBuilder(); builder.append( "/" ); QName nodeType = argument.getNodeType(); @@ -975,7 +973,7 @@ public class ControllerContext implements SchemaContextListener { } private CharSequence convertToRestconfIdentifier( final NodeIdentifierWithPredicates argument, - final ListSchemaNode node ) { + final ListSchemaNode node ) { QName nodeType = argument.getNodeType(); final CharSequence nodeIdentifier = this.toRestconfIdentifier( nodeType ); final Map keyValues = argument.getKeyValues(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java index f7f70e8d87..934d4434c3 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java @@ -18,9 +18,9 @@ import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import com.google.common.base.Preconditions; public final class EmptyNodeWrapper implements NodeWrapper>, Node { - + private Node unwrapped; - + private String localName; private URI namespace; private QName name; @@ -30,27 +30,27 @@ public final class EmptyNodeWrapper implements NodeWrapper>, Node public boolean isComposite() { return composite; } - + public void setComposite(boolean composite) { this.composite = composite; } - + public EmptyNodeWrapper(URI namespace, String localName) { this.localName = Preconditions.checkNotNull(localName); this.namespace = namespace; } - + @Override public void setQname(QName name) { Preconditions.checkState(unwrapped == null, "Cannot change the object, due to data inconsistencies."); this.name = name; } - + @Override public QName getQname() { return name; } - + @Override public String getLocalName() { if (unwrapped != null) { @@ -58,7 +58,7 @@ public final class EmptyNodeWrapper implements NodeWrapper>, Node } return localName; } - + @Override public URI getNamespace() { if (unwrapped != null) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java index 14a558967d..d66e1610a5 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java @@ -20,11 +20,11 @@ public final class IdentityValuesDTO { elementData.add(new IdentityValue(namespace, value, prefix)); this.originValue = originValue; } - + public IdentityValuesDTO(String originValue) { this.originValue = originValue; } - + public IdentityValuesDTO() { originValue = null; } @@ -32,21 +32,21 @@ public final class IdentityValuesDTO { public void add(String namespace, String value, String prefix) { elementData.add(new IdentityValue(namespace, value, prefix)); } - + public void add(IdentityValue identityValue) { elementData.add(identityValue); } - + public List getValuesWithNamespaces() { return Collections.unmodifiableList(elementData); } - + @Override public String toString() { return elementData.toString(); } - + public String getOriginValue() { return originValue; } @@ -86,7 +86,7 @@ public final class IdentityValuesDTO { public void setPredicates(List predicates) { this.predicates = predicates; } - + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -110,22 +110,22 @@ public final class IdentityValuesDTO { } } - + public static final class Predicate { - + private final IdentityValue name; private final String value; - + public Predicate(IdentityValue name, String value) { super(); this.name = name; this.value = value; } - + public IdentityValue getName() { return name; } - + public String getValue() { return value; } @@ -141,10 +141,10 @@ public final class IdentityValuesDTO { } return sb.toString(); } - + public boolean isLeafList() { return name == null ? true : false; } - + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NodeWrapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NodeWrapper.java index f9bd7d7aaa..48fd1a3dfc 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NodeWrapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/NodeWrapper.java @@ -15,16 +15,16 @@ import org.opendaylight.yangtools.yang.data.api.Node; public interface NodeWrapper> { void setQname(QName name); - + QName getQname(); - + T unwrap(); - + boolean isChangeAllowed(); - + URI getNamespace(); void setNamespace(URI namespace); - + String getLocalName(); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java index 42658d79f1..265cc5db45 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java @@ -41,7 +41,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RestCodec { - + private static final Logger logger = LoggerFactory.getLogger(RestCodec.class); private RestCodec() { @@ -180,7 +180,7 @@ public class RestCodec { logger.info("Idenetityref will be translated as NULL for data - {}", String.valueOf(valueWithNamespace)); return null; } - + return QName.create(module.getNamespace(), module.getRevision(), valueWithNamespace.getValue()); } @@ -292,7 +292,7 @@ public class RestCodec { } } } - + return result.isEmpty() ? null : new InstanceIdentifier(result); } @@ -312,7 +312,7 @@ public class RestCodec { return null; } } - + private static Module getModuleByNamespace(String namespace, MountInstance mountPoint) { URI validNamespace = resolveValidNamespace(namespace, mountPoint); @@ -328,7 +328,7 @@ public class RestCodec { } return module; } - + private static URI resolveValidNamespace(String namespace, MountInstance mountPoint) { URI validNamespace; if (mountPoint != null) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java index 4d22bfa73a..3131668ed9 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/SimpleNodeWrapper.java @@ -19,9 +19,9 @@ import org.opendaylight.yangtools.yang.data.impl.NodeFactory; import com.google.common.base.Preconditions; public final class SimpleNodeWrapper implements NodeWrapper>, SimpleNode { - + private SimpleNode simpleNode; - + private String localName; private Object value; private URI namespace; @@ -31,23 +31,23 @@ public final class SimpleNodeWrapper implements NodeWrapper>, Simp this.localName = Preconditions.checkNotNull(localName); this.value = value; } - + public SimpleNodeWrapper(URI namespace, String localName, Object value) { this(localName, value); this.namespace = namespace; } - + @Override public void setQname(QName name) { Preconditions.checkState(simpleNode == null, "Cannot change the object, due to data inconsistencies."); this.name = name; } - + @Override public QName getQname() { return name; } - + @Override public String getLocalName() { if (simpleNode != null) { @@ -55,7 +55,7 @@ public final class SimpleNodeWrapper implements NodeWrapper>, Simp } return localName; } - + @Override public URI getNamespace() { if (simpleNode != null) { @@ -83,7 +83,7 @@ public final class SimpleNodeWrapper implements NodeWrapper>, Simp name = new QName(namespace, localName); } simpleNode = NodeFactory.createImmutableSimpleNode(name, null, value); - + value = null; namespace = null; localName = null; @@ -126,7 +126,7 @@ public final class SimpleNodeWrapper implements NodeWrapper>, Simp public Object setValue(Object value) { return unwrap().setValue(value); } - + } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java index 8c344a79da..231fe7e02e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java @@ -9,7 +9,7 @@ package org.opendaylight.controller.sal.restconf.impl; import org.opendaylight.controller.sal.core.api.mount.MountInstance; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.model.api.*; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; public class StructuredData { @@ -17,7 +17,7 @@ public class StructuredData { private final DataSchemaNode schema; private final MountInstance mountPoint; - public StructuredData(CompositeNode data, DataSchemaNode schema, MountInstance mountPoint) { + public StructuredData(final CompositeNode data, final DataSchemaNode schema, final MountInstance mountPoint) { this.data = data; this.schema = schema; this.mountPoint = mountPoint; diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java index f2a0d48e0a..6282f37602 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java @@ -64,611 +64,611 @@ import com.google.common.eventbus.Subscribe; */ public class ListenerAdapter implements DataChangeListener { - private static final Logger logger = LoggerFactory - .getLogger(ListenerAdapter.class); - private final XmlMapper xmlMapper = new XmlMapper(); - private final SimpleDateFormat rfc3339 = new SimpleDateFormat( - "yyyy-MM-dd'T'hh:mm:ssZ"); - - private final InstanceIdentifier path; - private ListenerRegistration registration; - private final String streamName; - private Set subscribers = new ConcurrentSet<>(); - private final EventBus eventBus; - private final EventBusChangeRecorder eventBusChangeRecorder; - - /** - * Creates new {@link ListenerAdapter} listener specified by path and stream - * name. - * - * @param path - * Path to data in data store. - * @param streamName - * The name of the stream. - */ - ListenerAdapter(InstanceIdentifier path, String streamName) { - Preconditions.checkNotNull(path); - Preconditions - .checkArgument(streamName != null && !streamName.isEmpty()); - this.path = path; - this.streamName = streamName; - eventBus = new AsyncEventBus(Executors.newSingleThreadExecutor()); - eventBusChangeRecorder = new EventBusChangeRecorder(); - eventBus.register(eventBusChangeRecorder); - } - - @Override - public void onDataChanged( - DataChangeEvent change) { - if (!change.getCreatedConfigurationData().isEmpty() - || !change.getCreatedOperationalData().isEmpty() - || !change.getUpdatedConfigurationData().isEmpty() - || !change.getUpdatedOperationalData().isEmpty() - || !change.getRemovedConfigurationData().isEmpty() - || !change.getRemovedOperationalData().isEmpty()) { - String xml = prepareXmlFrom(change); - Event event = new Event(EventType.NOTIFY); - event.setData(xml); - eventBus.post(event); - } - } - - /** - * Tracks events of data change by customer. - */ - private final class EventBusChangeRecorder { - @Subscribe - public void recordCustomerChange(Event event) { - if (event.getType() == EventType.REGISTER) { - Channel subscriber = event.getSubscriber(); - if (!subscribers.contains(subscriber)) { - subscribers.add(subscriber); - } - } else if (event.getType() == EventType.DEREGISTER) { - subscribers.remove(event.getSubscriber()); - Notificator - .removeListenerIfNoSubscriberExists(ListenerAdapter.this); - } else if (event.getType() == EventType.NOTIFY) { - for (Channel subscriber : subscribers) { - if (subscriber.isActive()) { - logger.debug("Data are sent to subscriber {}:", - subscriber.remoteAddress()); - subscriber.writeAndFlush(new TextWebSocketFrame(event - .getData())); - } else { - logger.debug( - "Subscriber {} is removed - channel is not active yet.", - subscriber.remoteAddress()); - subscribers.remove(subscriber); - } - } - } - } - } - - /** - * Represents event of specific {@link EventType} type, holds data and - * {@link Channel} subscriber. - */ - private final class Event { - private final EventType type; - private Channel subscriber; - private String data; - - /** - * Creates new event specified by {@link EventType} type. - * - * @param type - * EventType - */ - public Event(EventType type) { - this.type = type; - } - - /** - * Gets the {@link Channel} subscriber. - * - * @return Channel - */ - public Channel getSubscriber() { - return subscriber; - } - - /** - * Sets subscriber for event. - * - * @param subscriber - * Channel - */ - public void setSubscriber(Channel subscriber) { - this.subscriber = subscriber; - } - - /** - * Gets event data. - * - * @return String representation of event data. - */ - public String getData() { - return data; - } - - /** - * Sets event data. - * - * @param String - * data. - */ - public void setData(String data) { - this.data = data; - } - - /** - * Gets event type. - * - * @return The type of the event. - */ - public EventType getType() { - return type; - } - } - - /** - * Type of the event. - */ - private enum EventType { - REGISTER, DEREGISTER, NOTIFY; - } - - /** - * Prepare data in printable form and transform it to String. - * - * @param change - * DataChangeEvent - * @return Data in printable form. - */ - private String prepareXmlFrom( - DataChangeEvent change) { - Document doc = createDocument(); - Element notificationElement = doc.createElementNS( - "urn:ietf:params:xml:ns:netconf:notification:1.0", - "notification"); - doc.appendChild(notificationElement); - - Element eventTimeElement = doc.createElement("eventTime"); - eventTimeElement.setTextContent(toRFC3339(new Date())); - notificationElement.appendChild(eventTimeElement); - - Element dataChangedNotificationEventElement = doc.createElementNS( - "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", - "data-changed-notification"); - addValuesToDataChangedNotificationEventElement(doc, - dataChangedNotificationEventElement, change); - notificationElement.appendChild(dataChangedNotificationEventElement); - - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(); - transformer - .setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); - transformer.setOutputProperty(OutputKeys.METHOD, "xml"); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - transformer.setOutputProperty( - "{http://xml.apache.org/xslt}indent-amount", "4"); - transformer.transform(new DOMSource(doc), new StreamResult( - new OutputStreamWriter(out, "UTF-8"))); - byte[] charData = out.toByteArray(); - return new String(charData, "UTF-8"); - } catch (TransformerException | UnsupportedEncodingException e) { - String msg = "Error during transformation of Document into String"; - logger.error(msg, e); - return msg; - } - } - - /** - * Formats data specified by RFC3339. - * - * @param d - * Date - * @return Data specified by RFC3339. - */ - private String toRFC3339(Date d) { - return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2"); - } - - /** - * Creates {@link Document} document. - * - * @return {@link Document} document. - */ - private Document createDocument() { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - Document doc = null; - try { - DocumentBuilder bob = dbf.newDocumentBuilder(); - doc = bob.newDocument(); - } catch (ParserConfigurationException e) { - return null; - } - return doc; - } - - /** - * Adds values to data changed notification event element. - * - * @param doc - * {@link Document} - * @param dataChangedNotificationEventElement - * {@link Element} - * @param change - * {@link DataChangeEvent} - */ - private void addValuesToDataChangedNotificationEventElement(Document doc, - Element dataChangedNotificationEventElement, - DataChangeEvent change) { - addValuesFromDataToElement(doc, change.getCreatedConfigurationData(), - dataChangedNotificationEventElement, Store.CONFIG, - Operation.CREATED); - addValuesFromDataToElement(doc, change.getCreatedOperationalData(), - dataChangedNotificationEventElement, Store.OPERATION, - Operation.CREATED); - if (change.getCreatedConfigurationData().isEmpty()) { - addValuesFromDataToElement(doc, - change.getUpdatedConfigurationData(), - dataChangedNotificationEventElement, Store.CONFIG, - Operation.UPDATED); - } - if (change.getCreatedOperationalData().isEmpty()) { - addValuesFromDataToElement(doc, change.getUpdatedOperationalData(), - dataChangedNotificationEventElement, Store.OPERATION, - Operation.UPDATED); - } - addValuesFromDataToElement(doc, change.getRemovedConfigurationData(), - dataChangedNotificationEventElement, Store.CONFIG, - Operation.DELETED); - addValuesFromDataToElement(doc, change.getRemovedOperationalData(), - dataChangedNotificationEventElement, Store.OPERATION, - Operation.DELETED); - } - - /** - * Adds values from data to element. - * - * @param doc - * {@link Document} - * @param data - * Set of {@link InstanceIdentifier}. - * @param element - * {@link Element} - * @param store - * {@link Store} - * @param operation - * {@link Operation} - */ - private void addValuesFromDataToElement(Document doc, - Set data, Element element, Store store, - Operation operation) { - if (data == null || data.isEmpty()) { - return; - } - for (InstanceIdentifier path : data) { - Node node = createDataChangeEventElement(doc, path, null, store, - operation); - element.appendChild(node); - } - } - - /** - * Adds values from data to element. - * - * @param doc - * {@link Document} - * @param data - * Map of {@link InstanceIdentifier} and {@link CompositeNode}. - * @param element - * {@link Element} - * @param store - * {@link Store} - * @param operation - * {@link Operation} - */ - private void addValuesFromDataToElement(Document doc, - Map data, Element element, - Store store, Operation operation) { - if (data == null || data.isEmpty()) { - return; - } - for (Entry entry : data.entrySet()) { - Node node = createDataChangeEventElement(doc, entry.getKey(), - entry.getValue(), store, operation); - element.appendChild(node); - } - } - - /** - * Creates changed event element from data. - * - * @param doc - * {@link Document} - * @param path - * Path to data in data store. - * @param data - * {@link CompositeNode} - * @param store - * {@link Store} - * @param operation - * {@link Operation} - * @return {@link Node} node represented by changed event element. - */ - private Node createDataChangeEventElement(Document doc, - InstanceIdentifier path, CompositeNode data, Store store, - Operation operation) { - Element dataChangeEventElement = doc.createElement("data-change-event"); - - Element pathElement = doc.createElement("path"); - addPathAsValueToElement(path, pathElement); - dataChangeEventElement.appendChild(pathElement); - - Element storeElement = doc.createElement("store"); - storeElement.setTextContent(store.value); - dataChangeEventElement.appendChild(storeElement); - - Element operationElement = doc.createElement("operation"); - operationElement.setTextContent(operation.value); - dataChangeEventElement.appendChild(operationElement); - - if (data != null) { - Element dataElement = doc.createElement("data"); - Node dataAnyXml = translateToXml(path, data); - Node adoptedNode = doc.adoptNode(dataAnyXml); - dataElement.appendChild(adoptedNode); - dataChangeEventElement.appendChild(dataElement); - } - - return dataChangeEventElement; - } - - /** - * Translates {@link CompositeNode} data to XML format. - * - * @param path - * Path to data in data store. - * @param data - * {@link CompositeNode} - * @return Data in XML format. - */ - private Node translateToXml(InstanceIdentifier path, CompositeNode data) { - DataNodeContainer schemaNode = ControllerContext.getInstance() - .getDataNodeContainerFor(path); - if (schemaNode == null) { - logger.info( - "Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.", - path); - return null; - } - try { - Document xml = xmlMapper.write(data, schemaNode); - return xml.getFirstChild(); - } catch (UnsupportedDataTypeException e) { - logger.error( - "Error occured during translation of notification to XML.", - e); - return null; - } - } - - /** - * Adds path as value to element. - * - * @param path - * Path to data in data store. - * @param element - * {@link Element} - */ - private void addPathAsValueToElement(InstanceIdentifier path, - Element element) { - // Map< key = namespace, value = prefix> - Map prefixes = new HashMap<>(); - InstanceIdentifier instanceIdentifier = path; - StringBuilder textContent = new StringBuilder(); - for (PathArgument pathArgument : instanceIdentifier.getPath()) { - textContent.append("/"); - writeIdentifierWithNamespacePrefix(element, textContent, - pathArgument.getNodeType(), prefixes); - if (pathArgument instanceof NodeIdentifierWithPredicates) { - Map predicates = ((NodeIdentifierWithPredicates) pathArgument) - .getKeyValues(); - for (QName keyValue : predicates.keySet()) { - String predicateValue = String.valueOf(predicates - .get(keyValue)); - textContent.append("["); - writeIdentifierWithNamespacePrefix(element, textContent, - keyValue, prefixes); - textContent.append("='"); - textContent.append(predicateValue); - textContent.append("'"); - textContent.append("]"); - } - } else if (pathArgument instanceof NodeWithValue) { - textContent.append("[.='"); - textContent.append(((NodeWithValue) pathArgument).getValue()); - textContent.append("'"); - textContent.append("]"); - } - } - element.setTextContent(textContent.toString()); - } - - /** - * Writes identifier that consists of prefix and QName. - * - * @param element - * {@link Element} - * @param textContent - * StringBuilder - * @param qName - * QName - * @param prefixes - * Map of namespaces and prefixes. - */ - private static void writeIdentifierWithNamespacePrefix(Element element, - StringBuilder textContent, QName qName, Map prefixes) { - String namespace = qName.getNamespace().toString(); - String prefix = prefixes.get(namespace); - if (prefix == null) { - prefix = qName.getPrefix(); - if (prefix == null || prefix.isEmpty() - || prefixes.containsValue(prefix)) { - prefix = generateNewPrefix(prefixes.values()); - } - } - - element.setAttribute("xmlns:" + prefix, namespace); - textContent.append(prefix); - prefixes.put(namespace, prefix); - - textContent.append(":"); - textContent.append(qName.getLocalName()); - } - - /** - * Generates new prefix which consists of four random characters . - * - * @param prefixes - * Collection of prefixes. - * @return New prefix which consists of four random characters . - */ - private static String generateNewPrefix(Collection prefixes) { - StringBuilder result = null; - Random random = new Random(); - do { - result = new StringBuilder(); - for (int i = 0; i < 4; i++) { - int randomNumber = 0x61 + (Math.abs(random.nextInt()) % 26); - result.append(Character.toChars(randomNumber)); - } - } while (prefixes.contains(result.toString())); - - return result.toString(); - } - - /** - * Gets path pointed to data in data store. - * - * @return Path pointed to data in data store. - */ - public InstanceIdentifier getPath() { - return path; - } - - /** - * Sets {@link ListenerRegistration} registration. - * - * @param registration - * ListenerRegistration - */ - public void setRegistration( - ListenerRegistration registration) { - this.registration = registration; - } - - /** - * Gets the name of the stream. - * - * @return The name of the stream. - */ - public String getStreamName() { - return streamName; - } - - /** - * Removes all subscribers and unregisters event bus change recorder form - * event bus. - */ - public void close() throws Exception { - subscribers = new ConcurrentSet<>(); - registration.close(); - registration = null; - eventBus.unregister(eventBusChangeRecorder); - } - - /** - * Checks if {@link ListenerRegistration} registration exist. - * - * @return True if exist, false otherwise. - */ - public boolean isListening() { - return registration == null ? false : true; - } - - /** - * Creates event of type {@link EventType#REGISTER}, set {@link Channel} - * subscriber to the event and post event into event bus. - * - * @param subscriber - * Channel - */ - public void addSubscriber(Channel subscriber) { - if (!subscriber.isActive()) { - logger.debug("Channel is not active between websocket server and subscriber {}" - + subscriber.remoteAddress()); - } - Event event = new Event(EventType.REGISTER); - event.setSubscriber(subscriber); - eventBus.post(event); - } - - /** - * Creates event of type {@link EventType#DEREGISTER}, sets {@link Channel} - * subscriber to the event and posts event into event bus. - * - * @param subscriber - */ - public void removeSubscriber(Channel subscriber) { - logger.debug("Subscriber {} is removed.", subscriber.remoteAddress()); - Event event = new Event(EventType.DEREGISTER); - event.setSubscriber(subscriber); - eventBus.post(event); - } - - /** - * Checks if exists at least one {@link Channel} subscriber. - * - * @return True if exist at least one {@link Channel} subscriber, false - * otherwise. - */ - public boolean hasSubscribers() { - return !subscribers.isEmpty(); - } - - /** - * Consists of two types {@link Store#CONFIG} and {@link Store#OPERATION}. - */ - private static enum Store { - CONFIG("config"), OPERATION("operation"); - - private final String value; - - private Store(String value) { - this.value = value; - } - } - - /** - * Consists of three types {@link Operation#CREATED}, - * {@link Operation#UPDATED} and {@link Operation#DELETED}. - */ - private static enum Operation { - CREATED("created"), UPDATED("updated"), DELETED("deleted"); - - private final String value; - - private Operation(String value) { - this.value = value; - } - } + private static final Logger logger = LoggerFactory + .getLogger(ListenerAdapter.class); + private final XmlMapper xmlMapper = new XmlMapper(); + private final SimpleDateFormat rfc3339 = new SimpleDateFormat( + "yyyy-MM-dd'T'hh:mm:ssZ"); + + private final InstanceIdentifier path; + private ListenerRegistration registration; + private final String streamName; + private Set subscribers = new ConcurrentSet<>(); + private final EventBus eventBus; + private final EventBusChangeRecorder eventBusChangeRecorder; + + /** + * Creates new {@link ListenerAdapter} listener specified by path and stream + * name. + * + * @param path + * Path to data in data store. + * @param streamName + * The name of the stream. + */ + ListenerAdapter(InstanceIdentifier path, String streamName) { + Preconditions.checkNotNull(path); + Preconditions + .checkArgument(streamName != null && !streamName.isEmpty()); + this.path = path; + this.streamName = streamName; + eventBus = new AsyncEventBus(Executors.newSingleThreadExecutor()); + eventBusChangeRecorder = new EventBusChangeRecorder(); + eventBus.register(eventBusChangeRecorder); + } + + @Override + public void onDataChanged( + DataChangeEvent change) { + if (!change.getCreatedConfigurationData().isEmpty() + || !change.getCreatedOperationalData().isEmpty() + || !change.getUpdatedConfigurationData().isEmpty() + || !change.getUpdatedOperationalData().isEmpty() + || !change.getRemovedConfigurationData().isEmpty() + || !change.getRemovedOperationalData().isEmpty()) { + String xml = prepareXmlFrom(change); + Event event = new Event(EventType.NOTIFY); + event.setData(xml); + eventBus.post(event); + } + } + + /** + * Tracks events of data change by customer. + */ + private final class EventBusChangeRecorder { + @Subscribe + public void recordCustomerChange(Event event) { + if (event.getType() == EventType.REGISTER) { + Channel subscriber = event.getSubscriber(); + if (!subscribers.contains(subscriber)) { + subscribers.add(subscriber); + } + } else if (event.getType() == EventType.DEREGISTER) { + subscribers.remove(event.getSubscriber()); + Notificator + .removeListenerIfNoSubscriberExists(ListenerAdapter.this); + } else if (event.getType() == EventType.NOTIFY) { + for (Channel subscriber : subscribers) { + if (subscriber.isActive()) { + logger.debug("Data are sent to subscriber {}:", + subscriber.remoteAddress()); + subscriber.writeAndFlush(new TextWebSocketFrame(event + .getData())); + } else { + logger.debug( + "Subscriber {} is removed - channel is not active yet.", + subscriber.remoteAddress()); + subscribers.remove(subscriber); + } + } + } + } + } + + /** + * Represents event of specific {@link EventType} type, holds data and + * {@link Channel} subscriber. + */ + private final class Event { + private final EventType type; + private Channel subscriber; + private String data; + + /** + * Creates new event specified by {@link EventType} type. + * + * @param type + * EventType + */ + public Event(EventType type) { + this.type = type; + } + + /** + * Gets the {@link Channel} subscriber. + * + * @return Channel + */ + public Channel getSubscriber() { + return subscriber; + } + + /** + * Sets subscriber for event. + * + * @param subscriber + * Channel + */ + public void setSubscriber(Channel subscriber) { + this.subscriber = subscriber; + } + + /** + * Gets event data. + * + * @return String representation of event data. + */ + public String getData() { + return data; + } + + /** + * Sets event data. + * + * @param String + * data. + */ + public void setData(String data) { + this.data = data; + } + + /** + * Gets event type. + * + * @return The type of the event. + */ + public EventType getType() { + return type; + } + } + + /** + * Type of the event. + */ + private enum EventType { + REGISTER, DEREGISTER, NOTIFY; + } + + /** + * Prepare data in printable form and transform it to String. + * + * @param change + * DataChangeEvent + * @return Data in printable form. + */ + private String prepareXmlFrom( + DataChangeEvent change) { + Document doc = createDocument(); + Element notificationElement = doc.createElementNS( + "urn:ietf:params:xml:ns:netconf:notification:1.0", + "notification"); + doc.appendChild(notificationElement); + + Element eventTimeElement = doc.createElement("eventTime"); + eventTimeElement.setTextContent(toRFC3339(new Date())); + notificationElement.appendChild(eventTimeElement); + + Element dataChangedNotificationEventElement = doc.createElementNS( + "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", + "data-changed-notification"); + addValuesToDataChangedNotificationEventElement(doc, + dataChangedNotificationEventElement, change); + notificationElement.appendChild(dataChangedNotificationEventElement); + + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer + .setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty( + "{http://xml.apache.org/xslt}indent-amount", "4"); + transformer.transform(new DOMSource(doc), new StreamResult( + new OutputStreamWriter(out, "UTF-8"))); + byte[] charData = out.toByteArray(); + return new String(charData, "UTF-8"); + } catch (TransformerException | UnsupportedEncodingException e) { + String msg = "Error during transformation of Document into String"; + logger.error(msg, e); + return msg; + } + } + + /** + * Formats data specified by RFC3339. + * + * @param d + * Date + * @return Data specified by RFC3339. + */ + private String toRFC3339(Date d) { + return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2"); + } + + /** + * Creates {@link Document} document. + * + * @return {@link Document} document. + */ + private Document createDocument() { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + Document doc = null; + try { + DocumentBuilder bob = dbf.newDocumentBuilder(); + doc = bob.newDocument(); + } catch (ParserConfigurationException e) { + return null; + } + return doc; + } + + /** + * Adds values to data changed notification event element. + * + * @param doc + * {@link Document} + * @param dataChangedNotificationEventElement + * {@link Element} + * @param change + * {@link DataChangeEvent} + */ + private void addValuesToDataChangedNotificationEventElement(Document doc, + Element dataChangedNotificationEventElement, + DataChangeEvent change) { + addValuesFromDataToElement(doc, change.getCreatedConfigurationData(), + dataChangedNotificationEventElement, Store.CONFIG, + Operation.CREATED); + addValuesFromDataToElement(doc, change.getCreatedOperationalData(), + dataChangedNotificationEventElement, Store.OPERATION, + Operation.CREATED); + if (change.getCreatedConfigurationData().isEmpty()) { + addValuesFromDataToElement(doc, + change.getUpdatedConfigurationData(), + dataChangedNotificationEventElement, Store.CONFIG, + Operation.UPDATED); + } + if (change.getCreatedOperationalData().isEmpty()) { + addValuesFromDataToElement(doc, change.getUpdatedOperationalData(), + dataChangedNotificationEventElement, Store.OPERATION, + Operation.UPDATED); + } + addValuesFromDataToElement(doc, change.getRemovedConfigurationData(), + dataChangedNotificationEventElement, Store.CONFIG, + Operation.DELETED); + addValuesFromDataToElement(doc, change.getRemovedOperationalData(), + dataChangedNotificationEventElement, Store.OPERATION, + Operation.DELETED); + } + + /** + * Adds values from data to element. + * + * @param doc + * {@link Document} + * @param data + * Set of {@link InstanceIdentifier}. + * @param element + * {@link Element} + * @param store + * {@link Store} + * @param operation + * {@link Operation} + */ + private void addValuesFromDataToElement(Document doc, + Set data, Element element, Store store, + Operation operation) { + if (data == null || data.isEmpty()) { + return; + } + for (InstanceIdentifier path : data) { + Node node = createDataChangeEventElement(doc, path, null, store, + operation); + element.appendChild(node); + } + } + + /** + * Adds values from data to element. + * + * @param doc + * {@link Document} + * @param data + * Map of {@link InstanceIdentifier} and {@link CompositeNode}. + * @param element + * {@link Element} + * @param store + * {@link Store} + * @param operation + * {@link Operation} + */ + private void addValuesFromDataToElement(Document doc, + Map data, Element element, + Store store, Operation operation) { + if (data == null || data.isEmpty()) { + return; + } + for (Entry entry : data.entrySet()) { + Node node = createDataChangeEventElement(doc, entry.getKey(), + entry.getValue(), store, operation); + element.appendChild(node); + } + } + + /** + * Creates changed event element from data. + * + * @param doc + * {@link Document} + * @param path + * Path to data in data store. + * @param data + * {@link CompositeNode} + * @param store + * {@link Store} + * @param operation + * {@link Operation} + * @return {@link Node} node represented by changed event element. + */ + private Node createDataChangeEventElement(Document doc, + InstanceIdentifier path, CompositeNode data, Store store, + Operation operation) { + Element dataChangeEventElement = doc.createElement("data-change-event"); + + Element pathElement = doc.createElement("path"); + addPathAsValueToElement(path, pathElement); + dataChangeEventElement.appendChild(pathElement); + + Element storeElement = doc.createElement("store"); + storeElement.setTextContent(store.value); + dataChangeEventElement.appendChild(storeElement); + + Element operationElement = doc.createElement("operation"); + operationElement.setTextContent(operation.value); + dataChangeEventElement.appendChild(operationElement); + + if (data != null) { + Element dataElement = doc.createElement("data"); + Node dataAnyXml = translateToXml(path, data); + Node adoptedNode = doc.adoptNode(dataAnyXml); + dataElement.appendChild(adoptedNode); + dataChangeEventElement.appendChild(dataElement); + } + + return dataChangeEventElement; + } + + /** + * Translates {@link CompositeNode} data to XML format. + * + * @param path + * Path to data in data store. + * @param data + * {@link CompositeNode} + * @return Data in XML format. + */ + private Node translateToXml(InstanceIdentifier path, CompositeNode data) { + DataNodeContainer schemaNode = ControllerContext.getInstance() + .getDataNodeContainerFor(path); + if (schemaNode == null) { + logger.info( + "Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.", + path); + return null; + } + try { + Document xml = xmlMapper.write(data, schemaNode); + return xml.getFirstChild(); + } catch (UnsupportedDataTypeException e) { + logger.error( + "Error occured during translation of notification to XML.", + e); + return null; + } + } + + /** + * Adds path as value to element. + * + * @param path + * Path to data in data store. + * @param element + * {@link Element} + */ + private void addPathAsValueToElement(InstanceIdentifier path, + Element element) { + // Map< key = namespace, value = prefix> + Map prefixes = new HashMap<>(); + InstanceIdentifier instanceIdentifier = path; + StringBuilder textContent = new StringBuilder(); + for (PathArgument pathArgument : instanceIdentifier.getPath()) { + textContent.append("/"); + writeIdentifierWithNamespacePrefix(element, textContent, + pathArgument.getNodeType(), prefixes); + if (pathArgument instanceof NodeIdentifierWithPredicates) { + Map predicates = ((NodeIdentifierWithPredicates) pathArgument) + .getKeyValues(); + for (QName keyValue : predicates.keySet()) { + String predicateValue = String.valueOf(predicates + .get(keyValue)); + textContent.append("["); + writeIdentifierWithNamespacePrefix(element, textContent, + keyValue, prefixes); + textContent.append("='"); + textContent.append(predicateValue); + textContent.append("'"); + textContent.append("]"); + } + } else if (pathArgument instanceof NodeWithValue) { + textContent.append("[.='"); + textContent.append(((NodeWithValue) pathArgument).getValue()); + textContent.append("'"); + textContent.append("]"); + } + } + element.setTextContent(textContent.toString()); + } + + /** + * Writes identifier that consists of prefix and QName. + * + * @param element + * {@link Element} + * @param textContent + * StringBuilder + * @param qName + * QName + * @param prefixes + * Map of namespaces and prefixes. + */ + private static void writeIdentifierWithNamespacePrefix(Element element, + StringBuilder textContent, QName qName, Map prefixes) { + String namespace = qName.getNamespace().toString(); + String prefix = prefixes.get(namespace); + if (prefix == null) { + prefix = qName.getPrefix(); + if (prefix == null || prefix.isEmpty() + || prefixes.containsValue(prefix)) { + prefix = generateNewPrefix(prefixes.values()); + } + } + + element.setAttribute("xmlns:" + prefix, namespace); + textContent.append(prefix); + prefixes.put(namespace, prefix); + + textContent.append(":"); + textContent.append(qName.getLocalName()); + } + + /** + * Generates new prefix which consists of four random characters . + * + * @param prefixes + * Collection of prefixes. + * @return New prefix which consists of four random characters . + */ + private static String generateNewPrefix(Collection prefixes) { + StringBuilder result = null; + Random random = new Random(); + do { + result = new StringBuilder(); + for (int i = 0; i < 4; i++) { + int randomNumber = 0x61 + (Math.abs(random.nextInt()) % 26); + result.append(Character.toChars(randomNumber)); + } + } while (prefixes.contains(result.toString())); + + return result.toString(); + } + + /** + * Gets path pointed to data in data store. + * + * @return Path pointed to data in data store. + */ + public InstanceIdentifier getPath() { + return path; + } + + /** + * Sets {@link ListenerRegistration} registration. + * + * @param registration + * ListenerRegistration + */ + public void setRegistration( + ListenerRegistration registration) { + this.registration = registration; + } + + /** + * Gets the name of the stream. + * + * @return The name of the stream. + */ + public String getStreamName() { + return streamName; + } + + /** + * Removes all subscribers and unregisters event bus change recorder form + * event bus. + */ + public void close() throws Exception { + subscribers = new ConcurrentSet<>(); + registration.close(); + registration = null; + eventBus.unregister(eventBusChangeRecorder); + } + + /** + * Checks if {@link ListenerRegistration} registration exist. + * + * @return True if exist, false otherwise. + */ + public boolean isListening() { + return registration == null ? false : true; + } + + /** + * Creates event of type {@link EventType#REGISTER}, set {@link Channel} + * subscriber to the event and post event into event bus. + * + * @param subscriber + * Channel + */ + public void addSubscriber(Channel subscriber) { + if (!subscriber.isActive()) { + logger.debug("Channel is not active between websocket server and subscriber {}" + + subscriber.remoteAddress()); + } + Event event = new Event(EventType.REGISTER); + event.setSubscriber(subscriber); + eventBus.post(event); + } + + /** + * Creates event of type {@link EventType#DEREGISTER}, sets {@link Channel} + * subscriber to the event and posts event into event bus. + * + * @param subscriber + */ + public void removeSubscriber(Channel subscriber) { + logger.debug("Subscriber {} is removed.", subscriber.remoteAddress()); + Event event = new Event(EventType.DEREGISTER); + event.setSubscriber(subscriber); + eventBus.post(event); + } + + /** + * Checks if exists at least one {@link Channel} subscriber. + * + * @return True if exist at least one {@link Channel} subscriber, false + * otherwise. + */ + public boolean hasSubscribers() { + return !subscribers.isEmpty(); + } + + /** + * Consists of two types {@link Store#CONFIG} and {@link Store#OPERATION}. + */ + private static enum Store { + CONFIG("config"), OPERATION("operation"); + + private final String value; + + private Store(String value) { + this.value = value; + } + } + + /** + * Consists of three types {@link Operation#CREATED}, + * {@link Operation#UPDATED} and {@link Operation#DELETED}. + */ + private static enum Operation { + CREATED("created"), UPDATED("updated"), DELETED("deleted"); + + private final String value; + + private Operation(String value) { + this.value = value; + } + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java index 6f154f8aff..a576eed269 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/Notificator.java @@ -21,11 +21,11 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; public class Notificator { private static Map listenersByStreamName = new ConcurrentHashMap<>(); - private static Map listenersByInstanceIdentifier = new ConcurrentHashMap<>(); - private static final Lock lock = new ReentrantLock(); + private static Map listenersByInstanceIdentifier = new ConcurrentHashMap<>(); + private static final Lock lock = new ReentrantLock(); - private Notificator() { - } + private Notificator() { + } /** * Returns list of all stream names @@ -35,152 +35,152 @@ public class Notificator { } - /** - * Gets {@link ListenerAdapter} specified by stream name. - * - * @param streamName - * The name of the stream. - * @return {@link ListenerAdapter} specified by stream name. - */ - public static ListenerAdapter getListenerFor(String streamName) { - return listenersByStreamName.get(streamName); - } - - /** - * Gets {@link ListenerAdapter} listener specified by - * {@link InstanceIdentifier} path. - * - * @param path - * Path to data in data repository. - * @return ListenerAdapter - */ - public static ListenerAdapter getListenerFor(InstanceIdentifier path) { - return listenersByInstanceIdentifier.get(path); - } - - /** - * Checks if the listener specified by {@link InstanceIdentifier} path - * exist. - * - * @param path - * Path to data in data repository. - * @return True if the listener exist, false otherwise. - */ - public static boolean existListenerFor(InstanceIdentifier path) { - return listenersByInstanceIdentifier.containsKey(path); - } - - /** - * Creates new {@link ListenerAdapter} listener from - * {@link InstanceIdentifier} path and stream name. - * - * @param path - * Path to data in data repository. - * @param streamName - * The name of the stream. - * @return New {@link ListenerAdapter} listener from - * {@link InstanceIdentifier} path and stream name. - */ - public static ListenerAdapter createListener(InstanceIdentifier path, - String streamName) { - ListenerAdapter listener = new ListenerAdapter(path, streamName); - try { - lock.lock(); - listenersByInstanceIdentifier.put(path, listener); - listenersByStreamName.put(streamName, listener); - } finally { - lock.unlock(); - } - return listener; - } - - /** - * Looks for listener determined by {@link InstanceIdentifier} path and - * removes it. - * - * @param path - * InstanceIdentifier - */ - public static void removeListener(InstanceIdentifier path) { - ListenerAdapter listener = listenersByInstanceIdentifier.get(path); - deleteListener(listener); - } - - /** - * Creates String representation of stream name from URI. Removes slash from - * URI in start and end position. - * - * @param uri - * URI for creation stream name. - * @return String representation of stream name. - */ - public static String createStreamNameFromUri(String uri) { - if (uri == null) { - return null; - } - String result = uri; - if (result.startsWith("/")) { - result = result.substring(1); - } - if (result.endsWith("/")) { - result = result.substring(0, result.length()); - } - return result; - } - - /** - * Removes all listeners. - */ - public static void removeAllListeners() { - for (ListenerAdapter listener : listenersByInstanceIdentifier.values()) { - try { - listener.close(); - } catch (Exception e) { - } - } - try { - lock.lock(); - listenersByStreamName = new ConcurrentHashMap<>(); - listenersByInstanceIdentifier = new ConcurrentHashMap<>(); - } finally { - lock.unlock(); - } - } - - /** - * Checks if listener has at least one subscriber. In case it doesn't have any, delete - * listener. - * - * @param listener - * ListenerAdapter - */ - public static void removeListenerIfNoSubscriberExists( - ListenerAdapter listener) { - if (!listener.hasSubscribers()) { - deleteListener(listener); - } - } - - /** - * Delete {@link ListenerAdapter} listener specified in parameter. - * - * @param listener - * ListenerAdapter - */ - private static void deleteListener(ListenerAdapter listener) { - if (listener != null) { - try { - listener.close(); - } catch (Exception e) { - } - try { - lock.lock(); - listenersByInstanceIdentifier.remove(listener.getPath()); - listenersByStreamName.remove(listener.getStreamName()); - } finally { - lock.unlock(); - } - } - } + /** + * Gets {@link ListenerAdapter} specified by stream name. + * + * @param streamName + * The name of the stream. + * @return {@link ListenerAdapter} specified by stream name. + */ + public static ListenerAdapter getListenerFor(String streamName) { + return listenersByStreamName.get(streamName); + } + + /** + * Gets {@link ListenerAdapter} listener specified by + * {@link InstanceIdentifier} path. + * + * @param path + * Path to data in data repository. + * @return ListenerAdapter + */ + public static ListenerAdapter getListenerFor(InstanceIdentifier path) { + return listenersByInstanceIdentifier.get(path); + } + + /** + * Checks if the listener specified by {@link InstanceIdentifier} path + * exist. + * + * @param path + * Path to data in data repository. + * @return True if the listener exist, false otherwise. + */ + public static boolean existListenerFor(InstanceIdentifier path) { + return listenersByInstanceIdentifier.containsKey(path); + } + + /** + * Creates new {@link ListenerAdapter} listener from + * {@link InstanceIdentifier} path and stream name. + * + * @param path + * Path to data in data repository. + * @param streamName + * The name of the stream. + * @return New {@link ListenerAdapter} listener from + * {@link InstanceIdentifier} path and stream name. + */ + public static ListenerAdapter createListener(InstanceIdentifier path, + String streamName) { + ListenerAdapter listener = new ListenerAdapter(path, streamName); + try { + lock.lock(); + listenersByInstanceIdentifier.put(path, listener); + listenersByStreamName.put(streamName, listener); + } finally { + lock.unlock(); + } + return listener; + } + + /** + * Looks for listener determined by {@link InstanceIdentifier} path and + * removes it. + * + * @param path + * InstanceIdentifier + */ + public static void removeListener(InstanceIdentifier path) { + ListenerAdapter listener = listenersByInstanceIdentifier.get(path); + deleteListener(listener); + } + + /** + * Creates String representation of stream name from URI. Removes slash from + * URI in start and end position. + * + * @param uri + * URI for creation stream name. + * @return String representation of stream name. + */ + public static String createStreamNameFromUri(String uri) { + if (uri == null) { + return null; + } + String result = uri; + if (result.startsWith("/")) { + result = result.substring(1); + } + if (result.endsWith("/")) { + result = result.substring(0, result.length()); + } + return result; + } + + /** + * Removes all listeners. + */ + public static void removeAllListeners() { + for (ListenerAdapter listener : listenersByInstanceIdentifier.values()) { + try { + listener.close(); + } catch (Exception e) { + } + } + try { + lock.lock(); + listenersByStreamName = new ConcurrentHashMap<>(); + listenersByInstanceIdentifier = new ConcurrentHashMap<>(); + } finally { + lock.unlock(); + } + } + + /** + * Checks if listener has at least one subscriber. In case it doesn't have any, delete + * listener. + * + * @param listener + * ListenerAdapter + */ + public static void removeListenerIfNoSubscriberExists( + ListenerAdapter listener) { + if (!listener.hasSubscribers()) { + deleteListener(listener); + } + } + + /** + * Delete {@link ListenerAdapter} listener specified in parameter. + * + * @param listener + * ListenerAdapter + */ + private static void deleteListener(ListenerAdapter listener) { + if (listener != null) { + try { + listener.close(); + } catch (Exception e) { + } + try { + lock.lock(); + listenersByInstanceIdentifier.remove(listener.getPath()); + listenersByStreamName.remove(listener.getStreamName()); + } finally { + lock.unlock(); + } + } + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java index 1640035420..fcfa8858ee 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServer.java @@ -16,45 +16,45 @@ import org.slf4j.LoggerFactory; */ public class WebSocketServer implements Runnable { - private static final Logger logger = LoggerFactory - .getLogger(WebSocketServer.class); - - public static final int PORT = 8181; - private EventLoopGroup bossGroup; - private EventLoopGroup workerGroup; - - @Override - public void run() { - bossGroup = new NioEventLoopGroup(); - workerGroup = new NioEventLoopGroup(); - try { - ServerBootstrap b = new ServerBootstrap(); - b.group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new WebSocketServerInitializer()); - - Channel ch = b.bind(PORT).sync().channel(); - logger.info("Web socket server started at port {}.", PORT); - - ch.closeFuture().sync(); - } catch (InterruptedException e) { - // NOOP - } finally { - stop(); - } - } - - /** - * Stops the web socket server and removes all listeners. - */ - private void stop() { - Notificator.removeAllListeners(); - if (bossGroup != null) { - bossGroup.shutdownGracefully(); - } - if (workerGroup != null) { - workerGroup.shutdownGracefully(); - } - } + private static final Logger logger = LoggerFactory + .getLogger(WebSocketServer.class); + + public static final int PORT = 8181; + private EventLoopGroup bossGroup; + private EventLoopGroup workerGroup; + + @Override + public void run() { + bossGroup = new NioEventLoopGroup(); + workerGroup = new NioEventLoopGroup(); + try { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new WebSocketServerInitializer()); + + Channel ch = b.bind(PORT).sync().channel(); + logger.info("Web socket server started at port {}.", PORT); + + ch.closeFuture().sync(); + } catch (InterruptedException e) { + // NOOP + } finally { + stop(); + } + } + + /** + * Stops the web socket server and removes all listeners. + */ + private void stop() { + Notificator.removeAllListeners(); + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + } + if (workerGroup != null) { + workerGroup.shutdownGracefully(); + } + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java index bf899a0b25..b5d6a6ea9b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java @@ -40,147 +40,147 @@ import org.slf4j.LoggerFactory; */ public class WebSocketServerHandler extends SimpleChannelInboundHandler { - private static final Logger logger = LoggerFactory - .getLogger(WebSocketServerHandler.class); - - private WebSocketServerHandshaker handshaker; - - @Override - protected void channelRead0(ChannelHandlerContext ctx, Object msg) - throws Exception { - if (msg instanceof FullHttpRequest) { - handleHttpRequest(ctx, (FullHttpRequest) msg); - } else if (msg instanceof WebSocketFrame) { - handleWebSocketFrame(ctx, (WebSocketFrame) msg); - } - } - - /** - * Checks if HTTP request method is GET and if is possible to decode HTTP - * result of request. - * - * @param ctx - * ChannelHandlerContext - * @param req - * FullHttpRequest - */ - private void handleHttpRequest(ChannelHandlerContext ctx, - FullHttpRequest req) throws Exception { - // Handle a bad request. - if (!req.getDecoderResult().isSuccess()) { - sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, - BAD_REQUEST)); - return; - } - - // Allow only GET methods. - if (req.getMethod() != GET) { - sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, - FORBIDDEN)); - return; - } - - String streamName = Notificator.createStreamNameFromUri(req.getUri()); - ListenerAdapter listener = Notificator.getListenerFor(streamName); - if (listener != null) { - listener.addSubscriber(ctx.channel()); - logger.debug("Subscriber successfully registered."); - } else { - logger.error("Listener for stream with name '{}' was not found.", - streamName); - sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, - INTERNAL_SERVER_ERROR)); - } - - // Handshake - WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( - getWebSocketLocation(req), null, false); - handshaker = wsFactory.newHandshaker(req); - if (handshaker == null) { - WebSocketServerHandshakerFactory - .sendUnsupportedWebSocketVersionResponse(ctx.channel()); - } else { - handshaker.handshake(ctx.channel(), req); - } - - } - - /** - * Checks response status, send response and close connection if necessary - * - * @param ctx - * ChannelHandlerContext - * @param req - * HttpRequest - * @param res - * FullHttpResponse - */ - private static void sendHttpResponse(ChannelHandlerContext ctx, - HttpRequest req, FullHttpResponse res) { - // Generate an error page if response getStatus code is not OK (200). - if (res.getStatus().code() != 200) { - ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), - CharsetUtil.UTF_8); - res.content().writeBytes(buf); - buf.release(); - setContentLength(res, res.content().readableBytes()); - } - - // Send the response and close the connection if necessary. - ChannelFuture f = ctx.channel().writeAndFlush(res); - if (!isKeepAlive(req) || res.getStatus().code() != 200) { - f.addListener(ChannelFutureListener.CLOSE); - } - } - - /** - * Handles web socket frame. - * - * @param ctx - * {@link ChannelHandlerContext} - * @param frame - * {@link WebSocketFrame} - */ - private void handleWebSocketFrame(ChannelHandlerContext ctx, - WebSocketFrame frame) throws IOException { - if (frame instanceof CloseWebSocketFrame) { - handshaker.close(ctx.channel(), - (CloseWebSocketFrame) frame.retain()); - String streamName = Notificator - .createStreamNameFromUri(((CloseWebSocketFrame) frame) - .reasonText()); - ListenerAdapter listener = Notificator.getListenerFor(streamName); - if (listener != null) { - listener.removeSubscriber(ctx.channel()); - logger.debug("Subscriber successfully registered."); - } - Notificator.removeListenerIfNoSubscriberExists(listener); - return; - } else if (frame instanceof PingWebSocketFrame) { - ctx.channel().write( - new PongWebSocketFrame(frame.content().retain())); - return; - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) - throws Exception { - if (cause instanceof java.nio.channels.ClosedChannelException == false) { - // cause.printStackTrace(); - } - ctx.close(); - } - - /** - * Get web socket location from HTTP request. - * - * @param req - * HTTP request from which the location will be returned - * @return String representation of web socket location. - */ - private static String getWebSocketLocation(HttpRequest req) { - return "http://" + req.headers().get(HOST) + req.getUri(); - } + private static final Logger logger = LoggerFactory + .getLogger(WebSocketServerHandler.class); + + private WebSocketServerHandshaker handshaker; + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Object msg) + throws Exception { + if (msg instanceof FullHttpRequest) { + handleHttpRequest(ctx, (FullHttpRequest) msg); + } else if (msg instanceof WebSocketFrame) { + handleWebSocketFrame(ctx, (WebSocketFrame) msg); + } + } + + /** + * Checks if HTTP request method is GET and if is possible to decode HTTP + * result of request. + * + * @param ctx + * ChannelHandlerContext + * @param req + * FullHttpRequest + */ + private void handleHttpRequest(ChannelHandlerContext ctx, + FullHttpRequest req) throws Exception { + // Handle a bad request. + if (!req.getDecoderResult().isSuccess()) { + sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, + BAD_REQUEST)); + return; + } + + // Allow only GET methods. + if (req.getMethod() != GET) { + sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, + FORBIDDEN)); + return; + } + + String streamName = Notificator.createStreamNameFromUri(req.getUri()); + ListenerAdapter listener = Notificator.getListenerFor(streamName); + if (listener != null) { + listener.addSubscriber(ctx.channel()); + logger.debug("Subscriber successfully registered."); + } else { + logger.error("Listener for stream with name '{}' was not found.", + streamName); + sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, + INTERNAL_SERVER_ERROR)); + } + + // Handshake + WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( + getWebSocketLocation(req), null, false); + handshaker = wsFactory.newHandshaker(req); + if (handshaker == null) { + WebSocketServerHandshakerFactory + .sendUnsupportedWebSocketVersionResponse(ctx.channel()); + } else { + handshaker.handshake(ctx.channel(), req); + } + + } + + /** + * Checks response status, send response and close connection if necessary + * + * @param ctx + * ChannelHandlerContext + * @param req + * HttpRequest + * @param res + * FullHttpResponse + */ + private static void sendHttpResponse(ChannelHandlerContext ctx, + HttpRequest req, FullHttpResponse res) { + // Generate an error page if response getStatus code is not OK (200). + if (res.getStatus().code() != 200) { + ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), + CharsetUtil.UTF_8); + res.content().writeBytes(buf); + buf.release(); + setContentLength(res, res.content().readableBytes()); + } + + // Send the response and close the connection if necessary. + ChannelFuture f = ctx.channel().writeAndFlush(res); + if (!isKeepAlive(req) || res.getStatus().code() != 200) { + f.addListener(ChannelFutureListener.CLOSE); + } + } + + /** + * Handles web socket frame. + * + * @param ctx + * {@link ChannelHandlerContext} + * @param frame + * {@link WebSocketFrame} + */ + private void handleWebSocketFrame(ChannelHandlerContext ctx, + WebSocketFrame frame) throws IOException { + if (frame instanceof CloseWebSocketFrame) { + handshaker.close(ctx.channel(), + (CloseWebSocketFrame) frame.retain()); + String streamName = Notificator + .createStreamNameFromUri(((CloseWebSocketFrame) frame) + .reasonText()); + ListenerAdapter listener = Notificator.getListenerFor(streamName); + if (listener != null) { + listener.removeSubscriber(ctx.channel()); + logger.debug("Subscriber successfully registered."); + } + Notificator.removeListenerIfNoSubscriberExists(listener); + return; + } else if (frame instanceof PingWebSocketFrame) { + ctx.channel().write( + new PongWebSocketFrame(frame.content().retain())); + return; + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) + throws Exception { + if (cause instanceof java.nio.channels.ClosedChannelException == false) { + // cause.printStackTrace(); + } + ctx.close(); + } + + /** + * Get web socket location from HTTP request. + * + * @param req + * HTTP request from which the location will be returned + * @return String representation of web socket location. + */ + private static String getWebSocketLocation(HttpRequest req) { + return "http://" + req.headers().get(HOST) + req.getUri(); + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java index 65ae5d6fab..d188a029e7 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerInitializer.java @@ -1,6 +1,5 @@ package org.opendaylight.controller.sal.streams.websockets; -import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; @@ -9,17 +8,16 @@ import io.netty.handler.codec.http.HttpServerCodec; /** * {@link WebSocketServerInitializer} is used to setup the - * {@link ChannelPipeline} of a {@link Channel}. + * {@link ChannelPipeline} of a {@link io.netty.channel.Channel}. */ -public class WebSocketServerInitializer extends - ChannelInitializer { +public class WebSocketServerInitializer extends ChannelInitializer { - @Override - protected void initChannel(SocketChannel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline(); - pipeline.addLast("codec-http", new HttpServerCodec()); - pipeline.addLast("aggregator", new HttpObjectAggregator(65536)); - pipeline.addLast("handler", new WebSocketServerHandler()); - } + @Override + protected void initChannel(final SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast("codec-http", new HttpServerCodec()); + pipeline.addLast("aggregator", new HttpObjectAggregator(65536)); + pipeline.addLast("handler", new WebSocketServerHandler()); + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/resources/WEB-INF/web.xml b/opendaylight/md-sal/sal-rest-connector/src/main/resources/WEB-INF/web.xml index 840887ecec..f39eae4542 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/resources/WEB-INF/web.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/main/resources/WEB-INF/web.xml @@ -18,39 +18,6 @@ /* - - CorsFilter - org.apache.catalina.filters.CorsFilter - - cors.allowed.origins - * - - - cors.allowed.methods - GET,POST,HEAD,OPTIONS,PUT,DELETE - - - cors.allowed.headers - Content-Type,X-Requested-With,accept,authorization, - origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers - - - cors.exposed.headers - Access-Control-Allow-Origin,Access-Control-Allow-Credentials - - - cors.support.credentials - true - - - cors.preflight.maxage - 10 - - - - CorsFilter - /* - NB api diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java index 8abf366bf7..21590ecb33 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnJsonChoiceCaseTest.java @@ -32,7 +32,7 @@ public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { * Test when some data are in one case node and other in another. This isn't * correct. Next Json validator should return error because nodes has to be * from one case below concrete choice. - * + * */ @Test public void nodeSchemasOnVariousChoiceCasePathTest() { @@ -44,7 +44,7 @@ public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { * Additionally data are loadef from various choices. This isn't correct. * Next Json validator should return error because nodes has to be from one * case below concrete choice. - * + * */ @Test public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest() { @@ -95,7 +95,7 @@ public class CnSnJsonChoiceCaseTest extends YangAndXmlAndDataSchemaLoader { } /** - * + * */ @Test public void nodeSchemasInMultipleChoicesTest() { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java index 4e32e7058c..1ec7253b8d 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java @@ -221,7 +221,7 @@ public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader assertEquals( "Json token type for key " + keyName, expToken, peek ); } - verifier.verify( jReader, keyName );; + verifier.verify( jReader, keyName ); } if( !expectedMap.isEmpty() ) { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java index 12555bc9a2..21a46a6cc3 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonLeafrefType.java @@ -25,9 +25,9 @@ import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchem import org.opendaylight.yangtools.yang.data.api.CompositeNode; /** - * + * * All tests are commented now because leafref isn't supported now - * + * */ public class CnSnToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java index 92de14bba4..086e648097 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnInstanceIdentifierToXmlTest.java @@ -25,14 +25,14 @@ import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchem import org.opendaylight.yangtools.yang.data.api.CompositeNode; /** - * + * * CnSn = Composite node and Simple node data structure Class contains test of * serializing simple nodes data values according data types from YANG schema to * XML file - * + * */ public class CnSnInstanceIdentifierToXmlTest extends YangAndXmlAndDataSchemaLoader { - + @BeforeClass public static void initialization() throws URISyntaxException { dataLoad("/instanceidentifier/yang", 4, "instance-identifier-module", "cont"); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java index 155ee9d590..9318af529b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java @@ -9,6 +9,8 @@ package org.opendaylight.controller.sal.restconf.impl.cnsn.to.xml.test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.IOException; import java.util.List; @@ -18,9 +20,6 @@ import javax.xml.transform.TransformerFactoryConfigurationError; import org.junit.BeforeClass; import org.junit.Test; - -import static org.mockito.Mockito.*; - import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.restconf.impl.test.TestUtils; import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader; @@ -166,9 +165,9 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { serializeToXml( prepareCnStructForYangData( TypeDefinitionAwareCodec.from(BinaryType.getInstance()) - .deserialize("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"), + .deserialize("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"), elName), "<" + elName + ">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"); + + elName + ">"); } @Test @@ -182,9 +181,9 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { String elName = "lfBits"; serializeToXml( prepareCnStructForYangData(TypeDefinitionAwareCodec.from( - BitsType.create( mock( SchemaPath.class ), bitList ) ) - .deserialize("one two"), elName), - "<" + elName + ">one two", "<" + elName + ">two one"); + BitsType.create( mock( SchemaPath.class ), bitList ) ) + .deserialize("one two"), elName), + "<" + elName + ">one two", "<" + elName + ">two one"); } @Test @@ -196,10 +195,10 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { String elName = "lfEnumeration"; serializeToXml( prepareCnStructForYangData(TypeDefinitionAwareCodec.from( - EnumerationType.create( mock( SchemaPath.class ), enumList, - Optional.absent() ) ) - .deserialize("enum2"), - elName), "<" + elName + ">enum2"); + EnumerationType.create( mock( SchemaPath.class ), enumList, + Optional.absent() ) ) + .deserialize("enum2"), + elName), "<" + elName + ">enum2"); } @Test @@ -231,9 +230,9 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { List bitList = Lists.newArrayList( mockBit1, mockBit2 ); List> types = Lists.>newArrayList( - Int8.getInstance(), - BitsType.create( mock( SchemaPath.class ) , bitList ), - BooleanType.getInstance() ); + Int8.getInstance(), + BitsType.create( mock( SchemaPath.class ) , bitList ), + BooleanType.getInstance() ); UnionType unionType = UnionType.create( types ); String elName = "lfUnion"; @@ -253,7 +252,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { + elName + ">str"); } - private void serializeToXml(CompositeNode compositeNode, String... xmlRepresentation) + private void serializeToXml(final CompositeNode compositeNode, final String... xmlRepresentation) throws TransformerFactoryConfigurationError { String xmlString = ""; try { @@ -275,7 +274,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { } - private CompositeNode prepareIdentityrefData(String prefix, boolean valueAsQName) { + private CompositeNode prepareIdentityrefData(final String prefix, final boolean valueAsQName) { MutableCompositeNode cont = NodeFactory.createMutableCompositeNode( TestUtils.buildQName("cont", "basic:module", "2013-12-2"), null, null, ModifyAction.CREATE, null); MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode( @@ -298,11 +297,11 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { } private CompositeNode prepareCnStructForYangData(final Object data, final String leafName) { - MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null, - ModifyAction.CREATE, null); + MutableCompositeNode cont = NodeFactory.createMutableCompositeNode( + TestUtils.buildQName("cont", "basic:module", "2013-12-2"), null, null, ModifyAction.CREATE, null); - MutableSimpleNode lf1 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName(leafName), cont, data, - ModifyAction.CREATE, null); + MutableSimpleNode lf1 = NodeFactory.createMutableSimpleNode( + TestUtils.buildQName(leafName, "basic:module", "2013-12-2"), cont, data, ModifyAction.CREATE, null); cont.getValue().add(lf1); cont.init(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlWithDataFromSeveralModulesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlWithDataFromSeveralModulesTest.java index b7a58886dc..f8d04c157f 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlWithDataFromSeveralModulesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlWithDataFromSeveralModulesTest.java @@ -42,10 +42,10 @@ public class CnSnToXmlWithDataFromSeveralModulesTest extends YangAndXmlAndDataSc // String output = // String.format("" + -// "\n" + -// "\n\t" + -// "\n\t\tlf1 m1 value" + -// "\n\t" + +// "\n" + +// "\n\t" + +// "\n\t\tlf1 m1 value" + +// "\n\t" + // "\n" + // "\n" + // "\n\t" + @@ -60,8 +60,8 @@ public class CnSnToXmlWithDataFromSeveralModulesTest extends YangAndXmlAndDataSc regex.append(".*"); - - + + regex.append(".*"); regex.append(".*xmlns=\"module:one\""); regex.append(".*>"); @@ -97,7 +97,7 @@ public class CnSnToXmlWithDataFromSeveralModulesTest extends YangAndXmlAndDataSc SimpleNodeWrapper lf1_m1 = new SimpleNodeWrapper(uriModule1, "lf1_m1", "lf1 m1 value"); cont_m1.addValue(lf1_m1); CompositeNodeWrapper contB_m1 = new CompositeNodeWrapper(uriModule1, "contB_m1"); - + data.addValue(contB_m1); data.addValue(cont_m1); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java index 67b5b8c93a..22b34a4420 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java @@ -7,38 +7,41 @@ */ package org.opendaylight.controller.sal.restconf.impl.test; -import java.util.concurrent.*; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.yangtools.yang.common.RpcResult; public class DummyFuture implements Future> { - + private final boolean cancel; private final boolean isCancelled; private final boolean isDone; private final RpcResult result; - + public DummyFuture() { cancel = false; isCancelled = false; isDone = false; result = null; } - - private DummyFuture(Builder builder) { + + private DummyFuture(final Builder builder) { cancel = builder.cancel; isCancelled = builder.isCancelled; isDone = builder.isDone; result = builder.result; } - + public static Builder builder() { return new DummyFuture.Builder(); } @Override - public boolean cancel(boolean mayInterruptIfRunning) { + public boolean cancel(final boolean mayInterruptIfRunning) { return cancel; } @@ -58,38 +61,38 @@ public class DummyFuture implements Future> { } @Override - public RpcResult get(long timeout, TimeUnit unit) throws InterruptedException, - ExecutionException, TimeoutException { + public RpcResult get(final long timeout, final TimeUnit unit) throws InterruptedException, + ExecutionException, TimeoutException { return result; } - + public static class Builder { - + private boolean cancel; private boolean isCancelled; private boolean isDone; private RpcResult result; - public Builder cancel(boolean cancel) { + public Builder cancel(final boolean cancel) { this.cancel = cancel; return this; } - - public Builder isCancelled(boolean isCancelled) { + + public Builder isCancelled(final boolean isCancelled) { this.isCancelled = isCancelled; return this; } - - public Builder isDone(boolean isDone) { + + public Builder isDone(final boolean isDone) { this.isDone = isDone; return this; } - - public Builder rpcResult(RpcResult result) { + + public Builder rpcResult(final RpcResult result) { this.result = result; return this; } - + public Future> build() { return new DummyFuture(this); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java index acc5c00935..16d14842db 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java @@ -9,7 +9,8 @@ package org.opendaylight.controller.sal.restconf.impl.test; import java.util.Collection; -import org.opendaylight.yangtools.yang.common.*; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; public class DummyRpcResult implements RpcResult { @@ -23,7 +24,7 @@ public class DummyRpcResult implements RpcResult { errors = null; } - private DummyRpcResult(Builder builder) { + private DummyRpcResult(final Builder builder) { isSuccessful = builder.isSuccessful; result = builder.result; errors = builder.errors; @@ -49,17 +50,17 @@ public class DummyRpcResult implements RpcResult { private T result; private Collection errors; - public Builder isSuccessful(boolean isSuccessful) { + public Builder isSuccessful(final boolean isSuccessful) { this.isSuccessful = isSuccessful; return this; } - public Builder result(T result) { + public Builder result(final T result) { this.result = result; return this; } - public Builder errors(Collection errors) { + public Builder errors(final Collection errors) { this.errors = errors; return this; } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java index 9caaf6b83a..d90e9539c8 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java @@ -10,7 +10,10 @@ package org.opendaylight.controller.sal.restconf.impl.test; import java.util.List; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.model.api.*; +import org.opendaylight.yangtools.yang.model.api.SchemaPath; +import org.opendaylight.yangtools.yang.model.api.Status; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; public class DummyType implements TypeDefinition { QName dummyQName = TestUtils.buildQName("dummy type", "simple:uri", "2012-12-17"); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java index f5aa453fa2..158569af73 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java @@ -7,7 +7,7 @@ */ package org.opendaylight.controller.sal.restconf.impl.test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; import java.net.URI; import java.net.URISyntaxException; @@ -50,7 +50,7 @@ public class NormalizeNodeTest extends YangAndXmlAndDataSchemaLoader { TestUtils.normalizeCompositeNode(prepareCnSn("normalize-node-module"), modules, schemaNodePath); } - private CompositeNode prepareCnSn(String namespace) { + private CompositeNode prepareCnSn(final String namespace) { URI uri = null; if (namespace != null) { try { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java index 408b14acfe..56a58eeadd 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java @@ -76,13 +76,13 @@ public class RestDeleteOperationTest extends JerseyTest { when(brokerFacade.commitConfigurationDataDelete(any(InstanceIdentifier.class))).thenReturn(dummyFuture); Response response = target(uri).request(MediaType.APPLICATION_XML).delete(); assertEquals(200, response.getStatus()); - + dummyFuture = createFuture(TransactionStatus.FAILED); when(brokerFacade.commitConfigurationDataDelete(any(InstanceIdentifier.class))).thenReturn(dummyFuture); response = target(uri).request(MediaType.APPLICATION_XML).delete(); assertEquals(500, response.getStatus()); } - + private Future> createFuture(TransactionStatus statusName) { RpcResult rpcResult = new DummyRpcResult.Builder().result(statusName).build(); return DummyFuture.builder().rpcResult(rpcResult).build(); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java index fc5d7be724..3f984c293b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java @@ -8,9 +8,15 @@ package org.opendaylight.controller.sal.restconf.impl.test; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -21,8 +27,8 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; @@ -48,9 +54,9 @@ import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; import org.opendaylight.controller.sal.restconf.impl.RestconfError; -import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; +import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -79,12 +85,12 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { Map expErrorInfo; - public ComplexErrorInfoVerifier( Map expErrorInfo ) { + public ComplexErrorInfoVerifier( final Map expErrorInfo ) { this.expErrorInfo = expErrorInfo; } @Override - public void verifyXML( Node errorInfoNode ) { + public void verifyXML( final Node errorInfoNode ) { Map mutableExpMap = Maps.newHashMap( expErrorInfo ); NodeList childNodes = errorInfoNode.getChildNodes(); @@ -93,9 +99,9 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { if( child instanceof Element ) { String expValue = mutableExpMap.remove( child.getNodeName() ); assertNotNull( "Found unexpected \"error-info\" child node: " + - child.getNodeName(), expValue ); + child.getNodeName(), expValue ); assertEquals( "Text content for \"error-info\" child node " + - child.getNodeName(), expValue, child.getTextContent() ); + child.getNodeName(), expValue, child.getTextContent() ); } } @@ -105,7 +111,7 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { } @Override - public void verifyJson( JsonElement errorInfoElement ) { + public void verifyJson( final JsonElement errorInfoElement ) { assertTrue( "\"error-info\" Json element is not an Object", errorInfoElement.isJsonObject() ); @@ -121,9 +127,9 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { for( Entry actual: actualErrorInfo.entrySet() ) { String expValue = mutableExpMap.remove( actual.getKey() ); assertNotNull( "Found unexpected \"error-info\" child node: " + - actual.getKey(), expValue ); + actual.getKey(), expValue ); assertEquals( "Text content for \"error-info\" child node " + - actual.getKey(), expValue, actual.getValue() ); + actual.getKey(), expValue, actual.getValue() ); } if( !mutableExpMap.isEmpty() ) { @@ -136,22 +142,22 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { String expTextContent; - public SimpleErrorInfoVerifier( String expErrorInfo ) { + public SimpleErrorInfoVerifier( final String expErrorInfo ) { this.expTextContent = expErrorInfo; } - void verifyContent( String actualContent ) { + void verifyContent( final String actualContent ) { assertNotNull( "Actual \"error-info\" text content is null", actualContent ); assertTrue( "", actualContent.contains( expTextContent ) ); } @Override - public void verifyXML( Node errorInfoNode ) { + public void verifyXML( final Node errorInfoNode ) { verifyContent( errorInfoNode.getTextContent() ); } @Override - public void verifyJson( JsonElement errorInfoElement ) { + public void verifyJson( final JsonElement errorInfoElement ) { verifyContent( errorInfoElement.getAsString() ); } } @@ -172,17 +178,17 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { NamespaceContext nsContext = new NamespaceContext() { @Override - public Iterator getPrefixes( String namespaceURI ) { + public Iterator getPrefixes( final String namespaceURI ) { return null; } @Override - public String getPrefix( String namespaceURI ) { + public String getPrefix( final String namespaceURI ) { return null; } @Override - public String getNamespaceURI( String prefix ) { + public String getNamespaceURI( final String prefix ) { return "ietf-restconf".equals( prefix ) ? Draft02.RestConfModule.NAMESPACE : null; } }; @@ -207,19 +213,19 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { protected Application configure() { ResourceConfig resourceConfig = new ResourceConfig(); resourceConfig = resourceConfig.registerInstances( mockRestConf, StructuredDataToXmlProvider.INSTANCE, - StructuredDataToJsonProvider.INSTANCE ); + StructuredDataToJsonProvider.INSTANCE ); resourceConfig.registerClasses( RestconfDocumentedExceptionMapper.class ); return resourceConfig; } - void stageMockEx( RestconfDocumentedException ex ) { + void stageMockEx( final RestconfDocumentedException ex ) { reset( mockRestConf ); when( mockRestConf.readOperationalData( any( String.class ) ) ).thenThrow( ex ); } - void testJsonResponse( RestconfDocumentedException ex, Status expStatus, ErrorType expErrorType, - ErrorTag expErrorTag, String expErrorMessage, String expErrorAppTag, - ErrorInfoVerifier errorInfoVerifier ) throws Exception { + void testJsonResponse( final RestconfDocumentedException ex, final Status expStatus, final ErrorType expErrorType, + final ErrorTag expErrorTag, final String expErrorMessage, final String expErrorAppTag, + final ErrorInfoVerifier errorInfoVerifier ) throws Exception { stageMockEx( ex ); @@ -228,51 +234,51 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { InputStream stream = verifyResponse( resp, MediaType.APPLICATION_JSON, expStatus ); verifyJsonResponseBody( stream, expErrorType, expErrorTag, expErrorMessage, - expErrorAppTag, errorInfoVerifier ); + expErrorAppTag, errorInfoVerifier ); } @Test public void testToJsonResponseWithMessageOnly() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error" ), Status.INTERNAL_SERVER_ERROR, - ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null ); + ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null ); // To test verification code -// String json = -// "{ errors: {" + -// " error: [{" + -// " error-tag : \"operation-failed\"" + -// " ,error-type : \"application\"" + -// " ,error-message : \"An error occurred\"" + -// " ,error-info : {" + -// " session-id: \"123\"" + -// " ,address: \"1.2.3.4\"" + -// " }" + -// " }]" + -// " }" + -// "}"; -// -// verifyJsonResponseBody( new java.io.StringBufferInputStream(json ), ErrorType.APPLICATION, -// ErrorTag.OPERATION_FAILED, "An error occurred", null, -// com.google.common.collect.ImmutableMap.of( "session-id", "123", "address", "1.2.3.4" ) ); + // String json = + // "{ errors: {" + + // " error: [{" + + // " error-tag : \"operation-failed\"" + + // " ,error-type : \"application\"" + + // " ,error-message : \"An error occurred\"" + + // " ,error-info : {" + + // " session-id: \"123\"" + + // " ,address: \"1.2.3.4\"" + + // " }" + + // " }]" + + // " }" + + // "}"; + // + // verifyJsonResponseBody( new java.io.StringBufferInputStream(json ), ErrorType.APPLICATION, + // ErrorTag.OPERATION_FAILED, "An error occurred", null, + // com.google.common.collect.ImmutableMap.of( "session-id", "123", "address", "1.2.3.4" ) ); } @Test public void testToJsonResponseWithInUseErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.IN_USE ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.IN_USE, "mock error", null, null ); + ErrorTag.IN_USE ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.IN_USE, "mock error", null, null ); } @Test public void testToJsonResponseWithInvalidValueErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.RPC, - ErrorTag.INVALID_VALUE ), - Status.BAD_REQUEST, ErrorType.RPC, - ErrorTag.INVALID_VALUE, "mock error", null, null ); + ErrorTag.INVALID_VALUE ), + Status.BAD_REQUEST, ErrorType.RPC, + ErrorTag.INVALID_VALUE, "mock error", null, null ); } @@ -280,9 +286,9 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { public void testToJsonResponseWithTooBigErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.TRANSPORT, - ErrorTag.TOO_BIG ), - Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT, - ErrorTag.TOO_BIG, "mock error", null, null ); + ErrorTag.TOO_BIG ), + Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT, + ErrorTag.TOO_BIG, "mock error", null, null ); } @@ -290,153 +296,153 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { public void testToJsonResponseWithMissingAttributeErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.MISSING_ATTRIBUTE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null ); + ErrorTag.MISSING_ATTRIBUTE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null ); } @Test public void testToJsonResponseWithBadAttributeErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.BAD_ATTRIBUTE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.BAD_ATTRIBUTE, "mock error", null, null ); + ErrorTag.BAD_ATTRIBUTE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.BAD_ATTRIBUTE, "mock error", null, null ); } @Test public void testToJsonResponseWithUnknownAttributeErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_ATTRIBUTE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null ); + ErrorTag.UNKNOWN_ATTRIBUTE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null ); } @Test public void testToJsonResponseWithBadElementErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.BAD_ELEMENT ), - Status.BAD_REQUEST, - ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT, "mock error", null, null ); + ErrorTag.BAD_ELEMENT ), + Status.BAD_REQUEST, + ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT, "mock error", null, null ); } @Test public void testToJsonResponseWithUnknownElementErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_ELEMENT ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null ); + ErrorTag.UNKNOWN_ELEMENT ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null ); } @Test public void testToJsonResponseWithUnknownNamespaceErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_NAMESPACE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null ); + ErrorTag.UNKNOWN_NAMESPACE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null ); } @Test public void testToJsonResponseWithMalformedMessageErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.MALFORMED_MESSAGE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.MALFORMED_MESSAGE, "mock error", null, null ); + ErrorTag.MALFORMED_MESSAGE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.MALFORMED_MESSAGE, "mock error", null, null ); } @Test public void testToJsonResponseWithAccessDeniedErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.ACCESS_DENIED ), - Status.FORBIDDEN, ErrorType.PROTOCOL, - ErrorTag.ACCESS_DENIED, "mock error", null, null ); + ErrorTag.ACCESS_DENIED ), + Status.FORBIDDEN, ErrorType.PROTOCOL, + ErrorTag.ACCESS_DENIED, "mock error", null, null ); } @Test public void testToJsonResponseWithLockDeniedErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.LOCK_DENIED ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.LOCK_DENIED, "mock error", null, null ); + ErrorTag.LOCK_DENIED ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.LOCK_DENIED, "mock error", null, null ); } @Test public void testToJsonResponseWithResourceDeniedErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.RESOURCE_DENIED ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.RESOURCE_DENIED, "mock error", null, null ); + ErrorTag.RESOURCE_DENIED ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.RESOURCE_DENIED, "mock error", null, null ); } @Test public void testToJsonResponseWithRollbackFailedErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.ROLLBACK_FAILED ), - Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, - ErrorTag.ROLLBACK_FAILED, "mock error", null, null ); + ErrorTag.ROLLBACK_FAILED ), + Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, + ErrorTag.ROLLBACK_FAILED, "mock error", null, null ); } @Test public void testToJsonResponseWithDataExistsErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.DATA_EXISTS ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.DATA_EXISTS, "mock error", null, null ); + ErrorTag.DATA_EXISTS ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.DATA_EXISTS, "mock error", null, null ); } @Test public void testToJsonResponseWithDataMissingErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.DATA_MISSING ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.DATA_MISSING, "mock error", null, null ); + ErrorTag.DATA_MISSING ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.DATA_MISSING, "mock error", null, null ); } @Test public void testToJsonResponseWithOperationNotSupportedErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.OPERATION_NOT_SUPPORTED ), - Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL, - ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null ); + ErrorTag.OPERATION_NOT_SUPPORTED ), + Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL, + ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null ); } @Test public void testToJsonResponseWithOperationFailedErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.OPERATION_FAILED ), - Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, - ErrorTag.OPERATION_FAILED, "mock error", null, null ); + ErrorTag.OPERATION_FAILED ), + Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, + ErrorTag.OPERATION_FAILED, "mock error", null, null ); } @Test public void testToJsonResponseWithPartialOperationErrorTag() throws Exception { testJsonResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.PARTIAL_OPERATION ), - Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, - ErrorTag.PARTIAL_OPERATION, "mock error", null, null ); + ErrorTag.PARTIAL_OPERATION ), + Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, + ErrorTag.PARTIAL_OPERATION, "mock error", null, null ); } @Test public void testToJsonResponseWithErrorAppTag() throws Exception { testJsonResponse( new RestconfDocumentedException( new RestconfError( - ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, - "mock error", "mock-app-tag" ) ), - Status.BAD_REQUEST, ErrorType.APPLICATION, - ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null ); + ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "mock error", "mock-app-tag" ) ), + Status.BAD_REQUEST, ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null ); } @Test @@ -456,10 +462,10 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { assertEquals( "\"error\" Json array element length", 2, arrayElement.size() ); verifyJsonErrorNode( arrayElement.get( 0 ), ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, - "mock error1", null, null ); + "mock error1", null, null ); verifyJsonErrorNode( arrayElement.get( 1 ), ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, - "mock error2", null, null ); + "mock error2", null, null ); } @Test @@ -467,12 +473,12 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { String errorInfo = "
            1.2.3.4
            123"; testJsonResponse( new RestconfDocumentedException( new RestconfError( - ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, - "mock error", "mock-app-tag", errorInfo ) ), - Status.BAD_REQUEST, ErrorType.APPLICATION, - ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", - new ComplexErrorInfoVerifier( ImmutableMap.of( - "session-id", "123", "address", "1.2.3.4" ) ) ); + ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "mock error", "mock-app-tag", errorInfo ) ), + Status.BAD_REQUEST, ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", + new ComplexErrorInfoVerifier( ImmutableMap.of( + "session-id", "123", "address", "1.2.3.4" ) ) ); } @Test @@ -480,14 +486,14 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { Exception cause = new Exception( "mock exception cause" ); testJsonResponse( new RestconfDocumentedException( "mock error", cause ), - Status.INTERNAL_SERVER_ERROR, ErrorType.APPLICATION, - ErrorTag.OPERATION_FAILED, "mock error", null, - new SimpleErrorInfoVerifier( cause.getMessage() ) ); + Status.INTERNAL_SERVER_ERROR, ErrorType.APPLICATION, + ErrorTag.OPERATION_FAILED, "mock error", null, + new SimpleErrorInfoVerifier( cause.getMessage() ) ); } - void testXMLResponse( RestconfDocumentedException ex, Status expStatus, ErrorType expErrorType, - ErrorTag expErrorTag, String expErrorMessage, - String expErrorAppTag, ErrorInfoVerifier errorInfoVerifier ) throws Exception + void testXMLResponse( final RestconfDocumentedException ex, final Status expStatus, final ErrorType expErrorType, + final ErrorTag expErrorTag, final String expErrorMessage, + final String expErrorAppTag, final ErrorInfoVerifier errorInfoVerifier ) throws Exception { stageMockEx( ex ); @@ -496,212 +502,212 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { InputStream stream = verifyResponse( resp, MediaType.APPLICATION_XML, expStatus ); verifyXMLResponseBody( stream, expErrorType, expErrorTag, expErrorMessage, - expErrorAppTag, errorInfoVerifier ); + expErrorAppTag, errorInfoVerifier ); } @Test public void testToXMLResponseWithMessageOnly() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error" ), Status.INTERNAL_SERVER_ERROR, - ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null ); + ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null ); // To test verification code -// String xml = -// ""+ -// " " + -// " application"+ -// " operation-failed"+ -// " An error occurred"+ -// " " + -// " 123" + -// "
            1.2.3.4
            " + -// "
            " + -// "
            " + -// "
            "; -// -// verifyXMLResponseBody( new java.io.StringBufferInputStream(xml), ErrorType.APPLICATION, -// ErrorTag.OPERATION_FAILED, "An error occurred", null, -// com.google.common.collect.ImmutableMap.of( "session-id", "123", "address", "1.2.3.4" ) ); + // String xml = + // ""+ + // " " + + // " application"+ + // " operation-failed"+ + // " An error occurred"+ + // " " + + // " 123" + + // "
            1.2.3.4
            " + + // "
            " + + // "
            " + + // "
            "; + // + // verifyXMLResponseBody( new java.io.StringBufferInputStream(xml), ErrorType.APPLICATION, + // ErrorTag.OPERATION_FAILED, "An error occurred", null, + // com.google.common.collect.ImmutableMap.of( "session-id", "123", "address", "1.2.3.4" ) ); } @Test public void testToXMLResponseWithInUseErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.IN_USE ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.IN_USE, "mock error", null, null ); + ErrorTag.IN_USE ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.IN_USE, "mock error", null, null ); } @Test public void testToXMLResponseWithInvalidValueErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.RPC, - ErrorTag.INVALID_VALUE ), - Status.BAD_REQUEST, ErrorType.RPC, - ErrorTag.INVALID_VALUE, "mock error", null, null ); + ErrorTag.INVALID_VALUE ), + Status.BAD_REQUEST, ErrorType.RPC, + ErrorTag.INVALID_VALUE, "mock error", null, null ); } @Test public void testToXMLResponseWithTooBigErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.TRANSPORT, - ErrorTag.TOO_BIG ), - Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT, - ErrorTag.TOO_BIG, "mock error", null, null ); + ErrorTag.TOO_BIG ), + Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT, + ErrorTag.TOO_BIG, "mock error", null, null ); } @Test public void testToXMLResponseWithMissingAttributeErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.MISSING_ATTRIBUTE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null ); + ErrorTag.MISSING_ATTRIBUTE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null ); } @Test public void testToXMLResponseWithBadAttributeErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.BAD_ATTRIBUTE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.BAD_ATTRIBUTE, "mock error", null, null ); + ErrorTag.BAD_ATTRIBUTE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.BAD_ATTRIBUTE, "mock error", null, null ); } @Test public void testToXMLResponseWithUnknownAttributeErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_ATTRIBUTE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null ); + ErrorTag.UNKNOWN_ATTRIBUTE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null ); } @Test public void testToXMLResponseWithBadElementErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.BAD_ELEMENT ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.BAD_ELEMENT, "mock error", null, null ); + ErrorTag.BAD_ELEMENT ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.BAD_ELEMENT, "mock error", null, null ); } @Test public void testToXMLResponseWithUnknownElementErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_ELEMENT ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null ); + ErrorTag.UNKNOWN_ELEMENT ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null ); } @Test public void testToXMLResponseWithUnknownNamespaceErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_NAMESPACE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null ); + ErrorTag.UNKNOWN_NAMESPACE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null ); } @Test public void testToXMLResponseWithMalformedMessageErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.MALFORMED_MESSAGE ), - Status.BAD_REQUEST, ErrorType.PROTOCOL, - ErrorTag.MALFORMED_MESSAGE, "mock error", null, null ); + ErrorTag.MALFORMED_MESSAGE ), + Status.BAD_REQUEST, ErrorType.PROTOCOL, + ErrorTag.MALFORMED_MESSAGE, "mock error", null, null ); } @Test public void testToXMLResponseWithAccessDeniedErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.ACCESS_DENIED ), - Status.FORBIDDEN, ErrorType.PROTOCOL, - ErrorTag.ACCESS_DENIED, "mock error", null, null ); + ErrorTag.ACCESS_DENIED ), + Status.FORBIDDEN, ErrorType.PROTOCOL, + ErrorTag.ACCESS_DENIED, "mock error", null, null ); } @Test public void testToXMLResponseWithLockDeniedErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.LOCK_DENIED ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.LOCK_DENIED, "mock error", null, null ); + ErrorTag.LOCK_DENIED ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.LOCK_DENIED, "mock error", null, null ); } @Test public void testToXMLResponseWithResourceDeniedErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.RESOURCE_DENIED ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.RESOURCE_DENIED, "mock error", null, null ); + ErrorTag.RESOURCE_DENIED ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.RESOURCE_DENIED, "mock error", null, null ); } @Test public void testToXMLResponseWithRollbackFailedErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.ROLLBACK_FAILED ), - Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, - ErrorTag.ROLLBACK_FAILED, "mock error", null, null ); + ErrorTag.ROLLBACK_FAILED ), + Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, + ErrorTag.ROLLBACK_FAILED, "mock error", null, null ); } @Test public void testToXMLResponseWithDataExistsErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.DATA_EXISTS ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.DATA_EXISTS, "mock error", null, null ); + ErrorTag.DATA_EXISTS ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.DATA_EXISTS, "mock error", null, null ); } @Test public void testToXMLResponseWithDataMissingErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.DATA_MISSING ), - Status.CONFLICT, ErrorType.PROTOCOL, - ErrorTag.DATA_MISSING, "mock error", null, null ); + ErrorTag.DATA_MISSING ), + Status.CONFLICT, ErrorType.PROTOCOL, + ErrorTag.DATA_MISSING, "mock error", null, null ); } @Test public void testToXMLResponseWithOperationNotSupportedErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.OPERATION_NOT_SUPPORTED ), - Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL, - ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null ); + ErrorTag.OPERATION_NOT_SUPPORTED ), + Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL, + ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null ); } @Test public void testToXMLResponseWithOperationFailedErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.OPERATION_FAILED ), - Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, - ErrorTag.OPERATION_FAILED, "mock error", null, null ); + ErrorTag.OPERATION_FAILED ), + Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, + ErrorTag.OPERATION_FAILED, "mock error", null, null ); } @Test public void testToXMLResponseWithPartialOperationErrorTag() throws Exception { testXMLResponse( new RestconfDocumentedException( "mock error", ErrorType.PROTOCOL, - ErrorTag.PARTIAL_OPERATION ), - Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, - ErrorTag.PARTIAL_OPERATION, "mock error", null, null ); + ErrorTag.PARTIAL_OPERATION ), + Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, + ErrorTag.PARTIAL_OPERATION, "mock error", null, null ); } @Test public void testToXMLResponseWithErrorAppTag() throws Exception { testXMLResponse( new RestconfDocumentedException( new RestconfError( - ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, - "mock error", "mock-app-tag" ) ), - Status.BAD_REQUEST, ErrorType.APPLICATION, - ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null ); + ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "mock error", "mock-app-tag" ) ), + Status.BAD_REQUEST, ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null ); } @Test @@ -709,12 +715,12 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { String errorInfo = "
            1.2.3.4
            123"; testXMLResponse( new RestconfDocumentedException( new RestconfError( - ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, - "mock error", "mock-app-tag", errorInfo ) ), - Status.BAD_REQUEST, ErrorType.APPLICATION, - ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", - new ComplexErrorInfoVerifier( ImmutableMap.of( - "session-id", "123", "address", "1.2.3.4" ) ) ); + ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, + "mock error", "mock-app-tag", errorInfo ) ), + Status.BAD_REQUEST, ErrorType.APPLICATION, + ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", + new ComplexErrorInfoVerifier( ImmutableMap.of( + "session-id", "123", "address", "1.2.3.4" ) ) ); } @Test @@ -722,9 +728,9 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { Exception cause = new Exception( "mock exception cause" ); testXMLResponse( new RestconfDocumentedException( "mock error", cause ), - Status.INTERNAL_SERVER_ERROR, ErrorType.APPLICATION, - ErrorTag.OPERATION_FAILED, "mock error", null, - new SimpleErrorInfoVerifier( cause.getMessage() ) ); + Status.INTERNAL_SERVER_ERROR, ErrorType.APPLICATION, + ErrorTag.OPERATION_FAILED, "mock error", null, + new SimpleErrorInfoVerifier( cause.getMessage() ) ); } @Test @@ -744,10 +750,10 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { NodeList children = getXMLErrorList( doc, 2 ); verifyXMLErrorNode( children.item( 0 ), ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, - "mock error1", null, null ); + "mock error1", null, null ); verifyXMLErrorNode( children.item( 1 ), ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, - "mock error2", null, null ); + "mock error2", null, null ); } @Test @@ -756,13 +762,13 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { stageMockEx( new RestconfDocumentedException( "mock error" ) ); Response resp = target("/operational/foo") - .request().header( "Accept", MediaType.APPLICATION_JSON ).get(); + .request().header( "Accept", MediaType.APPLICATION_JSON ).get(); InputStream stream = verifyResponse( resp, MediaType.APPLICATION_JSON, - Status.INTERNAL_SERVER_ERROR ); + Status.INTERNAL_SERVER_ERROR ); verifyJsonResponseBody( stream, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", - null, null ); + null, null ); } @Test @@ -771,14 +777,14 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { // The StructuredDataToJsonProvider should throw a RestconfDocumentedException with no data when( mockRestConf.readOperationalData( any( String.class ) ) ) - .thenReturn( new StructuredData( null, null, null ) ); + .thenReturn( new StructuredData( null, null, null ) ); Response resp = target("/operational/foo").request( MediaType.APPLICATION_JSON ).get(); verifyResponse( resp, MediaType.TEXT_PLAIN, Status.NOT_FOUND ); } - InputStream verifyResponse( Response resp, String expMediaType, Status expStatus ) { + InputStream verifyResponse( final Response resp, final String expMediaType, final Status expStatus ) { assertEquals( "getMediaType", MediaType.valueOf( expMediaType ), resp.getMediaType() ); assertEquals( "getStatus", expStatus.getStatusCode(), resp.getStatus() ); @@ -788,19 +794,19 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { return stream; } - void verifyJsonResponseBody( InputStream stream, ErrorType expErrorType, ErrorTag expErrorTag, - String expErrorMessage, String expErrorAppTag, - ErrorInfoVerifier errorInfoVerifier ) throws Exception { + void verifyJsonResponseBody( final InputStream stream, final ErrorType expErrorType, final ErrorTag expErrorTag, + final String expErrorMessage, final String expErrorAppTag, + final ErrorInfoVerifier errorInfoVerifier ) throws Exception { JsonArray arrayElement = parseJsonErrorArrayElement( stream ); assertEquals( "\"error\" Json array element length", 1, arrayElement.size() ); verifyJsonErrorNode( arrayElement.get( 0 ), expErrorType, expErrorTag, expErrorMessage, - expErrorAppTag, errorInfoVerifier ); + expErrorAppTag, errorInfoVerifier ); } - private JsonArray parseJsonErrorArrayElement( InputStream stream ) throws IOException { + private JsonArray parseJsonErrorArrayElement( final InputStream stream ) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteStreams.copy( stream, bos ); @@ -811,7 +817,7 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { try { rootElement = parser.parse( - new InputStreamReader( new ByteArrayInputStream( bos.toByteArray() ) ) ); + new InputStreamReader( new ByteArrayInputStream( bos.toByteArray() ) ) ); } catch( Exception e ) { throw new IllegalArgumentException( "Invalid JSON response:\n" + bos.toString(), e ); @@ -832,15 +838,15 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { JsonElement errorListElement = errorListEntrySet.iterator().next().getValue(); assertEquals( "\"errors\" child Json element name", "error", - errorListEntrySet.iterator().next().getKey() ); + errorListEntrySet.iterator().next().getKey() ); assertTrue( "\"error\" Json element is not an Array", errorListElement.isJsonArray() ); return errorListElement.getAsJsonArray(); } - void verifyJsonErrorNode( JsonElement errorEntryElement, ErrorType expErrorType, ErrorTag expErrorTag, - String expErrorMessage, String expErrorAppTag, - ErrorInfoVerifier errorInfoVerifier ) { + void verifyJsonErrorNode( final JsonElement errorEntryElement, final ErrorType expErrorType, final ErrorTag expErrorTag, + final String expErrorMessage, final String expErrorAppTag, + final ErrorInfoVerifier errorInfoVerifier ) { JsonElement errorInfoElement = null; Map actualErrorInfo = null; @@ -855,7 +861,7 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { } else { assertTrue( "\"error\" leaf Json element " + leafName + - " is not a Primitive", leafElement.isJsonPrimitive() ); + " is not a Primitive", leafElement.isJsonPrimitive() ); leafMap.put( leafName, leafElement.getAsString() ); } @@ -877,7 +883,7 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { } } - void verifyOptionalJsonLeaf( String actualValue, String expValue, String tagName ) { + void verifyOptionalJsonLeaf( final String actualValue, final String expValue, final String tagName ) { if( expValue != null ) { assertEquals( tagName, expValue, actualValue ); } @@ -886,20 +892,20 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { } } - void verifyXMLResponseBody( InputStream stream, ErrorType expErrorType, ErrorTag expErrorTag, - String expErrorMessage, String expErrorAppTag, - ErrorInfoVerifier errorInfoVerifier ) - throws Exception { + void verifyXMLResponseBody( final InputStream stream, final ErrorType expErrorType, final ErrorTag expErrorTag, + final String expErrorMessage, final String expErrorAppTag, + final ErrorInfoVerifier errorInfoVerifier ) + throws Exception { Document doc = parseXMLDocument( stream ); NodeList children = getXMLErrorList( doc, 1 ); verifyXMLErrorNode( children.item( 0 ), expErrorType, expErrorTag, expErrorMessage, - expErrorAppTag, errorInfoVerifier ); + expErrorAppTag, errorInfoVerifier ); } - private Document parseXMLDocument( InputStream stream ) throws IOException { + private Document parseXMLDocument( final InputStream stream ) throws IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); factory.setCoalescing(true); @@ -921,9 +927,9 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { return doc; } - void verifyXMLErrorNode( Node errorNode, ErrorType expErrorType, ErrorTag expErrorTag, - String expErrorMessage, String expErrorAppTag, - ErrorInfoVerifier errorInfoVerifier ) throws Exception { + void verifyXMLErrorNode( final Node errorNode, final ErrorType expErrorType, final ErrorTag expErrorTag, + final String expErrorMessage, final String expErrorAppTag, + final ErrorInfoVerifier errorInfoVerifier ) throws Exception { String errorType = (String)ERROR_TYPE.evaluate( errorNode, XPathConstants.STRING ); assertEquals( "error-type", expErrorType.getErrorTypeTag(), errorType ); @@ -945,19 +951,19 @@ public class RestconfDocumentedExceptionMapperTest extends JerseyTest { } } - void verifyOptionalXMLLeaf( Node fromNode, XPathExpression xpath, String expValue, - String tagName ) throws Exception { + void verifyOptionalXMLLeaf( final Node fromNode, final XPathExpression xpath, final String expValue, + final String tagName ) throws Exception { if( expValue != null ) { String actual = (String)xpath.evaluate( fromNode, XPathConstants.STRING ); assertEquals( tagName, expValue, actual ); } else { assertNull( "Found unexpected \"error\" leaf entry for: " + tagName, - xpath.evaluate( fromNode, XPathConstants.NODE ) ); + xpath.evaluate( fromNode, XPathConstants.NODE ) ); } } - NodeList getXMLErrorList( Node fromNode, int count ) throws Exception { + NodeList getXMLErrorList( final Node fromNode, final int count ) throws Exception { NodeList errorList = (NodeList)ERROR_LIST.evaluate( fromNode, XPathConstants.NODESET ); assertNotNull( "Root errors node is empty", errorList ); assertEquals( "Root errors node child count", count, errorList.getLength() ); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java index eb623096de..853c19f935 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java @@ -147,7 +147,7 @@ public final class TestUtils { } /** - * + * * Fill missing data (namespaces) and build correct data type in * {@code compositeNode} according to {@code dataSchemaNode}. The method * {@link RestconfImpl#createConfigurationData createConfigurationData} is @@ -165,7 +165,7 @@ public final class TestUtils { * Searches module with name {@code searchedModuleName} in {@code modules}. * If module name isn't specified and module set has only one element then * this element is returned. - * + * */ public static Module resolveModule(String searchedModuleName, Set modules) { assertNotNull("Modules can't be null.", modules); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/CompareLf.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/CompareLf.java index e935a268a2..12ab073202 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/CompareLf.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/CompareLf.java @@ -7,7 +7,8 @@ */ package org.opendaylight.controller.sal.restconf.impl.test.structures; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -19,7 +20,7 @@ public class CompareLf { Lf lf2 = new Lf("name", "value"); Lf lf3 = new Lf("name1", "value"); Lf lf4 = new Lf("name", "value1"); - + assertTrue(lf1.equals(lf2)); assertFalse(lf1.equals(lf3)); assertFalse(lf1.equals(lf4)); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/Lst.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/Lst.java index d4c7671c45..8eccf373b9 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/Lst.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/structures/Lst.java @@ -7,17 +7,18 @@ */ package org.opendaylight.controller.sal.restconf.impl.test.structures; -import java.util.*; +import java.util.HashSet; +import java.util.Set; public class Lst extends YangElement { - private Set lstItems; + private final Set lstItems; - public Lst(String name) { + public Lst(final String name) { super(name); lstItems = new HashSet<>(); } - public Lst addLstItem(LstItem lstItem) { + public Lst addLstItem(final LstItem lstItem) { lstItem.setLstName(name); while (this.lstItems.contains(lstItem)) { lstItem.incNumOfEqualItems(); @@ -31,7 +32,7 @@ public class Lst extends YangElement { } @Override - public boolean equals(Object obj) { + public boolean equals(final Object obj) { if (this == obj) { return true; } @@ -59,5 +60,4 @@ public class Lst extends YangElement { result = prime * result + ((lstItems == null) ? 0 : lstItems.hashCode()); return result; } - } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java index ffddb00485..62159ccad6 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java @@ -24,7 +24,7 @@ public class XmlAugmentedElementToCnSnTest { loadAndNormalizeData("/common/augment/xml/dataa.xml", "/common/augment/yang", "main","cont"); loadAndNormalizeData("/common/augment/xml/datab.xml", "/common/augment/yang", "main","cont"); } - + private void loadAndNormalizeData(String xmlPath, String yangPath, String topLevelElementName, String moduleName) { CompositeNode compNode = TestUtils.readInputToCnSn(xmlPath, false, XmlToCompositeNodeProvider.INSTANCE); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/xml/data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/xml/data.xml index 08cdb34290..5b1c8324ac 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/xml/data.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/augmentation/xml/data.xml @@ -1,16 +1,16 @@ - lf1 - lf2 - - lf11 - - - lf1_1 - - - lf1_2 - - lflst1_1 - lflst1_2 - lflst1_3 + lf1 + lf2 + + lf11 + + + lf1_1 + + + lf1_2 + + lflst1_1 + lflst1_2 + lflst1_3 \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_case_defined_without_case.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_case_defined_without_case.xml index b669842c22..c6e42dfb77 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_case_defined_without_case.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_case_defined_without_case.xml @@ -1,4 +1,4 @@ - 45 - lf2b val + 45 + lf2b val \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_container.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_container.xml index 9c751949d0..0d5fa4a514 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_container.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_container.xml @@ -1,5 +1,5 @@ - - lf11c val - + + lf11c val + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_leaflist.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_leaflist.xml index 6cebb6424a..0278389d73 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_leaflist.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_leaflist.xml @@ -1,4 +1,4 @@ - lflst1d_1 val - lflst1d_2 val + lflst1d_1 val + lflst1d_2 val \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_list.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_list.xml index 710da55de6..488873d5ef 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_list.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_list.xml @@ -1,8 +1,8 @@ - - lf11b_1 val - - - lf11b_2 val - + + lf11b_1 val + + + lf11b_2 val + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level.xml index 97e219736f..f21d83f8f0 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level.xml @@ -1,6 +1,6 @@ - - lf11c val - - lf2b value + + lf11c val + + lf2b value \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml index 331c8aec08..9e28730355 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml @@ -1,7 +1,7 @@ - - lf11c val - - lf2b value - lf2b value + + lf11c val + + lf2b value + lf2b value \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_no_first_case.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_no_first_case.xml index 43e9974a2c..dbd2684526 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_no_first_case.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_no_first_case.xml @@ -1,5 +1,5 @@ - lf1 val - 121 - lf1ab val + lf1 val + 121 + lf1ab val \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_random_level.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_random_level.xml index b1b78e4744..e3e66b78e6 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_random_level.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_random_level.xml @@ -1,6 +1,6 @@ - lf1aa val - lf1 val - 121 - lf1aaa val + lf1aa val + lf1 val + 121 + lf1aaa val \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_three_choices_same_level.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_three_choices_same_level.xml index ecc0caae56..49b4143a2e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_three_choices_same_level.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_three_choices_same_level.xml @@ -1,13 +1,13 @@ - lf1aaa value - lf2b value - - 33 - - - 33 - - - 37 - + lf1aaa value + lf2b value + + 33 + + + 33 + + + 37 + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_various_path_err.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_various_path_err.xml index c43dab60c0..e8634682cd 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_various_path_err.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/choice/xml/data_various_path_err.xml @@ -1,6 +1,6 @@ - lf1aa val - lf1 val - 121 - lf1ab value + lf1aa val + lf1 val + 121 + lf1ab value \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml index bbebabec4e..6bb975947b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml @@ -1,6 +1,6 @@ - - true - - true + + true + + true \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_from_leafref_to_leafref.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_from_leafref_to_leafref.xml index 1bb9013a7f..c6c20cb638 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_from_leafref_to_leafref.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_from_leafref_to_leafref.xml @@ -1,3 +1,3 @@ - 200 + 200 \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml index dfea9c811d..401247a367 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml @@ -1,3 +1,3 @@ - 137 + 137 \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_not_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_not_leaf.xml index 7b05b0c89f..10632a44af 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_not_leaf.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_ref_to_not_leaf.xml @@ -1,3 +1,3 @@ - 44.33 + 44.33 \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml index 0d8cf660ac..49d2dc39aa 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml @@ -1,5 +1,5 @@ - 345 - 346 - 347 + 345 + 346 + 347 \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml index 4a73a8b0c4..06200a69b5 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml @@ -1,4 +1,4 @@ - 121 - 121 + 121 + 121 \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/data.xml index f73ce1b65c..28d355dbab 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/data.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-data-types/xml/data.xml @@ -1,42 +1,42 @@ - -128 - 127 - -32768 - 32767 - -2147483648 - 2147483647 - -9223372036854775808 - 9223372036854775807 - 255 - 65535 - 4294967295 - lfstr - - true - false - bla - 43.32 - -0.43 - 43 - 43E3 - 33.12345 - enum3 - bit3 bit2 - ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz - - 324 - 33.3 - 55 - true - true - 10 - - - - bt1 - 33 - false - b1 - zero - x:iden + -128 + 127 + -32768 + 32767 + -2147483648 + 2147483647 + -9223372036854775808 + 9223372036854775807 + 255 + 65535 + 4294967295 + lfstr + + true + false + bla + 43.32 + -0.43 + 43 + 43E3 + 33.12345 + enum3 + bit3 bit2 + ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz + + 324 + 33.3 + 55 + true + true + 10 + + + + bt1 + 33 + false + b1 + zero + x:iden \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/data.xml index 17dc2657b0..61858d28b6 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/data.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/data.xml @@ -1,63 +1,63 @@ - lf - 56 - 55 - 57 - lflst12 str3 - - - lf1121 str22 - - 141 - lf112 str2 - - 55 - - - 4097 - 2049 - 1025 - - lf1111A str22 - 8 - - lf1111 str2 - - 5 - lf1111A str21 - - - - 56 - - - lf1121 str21 - - - lflst12 str1 - - 140 - lf112 str - - lf1111 str - 2048 - 1024 - 4096 - - lf1111A str11 - 4 - - - lf1111A str12 - 7 - - - - 65 - - - lf1121 str11 - - - lflst12 str2 + lf + 56 + 55 + 57 + lflst12 str3 + + + lf1121 str22 + + 141 + lf112 str2 + + 55 + + + 4097 + 2049 + 1025 + + lf1111A str22 + 8 + + lf1111 str2 + + 5 + lf1111A str21 + + + + 56 + + + lf1121 str21 + + + lflst12 str1 + + 140 + lf112 str + + lf1111 str + 2048 + 1024 + 4096 + + lf1111A str11 + 4 + + + lf1111A str12 + 7 + + + + 65 + + + lf1121 str11 + + + lflst12 str2 diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/empty_data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/empty_data.xml index 68470eab26..9cd503e09b 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/empty_data.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/cnsn-to-json/simple-yang-types/xml/empty_data.xml @@ -1,40 +1,40 @@ - - 1 - - - - - - - 35 - - - - - 2 - - - - 1024 - 4096 - - 4 - - - lf1111A str12 - - - - - - 3 - - - - - - - - + + 1 + + + + + + + 35 + + + + + 2 + + + + 1024 + 4096 + + 4 + + + lf1111A str12 + + + + + + 3 + + + + + + + + diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/test-data2/data-rpc-input.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/test-data2/data-rpc-input.xml index 5954c091e3..fb9726d5b1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/test-data2/data-rpc-input.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/full-versions/test-data2/data-rpc-input.xml @@ -1,8 +1,8 @@ - - - lf1 data - lf2 data - - + + + lf1 data + lf2 data + + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml index 768cb663eb..bd558fb6b9 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/instanceidentifier/xml/xmldata.xml @@ -1,10 +1,10 @@ - - value1 - value2 - /a:cont/a:cont1/b:lst11[b:keyvalue111="value1"][b:keyvalue112="value2"]/c:lf112 - lf112 value - + + value1 + value2 + /a:cont/a:cont1/b:lst11[b:keyvalue111="value1"][b:keyvalue112="value2"]/c:lf112 + lf112 value + diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.xml index 7e3aa97987..313f32dce1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/parts/ietf-interfaces_interfaces_absolute_path.xml @@ -1,8 +1,8 @@ - - eth0 - ethernetCsmacd - false - some interface - + + eth0 + ethernetCsmacd + false + some interface + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-container.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-container.xml index ce97dd1715..841d351049 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-container.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-container.xml @@ -1,14 +1,14 @@ - str0 - - - 121 - 131 - str1 - - str2 - - - 100 - + str0 + + + 121 + 131 + str1 + + str2 + + + 100 + diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list.xml index cab23c656e..9c4256a50c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/data-list.xml @@ -1,21 +1,21 @@ - - str0 - 121 - 131 - str1 - - str2 - - - 100 - - - - 221 - - 100 - - - lf1 + + str0 + 121 + 131 + str1 + + str2 + + + 100 + + + + 221 + + 100 + + + lf1 diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/empty-data.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/empty-data.xml index 162a556887..7d62b9e24d 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/empty-data.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/empty-data.xml @@ -1,8 +1,8 @@ - - - - - - + + + + + + diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml index aae2af36d1..ebf7ac61ea 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-element.xml @@ -1,5 +1,5 @@ - - iden + + iden \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml index 621d2bc84c..3fe1e4bf48 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-default-nmspc-in-parrent-element.xml @@ -1,5 +1,5 @@ - - iden + + iden \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml index 497c35f2fc..30a54185ff 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-nmspc-in-parrent-element.xml @@ -1,5 +1,5 @@ - - z:iden + + z:iden \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml index 925442fee1..7d31fa7a95 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-with-prefix.xml @@ -1,5 +1,5 @@ - - x:iden + + x:iden \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml index 5a86eb02a8..c65df1ab1e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml +++ b/opendaylight/md-sal/sal-rest-connector/src/test/resources/xml-to-cnsn/identityref/xml/data-no-nmspc-value-without-prefix.xml @@ -1,5 +1,5 @@ - iden + iden \ No newline at end of file diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/DocProvider.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/DocProvider.java index 9c180014d7..934412d95a 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/DocProvider.java +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/DocProvider.java @@ -7,11 +7,13 @@ */ package org.opendaylight.controller.sal.rest.doc; +import java.util.Collection; +import java.util.Collections; + import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.controller.sal.rest.doc.impl.ApiDocGenerator; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; @@ -20,74 +22,69 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Collection; -import java.util.Collections; - - -public class DocProvider implements BundleActivator, - ServiceTrackerCustomizer, - Provider, - AutoCloseable { - - private Logger _logger = LoggerFactory.getLogger(DocProvider.class); - - private ServiceTracker brokerServiceTracker; - private BundleContext bundleContext; - private Broker.ProviderSession session; - - @Override - public void close() throws Exception { - stop(bundleContext); - } - - @Override - public void onSessionInitiated(Broker.ProviderSession providerSession) { - SchemaService schemaService = providerSession.getService(SchemaService.class); - ApiDocGenerator.getInstance().setSchemaService(schemaService); - - _logger.debug("Restconf API Explorer started"); - - } - - @Override - public Collection getProviderFunctionality() { - return Collections.emptySet(); - } - - @Override - public void start(BundleContext context) throws Exception { - bundleContext = context; - brokerServiceTracker = new ServiceTracker(context, Broker.class, this); - brokerServiceTracker.open(); - } - - @Override - public void stop(BundleContext context) throws Exception { - if (brokerServiceTracker != null) - brokerServiceTracker.close(); - - if (session != null) - session.close(); - } - - @Override - public Broker addingService(ServiceReference reference) { - Broker broker = bundleContext.getService(reference); - session = broker.registerProvider(this, bundleContext); - return broker; - } - - @Override - public void modifiedService(ServiceReference reference, Broker service) { - if (session != null) - session.close(); - - Broker broker = bundleContext.getService(reference); - session = broker.registerProvider(this, bundleContext); - } - - @Override - public void removedService(ServiceReference reference, Broker service) { - bundleContext.ungetService(reference); - } +public class DocProvider implements BundleActivator, ServiceTrackerCustomizer, Provider, AutoCloseable { + + private static final Logger _logger = LoggerFactory.getLogger(DocProvider.class); + + private ServiceTracker brokerServiceTracker; + private BundleContext bundleContext; + private Broker.ProviderSession session; + + @Override + public void close() throws Exception { + stop(bundleContext); + } + + @Override + public void onSessionInitiated(final Broker.ProviderSession providerSession) { + SchemaService schemaService = providerSession.getService(SchemaService.class); + ApiDocGenerator.getInstance().setSchemaService(schemaService); + + _logger.debug("Restconf API Explorer started"); + } + + @Override + public Collection getProviderFunctionality() { + return Collections.emptySet(); + } + + @Override + public void start(final BundleContext context) throws Exception { + bundleContext = context; + brokerServiceTracker = new ServiceTracker<>(context, Broker.class, this); + brokerServiceTracker.open(); + } + + @Override + public void stop(final BundleContext context) throws Exception { + if (brokerServiceTracker != null) { + brokerServiceTracker.close(); + } + + if (session != null) { + session.close(); + } + } + + @Override + public Broker addingService(final ServiceReference reference) { + Broker broker = bundleContext.getService(reference); + session = broker.registerProvider(this, bundleContext); + return broker; + } + + @Override + public void modifiedService(final ServiceReference reference, final Broker service) { + if (session != null) { + session.close(); + } + + Broker broker = bundleContext.getService(reference); + session = broker.registerProvider(this, bundleContext); + } + + @Override + public void removedService(final ServiceReference reference, final Broker service) { + bundleContext.ungetService(reference); + } } diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGenerator.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGenerator.java index 3662090b87..bcd11bcb06 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGenerator.java +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGenerator.java @@ -7,137 +7,157 @@ */ package org.opendaylight.controller.sal.rest.doc.impl; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule; -import com.google.common.base.Preconditions; +import java.io.IOException; +import java.net.URI; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.core.UriInfo; + import org.json.JSONException; import org.json.JSONObject; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.controller.sal.rest.doc.model.builder.OperationBuilder; -import org.opendaylight.controller.sal.rest.doc.swagger.*; +import org.opendaylight.controller.sal.rest.doc.swagger.Api; +import org.opendaylight.controller.sal.rest.doc.swagger.ApiDeclaration; +import org.opendaylight.controller.sal.rest.doc.swagger.Operation; +import org.opendaylight.controller.sal.rest.doc.swagger.Parameter; +import org.opendaylight.controller.sal.rest.doc.swagger.Resource; +import org.opendaylight.controller.sal.rest.doc.swagger.ResourceList; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.model.api.*; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.RpcDefinition; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.core.UriInfo; -import java.io.IOException; -import java.net.URI; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule; +import com.google.common.base.Preconditions; /** * This class gathers all yang defined {@link Module}s and generates Swagger compliant documentation. */ public class ApiDocGenerator { - private static Logger _logger = LoggerFactory.getLogger(ApiDocGenerator.class); - - private static final ApiDocGenerator INSTANCE = new ApiDocGenerator(); - private ObjectMapper mapper = new ObjectMapper(); - private final ModelGenerator jsonConverter = new ModelGenerator(); - - private SchemaService schemaService; - - private final String API_VERSION = "1.0.0"; - private final String SWAGGER_VERSION = "1.2"; - private final String RESTCONF_CONTEXT_ROOT = "restconf"; - private final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); - - //For now its {@link HashMap}. It will be changed to thread-safe Map when schema change listener is implemented. - private final Map MODULE_DOC_CACHE = new HashMap(); - - private ApiDocGenerator(){ - mapper.registerModule(new JsonOrgModule()); - mapper.configure(SerializationFeature.INDENT_OUTPUT, true); - } - - /** - * Returns singleton instance - * @return - */ - public static ApiDocGenerator getInstance() { - return INSTANCE; - } - - /** - * - * @param schemaService - */ - public void setSchemaService(SchemaService schemaService) { - this.schemaService = schemaService; - } - /** - * - * @param uriInfo - * @return list of modules converted to swagger compliant resource list. - */ - public ResourceList getResourceListing(UriInfo uriInfo) { - - Preconditions.checkState(schemaService != null); - SchemaContext schemaContext = schemaService.getGlobalContext(); - Preconditions.checkState(schemaContext != null); - - Set modules = schemaContext.getModules(); - - ResourceList resourceList = new ResourceList(); - resourceList.setApiVersion(API_VERSION); - resourceList.setSwaggerVersion(SWAGGER_VERSION); - - List resources = new ArrayList<>(modules.size()); - _logger.info("Modules found [{}]", modules.size()); - - for (Module module : modules) { - Resource resource = new Resource(); - String revisionString = SIMPLE_DATE_FORMAT.format(module.getRevision()); - - _logger.debug("Working on [{},{}]...", module.getName(), revisionString); - ApiDeclaration doc = getApiDeclaration(module.getName(), revisionString, uriInfo); - - if (doc != null) { - URI uri = uriInfo.getRequestUriBuilder(). - path(generateCacheKey(module.getName(), revisionString)). - build(); - - resource.setPath(uri.toASCIIString()); - resources.add(resource); - } else { - _logger.debug("Could not generate doc for {},{}", module.getName(), revisionString); - } - } + private static final Logger _logger = LoggerFactory.getLogger(ApiDocGenerator.class); - resourceList.setApis(resources); + private static final ApiDocGenerator INSTANCE = new ApiDocGenerator(); + private final ObjectMapper mapper = new ObjectMapper(); + private final ModelGenerator jsonConverter = new ModelGenerator(); - return resourceList; - } + private SchemaService schemaService; - public ApiDeclaration getApiDeclaration(String module, String revision, UriInfo uriInfo) { + private static final String API_VERSION = "1.0.0"; + private static final String SWAGGER_VERSION = "1.2"; + private static final String RESTCONF_CONTEXT_ROOT = "restconf"; + private final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); - //Lookup cache - String cacheKey = generateCacheKey(module, revision); + //For now its {@link HashMap}. It will be changed to thread-safe Map when schema change listener is implemented. + private final Map MODULE_DOC_CACHE = new HashMap(); - if (MODULE_DOC_CACHE.containsKey(cacheKey)) { - _logger.debug("Serving from cache for {}", cacheKey); - return MODULE_DOC_CACHE.get(cacheKey); + private ApiDocGenerator(){ + mapper.registerModule(new JsonOrgModule()); + mapper.configure(SerializationFeature.INDENT_OUTPUT, true); } - Date rev = null; - try { - rev = SIMPLE_DATE_FORMAT.parse(revision); - } catch (ParseException e) { - throw new IllegalArgumentException(e); + /** + * Returns singleton instance + * @return + */ + public static ApiDocGenerator getInstance() { + return INSTANCE; } - SchemaContext schemaContext = schemaService.getGlobalContext(); - Preconditions.checkState(schemaContext != null); + /** + * + * @param schemaService + */ + public void setSchemaService(final SchemaService schemaService) { + this.schemaService = schemaService; + } + /** + * + * @param uriInfo + * @return list of modules converted to swagger compliant resource list. + */ + public ResourceList getResourceListing(final UriInfo uriInfo) { + + Preconditions.checkState(schemaService != null); + SchemaContext schemaContext = schemaService.getGlobalContext(); + Preconditions.checkState(schemaContext != null); + + Set modules = schemaContext.getModules(); + + ResourceList resourceList = new ResourceList(); + resourceList.setApiVersion(API_VERSION); + resourceList.setSwaggerVersion(SWAGGER_VERSION); + + List resources = new ArrayList<>(modules.size()); + _logger.info("Modules found [{}]", modules.size()); + + for (Module module : modules) { + Resource resource = new Resource(); + String revisionString = SIMPLE_DATE_FORMAT.format(module.getRevision()); + + _logger.debug("Working on [{},{}]...", module.getName(), revisionString); + ApiDeclaration doc = getApiDeclaration(module.getName(), revisionString, uriInfo); + + if (doc != null) { + URI uri = uriInfo.getRequestUriBuilder(). + path(generateCacheKey(module.getName(), revisionString)). + build(); + + resource.setPath(uri.toASCIIString()); + resources.add(resource); + } else { + _logger.debug("Could not generate doc for {},{}", module.getName(), revisionString); + } + } + + resourceList.setApis(resources); + + return resourceList; + } + + public ApiDeclaration getApiDeclaration(final String module, final String revision, final UriInfo uriInfo) { + + //Lookup cache + String cacheKey = generateCacheKey(module, revision); - Module m = schemaContext.findModuleByName(module, rev); - Preconditions.checkArgument(m != null, "Could not find module by name,revision: " + module + "," + revision); + if (MODULE_DOC_CACHE.containsKey(cacheKey)) { + _logger.debug("Serving from cache for {}", cacheKey); + return MODULE_DOC_CACHE.get(cacheKey); + } + + Date rev = null; + try { + rev = SIMPLE_DATE_FORMAT.parse(revision); + } catch (ParseException e) { + throw new IllegalArgumentException(e); + } - String basePath = new StringBuilder(uriInfo.getBaseUri().getScheme()) + SchemaContext schemaContext = schemaService.getGlobalContext(); + Preconditions.checkState(schemaContext != null); + + Module m = schemaContext.findModuleByName(module, rev); + Preconditions.checkArgument(m != null, "Could not find module by name,revision: " + module + "," + revision); + + String basePath = new StringBuilder(uriInfo.getBaseUri().getScheme()) .append("://") .append(uriInfo.getBaseUri().getHost()) .append(":") @@ -146,161 +166,161 @@ public class ApiDocGenerator { .append(RESTCONF_CONTEXT_ROOT) .toString(); - ApiDeclaration doc = getSwaggerDocSpec(m, basePath); - MODULE_DOC_CACHE.put(cacheKey, doc); - return doc; - } + ApiDeclaration doc = getSwaggerDocSpec(m, basePath); + MODULE_DOC_CACHE.put(cacheKey, doc); + return doc; + } - public ApiDeclaration getSwaggerDocSpec(Module m, String basePath) { - ApiDeclaration doc = new ApiDeclaration(); - doc.setApiVersion(API_VERSION); - doc.setSwaggerVersion(SWAGGER_VERSION); - doc.setBasePath(basePath); - doc.setProduces(Arrays.asList("application/json", "application/xml")); + public ApiDeclaration getSwaggerDocSpec(final Module m, final String basePath) { + ApiDeclaration doc = new ApiDeclaration(); + doc.setApiVersion(API_VERSION); + doc.setSwaggerVersion(SWAGGER_VERSION); + doc.setBasePath(basePath); + doc.setProduces(Arrays.asList("application/json", "application/xml")); - List apis = new ArrayList(); + List apis = new ArrayList(); - Set dataSchemaNodes = m.getChildNodes(); - _logger.debug("child nodes size [{}]", dataSchemaNodes.size()); - for (DataSchemaNode node : dataSchemaNodes) { - if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) { + Set dataSchemaNodes = m.getChildNodes(); + _logger.debug("child nodes size [{}]", dataSchemaNodes.size()); + for (DataSchemaNode node : dataSchemaNodes) { + if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) { - _logger.debug("Is Configuration node [{}] [{}]", node.isConfiguration(), node.getQName().getLocalName()); + _logger.debug("Is Configuration node [{}] [{}]", node.isConfiguration(), node.getQName().getLocalName()); - List pathParams = null; - if (node.isConfiguration()) { - pathParams = new ArrayList(); - String resourcePath = "/config/" + m.getName() + ":"; - addApis(node, apis, resourcePath, pathParams, true); + List pathParams = null; + if (node.isConfiguration()) { + pathParams = new ArrayList(); + String resourcePath = "/config/" + m.getName() + ":"; + addApis(node, apis, resourcePath, pathParams, true); + } + + pathParams = new ArrayList(); + String resourcePath = "/operational/" + m.getName() + ":"; + addApis(node, apis, resourcePath, pathParams, false); + } } - pathParams = new ArrayList(); - String resourcePath = "/operational/" + m.getName() + ":"; - addApis(node, apis, resourcePath, pathParams, false); - } - } + Set rpcs = m.getRpcs(); + for (RpcDefinition rpcDefinition : rpcs) { + String resourcePath = "/operations/" + m.getName() + ":"; + addRpcs(rpcDefinition, apis, resourcePath); - Set rpcs = m.getRpcs(); - for (RpcDefinition rpcDefinition : rpcs) { - String resourcePath = "/operations/" + m.getName() + ":"; - addRpcs(rpcDefinition, apis, resourcePath); + } + _logger.debug("Number of APIs found [{}]", apis.size()); + doc.setApis(apis); + JSONObject models = null; + + try { + models = jsonConverter.convertToJsonSchema(m); + doc.setModels(models); + _logger.debug(mapper.writeValueAsString(doc)); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + return doc; } - _logger.debug("Number of APIs found [{}]", apis.size()); - doc.setApis(apis); - JSONObject models = null; - - try { - models = jsonConverter.convertToJsonSchema(m); - doc.setModels(models); - _logger.debug(mapper.writeValueAsString(doc)); - } catch (IOException | JSONException e) { - e.printStackTrace(); + + private String generateCacheKey(final Module m) { + return generateCacheKey(m.getName(), SIMPLE_DATE_FORMAT.format(m.getRevision())); } - return doc; - } - - private String generateCacheKey(Module m) { - return generateCacheKey(m.getName(), SIMPLE_DATE_FORMAT.format(m.getRevision())); - } - - private String generateCacheKey(String module, String revision) { - return module + "," + revision; - } - - private void addApis(DataSchemaNode node, - List apis, - String parentPath, - List parentPathParams, - boolean addConfigApi) { - - Api api = new Api(); - List pathParams = new ArrayList(parentPathParams); - - String resourcePath = parentPath + createPath(node, pathParams) + "/"; - _logger.debug("Adding path: [{}]", resourcePath); - api.setPath(resourcePath); - api.setOperations(operations(node, pathParams, addConfigApi)); - apis.add(api); - if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) { - DataNodeContainer schemaNode = (DataNodeContainer) node; - Set dataSchemaNodes = schemaNode.getChildNodes(); - - for (DataSchemaNode childNode : dataSchemaNodes) { - addApis(childNode, apis, resourcePath, pathParams, addConfigApi); - } + private String generateCacheKey(final String module, final String revision) { + return module + "," + revision; } - } + private void addApis(final DataSchemaNode node, + final List apis, + final String parentPath, + final List parentPathParams, + final boolean addConfigApi) { + + Api api = new Api(); + List pathParams = new ArrayList(parentPathParams); + + String resourcePath = parentPath + createPath(node, pathParams) + "/"; + _logger.debug("Adding path: [{}]", resourcePath); + api.setPath(resourcePath); + api.setOperations(operations(node, pathParams, addConfigApi)); + apis.add(api); + if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) { + DataNodeContainer schemaNode = (DataNodeContainer) node; + Set dataSchemaNodes = schemaNode.getChildNodes(); + + for (DataSchemaNode childNode : dataSchemaNodes) { + addApis(childNode, apis, resourcePath, pathParams, addConfigApi); + } + } - private void addRpcs(RpcDefinition rpcDefn, List apis, String parentPath) { - Api rpc = new Api(); - String resourcePath = parentPath + rpcDefn.getQName().getLocalName(); - rpc.setPath(resourcePath); + } + + private void addRpcs(final RpcDefinition rpcDefn, final List apis, final String parentPath) { + Api rpc = new Api(); + String resourcePath = parentPath + rpcDefn.getQName().getLocalName(); + rpc.setPath(resourcePath); - Operation operationSpec = new Operation(); - operationSpec.setMethod("POST"); - operationSpec.setNotes(rpcDefn.getDescription()); - operationSpec.setNickname(rpcDefn.getQName().getLocalName()); - rpc.setOperations(Arrays.asList(operationSpec)); + Operation operationSpec = new Operation(); + operationSpec.setMethod("POST"); + operationSpec.setNotes(rpcDefn.getDescription()); + operationSpec.setNickname(rpcDefn.getQName().getLocalName()); + rpc.setOperations(Arrays.asList(operationSpec)); - apis.add(rpc); - } + apis.add(rpc); + } - /** - * @param node - * @param pathParams - * @return - */ - private List operations(DataSchemaNode node, List pathParams, boolean isConfig) { - List operations = new ArrayList<>(); + /** + * @param node + * @param pathParams + * @return + */ + private List operations(final DataSchemaNode node, final List pathParams, final boolean isConfig) { + List operations = new ArrayList<>(); - OperationBuilder.Get getBuilder = new OperationBuilder.Get(node); - operations.add(getBuilder.pathParams(pathParams).build()); + OperationBuilder.Get getBuilder = new OperationBuilder.Get(node); + operations.add(getBuilder.pathParams(pathParams).build()); - if (isConfig) { - OperationBuilder.Post postBuilder = new OperationBuilder.Post(node); - operations.add(postBuilder.pathParams(pathParams).build()); + if (isConfig) { + OperationBuilder.Post postBuilder = new OperationBuilder.Post(node); + operations.add(postBuilder.pathParams(pathParams).build()); - OperationBuilder.Put putBuilder = new OperationBuilder.Put(node); - operations.add(putBuilder.pathParams(pathParams).build()); + OperationBuilder.Put putBuilder = new OperationBuilder.Put(node); + operations.add(putBuilder.pathParams(pathParams).build()); - OperationBuilder.Delete deleteBuilder = new OperationBuilder.Delete(node); - operations.add(deleteBuilder.pathParams(pathParams).build()); + OperationBuilder.Delete deleteBuilder = new OperationBuilder.Delete(node); + operations.add(deleteBuilder.pathParams(pathParams).build()); + } + return operations; } - return operations; - } - - private String createPath(final DataSchemaNode schemaNode, List pathParams) { - ArrayList pathListParams = new ArrayList(); - StringBuilder path = new StringBuilder(); - QName _qName = schemaNode.getQName(); - String localName = _qName.getLocalName(); - path.append(localName); - - if ((schemaNode instanceof ListSchemaNode)) { - final List listKeys = ((ListSchemaNode) schemaNode).getKeyDefinition(); - for (final QName listKey : listKeys) { - { - DataSchemaNode _dataChildByName = ((DataNodeContainer) schemaNode).getDataChildByName(listKey); - pathListParams.add(((LeafSchemaNode) _dataChildByName)); - - String pathParamIdentifier = new StringBuilder("/{").append(listKey.getLocalName()).append("}").toString(); - path.append(pathParamIdentifier); - - Parameter pathParam = new Parameter(); - pathParam.setName(listKey.getLocalName()); - pathParam.setDescription(_dataChildByName.getDescription()); - pathParam.setType("string"); - pathParam.setParamType("path"); - - pathParams.add(pathParam); + + private String createPath(final DataSchemaNode schemaNode, final List pathParams) { + ArrayList pathListParams = new ArrayList(); + StringBuilder path = new StringBuilder(); + QName _qName = schemaNode.getQName(); + String localName = _qName.getLocalName(); + path.append(localName); + + if ((schemaNode instanceof ListSchemaNode)) { + final List listKeys = ((ListSchemaNode) schemaNode).getKeyDefinition(); + for (final QName listKey : listKeys) { + { + DataSchemaNode _dataChildByName = ((DataNodeContainer) schemaNode).getDataChildByName(listKey); + pathListParams.add(((LeafSchemaNode) _dataChildByName)); + + String pathParamIdentifier = new StringBuilder("/{").append(listKey.getLocalName()).append("}").toString(); + path.append(pathParamIdentifier); + + Parameter pathParam = new Parameter(); + pathParam.setName(listKey.getLocalName()); + pathParam.setDescription(_dataChildByName.getDescription()); + pathParam.setType("string"); + pathParam.setParamType("path"); + + pathParams.add(pathParam); + } + } } - } + return path.toString(); } - return path.toString(); - } } diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java index 597051ed30..719dd78064 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java @@ -7,492 +7,524 @@ */ package org.opendaylight.controller.sal.rest.doc.impl; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import org.opendaylight.yangtools.yang.model.api.*; -import org.opendaylight.yangtools.yang.model.api.type.*; +import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; +import org.opendaylight.yangtools.yang.model.api.ChoiceNode; +import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; +import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.RpcDefinition; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit; import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair; -import org.opendaylight.yangtools.yang.model.util.*; +import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; +import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint; +import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition; +import org.opendaylight.yangtools.yang.model.util.BooleanType; +import org.opendaylight.yangtools.yang.model.util.Decimal64; +import org.opendaylight.yangtools.yang.model.util.EnumerationType; +import org.opendaylight.yangtools.yang.model.util.ExtendedType; +import org.opendaylight.yangtools.yang.model.util.Int16; +import org.opendaylight.yangtools.yang.model.util.Int32; +import org.opendaylight.yangtools.yang.model.util.Int64; +import org.opendaylight.yangtools.yang.model.util.Int8; +import org.opendaylight.yangtools.yang.model.util.StringType; +import org.opendaylight.yangtools.yang.model.util.Uint16; +import org.opendaylight.yangtools.yang.model.util.Uint32; +import org.opendaylight.yangtools.yang.model.util.Uint64; +import org.opendaylight.yangtools.yang.model.util.Uint8; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.util.*; - /** * Generates JSON Schema for data defined in Yang */ public class ModelGenerator { - private static Logger _logger = LoggerFactory.getLogger(ModelGenerator.class); - - private static final String BASE_64 = "base64"; - private static final String BINARY_ENCODING_KEY = "binaryEncoding"; - private static final String MEDIA_KEY = "media"; - private static final String ONE_OF_KEY = "oneOf"; - private static final String UNIQUE_ITEMS_KEY = "uniqueItems"; - private static final String MAX_ITEMS = "maxItems"; - private static final String MIN_ITEMS = "minItems"; - private static final String SCHEMA_URL = "http://json-schema.org/draft-04/schema"; - private static final String SCHEMA_KEY = "$schema"; - private static final String MAX_LENGTH_KEY = "maxLength"; - private static final String MIN_LENGTH_KEY = "minLength"; - private static final String REQUIRED_KEY = "required"; - private static final String REF_KEY = "$ref"; - private static final String ITEMS_KEY = "items"; - private static final String TYPE_KEY = "type"; - private static final String PROPERTIES_KEY = "properties"; - private static final String DESCRIPTION_KEY = "description"; - private static final String OBJECT_TYPE = "object"; - private static final String ARRAY_TYPE = "array"; - private static final String ENUM = "enum"; - private static final String INTEGER = "integer"; - private static final String NUMBER = "number"; - private static final String BOOLEAN = "boolean"; - private static final String STRING = "string"; - - private static final Map>, String> YANG_TYPE_TO_JSON_TYPE_MAPPING; - - static { - Map>, String> tempMap1 = new HashMap>, String>(10); - tempMap1.put(StringType.class , STRING); - tempMap1.put(BooleanType.class , BOOLEAN); - tempMap1.put(Int8.class , INTEGER); - tempMap1.put(Int16.class , INTEGER); - tempMap1.put(Int32.class , INTEGER); - tempMap1.put(Int64.class , INTEGER); - tempMap1.put(Uint16.class , INTEGER); - tempMap1.put(Uint32.class , INTEGER); - tempMap1.put(Uint64.class , INTEGER); - tempMap1.put(Uint8.class , INTEGER); - tempMap1.put(Decimal64.class , NUMBER); - tempMap1.put(EnumerationType.class , ENUM); - //TODO: Binary type - - YANG_TYPE_TO_JSON_TYPE_MAPPING = Collections.unmodifiableMap(tempMap1); - } - - public ModelGenerator(){ - } - - public JSONObject convertToJsonSchema(Module module) throws IOException, JSONException { - JSONObject models = new JSONObject(); - processContainers(module, models); - processRPCs(module, models); - - return models; - } - - - - private void processContainers(Module module, JSONObject models) throws IOException, JSONException { - - String moduleName = module.getName(); - Set childNodes = module.getChildNodes(); - - for(DataSchemaNode childNode : childNodes){ - JSONObject moduleJSON=null; - String filename = childNode.getQName().getLocalName(); - /* - * For every container in the module - */ - if(childNode instanceof ContainerSchemaNode) { - moduleJSON = processContainer((ContainerSchemaNode)childNode, moduleName, true, models); - } - - if(moduleJSON!=null) { - _logger.debug("Adding model for [{}]", filename); - moduleJSON.put("id", filename); - models.put(filename, moduleJSON); - } + private static final Logger _logger = LoggerFactory.getLogger(ModelGenerator.class); + + private static final String BASE_64 = "base64"; + private static final String BINARY_ENCODING_KEY = "binaryEncoding"; + private static final String MEDIA_KEY = "media"; + private static final String ONE_OF_KEY = "oneOf"; + private static final String UNIQUE_ITEMS_KEY = "uniqueItems"; + private static final String MAX_ITEMS = "maxItems"; + private static final String MIN_ITEMS = "minItems"; + private static final String SCHEMA_URL = "http://json-schema.org/draft-04/schema"; + private static final String SCHEMA_KEY = "$schema"; + private static final String MAX_LENGTH_KEY = "maxLength"; + private static final String MIN_LENGTH_KEY = "minLength"; + private static final String REQUIRED_KEY = "required"; + private static final String REF_KEY = "$ref"; + private static final String ITEMS_KEY = "items"; + private static final String TYPE_KEY = "type"; + private static final String PROPERTIES_KEY = "properties"; + private static final String DESCRIPTION_KEY = "description"; + private static final String OBJECT_TYPE = "object"; + private static final String ARRAY_TYPE = "array"; + private static final String ENUM = "enum"; + private static final String INTEGER = "integer"; + private static final String NUMBER = "number"; + private static final String BOOLEAN = "boolean"; + private static final String STRING = "string"; + + private static final Map>, String> YANG_TYPE_TO_JSON_TYPE_MAPPING; + + static { + Map>, String> tempMap1 = new HashMap>, String>(10); + tempMap1.put(StringType.class , STRING); + tempMap1.put(BooleanType.class , BOOLEAN); + tempMap1.put(Int8.class , INTEGER); + tempMap1.put(Int16.class , INTEGER); + tempMap1.put(Int32.class , INTEGER); + tempMap1.put(Int64.class , INTEGER); + tempMap1.put(Uint16.class , INTEGER); + tempMap1.put(Uint32.class , INTEGER); + tempMap1.put(Uint64.class , INTEGER); + tempMap1.put(Uint8.class , INTEGER); + tempMap1.put(Decimal64.class , NUMBER); + tempMap1.put(EnumerationType.class , ENUM); + //TODO: Binary type + + YANG_TYPE_TO_JSON_TYPE_MAPPING = Collections.unmodifiableMap(tempMap1); + } + + public ModelGenerator(){ + } + + public JSONObject convertToJsonSchema(final Module module) throws IOException, JSONException { + JSONObject models = new JSONObject(); + processContainers(module, models); + processRPCs(module, models); + + return models; + } + + + + private void processContainers(final Module module, final JSONObject models) throws IOException, JSONException { + + String moduleName = module.getName(); + Set childNodes = module.getChildNodes(); + + for(DataSchemaNode childNode : childNodes){ + JSONObject moduleJSON=null; + String filename = childNode.getQName().getLocalName(); + /* + * For every container in the module + */ + if(childNode instanceof ContainerSchemaNode) { + moduleJSON = processContainer((ContainerSchemaNode)childNode, moduleName, true, models); + } + + if(moduleJSON!=null) { + _logger.debug("Adding model for [{}]", filename); + moduleJSON.put("id", filename); + models.put(filename, moduleJSON); + } + } + + } + + + /** + * Process the RPCs for a Module + * Spits out a file each of the name -input.json + * and -output.json for each RPC that contains + * input & output elements + * + * @param module + * @throws JSONException + * @throws IOException + */ + private void processRPCs(final Module module, final JSONObject models) throws JSONException, IOException { + + Set rpcs = module.getRpcs(); + String moduleName = module.getName(); + for(RpcDefinition rpc: rpcs) { + + ContainerSchemaNode input = rpc.getInput(); + if(input!=null) { + JSONObject inputJSON = processContainer(input, moduleName, true, models); + String filename = rpc.getQName().getLocalName() + "-input"; + inputJSON.put("id", filename); + //writeToFile(filename, inputJSON.toString(2), moduleName); + models.put(filename, inputJSON); + } + + ContainerSchemaNode output = rpc.getOutput(); + if(output!=null) { + JSONObject outputJSON = processContainer(output, moduleName, true, models); + String filename = rpc.getQName().getLocalName() + "-output"; + outputJSON.put("id", filename); + models.put(filename, outputJSON); + } + } + } + + + /** + * Processes the container node and populates the moduleJSON + * + * @param container + * @param moduleName + * @throws JSONException + * @throws IOException + */ + private JSONObject processContainer(final ContainerSchemaNode container, final String moduleName, final boolean addSchemaStmt, final JSONObject models) throws JSONException, IOException{ + JSONObject moduleJSON = getSchemaTemplate(); + if(addSchemaStmt) { + moduleJSON = getSchemaTemplate(); + } else { + moduleJSON = new JSONObject(); + } + moduleJSON.put(TYPE_KEY, OBJECT_TYPE); + + String containerDescription = container.getDescription(); + moduleJSON.put(DESCRIPTION_KEY, containerDescription); + + Set containerChildren = container.getChildNodes(); + JSONObject properties = processChildren(containerChildren, moduleName, models); + moduleJSON.put(PROPERTIES_KEY, properties); + return moduleJSON; + } + + /** + * Processes the nodes + * @param nodes + * @param moduleName + * @return + * @throws JSONException + * @throws IOException + */ + private JSONObject processChildren(final Set nodes, final String moduleName, final JSONObject models) throws JSONException, IOException { + + JSONObject properties = new JSONObject(); + + for(DataSchemaNode node : nodes){ + String name = node.getQName().getLocalName(); + JSONObject property = null; + if(node instanceof LeafSchemaNode) { + property = processLeafNode((LeafSchemaNode)node); + } else if (node instanceof ListSchemaNode) { + property = processListSchemaNode((ListSchemaNode)node, moduleName, models); + + } else if (node instanceof LeafListSchemaNode) { + property = processLeafListNode((LeafListSchemaNode)node); + + } else if (node instanceof ChoiceNode) { + property = processChoiceNode((ChoiceNode)node, moduleName, models); + + } else if (node instanceof AnyXmlSchemaNode) { + property = processAnyXMLNode((AnyXmlSchemaNode)node); + + } else if (node instanceof ContainerSchemaNode) { + property = processContainer((ContainerSchemaNode)node, moduleName, false, models); + + } else { + throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass()); + } + + property.putOpt(DESCRIPTION_KEY, node.getDescription()); + properties.put(name, property); + } + return properties; + } + + /** + * + * @param listNode + * @throws JSONException + */ + private JSONObject processLeafListNode(final LeafListSchemaNode listNode) throws JSONException { + JSONObject props = new JSONObject(); + props.put(TYPE_KEY, ARRAY_TYPE); + + JSONObject itemsVal = new JSONObject(); + processTypeDef(listNode.getType(), itemsVal); + props.put(ITEMS_KEY, itemsVal); + + ConstraintDefinition constraints = listNode.getConstraints(); + processConstraints(constraints, props); + + return props; } - } - - - /** - * Process the RPCs for a Module - * Spits out a file each of the name -input.json - * and -output.json for each RPC that contains - * input & output elements - * - * @param module - * @throws JSONException - * @throws IOException - */ - private void processRPCs(Module module, JSONObject models) throws JSONException, IOException { - - Set rpcs = module.getRpcs(); - String moduleName = module.getName(); - for(RpcDefinition rpc: rpcs) { - - ContainerSchemaNode input = rpc.getInput(); - if(input!=null) { - JSONObject inputJSON = processContainer(input, moduleName, true, models); - String filename = rpc.getQName().getLocalName() + "-input"; - inputJSON.put("id", filename); - //writeToFile(filename, inputJSON.toString(2), moduleName); - models.put(filename, inputJSON); - } - - ContainerSchemaNode output = rpc.getOutput(); - if(output!=null) { - JSONObject outputJSON = processContainer(output, moduleName, true, models); - String filename = rpc.getQName().getLocalName() + "-output"; - outputJSON.put("id", filename); - models.put(filename, outputJSON); - } + /** + * + * @param choiceNode + * @param moduleName + * @throws JSONException + * @throws IOException + */ + private JSONObject processChoiceNode(final ChoiceNode choiceNode, final String moduleName, final JSONObject models) throws JSONException, IOException { + + Set cases = choiceNode.getCases(); + + JSONArray choiceProps = new JSONArray(); + for(ChoiceCaseNode choiceCase: cases) { + String choiceName = choiceCase.getQName().getLocalName(); + JSONObject choiceProp = processChildren(choiceCase.getChildNodes(), moduleName, models); + JSONObject choiceObj = new JSONObject(); + choiceObj.put(choiceName, choiceProp); + choiceObj.put(TYPE_KEY, OBJECT_TYPE); + choiceProps.put(choiceObj); + } + + JSONObject oneOfProps = new JSONObject(); + oneOfProps.put(ONE_OF_KEY, choiceProps); + oneOfProps.put(TYPE_KEY, OBJECT_TYPE); + + return oneOfProps; } - } - - - /** - * Processes the container node and populates the moduleJSON - * - * @param container - * @param moduleName - * @throws JSONException - * @throws IOException - */ - private JSONObject processContainer(ContainerSchemaNode container, String moduleName, boolean addSchemaStmt, JSONObject models) throws JSONException, IOException{ - JSONObject moduleJSON = getSchemaTemplate(); - if(addSchemaStmt) { - moduleJSON = getSchemaTemplate(); - } else { - moduleJSON = new JSONObject(); + + + /** + * + * @param constraints + * @param props + * @throws JSONException + */ + private void processConstraints(final ConstraintDefinition constraints, final JSONObject props) throws JSONException { + boolean isMandatory = constraints.isMandatory(); + props.put(REQUIRED_KEY, isMandatory); + + Integer minElements = constraints.getMinElements(); + Integer maxElements = constraints.getMaxElements(); + if(minElements !=null) { + props.put(MIN_ITEMS, minElements); + } + if(maxElements !=null) { + props.put(MAX_ITEMS, maxElements); + } } - moduleJSON.put(TYPE_KEY, OBJECT_TYPE); - - String containerDescription = container.getDescription(); - moduleJSON.put(DESCRIPTION_KEY, containerDescription); - - Set containerChildren = ((ContainerSchemaNode)container).getChildNodes(); - JSONObject properties = processChildren(containerChildren, moduleName, models); - moduleJSON.put(PROPERTIES_KEY, properties); - return moduleJSON; - } - - /** - * Processes the nodes - * @param nodes - * @param moduleName - * @return - * @throws JSONException - * @throws IOException - */ - private JSONObject processChildren(Set nodes, String moduleName, JSONObject models) throws JSONException, IOException { - - JSONObject properties = new JSONObject(); - - for(DataSchemaNode node : nodes){ - String name = node.getQName().getLocalName(); - JSONObject property = null; - if(node instanceof LeafSchemaNode) { - property = processLeafNode((LeafSchemaNode)node); - } else if (node instanceof ListSchemaNode) { - property = processListSchemaNode((ListSchemaNode)node, moduleName, models); - - } else if (node instanceof LeafListSchemaNode) { - property = processLeafListNode((LeafListSchemaNode)node); - - } else if (node instanceof ChoiceNode) { - property = processChoiceNode((ChoiceNode)node, moduleName, models); - - } else if (node instanceof AnyXmlSchemaNode) { - property = processAnyXMLNode((AnyXmlSchemaNode)node); - - } else if (node instanceof ContainerSchemaNode) { - property = processContainer((ContainerSchemaNode)node, moduleName, false, models); - - } else { - throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass()); - } - - property.putOpt(DESCRIPTION_KEY, node.getDescription()); - properties.put(name, property); + + /** + * Parses a ListSchema node. + * + * Due to a limitation of the RAML--->JAX-RS tool, sub-properties + * must be in a separate JSON schema file. Hence, we have to write + * some properties to a new file, while continuing to process the rest. + * + * @param listNode + * @param moduleName + * @return + * @throws JSONException + * @throws IOException + */ + private JSONObject processListSchemaNode(final ListSchemaNode listNode, final String moduleName, final JSONObject models) throws JSONException, IOException { + + Set listChildren = listNode.getChildNodes(); + String fileName = listNode.getQName().getLocalName(); + + JSONObject childSchemaProperties = processChildren(listChildren, moduleName, models); + JSONObject childSchema = getSchemaTemplate(); + childSchema.put(TYPE_KEY, OBJECT_TYPE); + childSchema.put(PROPERTIES_KEY, childSchemaProperties); + + /* + * Due to a limitation of the RAML--->JAX-RS tool, sub-properties + * must be in a separate JSON schema file. Hence, we have to write + * some properties to a new file, while continuing to process the rest. + */ + //writeToFile(fileName, childSchema.toString(2), moduleName); + childSchema.put("id", fileName); + models.put(fileName, childSchema); + + + JSONObject listNodeProperties = new JSONObject(); + listNodeProperties.put(TYPE_KEY, ARRAY_TYPE); + + JSONObject items = new JSONObject(); + items.put(REF_KEY,fileName ); + listNodeProperties.put(ITEMS_KEY, items); + + return listNodeProperties; + } - return properties; - } - - /** - * - * @param listNode - * @throws JSONException - */ - private JSONObject processLeafListNode(LeafListSchemaNode listNode) throws JSONException { - JSONObject props = new JSONObject(); - props.put(TYPE_KEY, ARRAY_TYPE); - - JSONObject itemsVal = new JSONObject(); - processTypeDef(listNode.getType(), itemsVal); - props.put(ITEMS_KEY, itemsVal); - - ConstraintDefinition constraints = listNode.getConstraints(); - processConstraints(constraints, props); - - return props; - } - - /** - * - * @param choiceNode - * @param moduleName - * @throws JSONException - * @throws IOException - */ - private JSONObject processChoiceNode(ChoiceNode choiceNode, String moduleName, JSONObject models) throws JSONException, IOException { - - Set cases = choiceNode.getCases(); - - JSONArray choiceProps = new JSONArray(); - for(ChoiceCaseNode choiceCase: cases) { - String choiceName = choiceCase.getQName().getLocalName(); - JSONObject choiceProp = processChildren(choiceCase.getChildNodes(), moduleName, models); - JSONObject choiceObj = new JSONObject(); - choiceObj.put(choiceName, choiceProp); - choiceObj.put(TYPE_KEY, OBJECT_TYPE); - choiceProps.put(choiceObj); + + /** + * + * @param leafNode + * @return + * @throws JSONException + */ + private JSONObject processLeafNode(final LeafSchemaNode leafNode) throws JSONException { + JSONObject property = new JSONObject(); + + String leafDescription = leafNode.getDescription(); + property.put(DESCRIPTION_KEY, leafDescription); + + processConstraints(leafNode.getConstraints(), property); + processTypeDef(leafNode.getType(), property); + + return property; } - JSONObject oneOfProps = new JSONObject(); - oneOfProps.put(ONE_OF_KEY, choiceProps); - oneOfProps.put(TYPE_KEY, OBJECT_TYPE); + /** + * + * @param leafNode + * @return + * @throws JSONException + */ + private JSONObject processAnyXMLNode(final AnyXmlSchemaNode leafNode) throws JSONException { + JSONObject property = new JSONObject(); - return oneOfProps; - } + String leafDescription = leafNode.getDescription(); + property.put(DESCRIPTION_KEY, leafDescription); + processConstraints(leafNode.getConstraints(), property); - /** - * - * @param constraints - * @param props - * @throws JSONException - */ - private void processConstraints(ConstraintDefinition constraints, JSONObject props) throws JSONException { - boolean isMandatory = constraints.isMandatory(); - props.put(REQUIRED_KEY, isMandatory); + return property; + } - Integer minElements = constraints.getMinElements(); - Integer maxElements = constraints.getMaxElements(); - if(minElements !=null) { - props.put(MIN_ITEMS, minElements); + /** + * @param property + * @throws JSONException + */ + private void processTypeDef(final TypeDefinition leafTypeDef, final JSONObject property) throws JSONException { + + if(leafTypeDef instanceof ExtendedType){ + processExtendedType(leafTypeDef, property); + } else if (leafTypeDef instanceof EnumerationType) { + processEnumType((EnumerationType)leafTypeDef, property); + + } else if (leafTypeDef instanceof BitsTypeDefinition) { + processBitsType((BitsTypeDefinition)leafTypeDef, property); + + } else if (leafTypeDef instanceof UnionTypeDefinition) { + processUnionType((UnionTypeDefinition)leafTypeDef, property); + + } else if (leafTypeDef instanceof IdentityrefTypeDefinition) { + property.putOpt(TYPE_KEY, "object"); + } else if (leafTypeDef instanceof BinaryTypeDefinition) { + processBinaryType((BinaryTypeDefinition)leafTypeDef, property); + } else { + //System.out.println("In else: " + leafTypeDef.getClass()); + String jsonType = YANG_TYPE_TO_JSON_TYPE_MAPPING.get(leafTypeDef.getClass()); + if(jsonType==null) { + jsonType = "object"; + } + property.putOpt(TYPE_KEY, jsonType); + } } - if(maxElements !=null) { - props.put(MAX_ITEMS, maxElements); + + /** + * + * @param leafTypeDef + * @param property + * @throws JSONException + */ + private void processExtendedType(final TypeDefinition leafTypeDef, final JSONObject property) throws JSONException { + Object leafBaseType = leafTypeDef.getBaseType(); + if(leafBaseType instanceof ExtendedType){ + //recursively process an extended type until we hit a base type + processExtendedType((TypeDefinition)leafBaseType, property); + } else { + List lengthConstraints = ((ExtendedType) leafTypeDef).getLengthConstraints(); + for(LengthConstraint lengthConstraint: lengthConstraints) { + Number min = lengthConstraint.getMin(); + Number max = lengthConstraint.getMax(); + property.putOpt(MIN_LENGTH_KEY, min); + property.putOpt(MAX_LENGTH_KEY, max); + } + String jsonType = YANG_TYPE_TO_JSON_TYPE_MAPPING.get(leafBaseType.getClass()); + property.putOpt(TYPE_KEY,jsonType ); + } + } - } - - /** - * Parses a ListSchema node. - * - * Due to a limitation of the RAML--->JAX-RS tool, sub-properties - * must be in a separate JSON schema file. Hence, we have to write - * some properties to a new file, while continuing to process the rest. - * - * @param listNode - * @param moduleName - * @return - * @throws JSONException - * @throws IOException - */ - private JSONObject processListSchemaNode(ListSchemaNode listNode, String moduleName, JSONObject models) throws JSONException, IOException { - - Set listChildren = listNode.getChildNodes(); - String fileName = listNode.getQName().getLocalName(); - - JSONObject childSchemaProperties = processChildren(listChildren, moduleName, models); - JSONObject childSchema = getSchemaTemplate(); - childSchema.put(TYPE_KEY, OBJECT_TYPE); - childSchema.put(PROPERTIES_KEY, childSchemaProperties); - - /* - * Due to a limitation of the RAML--->JAX-RS tool, sub-properties - * must be in a separate JSON schema file. Hence, we have to write - * some properties to a new file, while continuing to process the rest. - */ - //writeToFile(fileName, childSchema.toString(2), moduleName); - childSchema.put("id", fileName); - models.put(fileName, childSchema); - - - JSONObject listNodeProperties = new JSONObject(); - listNodeProperties.put(TYPE_KEY, ARRAY_TYPE); - - JSONObject items = new JSONObject(); - items.put(REF_KEY,fileName ); - listNodeProperties.put(ITEMS_KEY, items); - - return listNodeProperties; - - } - - /** - * - * @param leafNode - * @return - * @throws JSONException - */ - private JSONObject processLeafNode(LeafSchemaNode leafNode) throws JSONException { - JSONObject property = new JSONObject(); - - String leafDescription = leafNode.getDescription(); - property.put(DESCRIPTION_KEY, leafDescription); - - processConstraints(leafNode.getConstraints(), property); - processTypeDef(leafNode.getType(), property); - - return property; - } - - /** - * - * @param leafNode - * @return - * @throws JSONException - */ - private JSONObject processAnyXMLNode(AnyXmlSchemaNode leafNode) throws JSONException { - JSONObject property = new JSONObject(); - - String leafDescription = leafNode.getDescription(); - property.put(DESCRIPTION_KEY, leafDescription); - - processConstraints(leafNode.getConstraints(), property); - - return property; - } - - /** - * @param property - * @throws JSONException - */ - private void processTypeDef(TypeDefinition leafTypeDef, JSONObject property) throws JSONException { - - if(leafTypeDef instanceof ExtendedType){ - processExtendedType(leafTypeDef, property); - } else if (leafTypeDef instanceof EnumerationType) { - processEnumType((EnumerationType)leafTypeDef, property); - - } else if (leafTypeDef instanceof BitsTypeDefinition) { - processBitsType((BitsTypeDefinition)leafTypeDef, property); - - } else if (leafTypeDef instanceof UnionTypeDefinition) { - processUnionType((UnionTypeDefinition)leafTypeDef, property); - - } else if (leafTypeDef instanceof IdentityrefTypeDefinition) { - property.putOpt(TYPE_KEY, "object"); - } else if (leafTypeDef instanceof BinaryTypeDefinition) { - processBinaryType((BinaryTypeDefinition)leafTypeDef, property); - } else { - //System.out.println("In else: " + leafTypeDef.getClass()); - String jsonType = YANG_TYPE_TO_JSON_TYPE_MAPPING.get(leafTypeDef.getClass()); - if(jsonType==null) { - jsonType = "object"; - } - property.putOpt(TYPE_KEY, jsonType); + + /* + * + */ + private void processBinaryType(final BinaryTypeDefinition binaryType, final JSONObject property) throws JSONException { + property.put(TYPE_KEY, STRING); + JSONObject media = new JSONObject(); + media.put(BINARY_ENCODING_KEY, BASE_64); + property.put(MEDIA_KEY, media); } - } - - /** - * - * @param leafTypeDef - * @param property - * @throws JSONException - */ - private void processExtendedType(TypeDefinition leafTypeDef, JSONObject property) throws JSONException { - Object leafBaseType = leafTypeDef.getBaseType(); - if(leafBaseType instanceof ExtendedType){ - //recursively process an extended type until we hit a base type - processExtendedType((TypeDefinition)leafBaseType, property); - } else { - List lengthConstraints = ((ExtendedType) leafTypeDef).getLengthConstraints(); - for(LengthConstraint lengthConstraint: lengthConstraints) { - Number min = lengthConstraint.getMin(); - Number max = lengthConstraint.getMax(); - property.putOpt(MIN_LENGTH_KEY, min); - property.putOpt(MAX_LENGTH_KEY, max); - } - String jsonType = YANG_TYPE_TO_JSON_TYPE_MAPPING.get(leafBaseType.getClass()); - property.putOpt(TYPE_KEY,jsonType ); + + /** + * + * @param enumLeafType + * @param property + * @throws JSONException + */ + private void processEnumType(final EnumerationType enumLeafType, final JSONObject property) throws JSONException { + List enumPairs = enumLeafType.getValues(); + List enumNames = new ArrayList(); + for(EnumPair enumPair: enumPairs) { + enumNames.add(enumPair.getName()); + } + property.putOpt(ENUM, new JSONArray(enumNames)); } - } - - /* - * - */ - private void processBinaryType(BinaryTypeDefinition binaryType, JSONObject property) throws JSONException { - property.put(TYPE_KEY, STRING); - JSONObject media = new JSONObject(); - media.put(BINARY_ENCODING_KEY, BASE_64); - property.put(MEDIA_KEY, media); - } - - /** - * - * @param enumLeafType - * @param property - * @throws JSONException - */ - private void processEnumType(EnumerationType enumLeafType, JSONObject property) throws JSONException { - List enumPairs = enumLeafType.getValues(); - List enumNames = new ArrayList(); - for(EnumPair enumPair: enumPairs) { - enumNames.add(enumPair.getName()); + /** + * + * @param bitsType + * @param property + * @throws JSONException + */ + private void processBitsType(final BitsTypeDefinition bitsType, final JSONObject property) throws JSONException{ + property.put(TYPE_KEY, ARRAY_TYPE); + property.put(MIN_ITEMS, 0); + property.put(UNIQUE_ITEMS_KEY, true); + JSONArray enumValues = new JSONArray(); + + List bits = bitsType.getBits(); + for(Bit bit: bits) { + enumValues.put(bit.getName()); + } + JSONObject itemsValue = new JSONObject(); + itemsValue.put(ENUM, enumValues); + property.put(ITEMS_KEY, itemsValue); } - property.putOpt(ENUM, new JSONArray(enumNames)); - } - - /** - * - * @param bitsType - * @param property - * @throws JSONException - */ - private void processBitsType(BitsTypeDefinition bitsType, JSONObject property) throws JSONException{ - property.put(TYPE_KEY, ARRAY_TYPE); - property.put(MIN_ITEMS, 0); - property.put(UNIQUE_ITEMS_KEY, true); - JSONArray enumValues = new JSONArray(); - - List bits = bitsType.getBits(); - for(Bit bit: bits) { - enumValues.put(bit.getName()); + + + /** + * + * @param unionType + * @param property + * @throws JSONException + */ + private void processUnionType(final UnionTypeDefinition unionType, final JSONObject property) throws JSONException{ + + List> unionTypes = unionType.getTypes(); + JSONArray unionArray = new JSONArray(); + for(TypeDefinition typeDef: unionTypes) { + unionArray.put(YANG_TYPE_TO_JSON_TYPE_MAPPING.get(typeDef.getClass())); + } + property.put(TYPE_KEY, unionArray); } - JSONObject itemsValue = new JSONObject(); - itemsValue.put(ENUM, enumValues); - property.put(ITEMS_KEY, itemsValue); - } - - - /** - * - * @param unionType - * @param property - * @throws JSONException - */ - private void processUnionType(UnionTypeDefinition unionType, JSONObject property) throws JSONException{ - - List> unionTypes = unionType.getTypes(); - JSONArray unionArray = new JSONArray(); - for(TypeDefinition typeDef: unionTypes) { - unionArray.put(YANG_TYPE_TO_JSON_TYPE_MAPPING.get(typeDef.getClass())); + + + /** + * Helper method to generate a pre-filled + * JSON schema object. + * @return + * @throws JSONException + */ + private JSONObject getSchemaTemplate() throws JSONException { + JSONObject schemaJSON = new JSONObject(); + schemaJSON.put(SCHEMA_KEY, SCHEMA_URL); + + return schemaJSON; } - property.put(TYPE_KEY, unionArray); - } - - - /** - * Helper method to generate a pre-filled - * JSON schema object. - * @return - * @throws JSONException - */ - private JSONObject getSchemaTemplate() throws JSONException { - JSONObject schemaJSON = new JSONObject(); - schemaJSON.put(SCHEMA_KEY, SCHEMA_URL); - - return schemaJSON; - } } diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/resources/WEB-INF/web.xml b/opendaylight/md-sal/sal-rest-docgen/src/main/resources/WEB-INF/web.xml index 356a395b97..2a778180d4 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/resources/WEB-INF/web.xml +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/resources/WEB-INF/web.xml @@ -31,7 +31,7 @@ cors.allowed.headers - Content-Type,X-Requested-With,accept,authorization, + Content-Type,X-Requested-With,accept,authorization, origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers diff --git a/opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/DocGeneratorTest.java b/opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/DocGeneratorTest.java index 127529a3c6..264bc67004 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/DocGeneratorTest.java +++ b/opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/DocGeneratorTest.java @@ -69,4 +69,4 @@ public class DocGeneratorTest { } } -} +} diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/kitchen_service/impl/KitchenServiceModule.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/kitchen_service/impl/KitchenServiceModule.java index 4dc3645131..a23def6262 100644 --- a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/kitchen_service/impl/KitchenServiceModule.java +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/kitchen_service/impl/KitchenServiceModule.java @@ -1,15 +1,14 @@ /** -* Generated file + * Generated file -* Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl -* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator -* Generated at: Wed Feb 05 11:31:30 CET 2014 -* -* Do not modify this file unless it is present under src/main directory -*/ + * Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Feb 05 11:31:30 CET 2014 + * + * Do not modify this file unless it is present under src/main directory + */ package org.opendaylight.controller.config.yang.config.kitchen_service.impl; -import org.opendaylight.controller.config.yang.config.kitchen_service.impl.AbstractKitchenServiceModule; import org.opendaylight.controller.sample.kitchen.api.EggsType; import org.opendaylight.controller.sample.kitchen.api.KitchenService; import org.opendaylight.controller.sample.kitchen.impl.KitchenServiceImpl; @@ -21,17 +20,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** -* -*/ + * + */ public final class KitchenServiceModule extends AbstractKitchenServiceModule { private static final Logger log = LoggerFactory.getLogger(KitchenServiceModule.class); - public KitchenServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + public KitchenServiceModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { super(identifier, dependencyResolver); } - public KitchenServiceModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, - KitchenServiceModule oldModule, java.lang.AutoCloseable oldInstance) { + public KitchenServiceModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, + final KitchenServiceModule oldModule, final java.lang.AutoCloseable oldInstance) { super(identifier, dependencyResolver, oldModule, oldInstance); } @@ -64,7 +63,7 @@ public final class KitchenServiceModule extends AbstractKitchenServiceModule { } @Override - public boolean makeBreakfast( EggsType eggs, Class toast, int toastDoneness ) { + public boolean makeBreakfast( final EggsType eggs, final Class toast, final int toastDoneness ) { return kitchenService.makeBreakfast( eggs, toast, toastDoneness ); } } diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/kitchen_service/impl/KitchenServiceModuleFactory.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/kitchen_service/impl/KitchenServiceModuleFactory.java index 2d6e7f3262..0c68cd2254 100644 --- a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/kitchen_service/impl/KitchenServiceModuleFactory.java +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/config/yang/config/kitchen_service/impl/KitchenServiceModuleFactory.java @@ -1,21 +1,17 @@ /** -* Generated file + * Generated file -* Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl -* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator -* Generated at: Wed Feb 05 11:31:30 CET 2014 -* -* Do not modify this file unless it is present under src/main directory -*/ + * Generated from: yang module name: toaster-consumer-impl yang module local name: toaster-consumer-impl + * Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator + * Generated at: Wed Feb 05 11:31:30 CET 2014 + * + * Do not modify this file unless it is present under src/main directory + */ package org.opendaylight.controller.config.yang.config.kitchen_service.impl; -import org.opendaylight.controller.config.yang.config.kitchen_service.impl.AbstractKitchenServiceModuleFactory; - /** -* -*/ -public class KitchenServiceModuleFactory extends AbstractKitchenServiceModuleFactory -{ - + * + */ +public class KitchenServiceModuleFactory extends AbstractKitchenServiceModuleFactory { } diff --git a/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml b/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml index c5a2a0d340..61c24c6b64 100644 --- a/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml +++ b/opendaylight/md-sal/samples/toaster-it/src/test/resources/controller.xml @@ -55,7 +55,7 @@ binding:binding-data-broker ref_binding-data-broker - + binding:binding-notification-service diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java index 7d9cc7ecbd..db216237d0 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java @@ -103,7 +103,7 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo final OpendaylightGroupStatisticsService groupStatsService, final OpendaylightMeterStatisticsService meterStatsService, final OpendaylightPortStatisticsService portStatsService, - final OpendaylightQueueStatisticsService queueStatsService, + final OpendaylightQueueStatisticsService queueStatsService, final StatisticsRequestScheduler srScheduler) { this.dps = Preconditions.checkNotNull(dps); this.targetNodeKey = Preconditions.checkNotNull(nodeKey); @@ -274,20 +274,20 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo this.srScheduler.addRequestToSchedulerQueue(flowTableStats); this.srScheduler.addRequestToSchedulerQueue(flowStats); - + this.srScheduler.addRequestToSchedulerQueue(nodeConnectorStats); - + this.srScheduler.addRequestToSchedulerQueue(groupStats); - + this.srScheduler.addRequestToSchedulerQueue(groupDescStats); - + this.srScheduler.addRequestToSchedulerQueue(meterStats); - + this.srScheduler.addRequestToSchedulerQueue(meterConfigStats); - + this.srScheduler.addRequestToSchedulerQueue(queueStats); } - + public synchronized void start(final Timer timer) { flowStats.start(dps); groupDescStats.start(dps); @@ -313,7 +313,7 @@ public final class NodeStatisticsHandler implements AutoCloseable, FlowCapableCo meterStats.close(); queueStats.close(); - //Clean up queued statistics request from scheduler queue + //Clean up queued statistics request from scheduler queue srScheduler.removeRequestsFromSchedulerQueue(this.getNodeRef()); logger.debug("Statistics handler for {} shut down", targetNodeKey.getId()); diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java index d8bea7c63a..b96d2be47e 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java @@ -66,7 +66,7 @@ public class StatisticsProvider implements AutoCloseable { private OpendaylightFlowTableStatisticsService flowTableStatsService; private OpendaylightQueueStatisticsService queueStatsService; - + private final StatisticsRequestScheduler srScheduler; public StatisticsProvider(final DataProviderService dataService) { @@ -90,7 +90,7 @@ public class StatisticsProvider implements AutoCloseable { flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class); queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class); this.srScheduler.start(); - + // Start receiving notifications this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter); diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java index bea43ef68a..0ae33b8c71 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsRequestScheduler.java @@ -24,7 +24,7 @@ import org.slf4j.LoggerFactory; /** * Main responsibility of the class is to check the MD-SAL data store read/write - * transaction accumulation level and send statistics request if number of pending + * transaction accumulation level and send statistics request if number of pending * read/write transactions are zero. * @author avishnoi@in.ibm.com * @@ -36,15 +36,15 @@ public class StatisticsRequestScheduler implements DataTransactionListener { private final Timer timer = new Timer("request-monitor", true); // We need ordered retrieval, and O(1) contains operation - private final Map requestQueue = + private final Map requestQueue = Collections.synchronizedMap(new LinkedHashMap()); - + private Long PendingTransactions; - + private long lastRequestTime = System.nanoTime(); - + private static final long REQUEST_MONITOR_INTERVAL = 1000; - + private final TimerTask task = new TimerTask() { @Override public void run() { @@ -58,11 +58,11 @@ public class StatisticsRequestScheduler implements DataTransactionListener { public StatisticsRequestScheduler(){ PendingTransactions = (long) 0; } - + public void addRequestToSchedulerQueue(AbstractStatsTracker statsRequest){ requestQueue.put(statsRequest, null); } - + public void removeRequestsFromSchedulerQueue(NodeRef node){ AbstractStatsTracker stats = null; synchronized(requestQueue){ @@ -97,7 +97,7 @@ public class StatisticsRequestScheduler implements DataTransactionListener { } @Override public void onStatusUpdated(DataModificationTransaction transaction, TransactionStatus status) { - + AbstractStatsTracker stats = null; synchronized(PendingTransactions){ switch(status){ @@ -119,7 +119,7 @@ public class StatisticsRequestScheduler implements DataTransactionListener { } sendStatsRequest(stats); } - + private void sendStatsRequest(AbstractStatsTracker stats){ if(stats != null){ try{ diff --git a/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/LLDPDiscoveryListener.java b/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/LLDPDiscoveryListener.java index ed96e3aa0c..c539ac81d4 100644 --- a/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/LLDPDiscoveryListener.java +++ b/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/LLDPDiscoveryListener.java @@ -24,7 +24,7 @@ class LLDPDiscoveryListener implements PacketProcessingListener { LLDPDiscoveryListener(LLDPDiscoveryProvider manager) { this.manager = manager; } - + public void onPacketReceived(PacketReceived lldp) { NodeConnectorRef src = LLDPDiscoveryUtils.lldpToNodeConnectorRef(lldp.getPayload()); if(src != null) { @@ -32,10 +32,10 @@ class LLDPDiscoveryListener implements PacketProcessingListener { ldb.setDestination(lldp.getIngress()); ldb.setSource(new NodeConnectorRef(src)); LinkDiscovered ld = ldb.build(); - + manager.getNotificationService().publish(ld); LLDPLinkAger.getInstance().put(ld); } } - + } diff --git a/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/LLDPLinkAger.java b/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/LLDPLinkAger.java index 7d2570551d..face5967c2 100644 --- a/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/LLDPLinkAger.java +++ b/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/LLDPLinkAger.java @@ -37,17 +37,17 @@ public class LLDPLinkAger { public static LLDPLinkAger getInstance() { return instance; } - + public void put(LinkDiscovered link) { Date expires = new Date(); expires.setTime(expires.getTime() + LLDPDiscoveryUtils.LLDP_EXPIRATION_TIME); linkToDate.put(link, expires); } - + public void close() { timer.cancel(); } - + private class LLDPAgingTask extends TimerTask { @Override @@ -64,9 +64,9 @@ public class LLDPLinkAger { } } } - + } - + } } diff --git a/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/utils/LLDPDiscoveryUtils.java b/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/utils/LLDPDiscoveryUtils.java index ce42283ebe..82ab443246 100644 --- a/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/utils/LLDPDiscoveryUtils.java +++ b/opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/utils/LLDPDiscoveryUtils.java @@ -27,10 +27,10 @@ import org.slf4j.LoggerFactory; public class LLDPDiscoveryUtils { static Logger LOG = LoggerFactory.getLogger(LLDPDiscoveryUtils.class); - + public static final Long LLDP_INTERVAL = (long) (1000*5); // Send LLDP every five seconds public static final Long LLDP_EXPIRATION_TIME = LLDP_INTERVAL*3; // Let up to three intervals pass before we decide we are expired. - + public static String macToString(byte[] mac) { StringBuilder b = new StringBuilder(); for (int i = 0; i < mac.length; i++) { @@ -39,7 +39,7 @@ public class LLDPDiscoveryUtils { return b.toString(); } - + public static NodeConnectorRef lldpToNodeConnectorRef(byte[] payload) { Ethernet ethPkt = new Ethernet(); try { @@ -50,7 +50,7 @@ public class LLDPDiscoveryUtils { if (ethPkt.getPayload() instanceof LLDP) { LLDP lldp = (LLDP) ethPkt.getPayload(); - + try { NodeId srcNodeId = null; NodeConnectorId srcNodeConnectorId = null; diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java index 542e972deb..6dbfd7225b 100644 --- a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java @@ -15,12 +15,8 @@ import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMap import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNode; import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNodeId; -import java.util.concurrent.Future; - import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryListener; @@ -36,146 +32,128 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRem import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.JdkFutureAdapters; - -class FlowCapableTopologyExporter implements // - FlowTopologyDiscoveryListener, // - OpendaylightInventoryListener // -{ - protected final static Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyExporter.class); - public static TopologyKey topology = new TopologyKey(new TopologyId("flow:1")); +import com.google.common.base.Preconditions; - // FIXME: Flow capable topology exporter should use transaction chaining API - private DataProviderService dataService; +class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, OpendaylightInventoryListener { + private final InstanceIdentifier topology; + private final OperationProcessor processor; - public DataProviderService getDataService() { - return dataService; - } - - public void setDataService(final DataProviderService dataService) { - this.dataService = dataService; - } - - private InstanceIdentifier topologyPath; - - public void start() { - TopologyBuilder tb = new TopologyBuilder(); - tb.setKey(topology); - topologyPath = InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, topology).build(); - Topology top = tb.build(); - DataModificationTransaction tx = dataService.beginTransaction(); - tx.putOperationalData(topologyPath, top); - listenOnTransactionState(tx.getIdentifier(),tx.commit()); + FlowCapableTopologyExporter(final OperationProcessor processor, final InstanceIdentifier topology) { + this.processor = Preconditions.checkNotNull(processor); + this.topology = Preconditions.checkNotNull(topology); } @Override - public synchronized void onNodeRemoved(final NodeRemoved notification) { - NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId()); - InstanceIdentifier nodeInstance = toNodeIdentifier(notification.getNodeRef()); - - DataModificationTransaction tx = dataService.beginTransaction(); - tx.removeOperationalData(nodeInstance); - removeAffectedLinks(tx, nodeId); - listenOnTransactionState(tx.getIdentifier(),tx.commit()); + public void onNodeRemoved(final NodeRemoved notification) { + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(final DataModificationTransaction transaction) { + NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId()); + InstanceIdentifier nodeInstance = toNodeIdentifier(notification.getNodeRef()); + transaction.removeOperationalData(nodeInstance); + removeAffectedLinks(transaction, nodeId); + } + }); } @Override - public synchronized void onNodeUpdated(final NodeUpdated notification) { + public void onNodeUpdated(final NodeUpdated notification) { FlowCapableNodeUpdated fcnu = notification.getAugmentation(FlowCapableNodeUpdated.class); if (fcnu != null) { - Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef()); - InstanceIdentifier path = getNodePath(toTopologyNodeId(notification.getId())); - DataModificationTransaction tx = dataService.beginTransaction(); - tx.putOperationalData(path, node); - listenOnTransactionState(tx.getIdentifier(),tx.commit()); + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(final DataModificationTransaction transaction) { + Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef()); + InstanceIdentifier path = getNodePath(toTopologyNodeId(notification.getId())); + transaction.putOperationalData(path, node); + } + }); } } @Override - public synchronized void onNodeConnectorRemoved(final NodeConnectorRemoved notification) { - InstanceIdentifier tpInstance = toTerminationPointIdentifier(notification - .getNodeConnectorRef()); - TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId()); - DataModificationTransaction tx = dataService.beginTransaction(); - tx.removeOperationalData(tpInstance); - removeAffectedLinks(tx, tpId); - listenOnTransactionState(tx.getIdentifier(),tx.commit()); + public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) { + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(final DataModificationTransaction transaction) { + InstanceIdentifier tpInstance = toTerminationPointIdentifier(notification + .getNodeConnectorRef()); + TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId()); + transaction.removeOperationalData(tpInstance); + removeAffectedLinks(transaction, tpId); + } + }); } @Override - public synchronized void onNodeConnectorUpdated(final NodeConnectorUpdated notification) { - FlowCapableNodeConnectorUpdated fcncu = notification.getAugmentation(FlowCapableNodeConnectorUpdated.class); + public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) { + final FlowCapableNodeConnectorUpdated fcncu = notification.getAugmentation(FlowCapableNodeConnectorUpdated.class); if (fcncu != null) { - NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId()); - TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()), - notification.getNodeConnectorRef()); - InstanceIdentifier path = tpPath(nodeId, point.getKey().getTpId()); - - DataModificationTransaction tx = dataService.beginTransaction(); - tx.putOperationalData(path, point); - if ((fcncu.getState() != null && fcncu.getState().isLinkDown()) - || (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) { - removeAffectedLinks(tx, point.getTpId()); - } - listenOnTransactionState(tx.getIdentifier(),tx.commit()); + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(final DataModificationTransaction transaction) { + NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId()); + TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()), + notification.getNodeConnectorRef()); + InstanceIdentifier path = tpPath(nodeId, point.getKey().getTpId()); + + transaction.putOperationalData(path, point); + if ((fcncu.getState() != null && fcncu.getState().isLinkDown()) + || (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) { + removeAffectedLinks(transaction, point.getTpId()); + } + } + }); } } @Override - public synchronized void onLinkDiscovered(final LinkDiscovered notification) { - Link link = toTopologyLink(notification); - InstanceIdentifier path = linkPath(link); - DataModificationTransaction tx = dataService.beginTransaction(); - tx.putOperationalData(path, link); - listenOnTransactionState(tx.getIdentifier(),tx.commit()); - + public void onLinkDiscovered(final LinkDiscovered notification) { + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(final DataModificationTransaction transaction) { + Link link = toTopologyLink(notification); + InstanceIdentifier path = linkPath(link); + transaction.putOperationalData(path, link); + } + }); } @Override - public synchronized void onLinkOverutilized(final LinkOverutilized notification) { + public void onLinkOverutilized(final LinkOverutilized notification) { // NOOP } @Override - public synchronized void onLinkRemoved(final LinkRemoved notification) { - InstanceIdentifier path = linkPath(toTopologyLink(notification)); - DataModificationTransaction tx = dataService.beginTransaction(); - tx.removeOperationalData(path); - listenOnTransactionState(tx.getIdentifier(),tx.commit()); + public void onLinkRemoved(final LinkRemoved notification) { + processor.enqueueOperation(new TopologyOperation() { + @Override + public void applyOperation(final DataModificationTransaction transaction) { + transaction.removeOperationalData(linkPath(toTopologyLink(notification))); + } + }); } @Override - public synchronized void onLinkUtilizationNormal(final LinkUtilizationNormal notification) { + public void onLinkUtilizationNormal(final LinkUtilizationNormal notification) { // NOOP } - private static InstanceIdentifier toNodeIdentifier(final NodeRef ref) { + private InstanceIdentifier toNodeIdentifier(final NodeRef ref) { org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey invNodeKey = getNodeKey(ref); - NodeKey nodeKey = new NodeKey(toTopologyNodeId(invNodeKey.getId())); - return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, topology) - .child(Node.class, nodeKey).build(); + return topology.child(Node.class, nodeKey); } private InstanceIdentifier toTerminationPointIdentifier(final NodeConnectorRef ref) { @@ -186,71 +164,39 @@ class FlowCapableTopologyExporter implements // private void removeAffectedLinks(final DataModificationTransaction transaction, final NodeId id) { TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction); - - Topology topologyData = reader.readOperationalData(topologyPath); - if (topologyData == null) { - return; - } - for (Link link : topologyData.getLink()) { - if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) { - InstanceIdentifier path = topologyPath.child(Link.class, link.getKey()); - transaction.removeOperationalData(path); + Topology topologyData = reader.readOperationalData(topology); + if (topologyData != null) { + for (Link link : topologyData.getLink()) { + if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) { + transaction.removeOperationalData(linkPath(link)); + } } } } private void removeAffectedLinks(final DataModificationTransaction transaction, final TpId id) { TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction); - Topology topologyData = reader.readOperationalData(topologyPath); - if (topologyData == null) { - return; - } - for (Link link : topologyData.getLink()) { - if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) { - InstanceIdentifier path = topologyPath.child(Link.class, link.getKey()); - transaction.removeOperationalData(path); + Topology topologyData = reader.readOperationalData(topology); + if (topologyData != null) { + for (Link link : topologyData.getLink()) { + if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) { + transaction.removeOperationalData(linkPath(link)); + } } } } private InstanceIdentifier getNodePath(final NodeId nodeId) { - NodeKey nodeKey = new NodeKey(nodeId); - return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, topology) - .child(Node.class, nodeKey).build(); + return topology.child(Node.class, new NodeKey(nodeId)); } private InstanceIdentifier tpPath(final NodeId nodeId, final TpId tpId) { NodeKey nodeKey = new NodeKey(nodeId); TerminationPointKey tpKey = new TerminationPointKey(tpId); - return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, topology) - .child(Node.class, nodeKey).child(TerminationPoint.class, tpKey).build(); + return topology.child(Node.class, nodeKey).child(TerminationPoint.class, tpKey); } private InstanceIdentifier linkPath(final Link link) { - InstanceIdentifier linkInstanceId = InstanceIdentifier.builder(NetworkTopology.class) - .child(Topology.class, topology).child(Link.class, link.getKey()).build(); - return linkInstanceId; - } - - /** - * @param txId transaction identificator - * @param future transaction result - */ - private static void listenOnTransactionState(final Object txId, Future> future) { - Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future),new FutureCallback>() { - - @Override - public void onFailure(Throwable t) { - LOG.error("Topology export failed for Tx:{}", txId, t); - - } - - @Override - public void onSuccess(RpcResult result) { - if(!result.isSuccessful()) { - LOG.error("Topology export failed for Tx:{}", txId); - } - } - }); + return topology.child(Link.class, link.getKey()); } } diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.java index e77ba8769c..d656bda932 100644 --- a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.java +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyProvider.java @@ -7,11 +7,20 @@ */ package org.opendaylight.md.controller.topology.manager; +import java.util.concurrent.ExecutionException; + import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.NotificationListener; import org.osgi.framework.BundleContext; import org.slf4j.Logger; @@ -19,58 +28,60 @@ import org.slf4j.LoggerFactory; public class FlowCapableTopologyProvider extends AbstractBindingAwareProvider implements AutoCloseable { private final static Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyProvider.class); + private Registration listenerRegistration; + private Thread thread; - private DataProviderService dataService; - - public DataProviderService getDataService() { - return this.dataService; - } + /** + * Gets called on start of a bundle. + * + * @param session + */ + @Override + public synchronized void onSessionInitiated(final ProviderContext session) { + final DataProviderService dataService = session.getSALService(DataProviderService.class); + final NotificationProviderService notificationService = session.getSALService(NotificationProviderService.class); - public void setDataService(final DataProviderService dataService) { - this.dataService = dataService; - } + final String name = "flow:1"; + final TopologyKey key = new TopologyKey(new TopologyId(name)); + final InstanceIdentifier path = InstanceIdentifier + .builder(NetworkTopology.class) + .child(Topology.class, key) + .build(); - private NotificationProviderService notificationService; + final OperationProcessor processor = new OperationProcessor(dataService); + final FlowCapableTopologyExporter listener = new FlowCapableTopologyExporter(processor, path); + this.listenerRegistration = notificationService.registerNotificationListener(listener); - public NotificationProviderService getNotificationService() { - return this.notificationService; - } + final DataModificationTransaction tx = dataService.beginTransaction(); + tx.putOperationalData(path, new TopologyBuilder().setKey(key).build()); + try { + tx.commit().get(); + } catch (InterruptedException | ExecutionException e) { + LOG.warn("Initial topology export failed, continuing anyway", e); + } - public void setNotificationService(final NotificationProviderService notificationService) { - this.notificationService = notificationService; + thread = new Thread(processor); + thread.setDaemon(true); + thread.setName("FlowCapableTopologyExporter-" + name); + thread.start(); } - private final FlowCapableTopologyExporter exporter = new FlowCapableTopologyExporter(); - private Registration listenerRegistration; - @Override - public void close() { - - FlowCapableTopologyProvider.LOG.info("FlowCapableTopologyProvider stopped."); - dataService = null; - notificationService = null; + public synchronized void close() throws InterruptedException { + LOG.info("FlowCapableTopologyProvider stopped."); if (this.listenerRegistration != null) { try { this.listenerRegistration.close(); } catch (Exception e) { - throw new IllegalStateException("Exception during close of listener registration.",e); + LOG.error("Failed to close listener registration", e); } + listenerRegistration = null; + } + if (thread != null) { + thread.interrupt(); + thread.join(); + thread = null; } - } - - /** - * Gets called on start of a bundle. - * - * @param session - */ - @Override - public void onSessionInitiated(final ProviderContext session) { - dataService = session.getSALService(DataProviderService.class); - notificationService = session.getSALService(NotificationProviderService.class); - this.exporter.setDataService(dataService); - this.exporter.start(); - this.listenerRegistration = notificationService.registerNotificationListener(this.exporter); - ; } /** @@ -81,6 +92,10 @@ public class FlowCapableTopologyProvider extends AbstractBindingAwareProvider im */ @Override public void stopImpl(final BundleContext context) { - this.close(); + try { + this.close(); + } catch (InterruptedException e) { + LOG.error("Failed to stop provider", e); + } } } diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java new file mode 100644 index 0000000000..d60c88032d --- /dev/null +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/OperationProcessor.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014 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.md.controller.topology.manager; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.LinkedBlockingQueue; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.binding.api.data.DataProviderService; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +final class OperationProcessor implements Runnable { + private static final Logger LOG = LoggerFactory.getLogger(OperationProcessor.class); + private static final int MAX_TRANSACTION_OPERATIONS = 100; + private static final int OPERATION_QUEUE_DEPTH = 500; + + private final BlockingQueue queue = new LinkedBlockingQueue<>(OPERATION_QUEUE_DEPTH); + // FIXME: Flow capable topology exporter should use transaction chaining API + private final DataProviderService dataService; + + OperationProcessor(final DataProviderService dataService) { + this.dataService = Preconditions.checkNotNull(dataService); + } + + void enqueueOperation(final TopologyOperation task) { + try { + queue.put(task); + } catch (InterruptedException e) { + LOG.warn("Interrupted while submitting task {}", task, e); + } + } + + @Override + public void run() { + try { + for (;;) { + TopologyOperation op = queue.take(); + + LOG.debug("New operations available, starting transaction"); + final DataModificationTransaction tx = dataService.beginTransaction(); + + int ops = 0; + do { + op.applyOperation(tx); + + ops++; + if (ops < MAX_TRANSACTION_OPERATIONS) { + op = queue.poll(); + } else { + op = null; + } + } while (op != null); + + LOG.debug("Processed {} operations, submitting transaction", ops); + + try { + final RpcResult s = tx.commit().get(); + if (!s.isSuccessful()) { + LOG.error("Topology export failed for Tx:{}", tx.getIdentifier()); + } + } catch (ExecutionException e) { + LOG.error("Topology export transaction {} failed", tx.getIdentifier(), e.getCause()); + } + } + } catch (InterruptedException e) { + LOG.info("Interrupted processing, terminating", e); + } + + // Drain all events, making sure any blocked threads are unblocked + while (!queue.isEmpty()) { + queue.poll(); + } + } +} diff --git a/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/TopologyOperation.java b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/TopologyOperation.java new file mode 100644 index 0000000000..29d06beade --- /dev/null +++ b/opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/TopologyOperation.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2014 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.md.controller.topology.manager; + +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; + +/** + * Internal interface for submitted operations. Implementations of this + * interface are enqueued and batched into data store transactions. + */ +interface TopologyOperation { + /** + * Execute the operation on top of the transaction. + * + * @param transaction Datastore transaction + */ + void applyOperation(DataModificationTransaction transaction); +} \ No newline at end of file diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SshClientChannelInitializer.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SshClientChannelInitializer.java index 799674487f..829ac304bd 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SshClientChannelInitializer.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SshClientChannelInitializer.java @@ -7,7 +7,7 @@ */ package org.opendaylight.controller.netconf.client; -import io.netty.channel.socket.SocketChannel; +import io.netty.channel.Channel; import io.netty.util.concurrent.Promise; import java.io.IOException; import org.opendaylight.controller.netconf.nettyutil.AbstractChannelInitializer; @@ -31,7 +31,7 @@ final class SshClientChannelInitializer extends AbstractChannelInitializer promise) { + public void initialize(final Channel ch, final Promise promise) { try { final Invoker invoker = Invoker.subsystem("netconf"); ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker)); @@ -42,7 +42,7 @@ final class SshClientChannelInitializer extends AbstractChannelInitializer promise) { ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/TcpClientChannelInitializer.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/TcpClientChannelInitializer.java index 4a0a089fae..ee8f8baf01 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/TcpClientChannelInitializer.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/TcpClientChannelInitializer.java @@ -7,7 +7,7 @@ */ package org.opendaylight.controller.netconf.client; -import io.netty.channel.socket.SocketChannel; +import io.netty.channel.Channel; import io.netty.util.concurrent.Promise; import org.opendaylight.controller.netconf.nettyutil.AbstractChannelInitializer; import org.opendaylight.protocol.framework.SessionListenerFactory; @@ -24,12 +24,7 @@ class TcpClientChannelInitializer extends AbstractChannelInitializer promise) { - super.initialize(ch, promise); - } - - @Override - protected void initializeSessionNegotiator(final SocketChannel ch, final Promise promise) { + protected void initializeSessionNegotiator(final Channel ch, final Promise promise) { ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { @Override diff --git a/opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/test/TestingNetconfClient.java b/opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/test/TestingNetconfClient.java index 60d8f3044a..afa17532d5 100644 --- a/opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/test/TestingNetconfClient.java +++ b/opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/test/TestingNetconfClient.java @@ -8,24 +8,35 @@ package org.opendaylight.controller.netconf.client.test; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.Sets; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.HashedWheelTimer; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GlobalEventExecutor; import java.io.Closeable; import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; +import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl; import org.opendaylight.controller.netconf.client.NetconfClientSession; import org.opendaylight.controller.netconf.client.NetconfClientSessionListener; import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener; import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Sets; -import io.netty.util.concurrent.Future; +import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration.NetconfClientProtocol; +import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder; +import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler; +import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword; +import org.opendaylight.protocol.framework.NeverReconnectStrategy; /** @@ -95,4 +106,29 @@ public class TestingNetconfClient implements Closeable { Preconditions.checkState(clientSession != null, "Client was not initialized successfully"); return Sets.newHashSet(clientSession.getServerCapabilities()); } + + public static void main(String[] args) throws Exception { + HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(); + NioEventLoopGroup nettyGroup = new NioEventLoopGroup(); + NetconfClientDispatcherImpl netconfClientDispatcher = new NetconfClientDispatcherImpl(nettyGroup, nettyGroup, hashedWheelTimer); + LoginPassword authHandler = new LoginPassword("admin", "admin"); + TestingNetconfClient client = new TestingNetconfClient("client", netconfClientDispatcher, getClientConfig("127.0.0.1", 1830, true, Optional.of(authHandler))); + System.out.println(client.getCapabilities()); + } + + private static NetconfClientConfiguration getClientConfig(String host ,int port, boolean ssh, Optional maybeAuthHandler) throws UnknownHostException { + InetSocketAddress netconfAddress = new InetSocketAddress(InetAddress.getByName(host), port); + final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create(); + b.withAddress(netconfAddress); + b.withSessionListener(new SimpleNetconfClientSessionListener()); + b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, + NetconfClientConfigurationBuilder.DEFAULT_CONNECTION_TIMEOUT_MILLIS)); + if (ssh) { + b.withProtocol(NetconfClientProtocol.SSH); + b.withAuthHandler(maybeAuthHandler.get()); + } else { + b.withProtocol(NetconfClientProtocol.TCP); + } + return b.build(); + } } diff --git a/opendaylight/netconf/netconf-impl/pom.xml b/opendaylight/netconf/netconf-impl/pom.xml index 1d94517152..c60506ef44 100644 --- a/opendaylight/netconf/netconf-impl/pom.xml +++ b/opendaylight/netconf/netconf-impl/pom.xml @@ -109,6 +109,7 @@ org.apache.felix maven-bundle-plugin + 2.3.7 org.opendaylight.controller.netconf.impl.osgi.NetconfImplActivator @@ -121,6 +122,7 @@ io.netty.buffer, io.netty.handler.codec, io.netty.channel.nio, + io.netty.channel.local, javax.annotation, javax.management, javax.net.ssl, diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java index de3dee1443..4dfb749818 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java @@ -8,8 +8,13 @@ package org.opendaylight.controller.netconf.impl; +import com.google.common.annotations.VisibleForTesting; +import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.local.LocalChannel; +import io.netty.channel.local.LocalServerChannel; import io.netty.channel.socket.SocketChannel; import io.netty.util.concurrent.Promise; import java.net.InetSocketAddress; @@ -27,6 +32,7 @@ public class NetconfServerDispatcher extends AbstractDispatcher() { @@ -37,6 +43,15 @@ public class NetconfServerDispatcher extends AbstractDispatcher() { + @Override + public void initializeChannel(final LocalChannel ch, final Promise promise) { + initializer.initialize(ch, promise); + } + }); + } + public static class ServerChannelInitializer extends AbstractChannelInitializer { public static final String DESERIALIZER_EX_HANDLER_KEY = "deserializerExHandler"; @@ -50,16 +65,15 @@ public class NetconfServerDispatcher extends AbstractDispatcher promise) { + protected void initializeSessionNegotiator(Channel ch, Promise promise) { ch.pipeline().addAfter(DESERIALIZER_EX_HANDLER_KEY, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, negotiatorFactory.getSessionNegotiator(null, ch, promise)); } } - } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java index 7130dc3501..6ab62ef29a 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java @@ -7,12 +7,13 @@ */ package org.opendaylight.controller.netconf.impl.osgi; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.HashedWheelTimer; import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; import java.util.Dictionary; import java.util.Hashtable; import java.util.concurrent.TimeUnit; - import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService; import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer; import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher; @@ -26,9 +27,6 @@ import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.util.HashedWheelTimer; - public class NetconfImplActivator implements BundleActivator { private static final Logger logger = LoggerFactory.getLogger(NetconfImplActivator.class); @@ -40,17 +38,16 @@ public class NetconfImplActivator implements BundleActivator { private ServiceRegistration regMonitoring; @Override - public void start(final BundleContext context) { - final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfServerAddress(context, - NetconfConfigUtil.DEFAULT_NETCONF_TCP_ADDRESS); - final NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl(); + public void start(final BundleContext context) { + + NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl(); startOperationServiceFactoryTracker(context, factoriesListener); - final SessionIdProvider idProvider = new SessionIdProvider(); + SessionIdProvider idProvider = new SessionIdProvider(); timer = new HashedWheelTimer(); - long connectionTimeoutMillis = NetconfConfigUtil.extractTimeoutMillis(context); + commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer()); SessionMonitoringService monitoringService = startMonitoringService(context, factoriesListener); @@ -62,24 +59,24 @@ public class NetconfImplActivator implements BundleActivator { NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer( serverNegotiatorFactory); + NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup); - NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, - eventLoopGroup); - - logger.info("Starting TCP netconf server at {}", address); - dispatch.createServer(address); + LocalAddress address = NetconfConfigUtil.getNetconfLocalAddress(); + logger.trace("Starting local netconf server at {}", address); + dispatch.createLocalServer(address); context.registerService(NetconfOperationProvider.class, factoriesListener, null); + } - private void startOperationServiceFactoryTracker(final BundleContext context, final NetconfOperationServiceFactoryListenerImpl factoriesListener) { + private void startOperationServiceFactoryTracker(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) { factoriesTracker = new NetconfOperationServiceFactoryTracker(context, factoriesListener); factoriesTracker.open(); } - private NetconfMonitoringServiceImpl startMonitoringService(final BundleContext context, final NetconfOperationServiceFactoryListenerImpl factoriesListener) { - final NetconfMonitoringServiceImpl netconfMonitoringServiceImpl = new NetconfMonitoringServiceImpl(factoriesListener); - final Dictionary dic = new Hashtable<>(); + private NetconfMonitoringServiceImpl startMonitoringService(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) { + NetconfMonitoringServiceImpl netconfMonitoringServiceImpl = new NetconfMonitoringServiceImpl(factoriesListener); + Dictionary dic = new Hashtable<>(); regMonitoring = context.registerService(NetconfMonitoringService.class, netconfMonitoringServiceImpl, dic); return netconfMonitoringServiceImpl; diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java index 140284e4ee..0969bd92a5 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java @@ -16,13 +16,13 @@ import static org.mockito.Mockito.mock; import ch.ethz.ssh2.Connection; import io.netty.channel.ChannelFuture; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.concurrent.GlobalEventExecutor; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.management.ManagementFactory; import java.net.InetSocketAddress; -import java.nio.file.Files; import java.util.Collection; import java.util.List; import junit.framework.Assert; @@ -50,16 +50,14 @@ import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil; +import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.opendaylight.controller.netconf.util.test.XmlFileLoader; import org.opendaylight.controller.netconf.util.xml.XmlUtil; -import org.opendaylight.controller.sal.authorization.AuthResultEnum; -import org.opendaylight.controller.usermanager.IUserManager; import org.opendaylight.protocol.framework.NeverReconnectStrategy; public class NetconfITSecureTest extends AbstractNetconfConfigTest { private static final InetSocketAddress tlsAddress = new InetSocketAddress("127.0.0.1", 12024); - private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023); private DefaultCommitNotificationProducer commitNot; private NetconfSSHServer sshServer; @@ -79,13 +77,10 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest { final NetconfServerDispatcher dispatchS = createDispatcher(factoriesListener); - ChannelFuture s = dispatchS.createServer(tcpAddress); + ChannelFuture s = dispatchS.createLocalServer(NetconfConfigUtil.getNetconfLocalAddress()); s.await(); - - sshServer = NetconfSSHServer.start(tlsAddress.getPort(), tcpAddress, getAuthProvider()); - Thread thread = new Thread(sshServer); - thread.setDaemon(true); - thread.start(); + EventLoopGroup bossGroup = new NioEventLoopGroup(); + sshServer = NetconfSSHServer.start(tlsAddress.getPort(), NetconfConfigUtil.getNetconfLocalAddress(), getAuthProvider(), bossGroup); } private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) { @@ -140,13 +135,10 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest { } public AuthProvider getAuthProvider() throws Exception { - final IUserManager userManager = mock(IUserManager.class); - doReturn(AuthResultEnum.AUTH_ACCEPT).when(userManager).authenticate(anyString(), anyString()); - - final File privateKeyFile = Files.createTempFile("tmp-netconf-test", "pk").toFile(); - privateKeyFile.deleteOnExit(); - String privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile); - return new AuthProvider(userManager, privateKeyPEMString); + AuthProvider mock = mock(AuthProvider.class); + doReturn(true).when(mock).authenticated(anyString(), anyString()); + doReturn(PEMGenerator.generate().toCharArray()).when(mock).getPEMAsCharArray(); + return mock; } public AuthenticationHandler getAuthHandler() throws IOException { diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java index fd43f67c05..60a5207daa 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java @@ -8,7 +8,6 @@ package org.opendaylight.controller.netconf.it; -import static java.util.Collections.emptyList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; @@ -17,6 +16,10 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import io.netty.channel.ChannelFuture; import java.io.IOException; import java.io.InputStream; import java.lang.management.ManagementFactory; @@ -29,10 +32,8 @@ import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; - import javax.management.ObjectName; import javax.xml.parsers.ParserConfigurationException; - import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -66,32 +67,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controll import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2; import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry; import org.opendaylight.yangtools.yang.data.impl.codec.IdentityCodec; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.SAXException; -import com.google.common.base.Throwables; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import io.netty.channel.ChannelFuture; - public class NetconfITTest extends AbstractNetconfConfigTest { // TODO refactor, pull common code up to AbstractNetconfITTest - private static final Logger logger = LoggerFactory.getLogger(NetconfITTest.class); - private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023); - private static final InetSocketAddress sshAddress = new InetSocketAddress("127.0.0.1", 10830); - private static final String USERNAME = "netconf"; - private static final String PASSWORD = "netconf"; - private NetconfMessage getConfig, getConfigCandidate, editConfig, - closeSession, startExi, stopExi; + + private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession; private DefaultCommitNotificationProducer commitNot; private NetconfServerDispatcher dispatch; @@ -139,10 +128,6 @@ public class NetconfITTest extends AbstractNetconfConfigTest { this.editConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/edit_config.xml"); this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml"); this.getConfigCandidate = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig_candidate.xml"); - this.startExi = XmlFileLoader - .xmlFileToNetconfMessage("netconfMessages/startExi.xml"); - this.stopExi = XmlFileLoader - .xmlFileToNetconfMessage("netconfMessages/stopExi.xml"); this.closeSession = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/closeSession.xml"); } @@ -166,7 +151,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { yangDependencies.add(resourceAsStream); } } - assertEquals("Some yang files were not found", emptyList(), failedToFind); + assertEquals("Some yang files were not found", Collections.emptyList(), failedToFind); return yangDependencies; } @@ -198,6 +183,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { public void testTwoSessions() throws Exception { try (TestingNetconfClient netconfClient = new TestingNetconfClient("1", clientDispatcher, getClientConfiguration(tcpAddress, 10000))) { try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("2", clientDispatcher, getClientConfiguration(tcpAddress, 10000))) { + assertNotNull(netconfClient2.getCapabilities()); } } } diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/AbstractChannelInitializer.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/AbstractChannelInitializer.java index e88bf53ae0..7897666ddc 100644 --- a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/AbstractChannelInitializer.java +++ b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/AbstractChannelInitializer.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.netconf.nettyutil; -import io.netty.channel.socket.SocketChannel; +import io.netty.channel.Channel; import io.netty.util.concurrent.Promise; import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.nettyutil.handler.FramingMechanismHandlerFactory; @@ -25,7 +25,7 @@ public abstract class AbstractChannelInitializer { public static final String NETCONF_MESSAGE_FRAME_ENCODER = "frameEncoder"; public static final String NETCONF_SESSION_NEGOTIATOR = "negotiator"; - public void initialize(SocketChannel ch, Promise promise) { + public void initialize(Channel ch, Promise promise) { ch.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfEOMAggregator()); initializeMessageDecoder(ch); ch.pipeline().addLast(NETCONF_MESSAGE_FRAME_ENCODER, FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM)); @@ -34,13 +34,13 @@ public abstract class AbstractChannelInitializer { initializeSessionNegotiator(ch, promise); } - protected void initializeMessageEncoder(SocketChannel ch) { + protected void initializeMessageEncoder(Channel ch) { // Special encoding handler for hello message to include additional header if available, // it is thrown away after successful negotiation ch.pipeline().addLast(NETCONF_MESSAGE_ENCODER, new NetconfHelloMessageToXMLEncoder()); } - protected void initializeMessageDecoder(SocketChannel ch) { + protected void initializeMessageDecoder(Channel ch) { // Special decoding handler for hello message to parse additional header if available, // it is thrown away after successful negotiation ch.pipeline().addLast(NETCONF_MESSAGE_DECODER, new NetconfXMLToHelloMessageDecoder()); @@ -50,6 +50,6 @@ public abstract class AbstractChannelInitializer { * Insert session negotiator into the pipeline. It must be inserted after message decoder * identified by {@link AbstractChannelInitializer#NETCONF_MESSAGE_DECODER}, (or any other custom decoder processor) */ - protected abstract void initializeSessionNegotiator(SocketChannel ch, Promise promise); + protected abstract void initializeSessionNegotiator(Channel ch, Promise promise); } diff --git a/opendaylight/netconf/netconf-ssh/pom.xml b/opendaylight/netconf/netconf-ssh/pom.xml index 622881352e..cbd3efc57f 100644 --- a/opendaylight/netconf/netconf-ssh/pom.xml +++ b/opendaylight/netconf/netconf-ssh/pom.xml @@ -56,21 +56,25 @@ org.apache.felix maven-bundle-plugin + 2.3.7 org.opendaylight.controller.netconf.ssh.osgi.NetconfSSHActivator com.google.common.base, - ch.ethz.ssh2, - ch.ethz.ssh2.signature, - org.apache.commons.io, - org.opendaylight.controller.netconf.util.osgi, - org.opendaylight.controller.usermanager, - org.opendaylight.controller.sal.authorization, - org.opendaylight.controller.sal.utils, - org.osgi.framework, - org.osgi.util.tracker, - org.slf4j, - org.bouncycastle.openssl + ch.ethz.ssh2, + ch.ethz.ssh2.signature, + org.apache.commons.io, + org.opendaylight.controller.netconf.util.osgi, + org.opendaylight.controller.usermanager, + org.opendaylight.controller.sal.authorization, + org.opendaylight.controller.sal.utils, + org.osgi.framework, + org.osgi.util.tracker, + org.slf4j, + org.bouncycastle.openssl, + io.netty.bootstrap, io.netty.buffer, io.netty.channel, io.netty.channel.local, io.netty.channel.nio, + io.netty.handler.stream, io.netty.util.concurrent, org.apache.commons.lang3, + org.opendaylight.controller.netconf.util.messages diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java index c6974d4982..08bf9836b2 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java @@ -7,79 +7,94 @@ */ package org.opendaylight.controller.netconf.ssh; -import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; -import org.opendaylight.controller.netconf.ssh.threads.SocketThread; -import org.opendaylight.controller.usermanager.IUserManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.concurrent.ThreadSafe; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; import java.io.IOException; -import java.net.InetSocketAddress; import java.net.ServerSocket; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.opendaylight.controller.netconf.ssh.threads.Handshaker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +/** + * Thread that accepts client connections. Accepted socket is forwarded to {@link org.opendaylight.controller.netconf.ssh.threads.Handshaker}, + * which is executed in {@link #handshakeExecutor}. + */ @ThreadSafe -public final class NetconfSSHServer implements Runnable { +public final class NetconfSSHServer extends Thread implements AutoCloseable { - private ServerSocket ss = null; - private static final Logger logger = LoggerFactory.getLogger(NetconfSSHServer.class); - private static final AtomicLong sesssionId = new AtomicLong(); - private final InetSocketAddress clientAddress; - private final AuthProvider authProvider; - private volatile boolean up = false; + private static final Logger logger = LoggerFactory.getLogger(NetconfSSHServer.class); + private static final AtomicLong sessionIdCounter = new AtomicLong(); - private NetconfSSHServer(int serverPort,InetSocketAddress clientAddress, AuthProvider authProvider) throws IllegalStateException, IOException { + private final ServerSocket serverSocket; + private final LocalAddress localAddress; + private final EventLoopGroup bossGroup; + private final AuthProvider authProvider; + private final ExecutorService handshakeExecutor; + private volatile boolean up; - logger.trace("Creating SSH server socket on port {}",serverPort); - this.ss = new ServerSocket(serverPort); - if (!ss.isBound()){ - throw new IllegalStateException("Socket can't be bound to requested port :"+serverPort); + private NetconfSSHServer(int serverPort, LocalAddress localAddress, AuthProvider authProvider, EventLoopGroup bossGroup) throws IOException { + super(NetconfSSHServer.class.getSimpleName()); + this.bossGroup = bossGroup; + logger.trace("Creating SSH server socket on port {}", serverPort); + this.serverSocket = new ServerSocket(serverPort); + if (serverSocket.isBound() == false) { + throw new IllegalStateException("Socket can't be bound to requested port :" + serverPort); } logger.trace("Server socket created."); - this.clientAddress = clientAddress; + this.localAddress = localAddress; this.authProvider = authProvider; this.up = true; + handshakeExecutor = Executors.newFixedThreadPool(10); } - public static NetconfSSHServer start(int serverPort, InetSocketAddress clientAddress,AuthProvider authProvider) throws IllegalStateException, IOException { - return new NetconfSSHServer(serverPort, clientAddress,authProvider); + public static NetconfSSHServer start(int serverPort, LocalAddress localAddress, AuthProvider authProvider, EventLoopGroup bossGroup) throws IOException { + NetconfSSHServer netconfSSHServer = new NetconfSSHServer(serverPort, localAddress, authProvider, bossGroup); + netconfSSHServer.start(); + return netconfSSHServer; } - public void stop() throws IOException { + @Override + public void close() throws IOException { up = false; logger.trace("Closing SSH server socket."); - ss.close(); + serverSocket.close(); + bossGroup.shutdownGracefully(); logger.trace("SSH server socket closed."); } - public void removeUserManagerService(){ - this.authProvider.removeUserManagerService(); - } - - public void addUserManagerService(IUserManager userManagerService){ - this.authProvider.addUserManagerService(userManagerService); - } - public boolean isUp(){ - return this.up; - } @Override public void run() { while (up) { - logger.trace("Starting new socket thread."); + Socket acceptedSocket = null; try { - SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet(), authProvider); - } - catch (IOException e) { - if( up ) { - logger.error("Exception occurred during socket thread initialization", e); + acceptedSocket = serverSocket.accept(); + } catch (IOException e) { + if (up == false) { + logger.trace("Exiting server thread", e); + } else { + logger.warn("Exception occurred during socket.accept", e); } - else { - // We're shutting down so an exception is expected as the socket's been closed. - // Log to debug. - logger.debug("Shutting down - got expected exception: " + e); + } + if (acceptedSocket != null) { + try { + Handshaker task = new Handshaker(acceptedSocket, localAddress, sessionIdCounter.incrementAndGet(), authProvider, bossGroup); + handshakeExecutor.submit(task); + } catch (IOException e) { + logger.warn("Cannot set PEMHostKey, closing connection", e); + try { + acceptedSocket.close(); + } catch (IOException e1) { + logger.warn("Ignoring exception while closing socket", e); + } } } } + logger.debug("Server thread is exiting"); } } diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java index 2e9a0b9d8b..5d39dd1eb8 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProvider.java @@ -7,41 +7,75 @@ */ package org.opendaylight.controller.netconf.ssh.authentication; -import java.io.IOException; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; import org.opendaylight.controller.sal.authorization.AuthResultEnum; import org.opendaylight.controller.usermanager.IUserManager; -import static com.google.common.base.Preconditions.checkNotNull; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class AuthProvider implements AuthProviderInterface { +public class AuthProvider { + private static final Logger logger = LoggerFactory.getLogger(AuthProvider.class); - private IUserManager um; private final String pem; + private IUserManager nullableUserManager; - public AuthProvider(IUserManager ium, String pemCertificate) throws IllegalArgumentException, IOException { + public AuthProvider(String pemCertificate, final BundleContext bundleContext) { checkNotNull(pemCertificate, "Parameter 'pemCertificate' is null"); - checkNotNull(ium, "No user manager service available."); - this.um = ium; pem = pemCertificate; + + ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer() { + @Override + public IUserManager addingService(final ServiceReference reference) { + logger.trace("Service {} added", reference); + nullableUserManager = bundleContext.getService(reference); + return nullableUserManager; + } + + @Override + public void modifiedService(final ServiceReference reference, final IUserManager service) { + logger.trace("Replacing modified service {} in netconf SSH.", reference); + nullableUserManager = service; + } + + @Override + public void removedService(final ServiceReference reference, final IUserManager service) { + logger.trace("Removing service {} from netconf SSH. " + + "SSH won't authenticate users until IUserManager service will be started.", reference); + synchronized (AuthProvider.this) { + nullableUserManager = null; + } + } + }; + ServiceTracker listenerTracker = new ServiceTracker<>(bundleContext, IUserManager.class, customizer); + listenerTracker.open(); } - @Override - public boolean authenticated(String username, String password) { - AuthResultEnum authResult = this.um.authenticate(username, password); + /** + * Authenticate user. This implementation tracks IUserManager and delegates the decision to it. If the service is not + * available, IllegalStateException is thrown. + */ + public synchronized boolean authenticated(String username, String password) { + if (nullableUserManager == null) { + logger.warn("Cannot authenticate user '{}', user manager service is missing", username); + throw new IllegalStateException("User manager service is not available"); + } + AuthResultEnum authResult = nullableUserManager.authenticate(username, password); + logger.debug("Authentication result for user '{}' : {}", username, authResult); return authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC); } - @Override public char[] getPEMAsCharArray() { return pem.toCharArray(); } - @Override - public void removeUserManagerService() { - this.um = null; - } - - @Override - public void addUserManagerService(IUserManager userManagerService) { - this.um = userManagerService; + @VisibleForTesting + void setNullableUserManager(IUserManager nullableUserManager) { + this.nullableUserManager = nullableUserManager; } } diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProviderInterface.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProviderInterface.java deleted file mode 100644 index fad0f79a4e..0000000000 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/AuthProviderInterface.java +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * 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.ssh.authentication; - -import org.opendaylight.controller.usermanager.IUserManager; - -public interface AuthProviderInterface { - - public boolean authenticated(String username, String password) throws IllegalStateException; - public char[] getPEMAsCharArray() throws Exception; - public void removeUserManagerService(); - public void addUserManagerService(IUserManager userManagerService); -} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java index 348fe006f3..53ab8219ee 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java @@ -8,8 +8,11 @@ package org.opendaylight.controller.netconf.ssh.authentication; +import com.google.common.annotations.VisibleForTesting; +import java.io.FileInputStream; import java.security.NoSuchAlgorithmException; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import org.bouncycastle.openssl.PEMWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,17 +29,55 @@ public class PEMGenerator { private static final Logger logger = LoggerFactory.getLogger(PEMGenerator.class); private static final int KEY_SIZE = 4096; + + public static String readOrGeneratePK(File privateKeyFile) throws IOException { + if (privateKeyFile.exists() == false) { + // generate & save to file + try { + return generateTo(privateKeyFile); + } catch (Exception e) { + logger.error("Exception occurred while generating PEM string to {}", privateKeyFile, e); + throw new IllegalStateException("Error generating RSA key from file " + privateKeyFile); + } + } else { + // read from file + try (FileInputStream fis = new FileInputStream(privateKeyFile)) { + return IOUtils.toString(fis); + } catch (final IOException e) { + logger.error("Error reading RSA key from file {}", privateKeyFile, e); + throw new IOException("Error reading RSA key from file " + privateKeyFile, e); + } + } + } + + /** + * Generate private key to a file and return its content as string. + * + * @param privateFile path where private key should be generated + * @return String representation of private key + * @throws IOException + * @throws NoSuchAlgorithmException + */ + @VisibleForTesting public static String generateTo(File privateFile) throws IOException, NoSuchAlgorithmException { + logger.info("Generating private key to {}", privateFile.getAbsolutePath()); + String privatePEM = generate(); + FileUtils.write(privateFile, privatePEM); + return privatePEM; + } + + @VisibleForTesting + public static String generate() throws NoSuchAlgorithmException, IOException { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); SecureRandom sr = new SecureRandom(); keyGen.initialize(KEY_SIZE, sr); KeyPair keypair = keyGen.generateKeyPair(); - logger.info("Generating private key to {}", privateFile.getAbsolutePath()); - String privatePEM = toString(keypair.getPrivate()); - FileUtils.write(privateFile, privatePEM); - return privatePEM; + return toString(keypair.getPrivate()); } + /** + * Get string representation of a key. + */ private static String toString(Key key) throws IOException { try (StringWriter writer = new StringWriter()) { try (PEMWriter pemWriter = new PEMWriter(writer)) { @@ -45,4 +86,5 @@ public class PEMGenerator { return writer.toString(); } } + } diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java index d74308cfad..a26843fae1 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java @@ -7,24 +7,24 @@ */ package org.opendaylight.controller.netconf.ssh.osgi; -import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import com.google.common.base.Optional; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.nio.NioEventLoopGroup; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.net.InetSocketAddress; import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; -import org.opendaylight.controller.usermanager.IUserManager; +import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil.InfixProp; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,112 +32,56 @@ import org.slf4j.LoggerFactory; * Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator * starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket * and listens for client connections. Each client connection creation is handled in separate - * {@link org.opendaylight.controller.netconf.ssh.threads.SocketThread} thread. + * {@link org.opendaylight.controller.netconf.ssh.threads.Handshaker} thread. * This thread creates two additional threads {@link org.opendaylight.controller.netconf.ssh.threads.IOThread} * forwarding data from/to client.IOThread closes servers session and server connection when it gets -1 on input stream. * {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}'s run method waits for -1 on input stream to finish. * All threads are daemons. - **/ -public class NetconfSSHActivator implements BundleActivator{ + */ +public class NetconfSSHActivator implements BundleActivator { + private static final Logger logger = LoggerFactory.getLogger(NetconfSSHActivator.class); private NetconfSSHServer server; - private static final Logger logger = LoggerFactory.getLogger(NetconfSSHActivator.class); - private IUserManager iUserManager; - private BundleContext context = null; - - private ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer(){ - @Override - public IUserManager addingService(final ServiceReference reference) { - logger.trace("Service {} added, let there be SSH bridge.", reference); - iUserManager = context.getService(reference); - try { - onUserManagerFound(iUserManager); - } catch (final Exception e) { - logger.trace("Can't start SSH server due to {}",e); - } - return iUserManager; - } - @Override - public void modifiedService(final ServiceReference reference, final IUserManager service) { - logger.trace("Replacing modified service {} in netconf SSH.", reference); - server.addUserManagerService(service); - } - @Override - public void removedService(final ServiceReference reference, final IUserManager service) { - logger.trace("Removing service {} from netconf SSH. " + - "SSH won't authenticate users until IUserManager service will be started.", reference); - removeUserManagerService(); - } - }; - @Override - public void start(final BundleContext context) { - this.context = context; - listenForManagerService(); + public void start(final BundleContext bundleContext) throws IOException { + server = startSSHServer(bundleContext); } @Override public void stop(BundleContext context) throws IOException { - if (server != null){ - server.stop(); - logger.trace("Netconf SSH bridge is down ..."); + if (server != null) { + server.close(); } } - private void startSSHServer() throws IOException { - checkNotNull(this.iUserManager, "No user manager service available."); - logger.trace("Starting netconf SSH bridge."); - final InetSocketAddress sshSocketAddress = NetconfConfigUtil.extractSSHNetconfAddress(context, - NetconfConfigUtil.DEFAULT_NETCONF_SSH_ADDRESS); - final InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfClientAddress(context, - NetconfConfigUtil.DEFAULT_NETCONF_TCP_ADDRESS); - String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(context)); + private static NetconfSSHServer startSSHServer(BundleContext bundleContext) throws IOException { + Optional maybeSshSocketAddress = NetconfConfigUtil.extractNetconfServerAddress(bundleContext, + InfixProp.ssh); - if (path.isEmpty()) { - throw new IllegalStateException("Missing netconf.ssh.pk.path key in configuration file."); + if (maybeSshSocketAddress.isPresent() == false) { + logger.trace("SSH bridge not configured"); + return null; } + InetSocketAddress sshSocketAddress = maybeSshSocketAddress.get(); + logger.trace("Starting netconf SSH bridge at {}", sshSocketAddress); - final File privateKeyFile = new File(path); - final String privateKeyPEMString; - if (privateKeyFile.exists() == false) { - // generate & save to file - try { - privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile); - } catch (Exception e) { - logger.error("Exception occurred while generating PEM string {}", e); - throw new IllegalStateException("Error generating RSA key from file " + path); - } - } else { - // read from file - try (FileInputStream fis = new FileInputStream(path)) { - privateKeyPEMString = IOUtils.toString(fis); - } catch (final IOException e) { - logger.error("Error reading RSA key from file '{}'", path); - throw new IOException("Error reading RSA key from file " + path, e); - } - } - final AuthProvider authProvider = new AuthProvider(iUserManager, privateKeyPEMString); - this.server = NetconfSSHServer.start(sshSocketAddress.getPort(), tcpSocketAddress, authProvider); + LocalAddress localAddress = NetconfConfigUtil.getNetconfLocalAddress(); + + String path = FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(bundleContext)); + checkState(StringUtils.isNotBlank(path), "Path to ssh private key is blank. Reconfigure %s", NetconfConfigUtil.getPrivateKeyKey()); + String privateKeyPEMString = PEMGenerator.readOrGeneratePK(new File(path)); + + final AuthProvider authProvider = new AuthProvider(privateKeyPEMString, bundleContext); + EventLoopGroup bossGroup = new NioEventLoopGroup(); + NetconfSSHServer server = NetconfSSHServer.start(sshSocketAddress.getPort(), localAddress, authProvider, bossGroup); final Thread serverThread = new Thread(server, "netconf SSH server thread"); serverThread.setDaemon(true); serverThread.start(); logger.trace("Netconf SSH bridge up and running."); + return server; } - private void onUserManagerFound(final IUserManager userManager) throws Exception{ - if (server!=null && server.isUp()){ - server.addUserManagerService(userManager); - } else { - startSSHServer(); - } - } - private void removeUserManagerService(){ - this.server.removeUserManagerService(); - } - private void listenForManagerService(){ - final ServiceTracker listenerTracker = new ServiceTracker<>(context, IUserManager.class,customizer); - listenerTracker.open(); - } + } diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/Handshaker.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/Handshaker.java new file mode 100644 index 0000000000..d999d378d9 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/Handshaker.java @@ -0,0 +1,406 @@ +/* + * 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.ssh.threads; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import ch.ethz.ssh2.AuthenticationResult; +import ch.ethz.ssh2.PtySettings; +import ch.ethz.ssh2.ServerAuthenticationCallback; +import ch.ethz.ssh2.ServerConnection; +import ch.ethz.ssh2.ServerConnectionCallback; +import ch.ethz.ssh2.ServerSession; +import ch.ethz.ssh2.ServerSessionCallback; +import ch.ethz.ssh2.SimpleServerSessionCallback; +import com.google.common.base.Supplier; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufProcessor; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.local.LocalChannel; +import io.netty.handler.stream.ChunkedStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import javax.annotation.concurrent.NotThreadSafe; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * One instance represents per connection, responsible for ssh handshake. + * Once auth succeeds and correct subsystem is chosen, backend connection with + * netty netconf server is made. This task finishes right after negotiation is done. + */ +@ThreadSafe +public class Handshaker implements Runnable { + private static final Logger logger = LoggerFactory.getLogger(Handshaker.class); + + private final ServerConnection ganymedConnection; + private final String session; + + + public Handshaker(Socket socket, LocalAddress localAddress, long sessionId, AuthProvider authProvider, + EventLoopGroup bossGroup) throws IOException { + + this.session = "Session " + sessionId; + + String remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replace("/", ""); + logger.debug("{} started with {}", session, remoteAddressWithPort); + String remoteAddress, remotePort; + if (remoteAddressWithPort.contains(":")) { + String[] split = remoteAddressWithPort.split(":"); + remoteAddress = split[0]; + remotePort = split[1]; + } else { + remoteAddress = remoteAddressWithPort; + remotePort = ""; + } + ServerAuthenticationCallbackImpl serverAuthenticationCallback = new ServerAuthenticationCallbackImpl( + authProvider, session); + + ganymedConnection = new ServerConnection(socket); + + ServerConnectionCallbackImpl serverConnectionCallback = new ServerConnectionCallbackImpl( + serverAuthenticationCallback, remoteAddress, remotePort, session, + getGanymedAutoCloseable(ganymedConnection), localAddress, bossGroup); + + // initialize ganymed + ganymedConnection.setPEMHostKey(authProvider.getPEMAsCharArray(), null); + ganymedConnection.setAuthenticationCallback(serverAuthenticationCallback); + ganymedConnection.setServerConnectionCallback(serverConnectionCallback); + } + + + private static AutoCloseable getGanymedAutoCloseable(final ServerConnection ganymedConnection) { + return new AutoCloseable() { + @Override + public void close() throws Exception { + ganymedConnection.close(); + } + }; + } + + @Override + public void run() { + // let ganymed process handshake + logger.trace("{} SocketThread is started", session); + try { + // TODO this should be guarded with a timer to prevent resource exhaustion + ganymedConnection.connect(); + } catch (IOException e) { + logger.warn("{} SocketThread error ", session, e); + } + logger.trace("{} SocketThread is exiting", session); + } +} + +/** + * Netty client handler that forwards bytes from backed server to supplied output stream. + * When backend server closes the connection, remoteConnection.close() is called to tear + * down ssh connection. + */ +class SSHClientHandler extends ChannelInboundHandlerAdapter { + private static final Logger logger = LoggerFactory.getLogger(SSHClientHandler.class); + private final AutoCloseable remoteConnection; + private final OutputStream remoteOutputStream; + private final String session; + private ChannelHandlerContext channelHandlerContext; + + public SSHClientHandler(AutoCloseable remoteConnection, OutputStream remoteOutputStream, + String session) { + this.remoteConnection = remoteConnection; + this.remoteOutputStream = remoteOutputStream; + this.session = session; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + this.channelHandlerContext = ctx; + logger.debug("{} Client active", session); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + ByteBuf bb = (ByteBuf) msg; + // we can block the server here so that slow client does not cause memory pressure + try { + bb.forEachByte(new ByteBufProcessor() { + @Override + public boolean process(byte value) throws Exception { + remoteOutputStream.write(value); + return true; + } + }); + } finally { + bb.release(); + } + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws IOException { + logger.trace("{} Flushing", session); + remoteOutputStream.flush(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + // Close the connection when an exception is raised. + logger.warn("{} Unexpected exception from downstream", session, cause); + ctx.close(); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + logger.trace("{} channelInactive() called, closing remote client ctx", session); + remoteConnection.close();//this should close socket and all threads created for this client + this.channelHandlerContext = null; + } + + public ChannelHandlerContext getChannelHandlerContext() { + return checkNotNull(channelHandlerContext, "Channel is not active"); + } +} + +/** + * Ganymed handler that gets unencrypted input and output streams, connects them to netty. + * Checks that 'netconf' subsystem is chosen by user. + * Launches new ClientInputStreamPoolingThread thread once session is established. + * Writes custom header to netty server, to inform it about IP address and username. + */ +class ServerConnectionCallbackImpl implements ServerConnectionCallback { + private static final Logger logger = LoggerFactory.getLogger(ServerConnectionCallbackImpl.class); + public static final String NETCONF_SUBSYSTEM = "netconf"; + + private final Supplier currentUserSupplier; + private final String remoteAddress; + private final String remotePort; + private final String session; + private final AutoCloseable ganymedConnection; + private final LocalAddress localAddress; + private final EventLoopGroup bossGroup; + + ServerConnectionCallbackImpl(Supplier currentUserSupplier, String remoteAddress, String remotePort, String session, + AutoCloseable ganymedConnection, LocalAddress localAddress, EventLoopGroup bossGroup) { + this.currentUserSupplier = currentUserSupplier; + this.remoteAddress = remoteAddress; + this.remotePort = remotePort; + this.session = session; + this.ganymedConnection = ganymedConnection; + // initialize netty local connection + this.localAddress = localAddress; + this.bossGroup = bossGroup; + } + + private static ChannelFuture initializeNettyConnection(LocalAddress localAddress, EventLoopGroup bossGroup, + final SSHClientHandler sshClientHandler) { + Bootstrap clientBootstrap = new Bootstrap(); + clientBootstrap.group(bossGroup).channel(LocalChannel.class); + + clientBootstrap.handler(new ChannelInitializer() { + @Override + public void initChannel(LocalChannel ch) throws Exception { + ch.pipeline().addLast(sshClientHandler); + } + }); + // asynchronously initialize local connection to netconf server + return clientBootstrap.connect(localAddress); + } + + @Override + public ServerSessionCallback acceptSession(final ServerSession serverSession) { + String currentUser = currentUserSupplier.get(); + final String additionalHeader = new NetconfHelloMessageAdditionalHeader(currentUser, remoteAddress, + remotePort, "ssh", "client").toFormattedString(); + + + return new SimpleServerSessionCallback() { + @Override + public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException { + return new Runnable() { + @Override + public void run() { + if (NETCONF_SUBSYSTEM.equals(subsystem)) { + // connect + final SSHClientHandler sshClientHandler = new SSHClientHandler(ganymedConnection, ss.getStdin(), session); + ChannelFuture clientChannelFuture = initializeNettyConnection(localAddress, bossGroup, sshClientHandler); + // get channel + final Channel channel = clientChannelFuture.awaitUninterruptibly().channel(); + new ClientInputStreamPoolingThread(session, ss.getStdout(), channel, new AutoCloseable() { + @Override + public void close() throws Exception { + logger.trace("Closing both ganymed and local connection"); + try { + ganymedConnection.close(); + } catch (Exception e) { + logger.warn("Ignoring exception while closing ganymed", e); + } + try { + channel.close(); + } catch (Exception e) { + logger.warn("Ignoring exception while closing channel", e); + } + } + }, sshClientHandler.getChannelHandlerContext()).start(); + + // write additional header + channel.writeAndFlush(Unpooled.copiedBuffer(additionalHeader.getBytes())); + } else { + logger.debug("{} Wrong subsystem requested:'{}', closing ssh session", serverSession, subsystem); + String reason = "Only netconf subsystem is supported, requested:" + subsystem; + closeSession(ss, reason); + } + } + }; + } + + public void closeSession(ServerSession ss, String reason) { + logger.trace("{} Closing session - {}", serverSession, reason); + try { + ss.getStdin().write(reason.getBytes()); + } catch (IOException e) { + logger.warn("{} Exception while closing session", serverSession, e); + } + ss.close(); + } + + @Override + public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException { + return new Runnable() { + @Override + public void run() { + closeSession(ss, "PTY request not supported"); + } + }; + } + + @Override + public Runnable requestShell(final ServerSession ss) throws IOException { + return new Runnable() { + @Override + public void run() { + closeSession(ss, "Shell not supported"); + } + }; + } + }; + } +} + +/** + * Only thread that is required during ssh session, forwards client's input to netty. + * When user closes connection, onEndOfInput.close() is called to tear down the local channel. + */ +class ClientInputStreamPoolingThread extends Thread { + private static final Logger logger = LoggerFactory.getLogger(ClientInputStreamPoolingThread.class); + + private final InputStream fromClientIS; + private final Channel serverChannel; + private final AutoCloseable onEndOfInput; + private final ChannelHandlerContext channelHandlerContext; + + ClientInputStreamPoolingThread(String session, InputStream fromClientIS, Channel serverChannel, AutoCloseable onEndOfInput, + ChannelHandlerContext channelHandlerContext) { + super(ClientInputStreamPoolingThread.class.getSimpleName() + " " + session); + this.fromClientIS = fromClientIS; + this.serverChannel = serverChannel; + this.onEndOfInput = onEndOfInput; + this.channelHandlerContext = channelHandlerContext; + } + + @Override + public void run() { + ChunkedStream chunkedStream = new ChunkedStream(fromClientIS); + try { + ByteBuf byteBuf; + while ((byteBuf = chunkedStream.readChunk(channelHandlerContext/*only needed for ByteBuf alloc */)) != null) { + serverChannel.writeAndFlush(byteBuf); + } + } catch (Exception e) { + logger.warn("Exception", e); + } finally { + logger.trace("End of input"); + // tear down connection + try { + onEndOfInput.close(); + } catch (Exception e) { + logger.warn("Ignoring exception while closing socket", e); + } + } + } +} + +/** + * Authentication handler for ganymed. + * Provides current user name after authenticating using supplied AuthProvider. + */ +@NotThreadSafe +class ServerAuthenticationCallbackImpl implements ServerAuthenticationCallback, Supplier { + private static final Logger logger = LoggerFactory.getLogger(ServerAuthenticationCallbackImpl.class); + private final AuthProvider authProvider; + private final String session; + private String currentUser; + + ServerAuthenticationCallbackImpl(AuthProvider authProvider, String session) { + this.authProvider = authProvider; + this.session = session; + } + + @Override + public String initAuthentication(ServerConnection sc) { + logger.trace("{} Established connection", session); + return "Established connection" + "\r\n"; + } + + @Override + public String[] getRemainingAuthMethods(ServerConnection sc) { + return new String[]{ServerAuthenticationCallback.METHOD_PASSWORD}; + } + + @Override + public AuthenticationResult authenticateWithNone(ServerConnection sc, String username) { + return AuthenticationResult.FAILURE; + } + + @Override + public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password) { + checkState(currentUser == null); + try { + if (authProvider.authenticated(username, password)) { + currentUser = username; + logger.trace("{} user {} authenticated", session, currentUser); + return AuthenticationResult.SUCCESS; + } + } catch (Exception e) { + logger.warn("{} Authentication failed", session, e); + } + return AuthenticationResult.FAILURE; + } + + @Override + public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm, + byte[] publicKey, byte[] signature) { + return AuthenticationResult.FAILURE; + } + + @Override + public String get() { + return currentUser; + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java deleted file mode 100644 index c53a625ad0..0000000000 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/IOThread.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.ssh.threads; - -import java.io.InputStream; -import java.io.OutputStream; - -import javax.annotation.concurrent.ThreadSafe; - -import org.apache.commons.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ch.ethz.ssh2.ServerConnection; -import ch.ethz.ssh2.ServerSession; - -@ThreadSafe -public class IOThread extends Thread { - - private static final Logger logger = LoggerFactory.getLogger(IOThread.class); - - private final InputStream inputStream; - private final OutputStream outputStream; - private final ServerSession servSession; - private final ServerConnection servconnection; - private String customHeader; - - - public IOThread (InputStream is, OutputStream os, String id,ServerSession ss, ServerConnection conn){ - this.inputStream = is; - this.outputStream = os; - this.servSession = ss; - this.servconnection = conn; - super.setName(id); - logger.trace("IOThread {} created", super.getName()); - } - - public IOThread (InputStream is, OutputStream os, String id,ServerSession ss, ServerConnection conn,String header){ - this.inputStream = is; - this.outputStream = os; - this.servSession = ss; - this.servconnection = conn; - this.customHeader = header; - super.setName(id); - logger.trace("IOThread {} created", super.getName()); - } - - @Override - public void run() { - logger.trace("thread {} started", super.getName()); - try { - if (this.customHeader!=null && !this.customHeader.equals("")){ - this.outputStream.write(this.customHeader.getBytes()); - logger.trace("adding {} header", this.customHeader); - } - IOUtils.copy(this.inputStream, this.outputStream); - } catch (Exception e) { - logger.error("inputstream -> outputstream copy error ",e); - } - logger.trace("closing server session"); - servSession.close(); - servconnection.close(); - logger.trace("thread {} is closing",super.getName()); - } -} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java deleted file mode 100644 index 04639cb36f..0000000000 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/SocketThread.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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.ssh.threads; - - -import ch.ethz.ssh2.AuthenticationResult; -import ch.ethz.ssh2.PtySettings; -import ch.ethz.ssh2.ServerAuthenticationCallback; -import ch.ethz.ssh2.ServerConnection; -import ch.ethz.ssh2.ServerConnectionCallback; -import ch.ethz.ssh2.ServerSession; -import ch.ethz.ssh2.ServerSessionCallback; -import ch.ethz.ssh2.SimpleServerSessionCallback; -import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.concurrent.ThreadSafe; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; - -@ThreadSafe -public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback { - private static final Logger logger = LoggerFactory.getLogger(SocketThread.class); - - private final Socket socket; - private final InetSocketAddress clientAddress; - private ServerConnection conn = null; - private final long sessionId; - private String currentUser; - private final String remoteAddressWithPort; - private final AuthProvider authProvider; - - - public static void start(Socket socket, - InetSocketAddress clientAddress, - long sessionId, - AuthProvider authProvider) throws IOException { - Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket, clientAddress, sessionId, authProvider)); - netconf_ssh_socket_thread.setDaemon(true); - netconf_ssh_socket_thread.start(); - } - - private SocketThread(Socket socket, - InetSocketAddress clientAddress, - long sessionId, - AuthProvider authProvider) throws IOException { - - this.socket = socket; - this.clientAddress = clientAddress; - this.sessionId = sessionId; - this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/", ""); - this.authProvider = authProvider; - - } - - @Override - public void run() { - conn = new ServerConnection(socket); - try { - conn.setPEMHostKey(authProvider.getPEMAsCharArray(), "netconf"); - } catch (Exception e) { - logger.warn("Server authentication setup failed.", e); - } - conn.setAuthenticationCallback(this); - conn.setServerConnectionCallback(this); - try { - conn.connect(); - } catch (IOException e) { - logger.error("SocketThread error ", e); - } - } - - @Override - public ServerSessionCallback acceptSession(final ServerSession session) { - SimpleServerSessionCallback cb = new SimpleServerSessionCallback() { - @Override - public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException { - return new Runnable() { - @Override - public void run() { - if (subsystem.equals("netconf")) { - IOThread netconf_ssh_input = null; - IOThread netconf_ssh_output = null; - try { - String hostName = clientAddress.getHostName(); - int portNumber = clientAddress.getPort(); - final Socket echoSocket = new Socket(hostName, portNumber); - logger.trace("echo socket created"); - - logger.trace("starting netconf_ssh_input thread"); - netconf_ssh_input = new IOThread(echoSocket.getInputStream(), ss.getStdin(), "input_thread_" + sessionId, ss, conn); - netconf_ssh_input.setDaemon(false); - netconf_ssh_input.start(); - - logger.trace("starting netconf_ssh_output thread"); - final String customHeader = "[" + currentUser + ";" + remoteAddressWithPort + ";ssh;;;;;;]\n"; - netconf_ssh_output = new IOThread(ss.getStdout(), echoSocket.getOutputStream(), "output_thread_" + sessionId, ss, conn, customHeader); - netconf_ssh_output.setDaemon(false); - netconf_ssh_output.start(); - - } catch (Exception t) { - logger.error("SSH bridge could not create echo socket: {}", t.getMessage(), t); - - try { - if (netconf_ssh_input != null) { - netconf_ssh_input.join(); - } - } catch (InterruptedException e1) { - Thread.currentThread().interrupt(); - logger.error("netconf_ssh_input join error ", e1); - } - - try { - if (netconf_ssh_output != null) { - netconf_ssh_output.join(); - } - } catch (InterruptedException e2) { - Thread.currentThread().interrupt(); - logger.error("netconf_ssh_output join error ", e2); - } - } - } else { - String reason = "Only netconf subsystem is supported, requested:" + subsystem; - closeSession(ss, reason); - } - } - }; - } - - public void closeSession(ServerSession ss, String reason) { - logger.trace("Closing session - {}", reason); - try { - ss.getStdin().write(reason.getBytes()); - } catch (IOException e) { - logger.debug("Exception while closing session", e); - } - ss.close(); - } - - @Override - public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException { - return new Runnable() { - @Override - public void run() { - closeSession(ss, "PTY request not supported"); - } - }; - } - - @Override - public Runnable requestShell(final ServerSession ss) throws IOException { - return new Runnable() { - @Override - public void run() { - closeSession(ss, "Shell not supported"); - } - }; - } - }; - - return cb; - } - - @Override - public String initAuthentication(ServerConnection sc) { - logger.trace("Established connection with host {}", remoteAddressWithPort); - return "Established connection with host " + remoteAddressWithPort + "\r\n"; - } - - @Override - public String[] getRemainingAuthMethods(ServerConnection sc) { - return new String[]{ServerAuthenticationCallback.METHOD_PASSWORD}; - } - - @Override - public AuthenticationResult authenticateWithNone(ServerConnection sc, String username) { - return AuthenticationResult.FAILURE; - } - - @Override - public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password) { - - try { - if (authProvider.authenticated(username, password)) { - currentUser = username; - logger.trace("user {}@{} authenticated", currentUser, remoteAddressWithPort); - return AuthenticationResult.SUCCESS; - } - } catch (Exception e) { - logger.warn("Authentication failed due to :" + e.getLocalizedMessage()); - } - return AuthenticationResult.FAILURE; - } - - @Override - public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm, - byte[] publickey, byte[] signature) { - return AuthenticationResult.FAILURE; - } - -} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/KeyGeneratorTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/KeyGeneratorTest.java deleted file mode 100644 index 298f91ce8d..0000000000 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/KeyGeneratorTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; -import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; -import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; -import org.opendaylight.controller.usermanager.IUserManager; -import org.opendaylight.controller.usermanager.UserConfig; - -import java.io.File; -import java.io.IOException; -import java.net.Inet4Address; -import java.net.InetSocketAddress; - -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doReturn; - -// This test is intended to be verified using ssh -@Ignore -public class KeyGeneratorTest { - - @Mock - private IUserManager iUserManager; - File tempFile; - - @Before - public void setUp() throws IOException { - MockitoAnnotations.initMocks(this); - doReturn(null).when(iUserManager).addLocalUser(any(UserConfig.class)); - tempFile = File.createTempFile("odltest", ".tmp"); - tempFile.deleteOnExit(); - } - - @After - public void tearDown() { - assertTrue(tempFile.delete()); - } - - @Test - public void test() throws Exception { - String pem = PEMGenerator.generateTo(tempFile); - - AuthProvider authProvider = new AuthProvider(iUserManager, pem); - InetSocketAddress inetSocketAddress = new InetSocketAddress(Inet4Address.getLoopbackAddress().getHostAddress(), 8383); - NetconfSSHServer server = NetconfSSHServer.start(1830, inetSocketAddress, authProvider); - - Thread serverThread = new Thread(server,"netconf SSH server thread"); - serverThread.start(); - serverThread.join(); - } -} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java deleted file mode 100644 index 663a0b4a82..0000000000 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/SSHServerTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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; - -import ch.ethz.ssh2.Connection; -import junit.framework.Assert; -import org.apache.commons.io.IOUtils; -import org.junit.Test; -import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; -import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.InputStream; -import java.net.InetSocketAddress; - - -public class SSHServerTest { - - private static final String USER = "netconf"; - private static final String PASSWORD = "netconf"; - private static final String HOST = "127.0.0.1"; - private static final int PORT = 1830; - private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 8383); - private static final Logger logger = LoggerFactory.getLogger(SSHServerTest.class); - private Thread sshServerThread; - - - - - public void startSSHServer() throws Exception{ - logger.info("Creating SSH server"); - StubUserManager um = new StubUserManager(USER,PASSWORD); - String pem; - try(InputStream is = getClass().getResourceAsStream("/RSA.pk")) { - pem = IOUtils.toString(is); - } - AuthProvider ap = new AuthProvider(um, pem); - NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress,ap); - sshServerThread = new Thread(server); - sshServerThread.setDaemon(true); - sshServerThread.start(); - logger.info("SSH server on"); - } - - @Test - public void connect(){ - try { - this.startSSHServer(); - Connection conn = new Connection(HOST,PORT); - Assert.assertNotNull(conn); - logger.info("connecting to SSH server"); - conn.connect(); - logger.info("authenticating ..."); - boolean isAuthenticated = conn.authenticateWithPassword(USER,PASSWORD); - Assert.assertTrue(isAuthenticated); - } catch (Exception e) { - logger.error("Error while starting SSH server.", e); - } - - } - -} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoClient.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoClient.java new file mode 100644 index 0000000000..5d0c71aa62 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoClient.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014 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.netty; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.local.LocalChannel; +import io.netty.channel.nio.NioEventLoopGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Sends one message when a connection is open and echoes back any received + * data to the server. Simply put, the echo client initiates the ping-pong + * traffic between the echo client and server by sending the first message to + * the server. + */ +public class EchoClient implements Runnable { + private static final Logger logger = LoggerFactory.getLogger(EchoClient.class); + + private final ChannelHandler clientHandler; + + + public EchoClient(ChannelHandler clientHandler) { + this.clientHandler = clientHandler; + } + + public void run() { + // Configure the client. + EventLoopGroup group = new NioEventLoopGroup(); + try { + Bootstrap b = new Bootstrap(); + b.group(group) + .channel(LocalChannel.class) + .handler(new ChannelInitializer() { + @Override + public void initChannel(LocalChannel ch) throws Exception { + ch.pipeline().addLast(clientHandler); + } + }); + + // Start the client. + LocalAddress localAddress = new LocalAddress("foo"); + ChannelFuture f = b.connect(localAddress).sync(); + + // Wait until the connection is closed. + f.channel().closeFuture().sync(); + } catch (Exception e) { + logger.error("Error in client", e); + throw new RuntimeException("Error in client", e); + } finally { + // Shut down the event loop to terminate all threads. + logger.info("Client is shutting down"); + group.shutdownGracefully(); + } + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoClientHandler.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoClientHandler.java new file mode 100644 index 0000000000..81182a580e --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoClientHandler.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 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.netty; + +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.Charsets; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handler implementation for the echo client. It initiates the ping-pong + * traffic between the echo client and server by sending the first message to + * the server. + */ +public class EchoClientHandler extends ChannelInboundHandlerAdapter { + private static final Logger logger = LoggerFactory.getLogger(EchoClientHandler.class); + + private ChannelHandlerContext ctx; + + @Override + public void channelActive(ChannelHandlerContext ctx) { + checkState(this.ctx == null); + logger.info("client active"); + this.ctx = ctx; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + ByteBuf bb = (ByteBuf) msg; + logger.info(">{}", bb.toString(Charsets.UTF_8)); + bb.release(); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + // Close the connection when an exception is raised. + logger.warn("Unexpected exception from downstream.", cause); + checkState(this.ctx.equals(ctx)); + ctx.close(); + this.ctx = null; + } + + public void write(String message) { + ByteBuf byteBuf = Unpooled.copiedBuffer(message.getBytes()); + ctx.writeAndFlush(byteBuf); + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoServer.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoServer.java new file mode 100644 index 0000000000..ec89d75f29 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoServer.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014 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.netty; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.local.LocalChannel; +import io.netty.channel.local.LocalServerChannel; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Echoes back any received data from a client. + */ +public class EchoServer implements Runnable { + private static final Logger logger = LoggerFactory.getLogger(EchoServer.class); + + public void run() { + // Configure the server. + EventLoopGroup bossGroup = new NioEventLoopGroup(1); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(LocalServerChannel.class) + .option(ChannelOption.SO_BACKLOG, 100) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(LocalChannel ch) throws Exception { + ch.pipeline().addLast(new EchoServerHandler()); + } + }); + + // Start the server. + LocalAddress localAddress = NetconfConfigUtil.getNetconfLocalAddress(); + ChannelFuture f = b.bind(localAddress).sync(); + + // Wait until the server socket is closed. + f.channel().closeFuture().sync(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + // Shut down all event loops to terminate all threads. + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + + public static void main(String[] args) throws Exception { + new Thread(new EchoServer()).start(); + Thread.sleep(1000); + EchoClientHandler clientHandler = new EchoClientHandler(); + EchoClient echoClient = new EchoClient(clientHandler); + new Thread(echoClient).start(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + do { + String message = reader.readLine(); + if (message == null || "exit".equalsIgnoreCase(message)) { + break; + } + logger.debug("Got '{}'", message); + clientHandler.write(message); + } while (true); + System.exit(0); + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoServerHandler.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoServerHandler.java new file mode 100644 index 0000000000..1286ec6875 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/EchoServerHandler.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014 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.netty; + +import com.google.common.base.Charsets; +import com.google.common.base.Splitter; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handler implementation for the echo server. + */ +@Sharable +public class EchoServerHandler extends ChannelInboundHandlerAdapter { + + private static final Logger logger = LoggerFactory.getLogger(EchoServerHandler.class.getName()); + private String fromLastNewLine = ""; + private final Splitter splitter = Splitter.onPattern("\r?\n"); + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + logger.debug("sleep start"); + Thread.sleep(1000); + logger.debug("sleep done"); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + ByteBuf byteBuf = (ByteBuf) msg; + String message = byteBuf.toString(Charsets.UTF_8); + logger.info("writing back '{}'", message); + ctx.write(msg); + fromLastNewLine += message; + for (String line : splitter.split(fromLastNewLine)) { + if ("quit".equals(line)) { + logger.info("closing server ctx"); + ctx.flush(); + ctx.close(); + break; + } + fromLastNewLine = line; // last line should be preserved + } + + // do not release byteBuf as it is handled back + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + logger.debug("flushing"); + ctx.flush(); + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/ProxyServer.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/ProxyServer.java new file mode 100644 index 0000000000..8f2c50278d --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/ProxyServer.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014 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.netty; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import java.net.InetSocketAddress; +import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; + +public class ProxyServer implements Runnable { + private final ProxyHandlerFactory proxyHandlerFactory; + + public ProxyServer(ProxyHandlerFactory proxyHandlerFactory) { + this.proxyHandlerFactory = proxyHandlerFactory; + } + + public void run() { + // Configure the server. + final EventLoopGroup bossGroup = new NioEventLoopGroup(); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + final LocalAddress localAddress = NetconfConfigUtil.getNetconfLocalAddress(); + ServerBootstrap serverBootstrap = new ServerBootstrap(); + serverBootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .option(ChannelOption.SO_BACKLOG, 100) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(proxyHandlerFactory.create(bossGroup, localAddress)); + } + }); + + // Start the server. + InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8080); + ChannelFuture f = serverBootstrap.bind(address).sync(); + + // Wait until the server socket is closed. + f.channel().closeFuture().sync(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + // Shut down all event loops to terminate all threads. + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + public static interface ProxyHandlerFactory { + ChannelHandler create(EventLoopGroup bossGroup, LocalAddress localAddress); + } + + public static void main(String[] args) { + ProxyHandlerFactory proxyHandlerFactory = new ProxyHandlerFactory() { + @Override + public ChannelHandler create(EventLoopGroup bossGroup, LocalAddress localAddress) { + return new ProxyServerHandler(bossGroup, localAddress); + } + }; + start(proxyHandlerFactory); + } + + public static void start(ProxyHandlerFactory proxyHandlerFactory) { + new Thread(new EchoServer()).start(); + new Thread(new ProxyServer(proxyHandlerFactory)).start(); + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/ProxyServerHandler.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/ProxyServerHandler.java new file mode 100644 index 0000000000..ecab21256e --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/ProxyServerHandler.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014 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.netty; + +import com.google.common.base.Charsets; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.local.LocalChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProxyServerHandler extends ChannelInboundHandlerAdapter { + private static final Logger logger = LoggerFactory.getLogger(ProxyServerHandler.class.getName()); + private final Bootstrap clientBootstrap; + private final LocalAddress localAddress; + + + private Channel clientChannel; + + public ProxyServerHandler(EventLoopGroup bossGroup, LocalAddress localAddress) { + clientBootstrap = new Bootstrap(); + clientBootstrap.group(bossGroup).channel(LocalChannel.class); + this.localAddress = localAddress; + } + + @Override + public void channelActive(ChannelHandlerContext remoteCtx) { + final ProxyClientHandler clientHandler = new ProxyClientHandler(remoteCtx); + clientBootstrap.handler(new ChannelInitializer() { + @Override + public void initChannel(LocalChannel ch) throws Exception { + ch.pipeline().addLast(clientHandler); + } + }); + ChannelFuture clientChannelFuture = clientBootstrap.connect(localAddress).awaitUninterruptibly(); + clientChannel = clientChannelFuture.channel(); + clientChannel.writeAndFlush(Unpooled.copiedBuffer("connected\n".getBytes())); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + logger.info("channelInactive - closing client connection"); + clientChannel.close(); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, final Object msg) { + logger.debug("Writing to client {}", msg); + clientChannel.write(msg); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + logger.debug("flushing"); + clientChannel.flush(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + // Close the connection when an exception is raised. + logger.warn("Unexpected exception from downstream.", cause); + ctx.close(); + } +} + +class ProxyClientHandler extends ChannelInboundHandlerAdapter { + private static final Logger logger = LoggerFactory.getLogger(ProxyClientHandler.class); + + private final ChannelHandlerContext remoteCtx; + + + public ProxyClientHandler(ChannelHandlerContext remoteCtx) { + this.remoteCtx = remoteCtx; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + logger.info("client active"); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + ByteBuf bb = (ByteBuf) msg; + logger.info(">{}", bb.toString(Charsets.UTF_8)); + remoteCtx.write(msg); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + logger.debug("Flushing server ctx"); + remoteCtx.flush(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + // Close the connection when an exception is raised. + logger.warn("Unexpected exception from downstream", cause); + ctx.close(); + } + + // called both when local or remote connection dies + @Override + public void channelInactive(ChannelHandlerContext ctx) { + logger.debug("channelInactive() called, closing remote client ctx"); + remoteCtx.close(); + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java new file mode 100644 index 0000000000..4e32e82e89 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 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.netty; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import io.netty.channel.nio.NioEventLoopGroup; +import org.junit.Test; +import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; +import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider; +import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; +import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SSHTest { + public static final Logger logger = LoggerFactory.getLogger(SSHTest.class); + + @Test + public void test() throws Exception { + new Thread(new EchoServer(), "EchoServer").start(); + AuthProvider authProvider = mock(AuthProvider.class); + doReturn(PEMGenerator.generate().toCharArray()).when(authProvider).getPEMAsCharArray(); + doReturn(true).when(authProvider).authenticated(anyString(), anyString()); + NetconfSSHServer thread = NetconfSSHServer.start(1831, NetconfConfigUtil.getNetconfLocalAddress(), authProvider, new NioEventLoopGroup()); + Thread.sleep(2000); + logger.info("Closing socket"); + thread.close(); + thread.join(); + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java new file mode 100644 index 0000000000..5e368bc566 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java @@ -0,0 +1,91 @@ +/* + * 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.ssh.authentication; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; + +import ch.ethz.ssh2.Connection; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import java.io.InputStream; +import java.net.InetSocketAddress; +import junit.framework.Assert; +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.netconf.StubUserManager; +import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; +import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class SSHServerTest { + + private static final String USER = "netconf"; + private static final String PASSWORD = "netconf"; + private static final String HOST = "127.0.0.1"; + private static final int PORT = 1830; + private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 8383); + private static final Logger logger = LoggerFactory.getLogger(SSHServerTest.class); + private Thread sshServerThread; + + @Mock + private BundleContext mockedContext; + + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + doReturn(null).when(mockedContext).createFilter(anyString()); + doNothing().when(mockedContext).addServiceListener(any(ServiceListener.class), anyString()); + doReturn(new ServiceReference[0]).when(mockedContext).getServiceReferences(anyString(), anyString()); + + logger.info("Creating SSH server"); + StubUserManager um = new StubUserManager(USER, PASSWORD); + String pem; + try (InputStream is = getClass().getResourceAsStream("/RSA.pk")) { + pem = IOUtils.toString(is); + } + AuthProvider ap = new AuthProvider(pem, mockedContext); + ap.setNullableUserManager(um); + EventLoopGroup bossGroup = new NioEventLoopGroup(); + NetconfSSHServer server = NetconfSSHServer.start(PORT, NetconfConfigUtil.getNetconfLocalAddress(), + ap, bossGroup); + + sshServerThread = new Thread(server); + sshServerThread.setDaemon(true); + sshServerThread.start(); + logger.info("SSH server on " + PORT); + } + + @Test + public void connect() { + try { + Connection conn = new Connection(HOST, PORT); + Assert.assertNotNull(conn); + logger.info("connecting to SSH server"); + conn.connect(); + logger.info("authenticating ..."); + boolean isAuthenticated = conn.authenticateWithPassword(USER, PASSWORD); + Assert.assertTrue(isAuthenticated); + } catch (Exception e) { + logger.error("Error while starting SSH server.", e); + } + + } + +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/resources/logback-test.xml b/opendaylight/netconf/netconf-ssh/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..324c234330 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + %date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + diff --git a/opendaylight/netconf/netconf-tcp/pom.xml b/opendaylight/netconf/netconf-tcp/pom.xml new file mode 100644 index 0000000000..65da6e987e --- /dev/null +++ b/opendaylight/netconf/netconf-tcp/pom.xml @@ -0,0 +1,63 @@ + + + + 4.0.0 + + org.opendaylight.controller + netconf-subsystem + 0.2.5-SNAPSHOT + ../ + + netconf-tcp + bundle + ${project.artifactId} + + + + ${project.groupId} + netconf-api + + + ${project.groupId} + netconf-util + + + commons-io + commons-io + + + org.slf4j + slf4j-api + + + org.opendaylight.yangtools + mockito-configuration + test + + + + + + + org.apache.felix + maven-bundle-plugin + 2.3.7 + + + org.opendaylight.controller.netconf.tcp.osgi.NetconfTCPActivator + com.google.common.base, io.netty.bootstrap, io.netty.channel, io.netty.channel.local, + io.netty.channel.nio, io.netty.channel.socket, io.netty.channel.socket.nio, io.netty.handler.logging, + io.netty.util.concurrent, org.opendaylight.controller.netconf.util.osgi, org.osgi.framework, org.slf4j + + + + + + + diff --git a/opendaylight/netconf/netconf-tcp/src/main/java/org/opendaylight/controller/netconf/tcp/netty/ProxyServer.java b/opendaylight/netconf/netconf-tcp/src/main/java/org/opendaylight/controller/netconf/tcp/netty/ProxyServer.java new file mode 100644 index 0000000000..2e0022cb07 --- /dev/null +++ b/opendaylight/netconf/netconf-tcp/src/main/java/org/opendaylight/controller/netconf/tcp/netty/ProxyServer.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014 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.tcp.netty; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.local.LocalChannel; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import java.net.InetSocketAddress; + +public class ProxyServer implements AutoCloseable { + private final EventLoopGroup bossGroup = new NioEventLoopGroup(); + private final EventLoopGroup workerGroup = new NioEventLoopGroup(); + private final ChannelFuture channelFuture; + + public ProxyServer(InetSocketAddress address, final LocalAddress localAddress) { + // Configure the server. + final Bootstrap clientBootstrap = new Bootstrap(); + clientBootstrap.group(bossGroup).channel(LocalChannel.class); + + ServerBootstrap serverBootstrap = new ServerBootstrap(); + serverBootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.DEBUG)) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(new ProxyServerHandler(clientBootstrap, localAddress)); + } + }); + + // Start the server. + channelFuture = serverBootstrap.bind(address).syncUninterruptibly(); + } + + @Override + public void close() { + channelFuture.channel().close(); + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } +} diff --git a/opendaylight/netconf/netconf-tcp/src/main/java/org/opendaylight/controller/netconf/tcp/netty/ProxyServerHandler.java b/opendaylight/netconf/netconf-tcp/src/main/java/org/opendaylight/controller/netconf/tcp/netty/ProxyServerHandler.java new file mode 100644 index 0000000000..fa8892853b --- /dev/null +++ b/opendaylight/netconf/netconf-tcp/src/main/java/org/opendaylight/controller/netconf/tcp/netty/ProxyServerHandler.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014 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.tcp.netty; + +import static com.google.common.base.Preconditions.checkState; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.local.LocalChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProxyServerHandler extends ChannelInboundHandlerAdapter { + private static final Logger logger = LoggerFactory.getLogger(ProxyServerHandler.class.getName()); + private final Bootstrap clientBootstrap; + private final LocalAddress localAddress; + + private Channel clientChannel; + + public ProxyServerHandler(Bootstrap clientBootstrap, LocalAddress localAddress) { + this.clientBootstrap = clientBootstrap; + this.localAddress = localAddress; + } + + @Override + public void channelActive(ChannelHandlerContext remoteCtx) { + final ProxyClientHandler clientHandler = new ProxyClientHandler(remoteCtx); + clientBootstrap.handler(new ChannelInitializer() { + @Override + public void initChannel(LocalChannel ch) throws Exception { + ch.pipeline().addLast(clientHandler); + } + }); + ChannelFuture clientChannelFuture = clientBootstrap.connect(localAddress).awaitUninterruptibly(); + clientChannel = clientChannelFuture.channel(); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + logger.trace("channelInactive - closing client channel"); + clientChannel.close(); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, final Object msg) { + logger.trace("Writing to client channel"); + clientChannel.write(msg); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + logger.trace("Flushing client channel"); + clientChannel.flush(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + // Close the connection when an exception is raised. + logger.warn("Unexpected exception from downstream.", cause); + ctx.close(); + } +} + +class ProxyClientHandler extends ChannelInboundHandlerAdapter { + private static final Logger logger = LoggerFactory.getLogger(ProxyClientHandler.class); + + private final ChannelHandlerContext remoteCtx; + private ChannelHandlerContext localCtx; + + public ProxyClientHandler(ChannelHandlerContext remoteCtx) { + this.remoteCtx = remoteCtx; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + checkState(this.localCtx == null); + logger.trace("Client channel active"); + this.localCtx = ctx; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + logger.trace("Forwarding message"); + remoteCtx.write(msg); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + logger.trace("Flushing remote ctx"); + remoteCtx.flush(); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + // Close the connection when an exception is raised. + logger.warn("Unexpected exception from downstream", cause); + checkState(this.localCtx.equals(ctx)); + ctx.close(); + } + + // called both when local or remote connection dies + @Override + public void channelInactive(ChannelHandlerContext ctx) { + logger.trace("channelInactive() called, closing remote client ctx"); + remoteCtx.close(); + } + +} diff --git a/opendaylight/netconf/netconf-tcp/src/main/java/org/opendaylight/controller/netconf/tcp/osgi/NetconfTCPActivator.java b/opendaylight/netconf/netconf-tcp/src/main/java/org/opendaylight/controller/netconf/tcp/osgi/NetconfTCPActivator.java new file mode 100644 index 0000000000..bc94e596d7 --- /dev/null +++ b/opendaylight/netconf/netconf-tcp/src/main/java/org/opendaylight/controller/netconf/tcp/osgi/NetconfTCPActivator.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 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.tcp.osgi; + +import com.google.common.base.Optional; +import java.net.InetSocketAddress; +import org.opendaylight.controller.netconf.tcp.netty.ProxyServer; +import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; +import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil.InfixProp; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Opens TCP port specified in config.ini, creates bridge between this port and local netconf server. + */ +public class NetconfTCPActivator implements BundleActivator { + private static final Logger logger = LoggerFactory.getLogger(NetconfTCPActivator.class); + private ProxyServer proxyServer; + + @Override + public void start(BundleContext context) { + final Optional maybeAddress = NetconfConfigUtil.extractNetconfServerAddress(context, InfixProp.tcp); + if (maybeAddress.isPresent() == false) { + logger.debug("Netconf tcp server is not configured to start"); + return; + } + InetSocketAddress address = maybeAddress.get(); + if (address.getAddress().isAnyLocalAddress()) { + logger.warn("Unprotected netconf TCP address is configured to ANY local address. This is a security risk. " + + "Consider changing {} to 127.0.0.1", NetconfConfigUtil.getNetconfServerAddressKey(InfixProp.tcp)); + } + logger.info("Starting TCP netconf server at {}", address); + proxyServer = new ProxyServer(address, NetconfConfigUtil.getNetconfLocalAddress()); + } + + @Override + public void stop(BundleContext context) { + if (proxyServer != null) { + proxyServer.close(); + } + } +} diff --git a/opendaylight/netconf/netconf-util/pom.xml b/opendaylight/netconf/netconf-util/pom.xml index dcbdcabbba..d9d957c663 100644 --- a/opendaylight/netconf/netconf-util/pom.xml +++ b/opendaylight/netconf/netconf-util/pom.xml @@ -53,13 +53,14 @@ org.apache.felix maven-bundle-plugin + 2.3.7 com.google.common.base, com.google.common.collect, io.netty.channel, io.netty.util.concurrent, javax.annotation, javax.xml.namespace, javax.xml.parsers, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.stream, javax.xml.validation, javax.xml.xpath, org.opendaylight.controller.netconf.api, org.opendaylight.controller.netconf.mapping.api, - org.osgi.framework, org.slf4j, org.w3c.dom, org.xml.sax + org.osgi.framework, org.slf4j, org.w3c.dom, org.xml.sax,io.netty.channel.local org.opendaylight.controller.netconf.util.* diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java index 0993b8ad0c..333fea3493 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java @@ -9,36 +9,35 @@ package org.opendaylight.controller.netconf.util.osgi; import com.google.common.base.Optional; +import io.netty.channel.local.LocalAddress; +import java.net.InetSocketAddress; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; - public final class NetconfConfigUtil { private static final Logger logger = LoggerFactory.getLogger(NetconfConfigUtil.class); - public static final InetSocketAddress DEFAULT_NETCONF_TCP_ADDRESS - = new InetSocketAddress("127.0.0.1", 8383); - public static final InetSocketAddress DEFAULT_NETCONF_SSH_ADDRESS - = new InetSocketAddress("0.0.0.0", 1830); - private static final String PREFIX_PROP = "netconf."; private NetconfConfigUtil() { } - private enum InfixProp { + public enum InfixProp { tcp, ssh } private static final String PORT_SUFFIX_PROP = ".port"; private static final String ADDRESS_SUFFIX_PROP = ".address"; - private static final String CLIENT_PROP = ".client"; private static final String PRIVATE_KEY_PATH_PROP = ".pk.path"; private static final String CONNECTION_TIMEOUT_MILLIS_PROP = "connectionTimeoutMillis"; private static final long DEFAULT_TIMEOUT_MILLIS = 5000; + private static final LocalAddress netconfLocalAddress = new LocalAddress("netconf"); + + public static LocalAddress getNetconfLocalAddress() { + return netconfLocalAddress; + } public static long extractTimeoutMillis(final BundleContext bundleContext) { final String key = PREFIX_PROP + CONNECTION_TIMEOUT_MILLIS_PROP; @@ -54,22 +53,6 @@ public final class NetconfConfigUtil { } } - public static InetSocketAddress extractTCPNetconfServerAddress(final BundleContext context, final InetSocketAddress defaultAddress) { - final Optional extracted = extractNetconfServerAddress(context, InfixProp.tcp); - final InetSocketAddress netconfTcpAddress = getNetconfAddress(defaultAddress, extracted, InfixProp.tcp); - logger.debug("Using {} as netconf tcp address", netconfTcpAddress); - if (netconfTcpAddress.getAddress().isAnyLocalAddress()) { - logger.warn("Unprotected netconf TCP address is configured to ANY local address. This is a security risk. " + - "Consider changing {} to 127.0.0.1", PREFIX_PROP + InfixProp.tcp + ADDRESS_SUFFIX_PROP); - } - return netconfTcpAddress; - } - - public static InetSocketAddress extractTCPNetconfClientAddress(final BundleContext context, final InetSocketAddress defaultAddress) { - final Optional extracted = extractNetconfClientAddress(context, InfixProp.tcp); - return getNetconfAddress(defaultAddress, extracted, InfixProp.tcp); - } - /** * Get extracted address or default. * @@ -93,15 +76,12 @@ public final class NetconfConfigUtil { return inetSocketAddress; } - public static InetSocketAddress extractSSHNetconfAddress(final BundleContext context, final InetSocketAddress defaultAddress) { - Optional extractedAddress = extractNetconfServerAddress(context, InfixProp.ssh); - InetSocketAddress netconfSSHAddress = getNetconfAddress(defaultAddress, extractedAddress, InfixProp.ssh); - logger.debug("Using {} as netconf SSH address", netconfSSHAddress); - return netconfSSHAddress; + public static String getPrivateKeyPath(final BundleContext context) { + return getPropertyValue(context, getPrivateKeyKey()); } - public static String getPrivateKeyPath(final BundleContext context) { - return getPropertyValue(context, PREFIX_PROP + InfixProp.ssh + PRIVATE_KEY_PATH_PROP); + public static String getPrivateKeyKey() { + return PREFIX_PROP + InfixProp.ssh + PRIVATE_KEY_PATH_PROP; } private static String getPropertyValue(final BundleContext context, final String propertyName) { @@ -112,16 +92,20 @@ public final class NetconfConfigUtil { return propertyValue; } + public static String getNetconfServerAddressKey(InfixProp infixProp) { + return PREFIX_PROP + infixProp + ADDRESS_SUFFIX_PROP; + } + /** * @param context from which properties are being read. * @param infixProp either tcp or ssh * @return value if address and port are present and valid, Optional.absent otherwise. * @throws IllegalStateException if address or port are invalid, or configuration is missing */ - private static Optional extractNetconfServerAddress(final BundleContext context, + public static Optional extractNetconfServerAddress(final BundleContext context, final InfixProp infixProp) { - final Optional address = getProperty(context, PREFIX_PROP + infixProp + ADDRESS_SUFFIX_PROP); + final Optional address = getProperty(context, getNetconfServerAddressKey(infixProp)); final Optional port = getProperty(context, PREFIX_PROP + infixProp + PORT_SUFFIX_PROP); if (address.isPresent() && port.isPresent()) { @@ -140,24 +124,6 @@ public final class NetconfConfigUtil { return new InetSocketAddress(address.get(), portNumber); } - private static Optional extractNetconfClientAddress(final BundleContext context, - final InfixProp infixProp) { - final Optional address = getProperty(context, - PREFIX_PROP + infixProp + CLIENT_PROP + ADDRESS_SUFFIX_PROP); - final Optional port = getProperty(context, - PREFIX_PROP + infixProp + CLIENT_PROP + PORT_SUFFIX_PROP); - - if (address.isPresent() && port.isPresent()) { - try { - return Optional.of(parseAddress(address, port)); - } catch (final RuntimeException e) { - logger.warn("Unable to parse client {} netconf address from {}:{}, fallback to server address", - infixProp, address, port, e); - } - } - return extractNetconfServerAddress(context, infixProp); - } - private static Optional getProperty(final BundleContext context, final String propKey) { String value = context.getProperty(propKey); if (value != null && value.isEmpty()) { diff --git a/opendaylight/netconf/pom.xml b/opendaylight/netconf/pom.xml index 4f87fd8626..d26fcf987e 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -27,6 +27,7 @@ netconf-mapping-api netconf-client netconf-ssh + netconf-tcp netconf-monitoring ietf-netconf-monitoring ietf-netconf-monitoring-extension @@ -99,6 +100,35 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.12 + + false + false + checkstyle-logging.xml + true + true + ${project.basedir} + **\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat,**\/*.yang + **\/target\/,**\/bin\/,**\/target-ide\/,**\/${jmxGeneratorPath}\/,**\/${salGeneratorPath}\/ + + + + org.opendaylight.yangtools + checkstyle-logging + ${yangtools.version} + + + + + + check + + + + org.apache.maven.plugins maven-compiler-plugin diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/ContainerFlow.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/ContainerFlow.java index ebf623b7b0..468313c164 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/ContainerFlow.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/ContainerFlow.java @@ -17,6 +17,7 @@ import org.opendaylight.controller.sal.action.SetNwDst; import org.opendaylight.controller.sal.action.SetNwSrc; import org.opendaylight.controller.sal.action.SetTpDst; import org.opendaylight.controller.sal.action.SetTpSrc; +import org.opendaylight.controller.sal.action.SetVlanId; import org.opendaylight.controller.sal.flowprogrammer.Flow; import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchType; @@ -54,18 +55,23 @@ public class ContainerFlow implements Serializable { @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } ContainerFlow other = (ContainerFlow) obj; if (match == null) { - if (other.match != null) + if (other.match != null) { return false; - } else if (!match.equals(other.match)) + } + } else if (!match.equals(other.match)) { return false; + } return true; } @@ -95,6 +101,11 @@ public class ContainerFlow implements Serializable { Match actionMatch = new Match(); for (Action action : flow.getActions()) { switch (action.getType()) { + case SET_VLAN_ID: + actionMatch.setField(MatchType.DL_VLAN, + ((Integer) ((SetVlanId) action).getVlanId()) + .shortValue()); + break; case SET_DL_TYPE: actionMatch.setField(MatchType.DL_TYPE, ((Integer) ((SetDlType) action).getDlType()) diff --git a/pom.xml b/pom.xml index 2a9da6c1ec..8ad038763c 100644 --- a/pom.xml +++ b/pom.xml @@ -122,6 +122,7 @@ opendaylight/commons/opendaylight opendaylight/commons/parent opendaylight/commons/logback_settings + opendaylight/commons/filter-valve features/base