From: Ed Warnicke Date: Fri, 14 Feb 2014 15:36:23 +0000 (+0000) Subject: Merge "Fixed bug when Binding-Aware Data Change Listeners we're not triggered." X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~456 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=f08d2774c06e55e377191b027ec9131921977e70;hp=12fa7a97a6a83f2f0ca3cf6bd57e97a2d672f2e7 Merge "Fixed bug when Binding-Aware Data Change Listeners we're not triggered." --- diff --git a/opendaylight/commons/opendaylight/pom.xml b/opendaylight/commons/opendaylight/pom.xml index fb548d4acd..93845a356d 100644 --- a/opendaylight/commons/opendaylight/pom.xml +++ b/opendaylight/commons/opendaylight/pom.xml @@ -799,11 +799,6 @@ clustering.stub ${clustering.stub.version} - - org.opendaylight.controller - configuration - ${controller.version} - org.opendaylight.controller configuration.implementation @@ -1442,7 +1437,6 @@ netty-timer-config ${config.version} - org.opendaylight.controller configuration diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 5aba5ca5cb..fca4936c7f 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -51,6 +51,16 @@ org.opendaylight.controller sal-broker-impl ${mdsal.version} + + + org.opendaylight.controller + sal-remote + ${mdsal.version} + + + org.opendaylight.controller + sal-restconf-broker + ${mdsal.version} org.opendaylight.controller @@ -175,6 +185,16 @@ concepts ${yangtools.version} + + org.opendaylight.yangtools + restconf-client-api + ${yangtools.version} + + + org.opendaylight.yangtools + restconf-client-impl + ${yangtools.version} + diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 8b4e478429..f900c0b18c 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -137,6 +137,11 @@ sal-connector-api ${project.version} + + org.opendaylight.controller + sal-binding-api + ${project.version} + org.opendaylight.controller sal @@ -148,6 +153,16 @@ + + org.opendaylight.controller + sal-remote + ${project.version} + + + org.opendaylight.controller + sal-binding-util + ${project.version} + 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 33b384a94c..69a2108065 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 @@ -19,8 +19,6 @@ public interface RpcConsumerRegistry extends BindingAwareService { * Returns a session specific instance (implementation) of requested * YANG module implentation / service provided by consumer. * - * @param service - * Broker service * @return Session specific implementation of service */ T getRpcService(Class module); diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index e5a74e42a1..fd2c8a2fa4 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -101,7 +101,7 @@ org.opendaylight.controller.sal.binding.impl.*, org.opendaylight.controller.sal.binding.codegen, org.opendaylight.controller.sal.binding.codegen.*, - org.opendaylight.controller.sal.binding.dom.*, + org.opendaylight.controller.sal.binding.osgi.*, diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java index 0762739c63..14006a3fce 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java @@ -7,10 +7,11 @@ */ package org.opendaylight.controller.config.yang.md.sal.binding.impl; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import java.util.Hashtable; import java.util.Map.Entry; import java.util.Set; - import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; import org.opendaylight.yangtools.concepts.Delegator; import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl; @@ -27,9 +28,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; - /** * */ @@ -63,7 +61,7 @@ public final class RuntimeMappingModule extends @Override public java.lang.AutoCloseable createInstance() { - + RuntimeGeneratedMappingServiceProxy potential = tryToReuseGlobalInstance(); if(potential != null) { return potential; @@ -100,7 +98,7 @@ public final class RuntimeMappingModule extends BindingIndependentMappingService, // Delegator, // AutoCloseable { - + private BindingIndependentMappingService delegate; private ServiceReference reference; private BundleContext bundleContext; @@ -113,56 +111,48 @@ public final class RuntimeMappingModule extends this.delegate = Preconditions.checkNotNull(delegate); } - @Override public CodecRegistry getCodecRegistry() { return delegate.getCodecRegistry(); } - @Override public CompositeNode toDataDom(DataObject data) { return delegate.toDataDom(data); } - @Override public Entry toDataDom( Entry, DataObject> entry) { return delegate.toDataDom(entry); } - @Override public InstanceIdentifier toDataDom( org.opendaylight.yangtools.yang.binding.InstanceIdentifier path) { return delegate.toDataDom(path); } - @Override public DataObject dataObjectFromDataDom( org.opendaylight.yangtools.yang.binding.InstanceIdentifier path, CompositeNode result) throws DeserializationException { return delegate.dataObjectFromDataDom(path, result); } - @Override public org.opendaylight.yangtools.yang.binding.InstanceIdentifier fromDataDom(InstanceIdentifier entry) throws DeserializationException { return delegate.fromDataDom(entry); } - @Override public Set getRpcQNamesFor(Class service) { return delegate.getRpcQNamesFor(service); } - @Override - public DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput) { - return delegate.dataObjectFromDataDom(inputClass, domInput); - } - @Override public Optional> getRpcServiceClassFor(String namespace, String revision) { - return delegate.getRpcServiceClassFor(namespace, revision); + return delegate.getRpcServiceClassFor(namespace,revision); } + public DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput) { + return delegate.dataObjectFromDataDom(inputClass, domInput); + } + @Override public void close() throws Exception { if(delegate != null) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend index d997af5912..a7dcf80e8d 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend @@ -23,8 +23,10 @@ import org.opendaylight.yangtools.yang.binding.Notification import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder import com.google.common.collect.Multimaps import org.opendaylight.yangtools.concepts.util.ListenerRegistry -import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener - +import org.opendaylight.controller.sal.binding.api.NotificationProviderService.NotificationInterestListener import java.util.Set +import com.google.common.collect.ImmutableSet +import java.util.concurrent.Future + class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable { val ListenerRegistry interestListeners = ListenerRegistry.create; @@ -100,7 +102,15 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab listenerToNotify = listenerToNotify + listeners.get(type as Class) } val tasks = listenerToNotify.map[new NotifyTask(it, notification)].toSet; - executor.invokeAll(tasks); + submitAll(executor,tasks); + } + + def submitAll(ExecutorService service, Set tasks) { + val ret = ImmutableSet.>builder(); + for(task : tasks) { + ret.add(service.submit(task)); + } + return ret.build(); } override registerNotificationListener(Class notificationType, 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 5292487d03..3ad1dabffe 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 @@ -7,8 +7,7 @@ */ package org.opendaylight.controller.sal.binding.impl; -import static com.google.common.base.Preconditions.checkState; - +import com.google.common.collect.ImmutableClassToInstanceMap; import org.opendaylight.controller.md.sal.binding.util.AbstractBindingSalProviderInstance; import org.opendaylight.controller.md.sal.binding.util.BindingContextUtils; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; @@ -33,8 +32,7 @@ import org.opendaylight.yangtools.yang.binding.RpcService; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableClassToInstanceMap; +import static com.google.common.base.Preconditions.checkState; public class RootBindingAwareBroker implements // Mutable, // 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 7f5e466c00..691c303688 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 @@ -20,8 +20,6 @@ public class DataChangeEventImpl

, D> implements DataChangeEven private final DataChange dataChange; private final D originalConfigurationSubtree; - - private final D originalOperationalSubtree; private final D updatedOperationalSubtree; private final D updatedConfigurationSubtree; diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index 8b193e03aa..8553d9eea5 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -64,6 +64,7 @@ + org.opendaylight.yangtools yang-maven-plugin diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend index 7e88ea17d0..c9fb1fc0b8 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDevice.xtend @@ -125,7 +125,7 @@ AutoCloseable { checkState(schemaSourceProvider != null, "Schema Source Provider must be set.") checkState(eventExecutor != null, "Event executor must be set."); - val listener = new NetconfDeviceListener(this, eventExecutor); + val listener = new NetconfDeviceListener(this); val task = startClientTask(dispatcher, listener) if (mountInstance != null) { commitHandlerReg = mountInstance.registerCommitHandler(ROOT_PATH, this) diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java index 69fe4aa190..13cd5dbcf0 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/NetconfDeviceListener.java @@ -7,61 +7,19 @@ */ package org.opendaylight.controller.sal.connect.netconf; -import com.google.common.base.Objects; - -import io.netty.util.concurrent.EventExecutor; -import io.netty.util.concurrent.Promise; - -import java.util.List; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.locks.ReentrantLock; - -import org.eclipse.xtext.xbase.lib.Exceptions; -import org.eclipse.xtext.xbase.lib.Functions.Function0; import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.client.AbstractNetconfClientNotifySessionListener; import org.opendaylight.controller.netconf.client.NetconfClientSession; -import org.opendaylight.controller.netconf.client.NetconfClientSessionListener; -import org.opendaylight.controller.netconf.util.xml.XmlElement; -import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; -import org.opendaylight.controller.sal.connect.netconf.NetconfDevice; -import org.opendaylight.controller.sal.connect.netconf.NetconfMapping; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; import org.opendaylight.yangtools.yang.data.api.CompositeNode; -import org.opendaylight.yangtools.yang.data.api.Node; -import org.w3c.dom.Document; - -@SuppressWarnings("all") -class NetconfDeviceListener extends NetconfClientSessionListener { - private final NetconfDevice device; - private final EventExecutor eventExecutor; - - public NetconfDeviceListener(final NetconfDevice device, final EventExecutor eventExecutor) { - this.device = device; - this.eventExecutor = eventExecutor; - } - private Promise messagePromise; - private ConcurrentMap> promisedMessages; +import com.google.common.base.Preconditions; - private final ReentrantLock promiseLock = new ReentrantLock(); +class NetconfDeviceListener extends AbstractNetconfClientNotifySessionListener { + private final NetconfDevice device; - public void onMessage(final NetconfClientSession session, final NetconfMessage message) { - if (isNotification(message)) { - this.onNotification(session, message); - } else { - try { - this.promiseLock.lock(); - boolean _notEquals = (!Objects.equal(this.messagePromise, null)); - if (_notEquals) { - this.device.logger.debug("Setting promised reply {} with message {}", this.messagePromise, message); - this.messagePromise.setSuccess(message); - this.messagePromise = null; - } - } finally { - this.promiseLock.unlock(); - } - } + public NetconfDeviceListener(final NetconfDevice device) { + this.device = Preconditions.checkNotNull(device); } /** @@ -76,6 +34,7 @@ class NetconfDeviceListener extends NetconfClientSessionListener { * NetconfClientSessionListener#onMessage(NetconfClientSession, * NetconfMessage)} */ + @Override public void onNotification(final NetconfClientSession session, final NetconfMessage message) { this.device.logger.debug("Received NETCONF notification.", message); CompositeNode domNotification = null; @@ -92,65 +51,4 @@ class NetconfDeviceListener extends NetconfClientSessionListener { } } } - - private static CompositeNode getNotificationBody(final CompositeNode node) { - List> _children = node.getChildren(); - for (final Node child : _children) { - if ((child instanceof CompositeNode)) { - return ((CompositeNode) child); - } - } - return null; - } - - public NetconfMessage getLastMessage(final int attempts, final int attemptMsDelay) throws InterruptedException { - final Promise promise = this.promiseReply(); - this.device.logger.debug("Waiting for reply {}", promise); - int _plus = (attempts * attemptMsDelay); - final boolean messageAvailable = promise.await(_plus); - if (messageAvailable) { - try { - try { - return promise.get(); - } catch (Throwable _e) { - throw Exceptions.sneakyThrow(_e); - } - } catch (final Throwable _t) { - if (_t instanceof ExecutionException) { - final ExecutionException e = (ExecutionException) _t; - IllegalStateException _illegalStateException = new IllegalStateException(e); - throw _illegalStateException; - } else { - throw Exceptions.sneakyThrow(_t); - } - } - } - String _plus_1 = ("Unsuccessful after " + Integer.valueOf(attempts)); - String _plus_2 = (_plus_1 + " attempts."); - IllegalStateException _illegalStateException_1 = new IllegalStateException(_plus_2); - throw _illegalStateException_1; - } - - public synchronized Promise promiseReply() { - this.device.logger.debug("Promising reply."); - this.promiseLock.lock(); - try { - boolean _equals = Objects.equal(this.messagePromise, null); - if (_equals) { - Promise _newPromise = this.eventExecutor. newPromise(); - this.messagePromise = _newPromise; - return this.messagePromise; - } - return this.messagePromise; - } finally { - this.promiseLock.unlock(); - } - } - - public boolean isNotification(final NetconfMessage message) { - Document _document = message.getDocument(); - final XmlElement xmle = XmlElement.fromDomDocument(_document); - String _name = xmle.getName(); - return XmlNetconfConstants.NOTIFICATION_ELEMENT_NAME.equals(_name); - } } diff --git a/opendaylight/md-sal/sal-remote/pom.xml b/opendaylight/md-sal/sal-remote/pom.xml index b6d0632068..d4f5d43e5e 100644 --- a/opendaylight/md-sal/sal-remote/pom.xml +++ b/opendaylight/md-sal/sal-remote/pom.xml @@ -6,13 +6,20 @@ 1.1-SNAPSHOT sal-remote - jar + 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 HEAD + + + org.opendaylight.controller + sal-binding-api + 1.1-SNAPSHOT + + @@ -80,12 +87,4 @@ - - - - org.opendaylight.controller - sal-binding-api - 1.1-SNAPSHOT - - diff --git a/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java b/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java deleted file mode 100644 index 1da603266b..0000000000 --- a/opendaylight/md-sal/sal-remote/src/main/java/org/opendaylight/controller/sal/restconf/service/impl/SalRemoteServiceImpl.java +++ /dev/null @@ -1,34 +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.restconf.service.impl; - -import java.util.concurrent.Future; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.BeginTransactionOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; -import org.opendaylight.yangtools.yang.common.RpcResult; - -public class SalRemoteServiceImpl implements SalRemoteService { - @Override - public Future> beginTransaction() { - return null; - } - - @Override - public Future> createDataChangeEventSubscription(CreateDataChangeEventSubscriptionInput input) { - return null; - } - - @Override - public Future> createNotificationStream(CreateNotificationStreamInput input) { - return null; - } -} diff --git a/opendaylight/md-sal/sal-restconf-broker/pom.xml b/opendaylight/md-sal/sal-restconf-broker/pom.xml index 8294c101e9..8159707d57 100644 --- a/opendaylight/md-sal/sal-restconf-broker/pom.xml +++ b/opendaylight/md-sal/sal-restconf-broker/pom.xml @@ -6,47 +6,87 @@ 1.1-SNAPSHOT sal-restconf-broker - jar + 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 HEAD - - - - org.apache.felix - maven-bundle-plugin - true - - - - org.opendaylight.controller sal-binding-api - 1.1-SNAPSHOT + + + org.opendaylight.controller + sal-binding-util org.opendaylight.controller sal-remote - 1.1-SNAPSHOT + + + org.opendaylight.controller + sal-broker-impl + + + org.opendaylight.controller + sal-binding-config org.opendaylight.controller sal-core-api - 1.1-SNAPSHOT org.opendaylight.yangtools restconf-client-api ${yangtools.version} + + org.opendaylight.yangtools + restconf-client-impl + ${yangtools.version} + org.slf4j slf4j-api + + + + org.apache.felix + maven-bundle-plugin + true + + + ${project.groupId}.${project.artifactId} + + * + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/ + + + + + + + diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java deleted file mode 100644 index 76c98e3dda..0000000000 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationServiceImpl.java +++ /dev/null @@ -1,47 +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.impl; - -import org.opendaylight.controller.sal.binding.api.NotificationListener; -import org.opendaylight.controller.sal.binding.api.NotificationService; -import org.opendaylight.yangtools.concepts.Registration; -import org.opendaylight.yangtools.yang.binding.Notification; - -public class NotificationServiceImpl implements NotificationService { - @Override - public void addNotificationListener(Class notificationType, NotificationListener listener) { - - } - - @Override - public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - - } - - @Override - public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - - } - - @Override - public void removeNotificationListener(Class notificationType, NotificationListener listener) { - - } - - @Override - public Registration> registerNotificationListener(Class notificationType, NotificationListener listener) { - //TODO implementation using sal-remote - return null; - } - - @Override - public Registration registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - //TODO implementation using sal-remote - return null; - } -} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java similarity index 98% rename from opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java rename to opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java index ad28305b22..6fe56c87ed 100644 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerServiceImpl.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/binding/impl/DataBrokerServiceImpl.java @@ -5,7 +5,7 @@ * 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.impl; +package org.opendaylight.controller.sal.restconf.binding.impl; import java.net.URL; import java.util.concurrent.Future; diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java index 988bfd8ca5..74b23201e7 100644 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/SalRemoteServiceBroker.java @@ -8,25 +8,60 @@ package org.opendaylight.controller.sal.restconf.broker; -import org.opendaylight.controller.sal.core.api.Broker; -import org.opendaylight.controller.sal.core.api.Consumer; -import org.opendaylight.controller.sal.core.api.Provider; +import com.google.common.collect.ImmutableClassToInstanceMap; +import org.opendaylight.controller.md.sal.binding.util.BindingContextUtils; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.controller.sal.binding.api.BindingAwareService; +import org.opendaylight.controller.sal.binding.api.NotificationService; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.restconf.broker.impl.RemoteServicesFactory; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; import org.osgi.framework.BundleContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static com.google.common.base.Preconditions.checkState; -public class SalRemoteServiceBroker implements Broker,AutoCloseable { +public class SalRemoteServiceBroker implements BindingAwareBroker,AutoCloseable { - @Override - public void close() throws Exception { + private static final Logger logger = LoggerFactory.getLogger(SalRemoteServiceBroker.class.toString()); + private ImmutableClassToInstanceMap supportedConsumerServices; + + private final String identifier; + + private RpcConsumerRegistry rpcBroker; + private NotificationService notificationBroker; + private DataBrokerService dataBroker; + private final RemoteServicesFactory servicesFactory; + + public SalRemoteServiceBroker(String instanceName,RestconfClientContext clientContext){ + this.identifier = instanceName; + this.servicesFactory = new RemoteServicesFactory(clientContext); } - @Override - public ConsumerSession registerConsumer(Consumer cons, BundleContext context) { - return null; + public void start() { + logger.info("Starting Binding Aware Broker: {}", identifier); + + supportedConsumerServices = ImmutableClassToInstanceMap. builder() + .put(NotificationService.class, servicesFactory.getNotificationService()) // + .put(DataBrokerService.class,servicesFactory.getDataBrokerService() ) // + .put(RpcConsumerRegistry.class,servicesFactory.getRpcConsumerRegistry() ).build(); } + public ProviderContext registerProvider(BindingAwareProvider provider, BundleContext ctx) { + throw new UnsupportedOperationException(); + } + @Override + public void close() throws Exception { + //TODO decide if serviceFactory should close clientContext or it has to be closed by consumer + } @Override - public ProviderSession registerProvider(Provider prov, BundleContext context) { - return null; + public ConsumerContext registerConsumer(BindingAwareConsumer consumer, BundleContext ctx) { + checkState(supportedConsumerServices != null, "Broker is not initialized."); + return BindingContextUtils.createConsumerContextAndInitialize(consumer, supportedConsumerServices); } + } diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java new file mode 100644 index 0000000000..5fad76ff08 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/event/RemoteDataChangeEvent.java @@ -0,0 +1,137 @@ +/* + * 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.restconf.broker.event; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.DataChangedNotification; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class RemoteDataChangeEvent implements DataChangeEvent,DataObject> { + + + private final DataChangedNotification dataChangedNotification; + + + public RemoteDataChangeEvent(DataChangedNotification dataChangedNotification){ + + this.dataChangedNotification = dataChangedNotification; + } + + @Override + public DataObject getOriginalConfigurationSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public DataObject getOriginalOperationalSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public DataObject getUpdatedConfigurationSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public DataObject getUpdatedOperationalSubtree() { + throw new UnsupportedOperationException(); + } + + @Override + public Map, DataObject> getCreatedOperationalData() { + return new HashMap, DataObject>(){{ + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){ + if (d.getOperation().getIntValue() == 0 && d.getStore().getIntValue() == 1){ + put(d.getPath(),d); + } + } + }}; + } + + @Override + public Map, DataObject> getCreatedConfigurationData() { + return new HashMap, DataObject>(){{ + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){ + if (d.getOperation().getIntValue() == 0 && d.getStore().getIntValue() == 0){ + put(d.getPath(),d); + } + } + }}; + } + + @Override + public Map, DataObject> getUpdatedOperationalData() { + return new HashMap, DataObject>(){{ + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){ + if (d.getOperation().getIntValue() == 1 && d.getStore().getIntValue() == 1){ + put(d.getPath(),d); + } + } + }}; + } + + @Override + public Map, DataObject> getUpdatedConfigurationData() { + return new HashMap, DataObject>(){{ + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){ + if (d.getOperation().getIntValue() == 1 && d.getStore().getIntValue() == 0){ + put(d.getPath(),d); + } + } + }}; + } + + @Override + public Set> getRemovedConfigurationData() { + return new HashSet>(){{ + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){ + if (d.getOperation().getIntValue() == 2 && d.getStore().getIntValue() == 0){ + add(d.getPath()); + } + } + }}; + } + + @Override + public Set> getRemovedOperationalData() { + return new HashSet>(){{ + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){ + if (d.getOperation().getIntValue() == 2 && d.getStore().getIntValue() == 1){ + add(d.getPath()); + } + } + }}; + } + + @Override + public Map, DataObject> getOriginalConfigurationData() { + return new HashMap, DataObject>(){{ + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){ + if (d.getOperation().getIntValue() == 1 && d.getStore().getIntValue() == 0){ + put(d.getPath(),d); + } + } + }}; + } + + @Override + public Map, DataObject> getOriginalOperationalData() { + return new HashMap, DataObject>(){{ + for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.data.changed.notification.DataChangeEvent d :dataChangedNotification.getDataChangeEvent()){ + if (d.getOperation().getIntValue() == 1 && d.getStore().getIntValue() == 1){ + put(d.getPath(),d); + } + } + }}; + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java new file mode 100644 index 0000000000..e6659c2265 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/DataBrokerServiceImpl.java @@ -0,0 +1,168 @@ +/* + * 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.restconf.broker.impl; + +import com.google.common.base.Optional; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.controller.sal.common.DataStoreIdentifier; +import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteDataChangeNotificationListener; +import org.opendaylight.controller.sal.restconf.broker.tools.RemoteStreamTools; +import org.opendaylight.controller.sal.restconf.broker.transactions.RemoteDataModificationTransaction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.BeginTransactionOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscriptionOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; +import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo; +import org.opendaylight.yangtools.restconf.client.api.event.ListenableEventStreamContext; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.DataRoot; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DataBrokerServiceImpl implements DataBrokerService { + + private static final Logger logger = LoggerFactory.getLogger(DataBrokerServiceImpl.class.toString()); + private RestconfClientContext restconfClientContext; + private SalRemoteService salRemoteService; + + public DataBrokerServiceImpl(RestconfClientContext restconfClientContext) { + this.restconfClientContext = restconfClientContext; + this.salRemoteService = this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService(); + } + @Override + public T getData(DataStoreIdentifier store, Class rootType) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public T getData(DataStoreIdentifier store, T filter) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public T getCandidateData(DataStoreIdentifier store, Class rootType) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public T getCandidateData(DataStoreIdentifier store, T filter) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public RpcResult editCandidateData(DataStoreIdentifier store, DataRoot changeSet) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public Future> commit(DataStoreIdentifier store) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public DataObject getData(InstanceIdentifier data) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public DataObject getConfigurationData(InstanceIdentifier data) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public DataModificationTransaction beginTransaction() { + Future> rpcResultFuture = this.salRemoteService.beginTransaction(); + //TODO finish yang model for proper remoteDataModificationTransaction setup + RemoteDataModificationTransaction remoteDataModificationTransaction = new RemoteDataModificationTransaction(); + return remoteDataModificationTransaction; + } + + @Override + public void registerChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public void unregisterChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Override + public DataObject readConfigurationData(InstanceIdentifier path) { + try { + Optional optDataObject = (Optional) this.restconfClientContext.getConfigurationDatastore().readData(path).get(); + if (optDataObject.isPresent()){ + return optDataObject.get(); + } + } catch (InterruptedException e) { + logger.trace("Reading configuration data interrupted {}",e); + } catch (ExecutionException e) { + logger.trace("Reading configuration execution exception {}",e); + } + throw new IllegalStateException("No data to return."); + } + + @Override + public DataObject readOperationalData(InstanceIdentifier path) { + try { + Optional optDataObject = (Optional) this.restconfClientContext.getOperationalDatastore().readData(path).get(); + if (optDataObject.isPresent()){ + return optDataObject.get(); + } + } catch (InterruptedException e) { + logger.trace("Reading configuration data interrupted {}",e); + } catch (ExecutionException e) { + logger.trace("Reading configuration execution exception {}",e); + } + throw new IllegalStateException("No data to return."); + } + @Override + public ListenerRegistration registerDataChangeListener(InstanceIdentifier path, DataChangeListener listener) { + CreateDataChangeEventSubscriptionInputBuilder inputBuilder = new CreateDataChangeEventSubscriptionInputBuilder(); + Future> rpcResultFuture = salRemoteService.createDataChangeEventSubscription(inputBuilder.setPath(path).build()); + String streamName = ""; + try { + if (rpcResultFuture.get().isSuccessful()){ + streamName = rpcResultFuture.get().getResult().getStreamName(); + } + } catch (InterruptedException e) { + logger.trace("Interupted while getting rpc result due to {}",e); + } catch (ExecutionException e) { + logger.trace("Execution exception while getting rpc result due to {}",e); + } + final Map desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext,streamName); + ListenableEventStreamContext restConfListenableEventStreamContext = restconfClientContext.getEventStreamContext(desiredEventStream.get(streamName)); + RemoteDataChangeNotificationListener remoteDataChangeNotificationListener = new RemoteDataChangeNotificationListener(listener); + restConfListenableEventStreamContext.registerNotificationListener(remoteDataChangeNotificationListener); + return new SalRemoteDataListenerRegistration(listener); + } + + private class SalRemoteDataListenerRegistration implements ListenerRegistration { + private DataChangeListener dataChangeListener; + public SalRemoteDataListenerRegistration(DataChangeListener dataChangeListener){ + this.dataChangeListener = dataChangeListener; + } + @Override + public DataChangeListener getInstance() { + return this.dataChangeListener; + } + @Override + public void close() throws Exception { + //noop + } + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java new file mode 100644 index 0000000000..a0162395f5 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/NotificationServiceImpl.java @@ -0,0 +1,118 @@ +/* + * 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.restconf.broker.impl; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.google.common.collect.SetMultimap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.controller.sal.binding.api.NotificationService; +import org.opendaylight.controller.sal.restconf.broker.listeners.RemoteNotificationListener; +import org.opendaylight.controller.sal.restconf.broker.tools.RemoteStreamTools; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.QName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; +import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo; +import org.opendaylight.yangtools.yang.binding.Notification; + +public class NotificationServiceImpl implements NotificationService { + private SalRemoteService salRemoteService; + private RestconfClientContext restconfClientContext; + + private final Multimap,NotificationListener> listeners; + private ExecutorService _executor; + + public NotificationServiceImpl(RestconfClientContext restconfClienetContext){ + this.restconfClientContext = restconfClienetContext; + this.salRemoteService = this.restconfClientContext.getRpcServiceContext(SalRemoteService.class).getRpcService(); + + HashMultimap,NotificationListener> _create = HashMultimap., NotificationListener>create(); + SetMultimap,NotificationListener> _synchronizedSetMultimap = Multimaps., NotificationListener>synchronizedSetMultimap(_create); + this.listeners = _synchronizedSetMultimap; + + } + public ExecutorService getExecutor() { + return this._executor; + } + + public void setExecutor(final ExecutorService executor) { + this._executor = executor; + } + + @Override + public void addNotificationListener(Class notificationType, NotificationListener listener) { + this.listeners.put(notificationType, listener); + } + + @Override + public void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException("Deprecated method. Use registerNotificationListener instead."); + throw _unsupportedOperationException; + } + + @Override + public void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException( + "Deprecated method. Use RegisterNotificationListener returned value to close registration."); + throw _unsupportedOperationException; + } + + @Override + public void removeNotificationListener(Class notificationType, NotificationListener listener) { + this.listeners.remove(notificationType, listener); + } + + @Override + public Registration> registerNotificationListener(Class notificationType, NotificationListener listener) { + //TODO implementation using sal-remote + List notifications = new ArrayList(); + notifications.add(new QName(notificationType.toString())); + String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, notifications); + final Map desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName); + RemoteNotificationListener remoteNotificationListener = new RemoteNotificationListener(listener); + ListenerRegistration listenerRegistration = restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(remoteNotificationListener); + SalNotificationRegistration salNotificationRegistration = new SalNotificationRegistration(listenerRegistration); + return salNotificationRegistration; + } + + @Override + public Registration registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener) { + //TODO implementation using sal-remote + String notificationStreamName = RemoteStreamTools.createNotificationStream(salRemoteService, null); + final Map desiredEventStream = RemoteStreamTools.createEventStream(restconfClientContext, notificationStreamName); + ListenerRegistration listenerRegistration = restconfClientContext.getEventStreamContext(desiredEventStream.get(desiredEventStream.get(notificationStreamName))).registerNotificationListener(listener); + return listenerRegistration; + } + + private class SalNotificationRegistration implements Registration>{ + private Registration registration; + + public SalNotificationRegistration(ListenerRegistration listenerRegistration){ + this.registration = listenerRegistration; + } + + @Override + public NotificationListener getInstance() { + return this.getInstance(); + } + + @Override + public void close() throws Exception { + this.registration.close(); + } + } + + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java new file mode 100644 index 0000000000..65ecd8b70b --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RemoteServicesFactory.java @@ -0,0 +1,35 @@ +/* + * 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.restconf.broker.impl; + +import org.opendaylight.controller.sal.binding.api.NotificationService; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; + +public class RemoteServicesFactory { + + private final RestconfClientContext restconfClientContext; + + public RemoteServicesFactory(RestconfClientContext restconfClientContext){ + this.restconfClientContext = restconfClientContext; + } + + public DataBrokerService getDataBrokerService(){ + return new DataBrokerServiceImpl(this.restconfClientContext); + } + + public NotificationService getNotificationService(){ + return new NotificationServiceImpl(this.restconfClientContext); + } + + public RpcConsumerRegistry getRpcConsumerRegistry(){ + return new RpcConsumerRegistryImpl(this.restconfClientContext); + } + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java similarity index 58% rename from opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java rename to opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java index e6a67ee8eb..82342ace26 100644 --- a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcConsumerRegistryImpl.java +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/impl/RpcConsumerRegistryImpl.java @@ -5,15 +5,21 @@ * 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.impl; +package org.opendaylight.controller.sal.restconf.broker.impl; import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; import org.opendaylight.yangtools.yang.binding.RpcService; public class RpcConsumerRegistryImpl implements RpcConsumerRegistry { + + private RestconfClientContext restconfClientContext; + + public RpcConsumerRegistryImpl(RestconfClientContext restconfClientContext){ + this.restconfClientContext = restconfClientContext; + } @Override public T getRpcService(Class module) { - //TODO implementation using restconf-client - return null; + return restconfClientContext.getRpcServiceContext(module).getRpcService(); } } diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java new file mode 100644 index 0000000000..df72ac8ce2 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteDataChangeNotificationListener.java @@ -0,0 +1,27 @@ +/* + * 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.restconf.broker.listeners; + +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener; +import org.opendaylight.controller.sal.restconf.broker.event.RemoteDataChangeEvent; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.DataChangedNotification; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteListener; + +public class RemoteDataChangeNotificationListener implements SalRemoteListener { + + + private final DataChangeListener dataChangeListener; + + public RemoteDataChangeNotificationListener(DataChangeListener dataChangeListener){ + this.dataChangeListener = dataChangeListener; + } + @Override + public void onDataChangedNotification(DataChangedNotification notification) { + this.dataChangeListener.onDataChanged(new RemoteDataChangeEvent(notification)); + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java new file mode 100644 index 0000000000..895a5030e9 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/RemoteNotificationListener.java @@ -0,0 +1,23 @@ +/* + * 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.restconf.broker.listeners; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; + +public class RemoteNotificationListener implements org.opendaylight.yangtools.yang.binding.NotificationListener { + + org.opendaylight.controller.sal.binding.api.NotificationListener listener; + + public RemoteNotificationListener(NotificationListener listener){ + this.listener = listener; + } + public NotificationListener getListener(){ + return this.listener; + } + +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java new file mode 100644 index 0000000000..16ca0aee93 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/listeners/SalNotificationListener.java @@ -0,0 +1,24 @@ +/* + * 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.restconf.broker.listeners; + +import org.opendaylight.controller.sal.binding.api.NotificationListener; +import org.opendaylight.yangtools.yang.binding.Notification; + + +public class SalNotificationListener implements NotificationListener { + private NotificationListener notificationListener; + + public SalNotificationListener( NotificationListener notificationListener){ + this.notificationListener = notificationListener; + } + @Override + public void onNotification(Notification notification) { + this.notificationListener.onNotification(notification); + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java new file mode 100644 index 0000000000..726f7f0649 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/tools/RemoteStreamTools.java @@ -0,0 +1,71 @@ +/* + * 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.restconf.broker.tools; + +import com.google.common.util.concurrent.ListenableFuture; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateNotificationStreamOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.QName; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.SalRemoteService; +import org.opendaylight.yangtools.restconf.client.api.RestconfClientContext; +import org.opendaylight.yangtools.restconf.client.api.event.EventStreamInfo; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RemoteStreamTools { + private static final Logger logger = LoggerFactory.getLogger(RemoteStreamTools.class.toString()); + + public static String createNotificationStream(SalRemoteService salRemoteService,List notifications){ + CreateNotificationStreamInputBuilder notificationStreamInputBuilder = new CreateNotificationStreamInputBuilder(); + + if (null == notifications){ + notificationStreamInputBuilder.setNotifications(notifications); + } + + Future> notificationStream = salRemoteService.createNotificationStream(notificationStreamInputBuilder.build()); + + String nofiticationStreamIdentifier = ""; + try { + if (notificationStream.get().isSuccessful()){ + nofiticationStreamIdentifier = notificationStream.get().getResult().getNotificationStreamIdentifier(); + } + } catch (InterruptedException e) { + logger.trace("Interrupted while resolving notification stream identifier due to {}",e); + } catch (ExecutionException e) { + logger.trace("Execution exception while resolving notification stream identifier due to {}",e); + } + return nofiticationStreamIdentifier; + } + + public static Map createEventStream(RestconfClientContext restconfClientContext, String desiredStreamName){ + ListenableFuture> availableEventStreams = restconfClientContext.getAvailableEventStreams(); + final Map desiredEventStream = new HashMap(); + + try { + Iterator it = availableEventStreams.get().iterator(); + while (it.hasNext()){ + if (it.next().getIdentifier().equals(desiredStreamName)){ + desiredEventStream.put(desiredStreamName,it.next()); + } + } + } catch (InterruptedException e) { + logger.trace("Resolving of event stream interrupted due to {}",e); + } catch (ExecutionException e) { + logger.trace("Resolving of event stream failed due to {}",e); + } + return desiredEventStream; + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java new file mode 100644 index 0000000000..7f9cc8f6c4 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/main/java/org/opendaylight/controller/sal/restconf/broker/transactions/RemoteDataModificationTransaction.java @@ -0,0 +1,122 @@ +/* + * 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.restconf.broker.transactions; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Future; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +public class RemoteDataModificationTransaction implements DataModificationTransaction { + //TODO implement this + + @Override + public Object getIdentifier() { + return null; + } + + @Override + public TransactionStatus getStatus() { + return null; + } + + @Override + public void putRuntimeData(InstanceIdentifier path, DataObject data) { + + } + + @Override + public void putOperationalData(InstanceIdentifier path, DataObject data) { + + } + + @Override + public void putConfigurationData(InstanceIdentifier path, DataObject data) { + + } + + @Override + public void removeRuntimeData(InstanceIdentifier path) { + + } + + @Override + public void removeOperationalData(InstanceIdentifier path) { + + } + + @Override + public void removeConfigurationData(InstanceIdentifier path) { + + } + + @Override + public Future> commit() { + return null; + } + + @Override + public ListenerRegistration registerListener(DataTransactionListener listener) { + return null; + } + + @Override + public Map, DataObject> getCreatedOperationalData() { + return null; + } + + @Override + public Map, DataObject> getCreatedConfigurationData() { + return null; + } + + @Override + public Map, DataObject> getUpdatedOperationalData() { + return null; + } + + @Override + public Map, DataObject> getUpdatedConfigurationData() { + return null; + } + + @Override + public Set> getRemovedConfigurationData() { + return null; + } + + @Override + public Set> getRemovedOperationalData() { + return null; + } + + @Override + public Map, DataObject> getOriginalConfigurationData() { + return null; + } + + @Override + public Map, DataObject> getOriginalOperationalData() { + return null; + } + + @Override + public DataObject readOperationalData(InstanceIdentifier path) { + return null; + } + + @Override + public DataObject readConfigurationData(InstanceIdentifier path) { + return null; + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java new file mode 100644 index 0000000000..eafc47d620 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/DataBrokerImplTest.java @@ -0,0 +1,15 @@ +/* + * 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.impl.test; + +public class DataBrokerImplTest { + + public static void main(String[] args){ + + } +} diff --git a/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java new file mode 100644 index 0000000000..a91b06ee76 --- /dev/null +++ b/opendaylight/md-sal/sal-restconf-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/test/NotificationServiceImplTest.java @@ -0,0 +1,15 @@ +/* + * 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.impl.test; + +public class NotificationServiceImplTest { + + public static void main(String[] args){ + + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java new file mode 100644 index 0000000000..af61db1a80 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java @@ -0,0 +1,317 @@ +/* + * Copyright IBM Corporation, 2013. 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.statistics.manager; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.annotations.VisibleForTesting; + +/** + * Utility class for comparing flows. + */ +final class FlowComparator { + private final static Logger logger = LoggerFactory.getLogger(FlowComparator.class); + + private FlowComparator() { + + } + + public static boolean flowEquals(Flow statsFlow, Flow storedFlow) { + if (statsFlow.getClass() != storedFlow.getClass()) { + return false; + } + if (statsFlow.getContainerName()== null) { + if (storedFlow.getContainerName()!= null) { + return false; + } + } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) { + return false; + } + if (statsFlow.getMatch()== null) { + if (storedFlow.getMatch() != null) { + return false; + } + } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) { + else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) { + return false; + } + if (storedFlow.getPriority() == null) { + if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) { + return false; + } + } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { + return false; + } + if (statsFlow.getTableId() == null) { + if (storedFlow.getTableId() != null) { + return false; + } + } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) { + return false; + } + return true; + } + + /** + * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch. + * Flow installation process has three steps + * 1) Store flow in config data store + * 2) and send it to plugin for installation + * 3) Flow gets installed in switch + * + * The flow user wants to install and what finally gets installed in switch can be slightly different. + * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch + * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch + * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip + * while comparing two ip addresses. + * + * Sometimes when user don't provide few values that is required by flow installation request, like + * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending + * request to the switch. So when statistics manager gets flow statistics, it gets the default value. + * But the flow stored in config data store don't have those defaults value. I included those checks + * in the customer flow/match equal function. + * + * + * @param statsFlow + * @param storedFlow + * @return + */ + public static boolean matchEquals(Match statsFlow, Match storedFlow) { + if (statsFlow == storedFlow) { + return true; + } + if (storedFlow.getClass() != statsFlow.getClass()) { + return false; + } + if (storedFlow.getEthernetMatch() == null) { + if (statsFlow.getEthernetMatch() != null) { + return false; + } + } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) { + return false; + } + if (storedFlow.getIcmpv4Match()== null) { + if (statsFlow.getIcmpv4Match() != null) { + return false; + } + } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) { + return false; + } + if (storedFlow.getIcmpv6Match() == null) { + if (statsFlow.getIcmpv6Match() != null) { + return false; + } + } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) { + return false; + } + if (storedFlow.getInPhyPort() == null) { + if (statsFlow.getInPhyPort() != null) { + return false; + } + } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) { + return false; + } + if (storedFlow.getInPort()== null) { + if (statsFlow.getInPort() != null) { + return false; + } + } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) { + return false; + } + if (storedFlow.getIpMatch()== null) { + if (statsFlow.getIpMatch() != null) { + return false; + } + } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) { + return false; + } + if (storedFlow.getLayer3Match()== null) { + if (statsFlow.getLayer3Match() != null) { + return false; + } + } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) { + return false; + } + if (storedFlow.getLayer4Match()== null) { + if (statsFlow.getLayer4Match() != null) { + return false; + } + } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) { + return false; + } + if (storedFlow.getMetadata() == null) { + if (statsFlow.getMetadata() != null) { + return false; + } + } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) { + return false; + } + if (storedFlow.getProtocolMatchFields() == null) { + if (statsFlow.getProtocolMatchFields() != null) { + return false; + } + } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) { + return false; + } + if (storedFlow.getTunnel()== null) { + if (statsFlow.getTunnel() != null) { + return false; + } + } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) { + return false; + } + if (storedFlow.getVlanMatch()== null) { + if (statsFlow.getVlanMatch() != null) { + return false; + } + } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) { + return false; + } + return true; + } + + @VisibleForTesting + static boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){ + boolean verdict = true; + if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){ + Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match; + Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match; + + if (verdict) { + verdict = compareNullSafe( + storedIpv4Match.getIpv4Destination(), statsIpv4Match.getIpv4Destination()); + } + if (verdict) { + verdict = compareNullSafe( + statsIpv4Match.getIpv4Source(), storedIpv4Match.getIpv4Source()); + } + } else { + Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match); + if (nullCheckOut != null) { + verdict = nullCheckOut; + } else { + verdict = storedLayer3Match.equals(statsLayer3Match); + } + } + + return verdict; + } + + private static boolean compareNullSafe(Ipv4Prefix statsIpv4, Ipv4Prefix storedIpv4) { + boolean verdict = true; + Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4); + if (checkDestNullValuesOut != null) { + verdict = checkDestNullValuesOut; + } else if(!IpAddressEquals(statsIpv4, storedIpv4)){ + verdict = false; + } + + return verdict; + } + + private static Boolean checkNullValues(Object v1, Object v2) { + Boolean verdict = null; + if (v1 == null && v2 != null) { + verdict = Boolean.FALSE; + } else if (v1 != null && v2 == null) { + verdict = Boolean.FALSE; + } else if (v1 == null && v2 == null) { + verdict = Boolean.TRUE; + } + + return verdict; + } + + /** + * TODO: why don't we use the default Ipv4Prefix.equals()? + * + * @param statsIpAddress + * @param storedIpAddress + * @return true if IPv4prefixes equals + */ + private static boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) { + IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue()); + IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue()); + + if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){ + return true; + } + if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){ + return true; + } + return false; + } + + private static boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ + return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt.getMask())); + } + + private static boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ + return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp()); + } + + /** + * Method return integer version of ip address. Converted int will be mask if + * mask specified + */ + private static IntegerIpAddress StrIpToIntIp(String ipAddresss){ + + String[] parts = ipAddresss.split("/"); + String ip = parts[0]; + int prefix; + + if (parts.length < 2) { + prefix = 32; + } else { + prefix = Integer.parseInt(parts[1]); + } + + IntegerIpAddress integerIpAddress = null; + try { + Inet4Address addr = (Inet4Address) InetAddress.getByName(ip); + byte[] addrBytes = addr.getAddress(); + int ipInt = ((addrBytes[0] & 0xFF) << 24) | + ((addrBytes[1] & 0xFF) << 16) | + ((addrBytes[2] & 0xFF) << 8) | + ((addrBytes[3] & 0xFF) << 0); + + int mask = 0xffffffff << 32 - prefix; + + integerIpAddress = new IntegerIpAddress(ipInt, mask); + } catch (UnknownHostException e){ + logger.error("Failed to determine host IP address by name: {}", e.getMessage(), e); + } + + return integerIpAddress; + } + + private static class IntegerIpAddress{ + int ip; + int mask; + public IntegerIpAddress(int ip, int mask) { + this.ip = ip; + this.mask = mask; + } + public int getIp() { + return ip; + } + public int getMask() { + return mask; + } + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsAger.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsAger.java deleted file mode 100644 index 4ecd620543..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsAger.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright IBM Corporation, 2013. 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.statistics.manager; - -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -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.meters.Meter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; -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.FlowStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; -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.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.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; - -/** - * Main responsibility of this class to clean up all the stale statistics data - * associated to Flow,Meter,Group,Queue. - * @author avishnoi@in.ibm.com - * - */ -public class NodeStatisticsAger { - - private final int NUMBER_OF_WAIT_CYCLES =2; - - private final StatisticsProvider statisticsProvider; - - private final NodeKey targetNodeKey; - - private final Map groupDescStatsUpdate - = new ConcurrentHashMap(); - - private final Map meterConfigStatsUpdate - = new ConcurrentHashMap(); - - private final Map flowStatsUpdate - = new ConcurrentHashMap(); - - private final Map queuesStatsUpdate - = new ConcurrentHashMap(); - - public NodeStatisticsAger(StatisticsProvider statisticsProvider, NodeKey nodeKey){ - this.targetNodeKey = nodeKey; - this.statisticsProvider = statisticsProvider; - } - - public class FlowEntry{ - private final Short tableId; - private final Flow flow; - - public FlowEntry(Short tableId, Flow flow){ - this.tableId = tableId; - this.flow = flow; - } - - public Short getTableId() { - return tableId; - } - - public Flow getFlow() { - return flow; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + getOuterType().hashCode(); - result = prime * result + ((flow == null) ? 0 : flow.hashCode()); - result = prime * result + ((tableId == null) ? 0 : tableId.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - FlowEntry other = (FlowEntry) obj; - if (!getOuterType().equals(other.getOuterType())) - return false; - if (flow == null) { - if (other.flow != null) - return false; - } else if (!flow.equals(other.flow)) - return false; - if (tableId == null) { - if (other.tableId != null) - return false; - } else if (!tableId.equals(other.tableId)) - return false; - return true; - } - - private NodeStatisticsAger getOuterType() { - return NodeStatisticsAger.this; - } - - } - - public class QueueEntry{ - private final NodeConnectorId nodeConnectorId; - private final QueueId queueId; - public QueueEntry(NodeConnectorId ncId, QueueId queueId){ - this.nodeConnectorId = ncId; - this.queueId = queueId; - } - public NodeConnectorId getNodeConnectorId() { - return nodeConnectorId; - } - public QueueId getQueueId() { - return queueId; - } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + getOuterType().hashCode(); - result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode()); - result = prime * result + ((queueId == null) ? 0 : queueId.hashCode()); - return result; - } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof QueueEntry)) { - return false; - } - QueueEntry other = (QueueEntry) obj; - if (!getOuterType().equals(other.getOuterType())) { - return false; - } - if (nodeConnectorId == null) { - if (other.nodeConnectorId != null) { - return false; - } - } else if (!nodeConnectorId.equals(other.nodeConnectorId)) { - return false; - } - if (queueId == null) { - if (other.queueId != null) { - return false; - } - } else if (!queueId.equals(other.queueId)) { - return false; - } - return true; - } - private NodeStatisticsAger getOuterType() { - return NodeStatisticsAger.this; - } - } - - public NodeKey getTargetNodeKey() { - return targetNodeKey; - } - - public Map getGroupDescStatsUpdate() { - return groupDescStatsUpdate; - } - - public Map getMeterConfigStatsUpdate() { - return meterConfigStatsUpdate; - } - - public Map getFlowStatsUpdate() { - return flowStatsUpdate; - } - - public Map getQueuesStatsUpdate() { - return queuesStatsUpdate; - } - - public void updateGroupDescStats(List list){ - Date expiryTime = getExpiryTime(); - for(GroupDescStats groupDescStats : list) - this.groupDescStatsUpdate.put(groupDescStats, expiryTime); - } - - public void updateMeterConfigStats(List list){ - Date expiryTime = getExpiryTime(); - for(MeterConfigStats meterConfigStats: list) - this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime); - } - - public void updateFlowStats(FlowEntry flowEntry){ - this.flowStatsUpdate.put(flowEntry, getExpiryTime()); - } - public void updateQueueStats(QueueEntry queueEntry){ - this.queuesStatsUpdate.put(queueEntry, getExpiryTime()); - } - - private Date getExpiryTime(){ - Date expires = new Date(); - expires.setTime(expires.getTime()+StatisticsProvider.STATS_THREAD_EXECUTION_TIME*NUMBER_OF_WAIT_CYCLES); - return expires; - } - - public void cleanStaleStatistics(){ - //Clean stale statistics related to group - for (Iterator it = this.groupDescStatsUpdate.keySet().iterator();it.hasNext();){ - GroupDescStats groupDescStats = it.next(); - Date now = new Date(); - Date expiryTime = this.groupDescStatsUpdate.get(groupDescStats); - if(now.after(expiryTime)){ - cleanGroupStatsFromDataStore(groupDescStats ); - it.remove(); - } - } - - //Clean stale statistics related to meter - for (Iterator it = this.meterConfigStatsUpdate.keySet().iterator();it.hasNext();){ - MeterConfigStats meterConfigStats = it.next(); - Date now = new Date(); - Date expiryTime = this.meterConfigStatsUpdate.get(meterConfigStats); - if(now.after(expiryTime)){ - cleanMeterStatsFromDataStore(meterConfigStats); - it.remove(); - } - } - - //Clean stale statistics related to flow - for (Iterator it = this.flowStatsUpdate.keySet().iterator();it.hasNext();){ - FlowEntry flowEntry = it.next(); - Date now = new Date(); - Date expiryTime = this.flowStatsUpdate.get(flowEntry); - if(now.after(expiryTime)){ - cleanFlowStatsFromDataStore(flowEntry); - it.remove(); - } - } - - //Clean stale statistics related to queue - for (Iterator it = this.queuesStatsUpdate.keySet().iterator();it.hasNext();){ - QueueEntry queueEntry = it.next(); - Date now = new Date(); - Date expiryTime = this.queuesStatsUpdate.get(queueEntry); - if(now.after(expiryTime)){ - cleanQueueStatsFromDataStore(queueEntry); - it.remove(); - } - } - - } - - private void cleanQueueStatsFromDataStore(QueueEntry queueEntry) { - InstanceIdentifier queueRef - = InstanceIdentifier.builder(Nodes.class) - .child(Node.class, this.targetNodeKey) - .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId())) - .augmentation(FlowCapableNodeConnector.class) - .child(Queue.class, new QueueKey(queueEntry.getQueueId())) - .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance(); - cleanStaleStatisticsFromDataStore(queueRef); - } - - private void cleanFlowStatsFromDataStore(FlowEntry flowEntry) { - InstanceIdentifier flowRef - = InstanceIdentifier.builder(Nodes.class).child(Node.class, this.targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(flowEntry.getTableId())) - .child(Flow.class,flowEntry.getFlow().getKey()) - .augmentation(FlowStatisticsData.class).toInstance(); - - cleanStaleStatisticsFromDataStore(flowRef); - - } - - private void cleanMeterStatsFromDataStore(MeterConfigStats meterConfigStats) { - InstanceIdentifierBuilder meterRef - = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Meter.class,new MeterKey(meterConfigStats.getMeterId())); - - InstanceIdentifier nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance(); - - cleanStaleStatisticsFromDataStore(nodeMeterConfigStatsAugmentation); - - InstanceIdentifier nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance(); - - cleanStaleStatisticsFromDataStore(nodeMeterStatisticsAugmentation); - - } - - private void cleanGroupStatsFromDataStore(GroupDescStats groupDescStats) { - InstanceIdentifierBuilder groupRef - = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey) - .augmentation(FlowCapableNode.class) - .child(Group.class,new GroupKey(groupDescStats.getGroupId())); - - InstanceIdentifier nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance(); - - cleanStaleStatisticsFromDataStore(nodeGroupDescStatsAugmentation); - - InstanceIdentifier nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance(); - - cleanStaleStatisticsFromDataStore(nodeGroupStatisticsAugmentation); - } - - private void cleanStaleStatisticsFromDataStore(InstanceIdentifier ii){ - if(ii != null){ - DataModificationTransaction it = this.statisticsProvider.startChange(); - it.removeOperationalData(ii); - it.commit(); - } - } -} 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 new file mode 100644 index 0000000000..395bacb5e3 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java @@ -0,0 +1,770 @@ +/* + * Copyright IBM Corporation, 2013. 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.statistics.manager; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +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.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; +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.TableBuilder; +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.inventory.rev130819.tables.table.FlowBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder; +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.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; +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.FlowTableStatisticsDataBuilder; +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.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; +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.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; +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.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +/** + * This class handles the lifecycle of per-node statistics. It receives data + * from StatisticsListener, stores it in the data store and keeps track of + * when the data should be removed. + * + * @author avishnoi@in.ibm.com + */ +public class NodeStatisticsHandler { + private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class); + private static final int NUMBER_OF_WAIT_CYCLES = 2; + + private final Map groupDescStatsUpdate = new HashMap<>(); + private final Map meterConfigStatsUpdate = new HashMap<>(); + private final Map flowStatsUpdate = new HashMap<>(); + private final Map queuesStatsUpdate = new HashMap<>(); + private final InstanceIdentifier targetNodeIdentifier; + private final StatisticsProvider statisticsProvider; + private final NodeKey targetNodeKey; + private int unaccountedFlowsCounter = 1; + + public NodeStatisticsHandler(StatisticsProvider statisticsProvider, NodeKey nodeKey){ + this.statisticsProvider = Preconditions.checkNotNull(statisticsProvider); + this.targetNodeKey = Preconditions.checkNotNull(nodeKey); + this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build(); + } + + private static class FlowEntry { + private final Short tableId; + private final Flow flow; + + public FlowEntry(Short tableId, Flow flow){ + this.tableId = tableId; + this.flow = flow; + } + + public Short getTableId() { + return tableId; + } + + public Flow getFlow() { + return flow; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((flow == null) ? 0 : flow.hashCode()); + result = prime * result + ((tableId == null) ? 0 : tableId.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + FlowEntry other = (FlowEntry) obj; + if (flow == null) { + if (other.flow != null) + return false; + } else if (!flow.equals(other.flow)) + return false; + if (tableId == null) { + if (other.tableId != null) + return false; + } else if (!tableId.equals(other.tableId)) + return false; + return true; + } + } + + private static final class QueueEntry{ + private final NodeConnectorId nodeConnectorId; + private final QueueId queueId; + public QueueEntry(NodeConnectorId ncId, QueueId queueId){ + this.nodeConnectorId = ncId; + this.queueId = queueId; + } + public NodeConnectorId getNodeConnectorId() { + return nodeConnectorId; + } + public QueueId getQueueId() { + return queueId; + } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode()); + result = prime * result + ((queueId == null) ? 0 : queueId.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof QueueEntry)) { + return false; + } + QueueEntry other = (QueueEntry) obj; + if (nodeConnectorId == null) { + if (other.nodeConnectorId != null) { + return false; + } + } else if (!nodeConnectorId.equals(other.nodeConnectorId)) { + return false; + } + if (queueId == null) { + if (other.queueId != null) { + return false; + } + } else if (!queueId.equals(other.queueId)) { + return false; + } + return true; + } + } + + public NodeKey getTargetNodeKey() { + return targetNodeKey; + } + + public synchronized void updateGroupDescStats(List list){ + final Long expiryTime = getExpiryTime(); + final DataModificationTransaction trans = statisticsProvider.startChange(); + + for (GroupDescStats groupDescStats : list) { + GroupBuilder groupBuilder = new GroupBuilder(); + GroupKey groupKey = new GroupKey(groupDescStats.getGroupId()); + groupBuilder.setKey(groupKey); + + InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Group.class,groupKey).toInstance(); + + NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder(); + GroupDescBuilder stats = new GroupDescBuilder(); + stats.fieldsFrom(groupDescStats); + groupDesc.setGroupDesc(stats.build()); + + //Update augmented data + groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build()); + + trans.putOperationalData(groupRef, groupBuilder.build()); + this.groupDescStatsUpdate.put(groupDescStats, expiryTime); + } + + trans.commit(); + } + + + public synchronized void updateGroupStats(List list) { + final DataModificationTransaction trans = statisticsProvider.startChange(); + + for(GroupStats groupStats : list) { + GroupBuilder groupBuilder = new GroupBuilder(); + GroupKey groupKey = new GroupKey(groupStats.getGroupId()); + groupBuilder.setKey(groupKey); + + InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Group.class,groupKey).toInstance(); + + NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder(); + GroupStatisticsBuilder stats = new GroupStatisticsBuilder(); + stats.fieldsFrom(groupStats); + groupStatisticsBuilder.setGroupStatistics(stats.build()); + + //Update augmented data + groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build()); + trans.putOperationalData(groupRef, groupBuilder.build()); + + // FIXME: should we be tracking this data? + } + + trans.commit(); + } + + public synchronized void updateMeterConfigStats(List list) { + final Long expiryTime = getExpiryTime(); + final DataModificationTransaction trans = statisticsProvider.startChange(); + + for(MeterConfigStats meterConfigStats : list) { + MeterBuilder meterBuilder = new MeterBuilder(); + MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId()); + meterBuilder.setKey(meterKey); + + InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Meter.class,meterKey).toInstance(); + + NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder(); + MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder(); + stats.fieldsFrom(meterConfigStats); + meterConfig.setMeterConfigStats(stats.build()); + + //Update augmented data + meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build()); + + trans.putOperationalData(meterRef, meterBuilder.build()); + this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime); + } + + trans.commit(); + } + + + public synchronized void updateMeterStats(List list) { + final DataModificationTransaction trans = statisticsProvider.startChange(); + + for(MeterStats meterStats : list) { + MeterBuilder meterBuilder = new MeterBuilder(); + MeterKey meterKey = new MeterKey(meterStats.getMeterId()); + meterBuilder.setKey(meterKey); + + InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Meter.class,meterKey).toInstance(); + + NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder(); + MeterStatisticsBuilder stats = new MeterStatisticsBuilder(); + stats.fieldsFrom(meterStats); + meterStatsBuilder.setMeterStatistics(stats.build()); + + //Update augmented data + meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build()); + trans.putOperationalData(meterRef, meterBuilder.build()); + + // FIXME: should we be tracking this data? + } + + trans.commit(); + } + + public synchronized void updateQueueStats(List list) { + final Long expiryTime = getExpiryTime(); + final DataModificationTransaction trans = statisticsProvider.startChange(); + + for (QueueIdAndStatisticsMap swQueueStats : list) { + + QueueEntry queueEntry = new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId()); + + FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder(); + + FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder(); + + queueStatisticsBuilder.fieldsFrom(swQueueStats); + + queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build()); + + InstanceIdentifier queueRef + = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, targetNodeKey) + .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId())) + .augmentation(FlowCapableNodeConnector.class) + .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance(); + + QueueBuilder queueBuilder = new QueueBuilder(); + FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build(); + queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd); + queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId())); + + logger.debug("Augmenting queue statistics {} of queue {} to port {}", + qsd, + swQueueStats.getQueueId(), + swQueueStats.getNodeConnectorId()); + + trans.putOperationalData(queueRef, queueBuilder.build()); + this.queuesStatsUpdate.put(queueEntry, expiryTime); + } + + trans.commit(); + } + + public synchronized void updateFlowTableStats(List list) { + final DataModificationTransaction trans = statisticsProvider.startChange(); + + for (FlowTableAndStatisticsMap ftStats : list) { + + InstanceIdentifier tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance(); + + FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder(); + + FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder(); + statisticsBuilder.setActiveFlows(ftStats.getActiveFlows()); + statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp()); + statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched()); + + final FlowTableStatistics stats = statisticsBuilder.build(); + statisticsDataBuilder.setFlowTableStatistics(stats); + + logger.debug("Augment flow table statistics: {} for table {} on Node {}", + stats,ftStats.getTableId(), targetNodeKey); + + TableBuilder tableBuilder = new TableBuilder(); + tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue())); + tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build()); + trans.putOperationalData(tableRef, tableBuilder.build()); + + // FIXME: should we be tracking this data? + } + + trans.commit(); + } + + public synchronized void updateNodeConnectorStats(List list) { + final DataModificationTransaction trans = statisticsProvider.startChange(); + + for(NodeConnectorStatisticsAndPortNumberMap portStats : list) { + + FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder + = new FlowCapableNodeConnectorStatisticsBuilder(); + statisticsBuilder.setBytes(portStats.getBytes()); + statisticsBuilder.setCollisionCount(portStats.getCollisionCount()); + statisticsBuilder.setDuration(portStats.getDuration()); + statisticsBuilder.setPackets(portStats.getPackets()); + statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError()); + statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops()); + statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors()); + statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError()); + statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError()); + statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops()); + statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors()); + + //Augment data to the node-connector + FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = + new FlowCapableNodeConnectorStatisticsDataBuilder(); + + statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build()); + + InstanceIdentifier nodeConnectorRef = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, targetNodeKey) + .child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance(); + + // FIXME: can we bypass this read? + NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef); + if(nodeConnector != null){ + final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build(); + logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString()); + NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder(); + nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats); + trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build()); + } + + // FIXME: should we be tracking this data? + } + + trans.commit(); + } + + public synchronized void updateAggregateFlowStats(Short tableId, AggregateFlowStatistics flowStats) { + if (tableId != null) { + final DataModificationTransaction trans = statisticsProvider.startChange(); + + + InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); + + AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder(); + AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(flowStats); + + aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build()); + + logger.debug("Augment aggregate statistics: {} for table {} on Node {}", + aggregateFlowStatisticsBuilder.build().toString(),tableId,targetNodeKey); + + TableBuilder tableBuilder = new TableBuilder(); + tableBuilder.setKey(new TableKey(tableId)); + tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build()); + trans.putOperationalData(tableRef, tableBuilder.build()); + + // FIXME: should we be tracking this data? + trans.commit(); + } + } + + public synchronized void updateGroupFeatures(GroupFeatures notification) { + final DataModificationTransaction trans = statisticsProvider.startChange(); + + final NodeBuilder nodeData = new NodeBuilder(); + nodeData.setKey(targetNodeKey); + + NodeGroupFeaturesBuilder nodeGroupFeatures = new NodeGroupFeaturesBuilder(); + GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(notification); + nodeGroupFeatures.setGroupFeatures(groupFeatures.build()); + + //Update augmented data + nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build()); + trans.putOperationalData(targetNodeIdentifier, nodeData.build()); + + // FIXME: should we be tracking this data? + trans.commit(); + } + + public synchronized void updateMeterFeatures(MeterFeatures features) { + final DataModificationTransaction trans = statisticsProvider.startChange(); + + final NodeBuilder nodeData = new NodeBuilder(); + nodeData.setKey(targetNodeKey); + + NodeMeterFeaturesBuilder nodeMeterFeatures = new NodeMeterFeaturesBuilder(); + MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(features); + nodeMeterFeatures.setMeterFeatures(meterFeature.build()); + + //Update augmented data + nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build()); + trans.putOperationalData(targetNodeIdentifier, nodeData.build()); + + // FIXME: should we be tracking this data? + trans.commit(); + } + + public synchronized void updateFlowStats(List list) { + final Long expiryTime = getExpiryTime(); + final DataModificationTransaction trans = statisticsProvider.startChange(); + + for(FlowAndStatisticsMapList map : list) { + short tableId = map.getTableId(); + boolean foundOriginalFlow = false; + + FlowBuilder flowBuilder = new FlowBuilder(); + + FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder(); + + FlowBuilder flow = new FlowBuilder(); + flow.setContainerName(map.getContainerName()); + flow.setBufferId(map.getBufferId()); + flow.setCookie(map.getCookie()); + flow.setCookieMask(map.getCookieMask()); + flow.setFlags(map.getFlags()); + flow.setFlowName(map.getFlowName()); + flow.setHardTimeout(map.getHardTimeout()); + if(map.getFlowId() != null) + flow.setId(new FlowId(map.getFlowId().getValue())); + flow.setIdleTimeout(map.getIdleTimeout()); + flow.setInstallHw(map.isInstallHw()); + flow.setInstructions(map.getInstructions()); + if(map.getFlowId()!= null) + flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue()))); + flow.setMatch(map.getMatch()); + flow.setOutGroup(map.getOutGroup()); + flow.setOutPort(map.getOutPort()); + flow.setPriority(map.getPriority()); + flow.setStrict(map.isStrict()); + flow.setTableId(tableId); + + Flow flowRule = flow.build(); + + FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(); + stats.setByteCount(map.getByteCount()); + stats.setPacketCount(map.getPacketCount()); + stats.setDuration(map.getDuration()); + + GenericStatistics flowStats = stats.build(); + + //Augment the data to the flow node + + FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder(); + flowStatistics.setByteCount(flowStats.getByteCount()); + flowStatistics.setPacketCount(flowStats.getPacketCount()); + flowStatistics.setDuration(flowStats.getDuration()); + flowStatistics.setContainerName(map.getContainerName()); + flowStatistics.setBufferId(map.getBufferId()); + flowStatistics.setCookie(map.getCookie()); + flowStatistics.setCookieMask(map.getCookieMask()); + flowStatistics.setFlags(map.getFlags()); + flowStatistics.setFlowName(map.getFlowName()); + flowStatistics.setHardTimeout(map.getHardTimeout()); + flowStatistics.setIdleTimeout(map.getIdleTimeout()); + flowStatistics.setInstallHw(map.isInstallHw()); + flowStatistics.setInstructions(map.getInstructions()); + flowStatistics.setMatch(map.getMatch()); + flowStatistics.setOutGroup(map.getOutGroup()); + flowStatistics.setOutPort(map.getOutPort()); + flowStatistics.setPriority(map.getPriority()); + flowStatistics.setStrict(map.isStrict()); + flowStatistics.setTableId(tableId); + + flowStatisticsData.setFlowStatistics(flowStatistics.build()); + + logger.debug("Flow : {}",flowRule.toString()); + logger.debug("Statistics to augment : {}",flowStatistics.build().toString()); + + InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); + + Table table= (Table)trans.readConfigurationData(tableRef); + + //TODO: Not a good way to do it, need to figure out better way. + //TODO: major issue in any alternate approach is that flow key is incrementally assigned + //to the flows stored in data store. + // Augment same statistics to all the matching masked flow + if(table != null){ + + for(Flow existingFlow : table.getFlow()){ + logger.debug("Existing flow in data store : {}",existingFlow.toString()); + if(FlowComparator.flowEquals(flowRule,existingFlow)){ + InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,existingFlow.getKey()).toInstance(); + flowBuilder.setKey(existingFlow.getKey()); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + logger.debug("Found matching flow in the datastore, augmenting statistics"); + foundOriginalFlow = true; + // Update entry with timestamp of latest response + flow.setKey(existingFlow.getKey()); + FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build()); + flowStatsUpdate.put(flowStatsEntry, expiryTime); + + trans.putOperationalData(flowRef, flowBuilder.build()); + } + } + } + + table = (Table)trans.readOperationalData(tableRef); + if(!foundOriginalFlow && table != null){ + + for(Flow existingFlow : table.getFlow()){ + FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class); + if(augmentedflowStatisticsData != null){ + FlowBuilder existingOperationalFlow = new FlowBuilder(); + existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics()); + logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString()); + if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){ + InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,existingFlow.getKey()).toInstance(); + flowBuilder.setKey(existingFlow.getKey()); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics"); + foundOriginalFlow = true; + + // Update entry with timestamp of latest response + flow.setKey(existingFlow.getKey()); + FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build()); + flowStatsUpdate.put(flowStatsEntry, expiryTime); + trans.putOperationalData(flowRef, flowBuilder.build()); + break; + } + } + } + } + if(!foundOriginalFlow){ + String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter); + this.unaccountedFlowsCounter++; + FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); + InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class,newFlowKey).toInstance(); + flowBuilder.setKey(newFlowKey); + flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); + logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow", + flowBuilder.build()); + + // Update entry with timestamp of latest response + flow.setKey(newFlowKey); + FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build()); + flowStatsUpdate.put(flowStatsEntry, expiryTime); + trans.putOperationalData(flowRef, flowBuilder.build()); + } + } + + trans.commit(); + } + + private static Long getExpiryTime(){ + final long now = System.nanoTime(); + return now + TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_THREAD_EXECUTION_TIME * NUMBER_OF_WAIT_CYCLES); + } + + public synchronized void cleanStaleStatistics(){ + final DataModificationTransaction trans = this.statisticsProvider.startChange(); + final long now = System.nanoTime(); + + //Clean stale statistics related to group + for (Iterator> it = this.groupDescStatsUpdate.entrySet().iterator();it.hasNext();){ + Entry e = it.next(); + if (now > e.getValue()) { + cleanGroupStatsFromDataStore(trans, e.getKey()); + it.remove(); + } + } + + //Clean stale statistics related to meter + for (Iterator> it = this.meterConfigStatsUpdate.entrySet().iterator();it.hasNext();){ + Entry e = it.next(); + if (now > e.getValue()) { + cleanMeterStatsFromDataStore(trans, e.getKey()); + it.remove(); + } + } + + //Clean stale statistics related to flow + for (Iterator> it = this.flowStatsUpdate.entrySet().iterator();it.hasNext();){ + Entry e = it.next(); + if (now > e.getValue()) { + cleanFlowStatsFromDataStore(trans, e.getKey()); + it.remove(); + } + } + + //Clean stale statistics related to queue + for (Iterator> it = this.queuesStatsUpdate.entrySet().iterator();it.hasNext();){ + Entry e = it.next(); + if (now > e.getValue()) { + cleanQueueStatsFromDataStore(trans, e.getKey()); + it.remove(); + } + } + + trans.commit(); + } + + private void cleanQueueStatsFromDataStore(DataModificationTransaction trans, QueueEntry queueEntry) { + InstanceIdentifier queueRef + = InstanceIdentifier.builder(Nodes.class) + .child(Node.class, this.targetNodeKey) + .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId())) + .augmentation(FlowCapableNodeConnector.class) + .child(Queue.class, new QueueKey(queueEntry.getQueueId())) + .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance(); + trans.removeOperationalData(queueRef); + } + + private void cleanFlowStatsFromDataStore(DataModificationTransaction trans, FlowEntry flowEntry) { + InstanceIdentifier flowRef + = InstanceIdentifier.builder(Nodes.class).child(Node.class, this.targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(flowEntry.getTableId())) + .child(Flow.class,flowEntry.getFlow().getKey()) + .augmentation(FlowStatisticsData.class).toInstance(); + trans.removeOperationalData(flowRef); + } + + private void cleanMeterStatsFromDataStore(DataModificationTransaction trans, MeterConfigStats meterConfigStats) { + InstanceIdentifierBuilder meterRef + = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Meter.class,new MeterKey(meterConfigStats.getMeterId())); + + InstanceIdentifier nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance(); + trans.removeOperationalData(nodeMeterConfigStatsAugmentation); + + InstanceIdentifier nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance(); + trans.removeOperationalData(nodeMeterStatisticsAugmentation); + } + + private void cleanGroupStatsFromDataStore(DataModificationTransaction trans, GroupDescStats groupDescStats) { + InstanceIdentifierBuilder groupRef + = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey) + .augmentation(FlowCapableNode.class) + .child(Group.class,new GroupKey(groupDescStats.getGroupId())); + + InstanceIdentifier nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance(); + trans.removeOperationalData(nodeGroupDescStatsAugmentation); + + InstanceIdentifier nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance(); + trans.removeOperationalData(nodeGroupStatisticsAugmentation); + } +} diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java new file mode 100644 index 0000000000..155815dc88 --- /dev/null +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsListener.java @@ -0,0 +1,187 @@ +/* + * Copyright IBM Corporation, 2013. 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.statistics.manager; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; +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.OpendaylightFlowTableStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener; +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.queue.statistics.rev131216.OpendaylightQueueStatisticsListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is responsible for listening for statistics update notifications and + * routing them to the appropriate NodeStatisticsHandler. + + * TODO: Need to add error message listener and clean-up the associated tx id + * if it exists in the tx-id cache. + * @author vishnoianil + */ +public class StatisticsListener implements OpendaylightGroupStatisticsListener, + OpendaylightMeterStatisticsListener, + OpendaylightFlowStatisticsListener, + OpendaylightPortStatisticsListener, + OpendaylightFlowTableStatisticsListener, + OpendaylightQueueStatisticsListener{ + + private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsListener.class); + private final StatisticsProvider statisticsManager; + private final MultipartMessageManager messageManager; + + /** + * default ctor + * @param manager + */ + public StatisticsListener(final StatisticsProvider manager){ + this.statisticsManager = manager; + this.messageManager = this.statisticsManager.getMultipartMessageManager(); + } + + @Override + public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) { + //Check if response is for the request statistics-manager sent. + if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) + return; + + //Add statistics to local cache + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateMeterConfigStats(notification.getMeterConfigStats()); + } + } + + @Override + public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) { + //Check if response is for the request statistics-manager sent. + if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) + return; + + //Add statistics to local cache + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateMeterStats(notification.getMeterStats()); + } + } + + @Override + public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) { + //Check if response is for the request statistics-manager sent. + if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) + return; + + final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateGroupDescStats(notification.getGroupDescStats()); + } + } + + @Override + public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) { + //Check if response is for the request statistics-manager sent. + if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) + return; + + final NodeStatisticsHandler handler = statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateGroupStats(notification.getGroupStats()); + } + } + + @Override + public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) { + final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (sna != null) { + sna.updateMeterFeatures(notification); + } + } + + @Override + public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) { + final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (sna != null) { + sna.updateGroupFeatures(notification); + } + } + + @Override + public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) { + //Check if response is for the request statistics-manager sent. + if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) + return; + + sucLogger.debug("Received flow stats update : {}",notification.toString()); + final NodeStatisticsHandler sna = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (sna != null) { + sna.updateFlowStats(notification.getFlowAndStatisticsMapList()); + } + } + + @Override + public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { + //Check if response is for the request statistics-manager sent. + if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) + return; + + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + final Short tableId = messageManager.getTableIdForTxId(notification.getId(),notification.getTransactionId()); + handler.updateAggregateFlowStats(tableId, notification); + } + } + + @Override + public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { + //Check if response is for the request statistics-manager sent. + if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) + return; + + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateNodeConnectorStats(notification.getNodeConnectorStatisticsAndPortNumberMap()); + } + } + + @Override + public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { + //Check if response is for the request statistics-manager sent. + if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) + return; + + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateFlowTableStats(notification.getFlowTableAndStatisticsMap()); + } + } + + @Override + public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) { + //Check if response is for the request statistics-manager sent. + if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) + return; + + //Add statistics to local cache + final NodeStatisticsHandler handler = this.statisticsManager.getStatisticsHandler(notification.getId()); + if (handler != null) { + handler.updateQueueStats(notification.getQueueIdAndStatisticsMap()); + } + } +} + diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java index 653cc8081a..b59482e96b 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsManagerActivator.java @@ -16,32 +16,23 @@ import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.osgi.framework.BundleContext; public class StatisticsManagerActivator extends AbstractBindingAwareProvider { + private StatisticsProvider statsProvider; - private static ProviderContext pSession; - - private static StatisticsProvider statsProvider = new StatisticsProvider(); - @Override public void onSessionInitiated(ProviderContext session) { - - pSession = session; - DataProviderService dps = session.getSALService(DataProviderService.class); - StatisticsManagerActivator.statsProvider.setDataService(dps); - DataBrokerService dbs = session.getSALService(DataBrokerService.class); - StatisticsManagerActivator.statsProvider.setDataBrokerService(dbs); - NotificationProviderService nps = session.getSALService(NotificationProviderService.class); - StatisticsManagerActivator.statsProvider.setNotificationService(nps); - StatisticsManagerActivator.statsProvider.start(); + final DataBrokerService dbs = session.getSALService(DataBrokerService.class); + final DataProviderService dps = session.getSALService(DataProviderService.class); + final NotificationProviderService nps = session.getSALService(NotificationProviderService.class); + statsProvider = new StatisticsProvider(dps); + statsProvider.start(dbs, nps, session); } - + @Override protected void stopImpl(BundleContext context) { - StatisticsManagerActivator.statsProvider.close(); - } - - public static ProviderContext getProviderContext(){ - return pSession; + if (statsProvider != null) { + statsProvider.close(); + statsProvider = null; + } } - } 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 325b342cd8..ab5d20a951 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 @@ -17,6 +17,7 @@ import java.util.concurrent.Future; import org.eclipse.xtext.xbase.lib.Exceptions; import org.opendaylight.controller.md.statistics.manager.MultipartMessageManager.StatsRequestType; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; 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; @@ -71,117 +72,78 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** +import com.google.common.base.Preconditions; + +/** * Following are main responsibilities of the class: - * 1) Invoke statistics request thread to send periodic statistics request to all the - * flow capable switch connected to the controller. It sends statistics request for - * Group,Meter,Table,Flow,Queue,Aggregate stats. - * - * 2) Invoke statistics ager thread, to clean up all the stale statistics data from + * 1) Invoke statistics request thread to send periodic statistics request to all the + * flow capable switch connected to the controller. It sends statistics request for + * Group,Meter,Table,Flow,Queue,Aggregate stats. + * + * 2) Invoke statistics ager thread, to clean up all the stale statistics data from * operational data store. - * + * * @author avishnoi@in.ibm.com * */ public class StatisticsProvider implements AutoCloseable { + public static final int STATS_THREAD_EXECUTION_TIME= 15000; - public final static Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class); - - private DataProviderService dps; - - private DataBrokerService dbs; + private static final Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class); + + private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager(); + private final InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance(); + private final DataProviderService dps; + + //Local caching of stats + private final ConcurrentMap statisticsCache = new ConcurrentHashMap<>(); - private NotificationProviderService nps; - private OpendaylightGroupStatisticsService groupStatsService; - + private OpendaylightMeterStatisticsService meterStatsService; - + private OpendaylightFlowStatisticsService flowStatsService; - + private OpendaylightPortStatisticsService portStatsService; private OpendaylightFlowTableStatisticsService flowTableStatsService; private OpendaylightQueueStatisticsService queueStatsService; - private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager(); - private StatisticsUpdateHandler statsUpdateHandler; - + private Thread statisticsRequesterThread; - + private Thread statisticsAgerThread; - private final InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).toInstance(); - - public static final int STATS_THREAD_EXECUTION_TIME= 15000; - //Local caching of stats - - private final ConcurrentMap statisticsCache = - new ConcurrentHashMap(); - - public DataProviderService getDataService() { - return this.dps; - } - - public void setDataService(final DataProviderService dataService) { - this.dps = dataService; - } - - public DataBrokerService getDataBrokerService() { - return this.dbs; - } - - public void setDataBrokerService(final DataBrokerService dataBrokerService) { - this.dbs = dataBrokerService; - } - public NotificationProviderService getNotificationService() { - return this.nps; - } - - public void setNotificationService(final NotificationProviderService notificationService) { - this.nps = notificationService; + public StatisticsProvider(final DataProviderService dataService) { + this.dps = Preconditions.checkNotNull(dataService); } public MultipartMessageManager getMultipartMessageManager() { return multipartMessageManager; } - private final StatisticsUpdateCommiter updateCommiter = new StatisticsUpdateCommiter(StatisticsProvider.this); - + private final StatisticsListener updateCommiter = new StatisticsListener(StatisticsProvider.this); + private Registration listenerRegistration; - - public void start() { - - NotificationProviderService nps = this.getNotificationService(); - Registration registerNotificationListener = nps.registerNotificationListener(this.updateCommiter); - this.listenerRegistration = registerNotificationListener; - + + public void start(final DataBrokerService dbs, final NotificationProviderService nps, final RpcConsumerRegistry rpcRegistry) { + + this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter); + statsUpdateHandler = new StatisticsUpdateHandler(StatisticsProvider.this); - - registerDataStoreUpdateListener(this.getDataBrokerService()); - + registerDataStoreUpdateListener(dbs); + // Get Group/Meter statistics service instance - groupStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightGroupStatisticsService.class); - - meterStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightMeterStatisticsService.class); - - flowStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightFlowStatisticsService.class); - - portStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightPortStatisticsService.class); - - flowTableStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightFlowTableStatisticsService.class); - - queueStatsService = StatisticsManagerActivator.getProviderContext(). - getRpcService(OpendaylightQueueStatisticsService.class); - + groupStatsService = rpcRegistry.getRpcService(OpendaylightGroupStatisticsService.class); + meterStatsService = rpcRegistry.getRpcService(OpendaylightMeterStatisticsService.class); + flowStatsService = rpcRegistry.getRpcService(OpendaylightFlowStatisticsService.class); + portStatsService = rpcRegistry.getRpcService(OpendaylightPortStatisticsService.class); + flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class); + queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class); + statisticsRequesterThread = new Thread( new Runnable(){ @Override @@ -189,7 +151,7 @@ public class StatisticsProvider implements AutoCloseable { while(true){ try { statsRequestSender(); - + Thread.sleep(STATS_THREAD_EXECUTION_TIME); }catch (Exception e){ spLogger.error("Exception occurred while sending stats request : {}",e); @@ -197,22 +159,22 @@ public class StatisticsProvider implements AutoCloseable { } } }); - + spLogger.debug("Statistics requester thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME); - + statisticsRequesterThread.start(); - + statisticsAgerThread = new Thread( new Runnable(){ @Override public void run() { while(true){ try { - for(NodeStatisticsAger nodeStatisticsAger : statisticsCache.values()){ + for(NodeStatisticsHandler nodeStatisticsAger : statisticsCache.values()){ nodeStatisticsAger.cleanStaleStatistics(); } multipartMessageManager.cleanStaleTransactionIds(); - + Thread.sleep(STATS_THREAD_EXECUTION_TIME); }catch (Exception e){ spLogger.error("Exception occurred while sending stats request : {}",e); @@ -220,14 +182,14 @@ public class StatisticsProvider implements AutoCloseable { } } }); - + spLogger.debug("Statistics ager thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME); statisticsAgerThread.start(); - + spLogger.info("Statistics Provider started."); } - + private void registerDataStoreUpdateListener(DataBrokerService dbs) { //Register for Node updates InstanceIdentifier pathNode = InstanceIdentifier.builder(Nodes.class) @@ -240,15 +202,15 @@ public class StatisticsProvider implements AutoCloseable { .child(Table.class) .child(Flow.class).toInstance(); dbs.registerDataChangeListener(pathFlow, statsUpdateHandler); - + //Register for meter updates InstanceIdentifier pathMeter = InstanceIdentifier.builder(Nodes.class).child(Node.class) .augmentation(FlowCapableNode.class) .child(Meter.class).toInstance(); dbs.registerDataChangeListener(pathMeter, statsUpdateHandler); - - //Register for group updates + + //Register for group updates InstanceIdentifier pathGroup = InstanceIdentifier.builder(Nodes.class).child(Node.class) .augmentation(FlowCapableNode.class) .child(Group.class).toInstance(); @@ -263,35 +225,33 @@ public class StatisticsProvider implements AutoCloseable { } protected DataModificationTransaction startChange() { - - DataProviderService dps = this.getDataService(); return dps.beginTransaction(); } - + private void statsRequestSender(){ - + List targetNodes = getAllConnectedNodes(); - + if(targetNodes == null) return; - + for (Node targetNode : targetNodes){ - + if(targetNode.getAugmentation(FlowCapableNode.class) != null){ sendStatisticsRequestsToNode(targetNode); } } } - + public void sendStatisticsRequestsToNode(Node targetNode){ - + spLogger.debug("Send requests for statistics collection to node : {})",targetNode.getId()); - + InstanceIdentifier targetInstanceId = InstanceIdentifier.builder(Nodes.class).child(Node.class,targetNode.getKey()).toInstance(); - + NodeRef targetNodeRef = new NodeRef(targetInstanceId); - + try{ if(flowStatsService != null){ sendAggregateFlowsStatsFromAllTablesRequest(targetNode.getKey()); @@ -318,15 +278,15 @@ public class StatisticsProvider implements AutoCloseable { spLogger.error("Exception occured while sending statistics requests : {}", e); } } - + public void sendAllFlowTablesStatisticsRequest(NodeRef targetNodeRef) throws InterruptedException, ExecutionException { - final GetFlowTablesStatisticsInputBuilder input = + final GetFlowTablesStatisticsInputBuilder input = new GetFlowTablesStatisticsInputBuilder(); - + input.setNode(targetNodeRef); - Future> response = + Future> response = flowTableStatsService.getFlowTablesStatistics(input.build()); this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNodeRef),response.get().getResult().getTransactionId() @@ -337,69 +297,69 @@ public class StatisticsProvider implements AutoCloseable { public void sendAllFlowsStatsFromAllTablesRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ final GetAllFlowsStatisticsFromAllFlowTablesInputBuilder input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder(); - + input.setNode(targetNode); - - Future> response = + + Future> response = flowStatsService.getAllFlowsStatisticsFromAllFlowTables(input.build()); - + this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() , StatsRequestType.ALL_FLOW); - + } - + public void sendFlowStatsFromTableRequest(NodeRef targetNode,Flow flow) throws InterruptedException, ExecutionException{ final GetFlowStatisticsFromFlowTableInputBuilder input = new GetFlowStatisticsFromFlowTableInputBuilder(); - + input.setNode(targetNode); input.fieldsFrom(flow); - - Future> response = + + Future> response = flowStatsService.getFlowStatisticsFromFlowTable(input.build()); - + this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() , StatsRequestType.ALL_FLOW); - + } public void sendAggregateFlowsStatsFromAllTablesRequest(NodeKey targetNodeKey) throws InterruptedException, ExecutionException{ - + List tablesId = getTablesFromNode(targetNodeKey); - + if(tablesId.size() != 0){ for(Short id : tablesId){ - + sendAggregateFlowsStatsFromTableRequest(targetNodeKey,id); } }else{ spLogger.debug("No details found in data store for flow tables associated with Node {}",targetNodeKey); } } - + public void sendAggregateFlowsStatsFromTableRequest(NodeKey targetNodeKey,Short tableId) throws InterruptedException, ExecutionException{ - + spLogger.debug("Send aggregate stats request for flow table {} to node {}",tableId,targetNodeKey); - GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = + GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder input = new GetAggregateFlowStatisticsFromFlowTableForAllFlowsInputBuilder(); - + input.setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).toInstance())); input.setTableId(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId(tableId)); - Future> response = + Future> response = flowStatsService.getAggregateFlowStatisticsFromFlowTableForAllFlows(input.build()); - + multipartMessageManager.setTxIdAndTableIdMapEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId(), tableId); this.multipartMessageManager.addTxIdToRequestTypeEntry(targetNodeKey.getId(), response.get().getResult().getTransactionId() , StatsRequestType.AGGR_FLOW); } public void sendAllNodeConnectorsStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - + final GetAllNodeConnectorsStatisticsInputBuilder input = new GetAllNodeConnectorsStatisticsInputBuilder(); - + input.setNode(targetNode); - Future> response = + Future> response = portStatsService.getAllNodeConnectorsStatistics(input.build()); this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() , StatsRequestType.ALL_PORT); @@ -407,68 +367,68 @@ public class StatisticsProvider implements AutoCloseable { } public void sendAllGroupStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - + final GetAllGroupStatisticsInputBuilder input = new GetAllGroupStatisticsInputBuilder(); - + input.setNode(targetNode); - Future> response = + Future> response = groupStatsService.getAllGroupStatistics(input.build()); - + this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() , StatsRequestType.ALL_GROUP); } - + public void sendGroupDescriptionRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ final GetGroupDescriptionInputBuilder input = new GetGroupDescriptionInputBuilder(); - + input.setNode(targetNode); - Future> response = + Future> response = groupStatsService.getGroupDescription(input.build()); this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() , StatsRequestType.GROUP_DESC); } - + public void sendAllMeterStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - + GetAllMeterStatisticsInputBuilder input = new GetAllMeterStatisticsInputBuilder(); - + input.setNode(targetNode); - Future> response = + Future> response = meterStatsService.getAllMeterStatistics(input.build()); - + this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() , StatsRequestType.ALL_METER);; } - + public void sendMeterConfigStatisticsRequest(NodeRef targetNode) throws InterruptedException, ExecutionException{ - + GetAllMeterConfigStatisticsInputBuilder input = new GetAllMeterConfigStatisticsInputBuilder(); - + input.setNode(targetNode); - Future> response = + Future> response = meterStatsService.getAllMeterConfigStatistics(input.build()); - + this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() , StatsRequestType.METER_CONFIG);; } - + public void sendAllQueueStatsFromAllNodeConnector(NodeRef targetNode) throws InterruptedException, ExecutionException { GetAllQueuesStatisticsFromAllPortsInputBuilder input = new GetAllQueuesStatisticsFromAllPortsInputBuilder(); - + input.setNode(targetNode); - - Future> response = + + Future> response = queueStatsService.getAllQueuesStatisticsFromAllPorts(input.build()); - + this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() , StatsRequestType.ALL_QUEUE_STATS);; @@ -476,35 +436,48 @@ public class StatisticsProvider implements AutoCloseable { public void sendQueueStatsFromGivenNodeConnector(NodeRef targetNode,NodeConnectorId nodeConnectorId, QueueId queueId) throws InterruptedException, ExecutionException { GetQueueStatisticsFromGivenPortInputBuilder input = new GetQueueStatisticsFromGivenPortInputBuilder(); - + input.setNode(targetNode); input.setNodeConnectorId(nodeConnectorId); input.setQueueId(queueId); - Future> response = + Future> response = queueStatsService.getQueueStatisticsFromGivenPort(input.build()); - + this.multipartMessageManager.addTxIdToRequestTypeEntry(getNodeId(targetNode), response.get().getResult().getTransactionId() , StatsRequestType.ALL_QUEUE_STATS);; } - public ConcurrentMap getStatisticsCache() { - return statisticsCache; + /** + * Get the handler for a particular node. + * + * @param nodeId source node + * @return Node statistics handler for that node. Null if the statistics should + * not handled. + */ + public final NodeStatisticsHandler getStatisticsHandler(final NodeId nodeId) { + Preconditions.checkNotNull(nodeId); + NodeStatisticsHandler ager = statisticsCache.get(nodeId); + if (ager == null) { + ager = new NodeStatisticsHandler(this, new NodeKey(nodeId)); + statisticsCache.put(nodeId, ager); + } + + return ager; } - + private List getAllConnectedNodes(){ - Nodes nodes = (Nodes) dps.readOperationalData(nodesIdentifier); if(nodes == null) return null; - + spLogger.debug("Number of connected nodes : {}",nodes.getNode().size()); return nodes.getNode(); } - + private List getTablesFromNode(NodeKey nodeKey){ InstanceIdentifier nodesIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,nodeKey).augmentation(FlowCapableNode.class).toInstance(); - + FlowCapableNode node = (FlowCapableNode)dps.readOperationalData(nodesIdentifier); List tablesId = new ArrayList(); if(node != null && node.getTable()!=null){ @@ -522,21 +495,21 @@ public class StatisticsProvider implements AutoCloseable { NodeKey nodeKey = InstanceIdentifier.keyOf(nodeII); return nodeKey.getId(); } - + @SuppressWarnings("deprecation") @Override public void close(){ - + try { spLogger.info("Statistics Provider stopped."); if (this.listenerRegistration != null) { - + this.listenerRegistration.close(); - + this.statisticsRequesterThread.destroy(); - + this.statisticsAgerThread.destroy(); - + } } catch (Throwable e) { throw Exceptions.sneakyThrow(e); diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java deleted file mode 100644 index a7c00d4591..0000000000 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiter.java +++ /dev/null @@ -1,997 +0,0 @@ -/* - * Copyright IBM Corporation, 2013. 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.statistics.manager; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.List; -import java.util.concurrent.ConcurrentMap; - -import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.FlowEntry; -import org.opendaylight.controller.md.statistics.manager.NodeStatisticsAger.QueueEntry; -import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix; -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.FlowId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey; -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.TableBuilder; -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.inventory.rev130819.tables.table.FlowBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder; -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.FlowStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder; -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.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; -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.FlowTableStatisticsDataBuilder; -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.OpendaylightFlowTableStatisticsListener; -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.FlowTableStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; -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.NodeConnectorBuilder; -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.NodeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder; -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.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class implement statistics manager related listener interface and augment all the - * received statistics data to data stores. - * TODO: Need to add error message listener and clean-up the associated tx id - * if it exists in the tx-id cache. - * @author vishnoianil - * - */ -public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener, - OpendaylightMeterStatisticsListener, - OpendaylightFlowStatisticsListener, - OpendaylightPortStatisticsListener, - OpendaylightFlowTableStatisticsListener, - OpendaylightQueueStatisticsListener{ - - private final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class); - - private final StatisticsProvider statisticsManager; - private final MultipartMessageManager messageManager; - - private int unaccountedFlowsCounter = 1; - - /** - * default ctor - * @param manager - */ - public StatisticsUpdateCommiter(final StatisticsProvider manager){ - - this.statisticsManager = manager; - this.messageManager = this.statisticsManager.getMultipartMessageManager(); - } - - public StatisticsProvider getStatisticsManager(){ - return statisticsManager; - } - - @Override - public void onMeterConfigStatsUpdated(MeterConfigStatsUpdated notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - - //Add statistics to local cache - ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); - if(!cache.containsKey(notification.getId())){ - cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key)); - } - cache.get(notification.getId()).updateMeterConfigStats(notification.getMeterConfigStats()); - - //Publish data to configuration data store - List meterConfigStatsList = notification.getMeterConfigStats(); - - for(MeterConfigStats meterConfigStats : meterConfigStatsList){ - DataModificationTransaction it = this.statisticsManager.startChange(); - MeterBuilder meterBuilder = new MeterBuilder(); - MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId()); - meterBuilder.setKey(meterKey); - - InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) - .augmentation(FlowCapableNode.class) - .child(Meter.class,meterKey).toInstance(); - - NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder(); - MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder(); - stats.fieldsFrom(meterConfigStats); - meterConfig.setMeterConfigStats(stats.build()); - - //Update augmented data - meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build()); - it.putOperationalData(meterRef, meterBuilder.build()); - it.commit(); - - } - } - - @Override - public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) { - - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - - List meterStatsList = notification.getMeterStats(); - - for(MeterStats meterStats : meterStatsList){ - - //Publish data to configuration data store - DataModificationTransaction it = this.statisticsManager.startChange(); - MeterBuilder meterBuilder = new MeterBuilder(); - MeterKey meterKey = new MeterKey(meterStats.getMeterId()); - meterBuilder.setKey(meterKey); - - InstanceIdentifier meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) - .augmentation(FlowCapableNode.class) - .child(Meter.class,meterKey).toInstance(); - - NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder(); - MeterStatisticsBuilder stats = new MeterStatisticsBuilder(); - stats.fieldsFrom(meterStats); - meterStatsBuilder.setMeterStatistics(stats.build()); - - //Update augmented data - meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build()); - it.putOperationalData(meterRef, meterBuilder.build()); - it.commit(); - } - } - - @Override - public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) { - - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - - //Add statistics to local cache - ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); - if(!cache.containsKey(notification.getId())){ - cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key)); - } - cache.get(notification.getId()).updateGroupDescStats(notification.getGroupDescStats()); - - //Publish data to configuration data store - List groupDescStatsList = notification.getGroupDescStats(); - - for(GroupDescStats groupDescStats : groupDescStatsList){ - DataModificationTransaction it = this.statisticsManager.startChange(); - - GroupBuilder groupBuilder = new GroupBuilder(); - GroupKey groupKey = new GroupKey(groupDescStats.getGroupId()); - groupBuilder.setKey(groupKey); - - InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) - .augmentation(FlowCapableNode.class) - .child(Group.class,groupKey).toInstance(); - - NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder(); - GroupDescBuilder stats = new GroupDescBuilder(); - stats.fieldsFrom(groupDescStats); - groupDesc.setGroupDesc(stats.build()); - - //Update augmented data - groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build()); - - it.putOperationalData(groupRef, groupBuilder.build()); - it.commit(); - } - } - - @Override - public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) { - - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - //Publish data to configuration data store - NodeKey key = new NodeKey(notification.getId()); - List groupStatsList = notification.getGroupStats(); - - for(GroupStats groupStats : groupStatsList){ - DataModificationTransaction it = this.statisticsManager.startChange(); - - GroupBuilder groupBuilder = new GroupBuilder(); - GroupKey groupKey = new GroupKey(groupStats.getGroupId()); - groupBuilder.setKey(groupKey); - - InstanceIdentifier groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key) - .augmentation(FlowCapableNode.class) - .child(Group.class,groupKey).toInstance(); - - NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder(); - GroupStatisticsBuilder stats = new GroupStatisticsBuilder(); - stats.fieldsFrom(groupStats); - groupStatisticsBuilder.setGroupStatistics(stats.build()); - - //Update augmented data - groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build()); - it.putOperationalData(groupRef, groupBuilder.build()); - it.commit(); - } - } - - @Override - public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) { - - MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder(); - meterFeature.setMeterBandSupported(notification.getMeterBandSupported()); - meterFeature.setMeterCapabilitiesSupported(notification.getMeterCapabilitiesSupported()); - meterFeature.setMaxBands(notification.getMaxBands()); - meterFeature.setMaxColor(notification.getMaxColor()); - meterFeature.setMaxMeter(notification.getMaxMeter()); - - //Publish data to configuration data store - DataModificationTransaction it = this.statisticsManager.startChange(); - NodeKey key = new NodeKey(notification.getId()); - NodeRef ref = getNodeRef(key); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(key); - - NodeMeterFeaturesBuilder nodeMeterFeatures= new NodeMeterFeaturesBuilder(); - nodeMeterFeatures.setMeterFeatures(meterFeature.build()); - - //Update augmented data - nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build()); - - InstanceIdentifier refValue = ref.getValue(); - it.putOperationalData(refValue, nodeData.build()); - it.commit(); - } - - @Override - public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) { - - GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder(); - groupFeatures.setActions(notification.getActions()); - groupFeatures.setGroupCapabilitiesSupported(notification.getGroupCapabilitiesSupported()); - groupFeatures.setGroupTypesSupported(notification.getGroupTypesSupported()); - groupFeatures.setMaxGroups(notification.getMaxGroups()); - - //Publish data to configuration data store - DataModificationTransaction it = this.statisticsManager.startChange(); - NodeKey key = new NodeKey(notification.getId()); - NodeRef ref = getNodeRef(key); - - final NodeBuilder nodeData = new NodeBuilder(); - nodeData.setKey(key); - - NodeGroupFeaturesBuilder nodeGroupFeatures= new NodeGroupFeaturesBuilder(); - nodeGroupFeatures.setGroupFeatures(groupFeatures.build()); - - //Update augmented data - nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build()); - - InstanceIdentifier refValue = ref.getValue(); - it.putOperationalData(refValue, nodeData.build()); - it.commit(); - } - - @Override - public void onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) { - - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - sucLogger.debug("Received flow stats update : {}",notification.toString()); - - for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){ - short tableId = map.getTableId(); - - DataModificationTransaction it = this.statisticsManager.startChange(); - - boolean foundOriginalFlow = false; - - FlowBuilder flowBuilder = new FlowBuilder(); - - FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder(); - - FlowBuilder flow = new FlowBuilder(); - flow.setContainerName(map.getContainerName()); - flow.setBufferId(map.getBufferId()); - flow.setCookie(map.getCookie()); - flow.setCookieMask(map.getCookieMask()); - flow.setFlags(map.getFlags()); - flow.setFlowName(map.getFlowName()); - flow.setHardTimeout(map.getHardTimeout()); - if(map.getFlowId() != null) - flow.setId(new FlowId(map.getFlowId().getValue())); - flow.setIdleTimeout(map.getIdleTimeout()); - flow.setInstallHw(map.isInstallHw()); - flow.setInstructions(map.getInstructions()); - if(map.getFlowId()!= null) - flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue()))); - flow.setMatch(map.getMatch()); - flow.setOutGroup(map.getOutGroup()); - flow.setOutPort(map.getOutPort()); - flow.setPriority(map.getPriority()); - flow.setStrict(map.isStrict()); - flow.setTableId(tableId); - - Flow flowRule = flow.build(); - - FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(); - stats.setByteCount(map.getByteCount()); - stats.setPacketCount(map.getPacketCount()); - stats.setDuration(map.getDuration()); - - GenericStatistics flowStats = stats.build(); - - //Add statistics to local cache - ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); - if(!cache.containsKey(notification.getId())){ - cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key)); - } - NodeStatisticsAger nsa = cache.get(notification.getId()); - - //Augment the data to the flow node - - FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder(); - flowStatistics.setByteCount(flowStats.getByteCount()); - flowStatistics.setPacketCount(flowStats.getPacketCount()); - flowStatistics.setDuration(flowStats.getDuration()); - flowStatistics.setContainerName(map.getContainerName()); - flowStatistics.setBufferId(map.getBufferId()); - flowStatistics.setCookie(map.getCookie()); - flowStatistics.setCookieMask(map.getCookieMask()); - flowStatistics.setFlags(map.getFlags()); - flowStatistics.setFlowName(map.getFlowName()); - flowStatistics.setHardTimeout(map.getHardTimeout()); - flowStatistics.setIdleTimeout(map.getIdleTimeout()); - flowStatistics.setInstallHw(map.isInstallHw()); - flowStatistics.setInstructions(map.getInstructions()); - flowStatistics.setMatch(map.getMatch()); - flowStatistics.setOutGroup(map.getOutGroup()); - flowStatistics.setOutPort(map.getOutPort()); - flowStatistics.setPriority(map.getPriority()); - flowStatistics.setStrict(map.isStrict()); - flowStatistics.setTableId(tableId); - - flowStatisticsData.setFlowStatistics(flowStatistics.build()); - - sucLogger.debug("Flow : {}",flowRule.toString()); - sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString()); - - InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); - - Table table= (Table)it.readConfigurationData(tableRef); - - //TODO: Not a good way to do it, need to figure out better way. - //TODO: major issue in any alternate approach is that flow key is incrementally assigned - //to the flows stored in data store. - // Augment same statistics to all the matching masked flow - if(table != null){ - - for(Flow existingFlow : table.getFlow()){ - sucLogger.debug("Existing flow in data store : {}",existingFlow.toString()); - if(flowEquals(flowRule,existingFlow)){ - it = this.statisticsManager.startChange(); - InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flowBuilder.setKey(existingFlow.getKey()); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - sucLogger.debug("Found matching flow in the datastore, augmenting statistics"); - foundOriginalFlow = true; - // Update entry with timestamp of latest response - flow.setKey(existingFlow.getKey()); - FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build()); - cache.get(notification.getId()).updateFlowStats(flowStatsEntry); - - it.putOperationalData(flowRef, flowBuilder.build()); - it.commit(); - } - } - } - - table= (Table)it.readOperationalData(tableRef); - if(!foundOriginalFlow && table != null){ - - for(Flow existingFlow : table.getFlow()){ - FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class); - if(augmentedflowStatisticsData != null){ - FlowBuilder existingOperationalFlow = new FlowBuilder(); - existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics()); - sucLogger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString()); - if(flowEquals(flowRule,existingOperationalFlow.build())){ - InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flowBuilder.setKey(existingFlow.getKey()); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - sucLogger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics"); - foundOriginalFlow = true; - - // Update entry with timestamp of latest response - flow.setKey(existingFlow.getKey()); - FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build()); - cache.get(notification.getId()).updateFlowStats(flowStatsEntry); - - it.putOperationalData(flowRef, flowBuilder.build()); - it.commit(); - break; - } - } - } - } - if(!foundOriginalFlow){ - String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter); - this.unaccountedFlowsCounter++; - FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); - InstanceIdentifier flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,newFlowKey).toInstance(); - flowBuilder.setKey(newFlowKey); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - sucLogger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",flowBuilder.build()); - - // Update entry with timestamp of latest response - flow.setKey(newFlowKey); - FlowEntry flowStatsEntry = nsa.new FlowEntry(tableId,flow.build()); - cache.get(notification.getId()).updateFlowStats(flowStatsEntry); - - it.putOperationalData(flowRef, flowBuilder.build()); - it.commit(); - } - } - } - - @Override - public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - - Short tableId = messageManager.getTableIdForTxId(notification.getId(),notification.getTransactionId()); - if(tableId != null){ - - DataModificationTransaction it = this.statisticsManager.startChange(); - - InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); - - AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder(); - AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder(); - aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount()); - aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount()); - aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount()); - aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build()); - - sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key); - - TableBuilder tableBuilder = new TableBuilder(); - tableBuilder.setKey(new TableKey(tableId)); - tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build()); - it.putOperationalData(tableRef, tableBuilder.build()); - it.commit(); - - } - } - - @Override - public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - - List portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap(); - for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){ - - DataModificationTransaction it = this.statisticsManager.startChange(); - - FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder - = new FlowCapableNodeConnectorStatisticsBuilder(); - statisticsBuilder.setBytes(portStats.getBytes()); - statisticsBuilder.setCollisionCount(portStats.getCollisionCount()); - statisticsBuilder.setDuration(portStats.getDuration()); - statisticsBuilder.setPackets(portStats.getPackets()); - statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError()); - statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops()); - statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors()); - statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError()); - statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError()); - statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops()); - statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors()); - - //Augment data to the node-connector - FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = - new FlowCapableNodeConnectorStatisticsDataBuilder(); - - statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build()); - - InstanceIdentifier nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance(); - - NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef); - - if(nodeConnector != null){ - sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString()); - NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder(); - nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build()); - it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build()); - it.commit(); - } - } - } - - @Override - public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) { - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - - List flowTablesStatsList = notification.getFlowTableAndStatisticsMap(); - for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){ - - DataModificationTransaction it = this.statisticsManager.startChange(); - - InstanceIdentifier
tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key) - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance(); - - FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder(); - - FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder(); - statisticsBuilder.setActiveFlows(ftStats.getActiveFlows()); - statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp()); - statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched()); - - statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build()); - - sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key); - - TableBuilder tableBuilder = new TableBuilder(); - tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue())); - tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build()); - it.putOperationalData(tableRef, tableBuilder.build()); - it.commit(); - } - } - - @Override - public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) { - - //Check if response is for the request statistics-manager sent. - if(!messageManager.isRequestTxIdExist(notification.getId(),notification.getTransactionId(),notification.isMoreReplies())) - return; - - NodeKey key = new NodeKey(notification.getId()); - - //Add statistics to local cache - ConcurrentMap cache = this.statisticsManager.getStatisticsCache(); - if(!cache.containsKey(notification.getId())){ - cache.put(notification.getId(), new NodeStatisticsAger(statisticsManager,key)); - } - - NodeStatisticsAger nsa = cache.get(notification.getId()); - - List queuesStats = notification.getQueueIdAndStatisticsMap(); - for(QueueIdAndStatisticsMap swQueueStats : queuesStats){ - - QueueEntry queueEntry = nsa.new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId()); - nsa.updateQueueStats(queueEntry); - - FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder(); - - FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder(); - - queueStatisticsBuilder.fieldsFrom(swQueueStats); - - queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build()); - - DataModificationTransaction it = this.statisticsManager.startChange(); - - InstanceIdentifier queueRef - = InstanceIdentifier.builder(Nodes.class) - .child(Node.class, key) - .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId())) - .augmentation(FlowCapableNodeConnector.class) - .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance(); - - QueueBuilder queueBuilder = new QueueBuilder(); - queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build()); - queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId())); - - sucLogger.debug("Augmenting queue statistics {} of queue {} to port {}" - ,queueStatisticsDataBuilder.build().toString(), - swQueueStats.getQueueId(), - swQueueStats.getNodeConnectorId()); - - it.putOperationalData(queueRef, queueBuilder.build()); - it.commit(); - - } - - } - - private static NodeRef getNodeRef(NodeKey nodeKey){ - InstanceIdentifierBuilder builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey); - return new NodeRef(builder.toInstance()); - } - - public boolean flowEquals(Flow statsFlow, Flow storedFlow) { - if (statsFlow.getClass() != storedFlow.getClass()) { - return false; - } - if (statsFlow.getContainerName()== null) { - if (storedFlow.getContainerName()!= null) { - return false; - } - } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) { - return false; - } - if (statsFlow.getMatch()== null) { - if (storedFlow.getMatch() != null) { - return false; - } - } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) { - else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) { - return false; - } - if (storedFlow.getPriority() == null) { - if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) { - return false; - } - } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) { - return false; - } - if (statsFlow.getTableId() == null) { - if (storedFlow.getTableId() != null) { - return false; - } - } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) { - return false; - } - return true; - } - - /** - * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch. - * Flow installation process has three steps - * 1) Store flow in config data store - * 2) and send it to plugin for installation - * 3) Flow gets installed in switch - * - * The flow user wants to install and what finally gets installed in switch can be slightly different. - * E.g, If user installs flow with src/dst ip=10.0.0.1/24, when it get installed in the switch - * src/dst ip will be changes to 10.0.0.0/24 because of netmask of 24. When statistics manager fetch - * stats it gets 10.0.0.0/24 rather then 10.0.0.1/24. Custom match takes care of by using masked ip - * while comparing two ip addresses. - * - * Sometimes when user don't provide few values that is required by flow installation request, like - * priority,hard timeout, idle timeout, cookies etc, plugin usages default values before sending - * request to the switch. So when statistics manager gets flow statistics, it gets the default value. - * But the flow stored in config data store don't have those defaults value. I included those checks - * in the customer flow/match equal function. - * - * - * @param statsFlow - * @param storedFlow - * @return - */ - - public boolean matchEquals(Match statsFlow, Match storedFlow) { - if (statsFlow == storedFlow) { - return true; - } - if (storedFlow.getClass() != statsFlow.getClass()) { - return false; - } - if (storedFlow.getEthernetMatch() == null) { - if (statsFlow.getEthernetMatch() != null) { - return false; - } - } else if(!storedFlow.getEthernetMatch().equals(statsFlow.getEthernetMatch())) { - return false; - } - if (storedFlow.getIcmpv4Match()== null) { - if (statsFlow.getIcmpv4Match() != null) { - return false; - } - } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) { - return false; - } - if (storedFlow.getIcmpv6Match() == null) { - if (statsFlow.getIcmpv6Match() != null) { - return false; - } - } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) { - return false; - } - if (storedFlow.getInPhyPort() == null) { - if (statsFlow.getInPhyPort() != null) { - return false; - } - } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) { - return false; - } - if (storedFlow.getInPort()== null) { - if (statsFlow.getInPort() != null) { - return false; - } - } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) { - return false; - } - if (storedFlow.getIpMatch()== null) { - if (statsFlow.getIpMatch() != null) { - return false; - } - } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) { - return false; - } - if (storedFlow.getLayer3Match()== null) { - if (statsFlow.getLayer3Match() != null) { - return false; - } - } else if(!layer3MatchEquals(statsFlow.getLayer3Match(),storedFlow.getLayer3Match())) { - return false; - } - if (storedFlow.getLayer4Match()== null) { - if (statsFlow.getLayer4Match() != null) { - return false; - } - } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) { - return false; - } - if (storedFlow.getMetadata() == null) { - if (statsFlow.getMetadata() != null) { - return false; - } - } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) { - return false; - } - if (storedFlow.getProtocolMatchFields() == null) { - if (statsFlow.getProtocolMatchFields() != null) { - return false; - } - } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) { - return false; - } - if (storedFlow.getTunnel()== null) { - if (statsFlow.getTunnel() != null) { - return false; - } - } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) { - return false; - } - if (storedFlow.getVlanMatch()== null) { - if (statsFlow.getVlanMatch() != null) { - return false; - } - } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) { - return false; - } - return true; - } - - protected static boolean layer3MatchEquals(Layer3Match statsLayer3Match, Layer3Match storedLayer3Match){ - boolean verdict = true; - if(statsLayer3Match instanceof Ipv4Match && storedLayer3Match instanceof Ipv4Match){ - Ipv4Match statsIpv4Match = (Ipv4Match)statsLayer3Match; - Ipv4Match storedIpv4Match = (Ipv4Match)storedLayer3Match; - - if (verdict) { - verdict = compareNullSafe( - storedIpv4Match.getIpv4Destination(), statsIpv4Match.getIpv4Destination()); - } - if (verdict) { - verdict = compareNullSafe( - statsIpv4Match.getIpv4Source(), storedIpv4Match.getIpv4Source()); - } - } else { - Boolean nullCheckOut = checkNullValues(storedLayer3Match, statsLayer3Match); - if (nullCheckOut != null) { - verdict = nullCheckOut; - } else { - verdict = storedLayer3Match.equals(statsLayer3Match); - } - } - - return verdict; - } - - private static boolean compareNullSafe(Ipv4Prefix statsIpv4, Ipv4Prefix storedIpv4) { - boolean verdict = true; - Boolean checkDestNullValuesOut = checkNullValues(storedIpv4, statsIpv4); - if (checkDestNullValuesOut != null) { - verdict = checkDestNullValuesOut; - } else if(!IpAddressEquals(statsIpv4, storedIpv4)){ - verdict = false; - } - - return verdict; - } - - private static Boolean checkNullValues(Object v1, Object v2) { - Boolean verdict = null; - if (v1 == null && v2 != null) { - verdict = Boolean.FALSE; - } else if (v1 != null && v2 == null) { - verdict = Boolean.FALSE; - } else if (v1 == null && v2 == null) { - verdict = Boolean.TRUE; - } - - return verdict; - } - - /** - * TODO: why don't we use the default Ipv4Prefix.equals()? - * - * @param statsIpAddress - * @param storedIpAddress - * @return true if IPv4prefixes equals - */ - private static boolean IpAddressEquals(Ipv4Prefix statsIpAddress, Ipv4Prefix storedIpAddress) { - IntegerIpAddress statsIpAddressInt = StrIpToIntIp(statsIpAddress.getValue()); - IntegerIpAddress storedIpAddressInt = StrIpToIntIp(storedIpAddress.getValue()); - - if(IpAndMaskBasedMatch(statsIpAddressInt,storedIpAddressInt)){ - return true; - } - if(IpBasedMatch(statsIpAddressInt,storedIpAddressInt)){ - return true; - } - return false; - } - - private static boolean IpAndMaskBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ - return ((statsIpAddressInt.getIp() & statsIpAddressInt.getMask()) == (storedIpAddressInt.getIp() & storedIpAddressInt.getMask())); - } - - private static boolean IpBasedMatch(IntegerIpAddress statsIpAddressInt,IntegerIpAddress storedIpAddressInt){ - return (statsIpAddressInt.getIp() == storedIpAddressInt.getIp()); - } - - /** - * Method return integer version of ip address. Converted int will be mask if - * mask specified - */ - private static IntegerIpAddress StrIpToIntIp(String ipAddresss){ - - String[] parts = ipAddresss.split("/"); - String ip = parts[0]; - int prefix; - - if (parts.length < 2) { - prefix = 32; - } else { - prefix = Integer.parseInt(parts[1]); - } - - IntegerIpAddress integerIpAddress = null; - try { - Inet4Address addr = (Inet4Address) InetAddress.getByName(ip); - byte[] addrBytes = addr.getAddress(); - int ipInt = ((addrBytes[0] & 0xFF) << 24) | - ((addrBytes[1] & 0xFF) << 16) | - ((addrBytes[2] & 0xFF) << 8) | - ((addrBytes[3] & 0xFF) << 0); - - int mask = 0xffffffff << 32 - prefix; - - integerIpAddress = new IntegerIpAddress(ipInt, mask); - } catch (UnknownHostException e){ - sucLogger.error("Failed to determine host IP address by name: {}", e.getMessage(), e); - } - - return integerIpAddress; - } - - static class IntegerIpAddress{ - int ip; - int mask; - public IntegerIpAddress(int ip, int mask) { - this.ip = ip; - this.mask = mask; - } - public int getIp() { - return ip; - } - public int getMask() { - return mask; - } - } -} - diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java index 941a8f8c2c..acf182ad2b 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateHandler.java @@ -36,39 +36,33 @@ import org.slf4j.LoggerFactory; /** * Following are two main responsibilities of the class - * 1) Listen for the create changes in config data store for tree nodes (Flow,Group,Meter,Queue) + * 1) Listen for the create changes in config data store for tree nodes (Flow,Group,Meter,Queue) * and send statistics request to the switch to fetch the statistics - * + * * 2)Listen for the remove changes in config data store for tree nodes (Flow,Group,Meter,Queue) * and remove the relative statistics data from operational data store. - * + * * @author avishnoi@in.ibm.com * */ public class StatisticsUpdateHandler implements DataChangeListener { - public final static Logger suhLogger = LoggerFactory.getLogger(StatisticsUpdateHandler.class); - + private static final Logger suhLogger = LoggerFactory.getLogger(StatisticsUpdateHandler.class); private final StatisticsProvider statisticsManager; - - public StatisticsUpdateHandler(final StatisticsProvider manager){ + public StatisticsUpdateHandler(final StatisticsProvider manager){ this.statisticsManager = manager; } - - public StatisticsProvider getStatisticsManager(){ - return statisticsManager; - } @SuppressWarnings("unchecked") @Override public void onDataChanged(DataChangeEvent, DataObject> change) { - + Map, DataObject> nodeAdditions = change.getCreatedOperationalData(); for (InstanceIdentifier dataObjectInstance : nodeAdditions.keySet()) { DataObject dataObject = nodeAdditions.get(dataObjectInstance); if(dataObject instanceof Node){ - + Node node = (Node) dataObject; if(node.getAugmentation(FlowCapableNode.class) != null){ this.statisticsManager.sendStatisticsRequestsToNode(node); @@ -114,56 +108,50 @@ public class StatisticsUpdateHandler implements DataChangeListener { } } } - + + DataModificationTransaction it = this.statisticsManager.startChange(); Set> removals = change.getRemovedConfigurationData(); for (InstanceIdentifier dataObjectInstance : removals) { DataObject dataObject = change.getOriginalConfigurationData().get(dataObjectInstance); - + if(dataObject instanceof Flow){ InstanceIdentifier flowII = (InstanceIdentifier)dataObjectInstance; - InstanceIdentifier flowAugmentation = + InstanceIdentifier flowAugmentation = InstanceIdentifier.builder(flowII).augmentation(FlowStatisticsData.class).toInstance(); - removeAugmentedOperationalData(flowAugmentation); + it.removeOperationalData(flowAugmentation); } if(dataObject instanceof Meter){ InstanceIdentifier meterII = (InstanceIdentifier)dataObjectInstance; - - InstanceIdentifier nodeMeterConfigStatsAugmentation = + + InstanceIdentifier nodeMeterConfigStatsAugmentation = InstanceIdentifier.builder(meterII).augmentation(NodeMeterConfigStats.class).toInstance(); - removeAugmentedOperationalData(nodeMeterConfigStatsAugmentation); + it.removeOperationalData(nodeMeterConfigStatsAugmentation); - InstanceIdentifier nodeMeterStatisticsAugmentation = + InstanceIdentifier nodeMeterStatisticsAugmentation = InstanceIdentifier.builder(meterII).augmentation(NodeMeterStatistics.class).toInstance(); - removeAugmentedOperationalData(nodeMeterStatisticsAugmentation); + it.removeOperationalData(nodeMeterStatisticsAugmentation); } - + if(dataObject instanceof Group){ InstanceIdentifier groupII = (InstanceIdentifier)dataObjectInstance; - - InstanceIdentifier nodeGroupDescStatsAugmentation = + + InstanceIdentifier nodeGroupDescStatsAugmentation = InstanceIdentifier.builder(groupII).augmentation(NodeGroupDescStats.class).toInstance(); - removeAugmentedOperationalData(nodeGroupDescStatsAugmentation); + it.removeOperationalData(nodeGroupDescStatsAugmentation); - InstanceIdentifier nodeGroupStatisticsAugmentation = + InstanceIdentifier nodeGroupStatisticsAugmentation = InstanceIdentifier.builder(groupII).augmentation(NodeGroupStatistics.class).toInstance(); - removeAugmentedOperationalData(nodeGroupStatisticsAugmentation); + it.removeOperationalData(nodeGroupStatisticsAugmentation); } - + if(dataObject instanceof Queue){ InstanceIdentifier queueII = (InstanceIdentifier)dataObjectInstance; - - InstanceIdentifier nodeConnectorQueueStatisticsDataAugmentation = + + InstanceIdentifier nodeConnectorQueueStatisticsDataAugmentation = InstanceIdentifier.builder(queueII).augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance(); - removeAugmentedOperationalData(nodeConnectorQueueStatisticsDataAugmentation); + it.removeOperationalData(nodeConnectorQueueStatisticsDataAugmentation); } } - } - - private void removeAugmentedOperationalData(InstanceIdentifier dataObjectInstance ){ - if(dataObjectInstance != null){ - DataModificationTransaction it = this.statisticsManager.startChange(); - it.removeOperationalData(dataObjectInstance); - it.commit(); - } + it.commit(); } } diff --git a/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java index 5da6ef3490..bf523a433b 100644 --- a/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java +++ b/opendaylight/md-sal/statistics-manager/src/test/java/org/opendaylight/controller/md/statistics/manager/StatisticsUpdateCommiterTest.java @@ -17,15 +17,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * + * */ public class StatisticsUpdateCommiterTest { - + private static final Logger LOG = LoggerFactory .getLogger(StatisticsUpdateCommiterTest.class); /** - * Test method for {@link org.opendaylight.controller.md.statistics.manager.StatisticsUpdateCommiter#layer3MatchEquals(org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match, org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match)}. + * Test method for {@link org.opendaylight.controller.md.statistics.manager.StatisticsListener#layer3MatchEquals(org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match, org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match)}. */ @Test public void testLayer3MatchEquals() { @@ -34,45 +34,45 @@ public class StatisticsUpdateCommiterTest { {{"10.1.2.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.1.0/24"}}, {{"10.1.1.0/24", "10.1.2.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}}, {{"10.1.1.0/24", "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}}, - + {{"10.1.1.0/24", null}, {"10.1.1.0/24", "10.1.2.0/24"}}, {{"10.1.1.0/24", null}, {"10.1.2.0/24", "10.1.2.0/24"}}, {{"10.1.1.0/24", null}, {"10.1.2.0/24", null}}, {{"10.1.1.0/24", null}, {"10.1.1.0/24", null}}, - + {{null, "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.1.0/24"}}, {{null, "10.1.1.0/24"}, {"10.1.2.0/24", "10.1.2.0/24"}}, {{null, "10.1.1.0/24"}, {null, "10.1.2.0/24"}}, {{null, "10.1.1.0/24"}, {null, "10.1.1.0/24"}}, - + {{null, null}, {null, "10.1.1.0/24"}}, {{null, null}, {null, null}}, }; - + boolean[] matches = new boolean[] { - true, + true, false, false, false, - + false, false, false, true, - + false, false, false, true, - + false, true }; - + for (int i = 0; i < matches.length; i++) { checkComparisonOfL3Match( - matchSeeds[i][0][0], matchSeeds[i][0][1], - matchSeeds[i][1][0], matchSeeds[i][1][1], + matchSeeds[i][0][0], matchSeeds[i][0][1], + matchSeeds[i][1][0], matchSeeds[i][1][1], matches[i]); } } @@ -83,23 +83,23 @@ public class StatisticsUpdateCommiterTest { * @param m2Source match2 - src * @param msDestination match2 - dest * @param matches expected match output - * + * */ - private static void checkComparisonOfL3Match(String m1Source, String m1Destination, + private static void checkComparisonOfL3Match(String m1Source, String m1Destination, String m2Source, String msDestination, boolean matches) { Ipv4Match m1Layer3 = prepareIPv4Match(m1Source, m1Destination); Ipv4Match m2Layer3 = prepareIPv4Match(m2Source, msDestination); boolean comparisonResult; try { - comparisonResult = StatisticsUpdateCommiter.layer3MatchEquals(m1Layer3, m2Layer3); - Assert.assertEquals("failed to compare: "+m1Layer3+" vs. "+m2Layer3, + comparisonResult = FlowComparator.layer3MatchEquals(m1Layer3, m2Layer3); + Assert.assertEquals("failed to compare: "+m1Layer3+" vs. "+m2Layer3, matches, comparisonResult); } catch (Exception e) { LOG.error("failed to compare: {} vs. {}", m1Layer3, m2Layer3, e); Assert.fail(e.getMessage()); } } - + private static Ipv4Match prepareIPv4Match(String source, String destination) { Ipv4MatchBuilder ipv4MatchBuilder = new Ipv4MatchBuilder(); if (source != null) { @@ -108,7 +108,7 @@ public class StatisticsUpdateCommiterTest { if (destination != null) { ipv4MatchBuilder.setIpv4Destination(new Ipv4Prefix(destination)); } - + return ipv4MatchBuilder.build(); } diff --git a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java index 01d872d89c..460aec6ac6 100644 --- a/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java +++ b/opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java @@ -8,16 +8,27 @@ package org.opendaylight.controller.netconf.persist.impl; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import io.netty.channel.EventLoopGroup; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.annotation.concurrent.Immutable; + import org.opendaylight.controller.config.api.ConflictingVersionException; import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.client.NetconfClient; import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; import org.opendaylight.controller.netconf.util.NetconfUtil; -import org.opendaylight.controller.netconf.util.messages.NetconfMessageAdditionalHeader; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -27,20 +38,12 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import javax.annotation.concurrent.Immutable; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; +import com.google.common.base.Preconditions; +import io.netty.channel.EventLoopGroup; @Immutable public class ConfigPusher { - private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterNotificationHandler.class); + private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.class); private static final int NETCONF_SEND_ATTEMPT_MS_DELAY = 1000; private static final int NETCONF_SEND_ATTEMPTS = 20; @@ -59,7 +62,7 @@ public class ConfigPusher { } public ConfigPusher(InetSocketAddress address, EventLoopGroup nettyThreadGroup, - long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) { + long maxWaitForCapabilitiesMillis, long connectionTimeoutMillis) { this.address = address; this.nettyThreadGroup = nettyThreadGroup; this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis; @@ -129,8 +132,8 @@ public class ConfigPusher { final long deadlineNanos = pollingStartNanos + TimeUnit.MILLISECONDS.toNanos(maxWaitForCapabilitiesMillis); int attempt = 0; - String additionalHeader = NetconfMessageAdditionalHeader.toString("unknown", address.getAddress().getHostAddress(), - Integer.toString(address.getPort()), "tcp", Optional.of("persister")); + NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("unknown", address.getAddress().getHostAddress(), + Integer.toString(address.getPort()), "tcp", "persister"); Set latestCapabilities = null; while (System.nanoTime() < deadlineNanos) { @@ -224,13 +227,12 @@ public class ConfigPusher { NetconfMessage netconfMessage = netconfClient.sendMessage(request, NETCONF_SEND_ATTEMPTS, NETCONF_SEND_ATTEMPT_MS_DELAY); NetconfUtil.checkIsMessageOk(netconfMessage); return netconfMessage; - } catch (RuntimeException e) { // TODO: change NetconfClient#sendMessage to throw checked exceptions + } catch (RuntimeException | ExecutionException | InterruptedException | TimeoutException e) { logger.debug("Error while executing netconf transaction {} to {}", request, netconfClient, e); throw new IOException("Failed to execute netconf transaction", e); } } - // load editConfig.xml template, populate /rpc/edit-config/config with parameter private static NetconfMessage createEditConfigMessage(Element dataElement) { String editConfigResourcePath = "/netconfOp/editConfig.xml"; @@ -316,4 +318,4 @@ public class ConfigPusher { '}'; } } -} \ No newline at end of file +} diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java new file mode 100644 index 0000000000..bd75c27dd6 --- /dev/null +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java @@ -0,0 +1,86 @@ +/* + * 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.api; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; + +import java.io.IOException; + +import org.opendaylight.protocol.framework.AbstractProtocolSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractNetconfSession> extends AbstractProtocolSession implements NetconfSession { + private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSession.class); + private final L sessionListener; + private final long sessionId; + private boolean up = false; + + protected final Channel channel; + + protected AbstractNetconfSession(L sessionListener, Channel channel, long sessionId) { + this.sessionListener = sessionListener; + this.channel = channel; + this.sessionId = sessionId; + logger.debug("Session {} created", toString()); + } + + protected abstract S thisInstance(); + + @Override + public void close() { + channel.close(); + up = false; + sessionListener.onSessionTerminated(thisInstance(), new NetconfTerminationReason("Session closed")); + } + + @Override + protected void handleMessage(NetconfMessage netconfMessage) { + logger.debug("handling incoming message"); + sessionListener.onMessage(thisInstance(), netconfMessage); + } + + @Override + public ChannelFuture sendMessage(NetconfMessage netconfMessage) { + return channel.writeAndFlush(netconfMessage); + } + + @Override + protected void endOfInput() { + logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up" + : "initialized"); + if (isUp()) { + this.sessionListener.onSessionDown(thisInstance(), new IOException("End of input detected. Close the session.")); + } + } + + @Override + protected void sessionUp() { + logger.debug("Session {} up", toString()); + sessionListener.onSessionUp(thisInstance()); + this.up = true; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("ServerNetconfSession{"); + sb.append("sessionId=").append(sessionId); + sb.append('}'); + return sb.toString(); + } + + public final boolean isUp() { + return up; + } + + public final long getSessionId() { + return sessionId; + } +} + diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java index afca33328e..78586a3fec 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfMessage.java @@ -10,30 +10,18 @@ package org.opendaylight.controller.netconf.api; import org.w3c.dom.Document; -import com.google.common.base.Optional; - /** * NetconfMessage represents a wrapper around org.w3c.dom.Document. Needed for * implementing ProtocolMessage interface. */ -public final class NetconfMessage { - private final String additionalHeader; +public class NetconfMessage { private final Document doc; public NetconfMessage(final Document doc) { - this(doc, null); - } - - public NetconfMessage(Document doc, String additionalHeader) { this.doc = doc; - this.additionalHeader = additionalHeader; } public Document getDocument() { return this.doc; } - - public Optional getAdditionalHeader() { - return additionalHeader== null ? Optional.absent() : Optional.of(additionalHeader); - } } diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java index 4770cb128f..e52e71ceea 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java @@ -7,78 +7,10 @@ */ package org.opendaylight.controller.netconf.api; -import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; -import java.io.IOException; +import org.opendaylight.protocol.framework.ProtocolSession; -import org.opendaylight.protocol.framework.AbstractProtocolSession; -import org.opendaylight.protocol.framework.SessionListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class NetconfSession extends AbstractProtocolSession { - private static final Logger logger = LoggerFactory.getLogger(NetconfSession.class); - private final SessionListener sessionListener; - private final long sessionId; - private boolean up = false; - - protected final Channel channel; - - protected NetconfSession(SessionListener sessionListener, Channel channel, long sessionId) { - this.sessionListener = sessionListener; - this.channel = channel; - this.sessionId = sessionId; - logger.debug("Session {} created", toString()); - } - - @Override - public void close() { - channel.close(); - up = false; - sessionListener.onSessionTerminated(this, new NetconfTerminationReason("Session closed")); - } - - @Override - protected void handleMessage(NetconfMessage netconfMessage) { - logger.debug("handling incoming message"); - sessionListener.onMessage(this, netconfMessage); - } - - public ChannelFuture sendMessage(NetconfMessage netconfMessage) { - return channel.writeAndFlush(netconfMessage); - } - - @Override - protected void endOfInput() { - logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up" - : "initialized"); - if (isUp()) { - this.sessionListener.onSessionDown(this, new IOException("End of input detected. Close the session.")); - } - } - - @Override - protected void sessionUp() { - logger.debug("Session {} up", toString()); - sessionListener.onSessionUp(this); - this.up = true; - } - - @Override - public String toString() { - final StringBuffer sb = new StringBuffer("ServerNetconfSession{"); - sb.append("sessionId=").append(sessionId); - sb.append('}'); - return sb.toString(); - } - - public final boolean isUp() { - return up; - } - - public final long getSessionId() { - return sessionId; - } +public interface NetconfSession extends ProtocolSession { + ChannelFuture sendMessage(NetconfMessage message); } - diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSessionListener.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSessionListener.java index 54cb471604..0f7869d97a 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSessionListener.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSessionListener.java @@ -10,7 +10,6 @@ package org.opendaylight.controller.netconf.api; import org.opendaylight.protocol.framework.SessionListener; -public interface NetconfSessionListener extends - SessionListener { +public interface NetconfSessionListener extends SessionListener { } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java index 48109d1353..6ae966d1f7 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java @@ -15,7 +15,7 @@ import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; /** * Class extending {@link NetconfClientSessionListener} to provide notification capability. */ -public abstract class AbstractNetconfClientNotifySessionListener extends NetconfClientSessionListener { +public abstract class AbstractNetconfClientNotifySessionListener extends SimpleNetconfClientSessionListener { /* * Maybe some capabilities could be expressed as internal NetconfClientSessionListener handlers. * It would enable NetconfClient functionality to be extended by using namespace handlers. @@ -31,7 +31,7 @@ public abstract class AbstractNetconfClientNotifySessionListener extends Netconf * @param message {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)} */ @Override - public final synchronized void onMessage(NetconfClientSession session, NetconfMessage message) { + public final void onMessage(NetconfClientSession session, NetconfMessage message) { if (isNotification(message)) { onNotification(session, message); } else { diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java index b8951a4789..4cdca208bc 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java @@ -8,17 +8,8 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Preconditions; -import com.google.common.base.Stopwatch; -import com.google.common.collect.Sets; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GlobalEventExecutor; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.protocol.framework.NeverReconnectStrategy; -import org.opendaylight.protocol.framework.ReconnectStrategy; -import org.opendaylight.protocol.framework.TimedReconnectStrategy; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.Closeable; import java.io.IOException; @@ -27,7 +18,23 @@ 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.protocol.framework.NeverReconnectStrategy; +import org.opendaylight.protocol.framework.ReconnectStrategy; +import org.opendaylight.protocol.framework.TimedReconnectStrategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; +import com.google.common.collect.Sets; +/** + * @deprecated Use {@link NetconfClientDispatcher.createClient()} or {@link NetconfClientDispatcher.createReconnectingClient()} instead. + */ +@Deprecated public class NetconfClient implements Closeable { private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class); @@ -50,7 +57,7 @@ public class NetconfClient implements Closeable { private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException { this.label = clientLabelForLogging; dispatch = netconfClientDispatcher; - sessionListener = new NetconfClientSessionListener(); + sessionListener = new SimpleNetconfClientSessionListener(); Future clientFuture = dispatch.createClient(address, sessionListener, strat); this.address = address; clientSession = get(clientFuture); @@ -71,7 +78,8 @@ public class NetconfClient implements Closeable { return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher); } - public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher,NetconfClientSessionListener listener) throws InterruptedException { + public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, + ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException { return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher,listener); } @@ -98,25 +106,31 @@ public class NetconfClient implements Closeable { this.sessionId = clientSession.getSessionId(); } - public NetconfMessage sendMessage(NetconfMessage message) { + public Future sendRequest(NetconfMessage message) { + return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message); + } + + /** + * @deprecated Use {@link sendRequest} instead + */ + @Deprecated + public NetconfMessage sendMessage(NetconfMessage message) throws ExecutionException, InterruptedException, TimeoutException { return sendMessage(message, 5, 1000); } - public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) { - Stopwatch stopwatch = new Stopwatch().start(); - Preconditions.checkState(clientSession.isUp(), "Session was not up yet"); + /** + * @deprecated Use {@link sendRequest} instead + */ + @Deprecated + public NetconfMessage sendMessage(NetconfMessage message, int attempts, int attemptMsDelay) throws ExecutionException, InterruptedException, TimeoutException { //logger.debug("Sending message: {}",XmlUtil.toString(message.getDocument())); - clientSession.sendMessage(message); + final Stopwatch stopwatch = new Stopwatch().start(); + try { - return sessionListener.getLastMessage(attempts, attemptMsDelay); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException(this + " Cannot read message from " + address, e); - } catch (IllegalStateException e) { - throw new IllegalStateException(this + " Cannot read message from " + address, e); + return sendRequest(message).get(attempts * attemptMsDelay, TimeUnit.MILLISECONDS); } finally { stopwatch.stop(); - logger.debug("Total time spent waiting for response {} ms", stopwatch.elapsed(TimeUnit.MILLISECONDS)); + logger.debug("Total time spent waiting for response from {}: {} ms", address, stopwatch.elapsed(TimeUnit.MILLISECONDS)); } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java index 1228a84a8a..43664b3233 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java @@ -8,43 +8,47 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Optional; import io.netty.channel.EventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.util.HashedWheelTimer; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfSession; -import org.opendaylight.controller.netconf.api.NetconfTerminationReason; + +import java.io.Closeable; +import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.util.AbstractChannelInitializer; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.protocol.framework.AbstractDispatcher; import org.opendaylight.protocol.framework.ReconnectStrategy; -import org.opendaylight.protocol.framework.SessionListener; +import org.opendaylight.protocol.framework.ReconnectStrategyFactory; import org.opendaylight.protocol.framework.SessionListenerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.Closeable; -import java.net.InetSocketAddress; +import com.google.common.base.Optional; public class NetconfClientDispatcher extends AbstractDispatcher implements Closeable { - private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class); + private static final Logger logger = LoggerFactory.getLogger(NetconfClientDispatcher.class); - private final NetconfClientSessionNegotiatorFactory negotatorFactory; + private final NetconfClientSessionNegotiatorFactory negotiatorFactory; private final HashedWheelTimer timer; - public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, long clientConnectionTimeoutMillis) { + public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, + long clientConnectionTimeoutMillis) { super(bossGroup, workerGroup); timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.absent(), clientConnectionTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, + Optional. absent(), clientConnectionTimeoutMillis); } - public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, String additionalHeader, long connectionTimeoutMillis) { + public NetconfClientDispatcher(EventLoopGroup bossGroup, EventLoopGroup workerGroup, + NetconfHelloMessageAdditionalHeader additionalHeader, long connectionTimeoutMillis) { super(bossGroup, workerGroup); timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), connectionTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), + connectionTimeoutMillis); } public Future createClient(InetSocketAddress address, @@ -58,38 +62,54 @@ public class NetconfClientDispatcher extends AbstractDispatcher promise) { - new ClientChannelInitializer( negotatorFactory, sessionListener).initialize(ch, promise); + new ClientChannelInitializer(negotiatorFactory, sessionListener).initialize(ch, promise); } }); } - private static class ClientChannelInitializer extends AbstractChannelInitializer { + public Future createReconnectingClient(final InetSocketAddress address, + final NetconfClientSessionListener listener, + final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) { + final ClientChannelInitializer init = new ClientChannelInitializer(negotiatorFactory, listener); + + return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy, + new PipelineInitializer() { + @Override + public void initializeChannel(final SocketChannel ch, final Promise promise) { + init.initialize(ch, promise); + } + }); + } + + private static class ClientChannelInitializer extends AbstractChannelInitializer { private final NetconfClientSessionNegotiatorFactory negotiatorFactory; private final NetconfClientSessionListener sessionListener; private ClientChannelInitializer(NetconfClientSessionNegotiatorFactory negotiatorFactory, - NetconfClientSessionListener sessionListener) { + NetconfClientSessionListener sessionListener) { this.negotiatorFactory = negotiatorFactory; this.sessionListener = sessionListener; } @Override - public void initialize(SocketChannel ch, Promise promise) { + public void initialize(SocketChannel ch, Promise promise) { super.initialize(ch,promise); } @Override - protected void initializeAfterDecoder(SocketChannel ch, Promise promise) { - ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { - @Override - public SessionListener getSessionListener() { - return sessionListener; - } - }, ch, promise)); + protected void initializeSessionNegotiator(SocketChannel ch, Promise promise) { + ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, + negotiatorFactory.getSessionNegotiator( + new SessionListenerFactory() { + @Override + public NetconfClientSessionListener getSessionListener() { + return sessionListener; + } + }, ch, promise)); } - } + @Override public void close() { try { diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java index 5ee89fec40..2d07dd5833 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java @@ -12,19 +12,16 @@ import io.netty.channel.Channel; import java.util.Collection; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfSession; -import org.opendaylight.controller.netconf.api.NetconfTerminationReason; -import org.opendaylight.protocol.framework.SessionListener; +import org.opendaylight.controller.netconf.api.AbstractNetconfSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class NetconfClientSession extends NetconfSession { +public final class NetconfClientSession extends AbstractNetconfSession { private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class); private final Collection capabilities; - public NetconfClientSession(SessionListener sessionListener, Channel channel, long sessionId, + public NetconfClientSession(NetconfClientSessionListener sessionListener, Channel channel, long sessionId, Collection capabilities) { super(sessionListener,channel,sessionId); this.capabilities = capabilities; @@ -35,4 +32,8 @@ public class NetconfClientSession extends NetconfSession { return capabilities; } + @Override + protected NetconfClientSession thisInstance() { + return this; + } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java index d3c1b22c84..21be3a8cab 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java @@ -1,75 +1,14 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * 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.client; -import com.google.common.base.Preconditions; -import com.google.common.collect.Lists; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfTerminationReason; -import org.opendaylight.protocol.framework.SessionListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -public class NetconfClientSessionListener implements - SessionListener { - - private static final Logger logger = LoggerFactory.getLogger(NetconfClientSessionListener.class); - private AtomicBoolean up = new AtomicBoolean(false); - - @Override - public void onSessionUp(NetconfClientSession clientSession) { - up.set(true); - } - - @Override - public void onSessionDown(NetconfClientSession clientSession, Exception e) { - logger.debug("Client Session {} down, reason: {}", clientSession, e.getMessage()); - up.set(false); - } - - @Override - public void onSessionTerminated(NetconfClientSession clientSession, - NetconfTerminationReason netconfTerminationReason) { - logger.debug("Client Session {} terminated, reason: {}", clientSession, - netconfTerminationReason.getErrorMessage()); - up.set(false); - } - - @Override - public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) { - synchronized (messages) { - this.messages.add(message); - } - } - - private int lastReadMessage = -1; - private List messages = Lists.newArrayList(); - - public NetconfMessage getLastMessage(int attempts, int attemptMsDelay) throws InterruptedException { - Preconditions.checkState(up.get(), "Session was not up yet"); - - for (int i = 0; i < attempts; i++) { - synchronized (messages) { - if (messages.size() - 1 > lastReadMessage) { - lastReadMessage++; - return messages.get(lastReadMessage); - } - } +import org.opendaylight.controller.netconf.api.NetconfSessionListener; - if (up.get() == false) - throw new IllegalStateException("Session ended while trying to read message"); - Thread.sleep(attemptMsDelay); - } +public interface NetconfClientSessionListener extends NetconfSessionListener { - throw new IllegalStateException("No netconf message to read"); - } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java index 100b98c15a..c742bafe5e 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java @@ -8,33 +8,35 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Function; -import com.google.common.collect.Collections2; -import io.netty.channel.Channel; -import io.netty.util.Timer; -import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfMessage; +import java.util.Collection; +import java.util.List; + +import javax.annotation.Nullable; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; + import org.opendaylight.controller.netconf.api.NetconfSessionPreferences; import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; -import org.opendaylight.protocol.framework.SessionListener; import org.w3c.dom.Document; import org.w3c.dom.Node; -import javax.annotation.Nullable; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import java.util.Collection; -import java.util.List; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; + +import io.netty.channel.Channel; +import io.netty.util.Timer; +import io.netty.util.concurrent.Promise; public class NetconfClientSessionNegotiator extends - AbstractNetconfSessionNegotiator { + AbstractNetconfSessionNegotiator { protected NetconfClientSessionNegotiator(NetconfSessionPreferences sessionPreferences, - Promise promise, Channel channel, Timer timer, SessionListener sessionListener, + Promise promise, Channel channel, Timer timer, NetconfClientSessionListener sessionListener, long connectionTimeoutMillis) { super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis); } @@ -69,7 +71,7 @@ public class NetconfClientSessionNegotiator extends } @Override - protected NetconfClientSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) { + protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel, NetconfHelloMessage message) { return new NetconfClientSession(sessionListener, channel, extractSessionId(message.getDocument()), getCapabilities(message.getDocument())); } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java index db6c024e5a..bb372b3aff 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java @@ -8,31 +8,34 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; import io.netty.channel.Channel; import io.netty.util.Timer; import io.netty.util.concurrent.Promise; + +import java.io.IOException; +import java.io.InputStream; + import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfSessionPreferences; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.opendaylight.protocol.framework.SessionListenerFactory; import org.opendaylight.protocol.framework.SessionNegotiator; import org.opendaylight.protocol.framework.SessionNegotiatorFactory; import org.xml.sax.SAXException; -import java.io.IOException; -import java.io.InputStream; - -public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory { +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; - private final Timer timer; +public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory { - private final Optional additionalHeader; + private final Optional additionalHeader; private final long connectionTimeoutMillis; + private final Timer timer; - public NetconfClientSessionNegotiatorFactory(Timer timer, Optional additionalHeader, long connectionTimeoutMillis) { - this.timer = timer; + public NetconfClientSessionNegotiatorFactory(Timer timer, Optional additionalHeader, long connectionTimeoutMillis) { + this.timer = Preconditions.checkNotNull(timer); this.additionalHeader = additionalHeader; this.connectionTimeoutMillis = connectionTimeoutMillis; } @@ -48,16 +51,18 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF } @Override - public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel, - Promise promise) { + public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel, + Promise promise) { // Hello message needs to be recreated every time NetconfMessage helloMessage = loadHelloMessageTemplate(); + if(this.additionalHeader.isPresent()) { - helloMessage = new NetconfMessage(helloMessage.getDocument(), additionalHeader.get()); - } + helloMessage = new NetconfHelloMessage(helloMessage.getDocument(), additionalHeader.get()); + } else + helloMessage = new NetconfHelloMessage(helloMessage.getDocument()); + NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage); return new NetconfClientSessionNegotiator(proposal, promise, channel, timer, sessionListenerFactory.getSessionListener(), connectionTimeoutMillis); } - } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java index c1d5b2bdf7..5b82ff2215 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java @@ -17,15 +17,13 @@ import io.netty.util.concurrent.Promise; import java.io.IOException; import java.net.InetSocketAddress; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfSession; -import org.opendaylight.controller.netconf.api.NetconfTerminationReason; import org.opendaylight.controller.netconf.util.AbstractChannelInitializer; import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler; import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler; import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.protocol.framework.ReconnectStrategy; -import org.opendaylight.protocol.framework.SessionListener; +import org.opendaylight.protocol.framework.ReconnectStrategyFactory; import org.opendaylight.protocol.framework.SessionListenerFactory; import com.google.common.base.Optional; @@ -34,22 +32,24 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { private final AuthenticationHandler authHandler; private final HashedWheelTimer timer; - private final NetconfClientSessionNegotiatorFactory negotatorFactory; + private final NetconfClientSessionNegotiatorFactory negotiatorFactory; public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup, EventLoopGroup workerGroup, long connectionTimeoutMillis) { super(bossGroup, workerGroup, connectionTimeoutMillis); this.authHandler = authHandler; this.timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.absent(), connectionTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, + Optional. absent(), connectionTimeoutMillis); } public NetconfSshClientDispatcher(AuthenticationHandler authHandler, EventLoopGroup bossGroup, - EventLoopGroup workerGroup, String additionalHeader, long socketTimeoutMillis) { + EventLoopGroup workerGroup, NetconfHelloMessageAdditionalHeader additionalHeader, long socketTimeoutMillis) { super(bossGroup, workerGroup, additionalHeader, socketTimeoutMillis); this.authHandler = authHandler; this.timer = new HashedWheelTimer(); - this.negotatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), socketTimeoutMillis); + this.negotiatorFactory = new NetconfClientSessionNegotiatorFactory(timer, Optional.of(additionalHeader), + socketTimeoutMillis); } @Override @@ -59,13 +59,28 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { @Override public void initializeChannel(SocketChannel arg0, Promise arg1) { - new NetconfSshClientInitializer(authHandler, negotatorFactory, sessionListener).initialize(arg0, arg1); + new NetconfSshClientInitializer(authHandler, negotiatorFactory, sessionListener).initialize(arg0, arg1); } }); } - private static final class NetconfSshClientInitializer extends AbstractChannelInitializer { + @Override + public Future createReconnectingClient(final InetSocketAddress address, + final NetconfClientSessionListener listener, + final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) { + final NetconfSshClientInitializer init = new NetconfSshClientInitializer(authHandler, negotiatorFactory, listener); + + return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy, + new PipelineInitializer() { + @Override + public void initializeChannel(final SocketChannel ch, final Promise promise) { + init.initialize(ch, promise); + } + }); + } + + private static final class NetconfSshClientInitializer extends AbstractChannelInitializer { private final AuthenticationHandler authenticationHandler; private final NetconfClientSessionNegotiatorFactory negotiatorFactory; @@ -80,7 +95,7 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { } @Override - public void initialize(SocketChannel ch, Promise promise) { + public void initialize(SocketChannel ch, Promise promise) { try { Invoker invoker = Invoker.subsystem("netconf"); ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker)); @@ -91,14 +106,15 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher { } @Override - protected void initializeAfterDecoder(SocketChannel ch, Promise promise) { - ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { + protected void initializeSessionNegotiator(SocketChannel ch, + Promise promise) { + ch.pipeline().addAfter(NETCONF_MESSAGE_DECODER, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, + negotiatorFactory.getSessionNegotiator(new SessionListenerFactory() { @Override - public SessionListener getSessionListener() { + public NetconfClientSessionListener getSessionListener() { return sessionListener; } }, ch, promise)); - } } } diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java new file mode 100644 index 0000000000..e96161c29a --- /dev/null +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java @@ -0,0 +1,114 @@ +/* + * 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.client; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GlobalEventExecutor; +import io.netty.util.concurrent.Promise; + +import java.util.ArrayDeque; +import java.util.Queue; + +import javax.annotation.concurrent.GuardedBy; + +import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.api.NetconfTerminationReason; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; + +public class SimpleNetconfClientSessionListener implements NetconfClientSessionListener { + private static final class RequestEntry { + final Promise promise; + final NetconfMessage request; + + public RequestEntry(Promise future, NetconfMessage request) { + this.promise = Preconditions.checkNotNull(future); + this.request = Preconditions.checkNotNull(request); + } + } + + private static final Logger logger = LoggerFactory.getLogger(SimpleNetconfClientSessionListener.class); + + @GuardedBy("this") + private final Queue requests = new ArrayDeque<>(); + + @GuardedBy("this") + private NetconfClientSession clientSession; + + @GuardedBy("this") + private void dispatchRequest() { + while (!requests.isEmpty()) { + final RequestEntry e = requests.peek(); + if (e.promise.setUncancellable()) { + logger.debug("Sending message {}", e.request); + clientSession.sendMessage(e.request); + break; + } + + logger.debug("Message {} has been cancelled, skipping it", e.request); + requests.poll(); + } + } + + @Override + public final synchronized void onSessionUp(NetconfClientSession clientSession) { + this.clientSession = Preconditions.checkNotNull(clientSession); + logger.debug("Client session {} went up", clientSession); + dispatchRequest(); + } + + private synchronized void tearDown(final Exception cause) { + final RequestEntry e = requests.poll(); + if (e != null) { + e.promise.setFailure(cause); + } + + this.clientSession = null; + } + + @Override + public final void onSessionDown(NetconfClientSession clientSession, Exception e) { + logger.debug("Client Session {} went down unexpectedly", clientSession, e); + tearDown(e); + } + + @Override + public final void onSessionTerminated(NetconfClientSession clientSession, + NetconfTerminationReason netconfTerminationReason) { + logger.debug("Client Session {} terminated, reason: {}", clientSession, + netconfTerminationReason.getErrorMessage()); + tearDown(new RuntimeException(netconfTerminationReason.getErrorMessage())); + } + + @Override + public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) { + logger.debug("New message arrived: {}", message); + + final RequestEntry e = requests.poll(); + if (e != null) { + e.promise.setSuccess(message); + dispatchRequest(); + } else { + logger.info("Ignoring unsolicited message {}", message); + } + } + + final synchronized Future sendRequest(NetconfMessage message) { + final RequestEntry req = new RequestEntry(GlobalEventExecutor.INSTANCE.newPromise(), message); + + requests.add(req); + if (clientSession != null) { + dispatchRequest(); + } + + return req.promise; + } +} 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 7c5bd0cb21..ee9009762e 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 @@ -12,14 +12,14 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfSession; + +import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.impl.util.DeserializerExceptionHandler; import org.opendaylight.controller.netconf.util.AbstractChannelInitializer; import org.opendaylight.protocol.framework.AbstractDispatcher; -import java.net.InetSocketAddress; - -public class NetconfServerDispatcher extends AbstractDispatcher { +public class NetconfServerDispatcher extends AbstractDispatcher { private final ServerChannelInitializer initializer; @@ -31,15 +31,17 @@ public class NetconfServerDispatcher extends AbstractDispatcher() { + return super.createServer(address, new PipelineInitializer() { @Override - public void initializeChannel(final SocketChannel ch, final Promise promise) { + public void initializeChannel(final SocketChannel ch, final Promise promise) { initializer.initialize(ch, promise); } }); } - public static class ServerChannelInitializer extends AbstractChannelInitializer { + public static class ServerChannelInitializer extends AbstractChannelInitializer { + + public static final String DESERIALIZER_EX_HANDLER_KEY = "deserializerExHandler"; private final NetconfServerSessionNegotiatorFactory negotiatorFactory; private final NetconfServerSessionListenerFactory listenerFactory; @@ -51,11 +53,15 @@ public class NetconfServerDispatcher extends AbstractDispatcher promise) { - ch.pipeline().addLast("deserializerExHandler", new DeserializerExceptionHandler()); - ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise)); + protected void initializeMessageDecoder(SocketChannel ch) { + super.initializeMessageDecoder(ch); + ch.pipeline().addLast(DESERIALIZER_EX_HANDLER_KEY, new DeserializerExceptionHandler()); } + @Override + protected void initializeSessionNegotiator(SocketChannel ch, Promise promise) { + ch.pipeline().addAfter(DESERIALIZER_EX_HANDLER_KEY, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise)); + } } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java index 1d22fa050b..9ddc64f1a1 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java @@ -15,11 +15,9 @@ import java.util.Date; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfSession; -import org.opendaylight.controller.netconf.api.NetconfTerminationReason; +import org.opendaylight.controller.netconf.api.AbstractNetconfSession; import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; -import org.opendaylight.protocol.framework.SessionListener; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp; @@ -37,17 +35,17 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; -public class NetconfServerSession extends NetconfSession implements NetconfManagementSession { +public final class NetconfServerSession extends AbstractNetconfSession implements NetconfManagementSession { private static final Logger logger = LoggerFactory.getLogger(NetconfServerSession.class); - private final NetconfServerSessionNegotiator.AdditionalHeader header; + private final NetconfHelloMessageAdditionalHeader header; private Date loginTime; private long inRpcSuccess, inRpcFail, outRpcError; - public NetconfServerSession(SessionListener sessionListener, Channel channel, long sessionId, - NetconfServerSessionNegotiator.AdditionalHeader header) { + public NetconfServerSession(NetconfServerSessionListener sessionListener, Channel channel, long sessionId, + NetconfHelloMessageAdditionalHeader header) { super(sessionListener, channel, sessionId); this.header = header; logger.debug("Session {} created", toString()); @@ -74,6 +72,9 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag public static final String ISO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + private static final String dateTimePatternString = DateAndTime.PATTERN_CONSTANTS.get(0); + private static final Pattern dateTimePattern = Pattern.compile(dateTimePatternString); + @Override public Session toManagementSession() { SessionBuilder builder = new SessionBuilder(); @@ -83,16 +84,16 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag Preconditions.checkState(DateAndTime.PATTERN_CONSTANTS.size() == 1); String formattedDateTime = formatDateTime(loginTime); - String pattern = DateAndTime.PATTERN_CONSTANTS.get(0); - Matcher matcher = Pattern.compile(pattern).matcher(formattedDateTime); - Preconditions.checkState(matcher.matches(), "Formatted datetime %s does not match pattern %s", formattedDateTime, pattern); + + Matcher matcher = dateTimePattern.matcher(formattedDateTime); + Preconditions.checkState(matcher.matches(), "Formatted datetime %s does not match pattern %s", formattedDateTime, dateTimePattern); builder.setLoginTime(new DateAndTime(formattedDateTime)); builder.setInBadRpcs(new ZeroBasedCounter32(inRpcFail)); builder.setInRpcs(new ZeroBasedCounter32(inRpcSuccess)); builder.setOutRpcErrors(new ZeroBasedCounter32(outRpcError)); - builder.setUsername(header.getUsername()); + builder.setUsername(header.getUserName()); builder.setTransport(getTransportForString(header.getTransport())); builder.setOutNotifications(new ZeroBasedCounter32(0L)); @@ -100,7 +101,7 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag builder.setKey(new SessionKey(getSessionId())); Session1Builder builder1 = new Session1Builder(); - builder1.setSessionIdentifier(header.getSessionType()); + builder1.setSessionIdentifier(header.getSessionIdentifier()); builder.addAugmentation(Session1.class, builder1.build()); return builder.build(); @@ -108,9 +109,9 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag private Class getTransportForString(String transport) { switch(transport) { - case "ssh" : return NetconfSsh.class; - case "tcp" : return NetconfTcp.class; - default: throw new IllegalArgumentException("Unknown transport type " + transport); + case "ssh" : return NetconfSsh.class; + case "tcp" : return NetconfTcp.class; + default: throw new IllegalArgumentException("Unknown transport type " + transport); } } @@ -119,4 +120,8 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag return dateFormat.format(loginTime); } + @Override + protected NetconfServerSession thisInstance() { + return this; + } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java index 43e55d746a..460288fe33 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionListener.java @@ -8,10 +8,11 @@ package org.opendaylight.controller.netconf.impl; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableMap; +import static com.google.common.base.Preconditions.checkState; + import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.api.NetconfSessionListener; import org.opendaylight.controller.netconf.api.NetconfTerminationReason; import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl; import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService; @@ -19,25 +20,22 @@ import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; -import org.opendaylight.protocol.framework.SessionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; -import static com.google.common.base.Preconditions.checkState; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; -public class NetconfServerSessionListener implements - SessionListener { +public class NetconfServerSessionListener implements NetconfSessionListener { + public static final String MESSAGE_ID = "message-id"; static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionListener.class); - public static final String MESSAGE_ID = "message-id"; private final SessionMonitoringService monitoringService; + private final NetconfOperationRouterImpl operationRouter; - private NetconfOperationRouterImpl operationRouter; - - public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter, - SessionMonitoringService monitoringService) { + public NetconfServerSessionListener(NetconfOperationRouterImpl operationRouter, SessionMonitoringService monitoringService) { this.operationRouter = operationRouter; this.monitoringService = monitoringService; } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java index 91555861dc..1b4dfff42b 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java @@ -8,86 +8,48 @@ package org.opendaylight.controller.netconf.impl; -import com.google.common.base.Optional; -import io.netty.channel.Channel; -import io.netty.util.Timer; -import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfMessage; +import java.net.InetSocketAddress; + import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences; -import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil; import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator; -import org.opendaylight.protocol.framework.SessionListener; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetSocketAddress; +import com.google.common.base.Optional; + +import io.netty.channel.Channel; +import io.netty.util.Timer; +import io.netty.util.concurrent.Promise; public class NetconfServerSessionNegotiator extends - AbstractNetconfSessionNegotiator { + AbstractNetconfSessionNegotiator { static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class); protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences, - Promise promise, Channel channel, Timer timer, SessionListener sessionListener, + Promise promise, Channel channel, Timer timer, NetconfServerSessionListener sessionListener, long connectionTimeoutMillis) { super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis); } @Override - protected NetconfServerSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) { - Optional additionalHeader = message.getAdditionalHeader(); + protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfHelloMessage message) { + Optional additionalHeader = message.getAdditionalHeader(); - AdditionalHeader parsedHeader; + NetconfHelloMessageAdditionalHeader parsedHeader; if (additionalHeader.isPresent()) { - parsedHeader = AdditionalHeaderUtil.fromString(additionalHeader.get()); + parsedHeader = additionalHeader.get(); } else { - parsedHeader = new AdditionalHeader("unknown", ((InetSocketAddress)channel.localAddress()).getHostString(), + InetSocketAddress inetSocketAddress = (InetSocketAddress) channel.localAddress(); + parsedHeader = new NetconfHelloMessageAdditionalHeader("unknown", inetSocketAddress.getHostString(), Integer.toString(inetSocketAddress.getPort()), "tcp", "client"); } + logger.debug("Additional header from hello parsed as {} from {}", parsedHeader, additionalHeader); return new NetconfServerSession(sessionListener, channel, sessionPreferences.getSessionId(), parsedHeader); } - public static class AdditionalHeader { - - private final String username; - private final String address; - private final String transport; - private final String sessionIdentifier; - - public AdditionalHeader(String userName, String hostAddress, String transport, String sessionIdentifier) { - this.address = hostAddress; - this.username = userName; - this.transport = transport; - this.sessionIdentifier = sessionIdentifier; - } - - String getUsername() { - return username; - } - - String getAddress() { - return address; - } - - String getTransport() { - return transport; - } - - String getSessionType() { - return sessionIdentifier; - } - - @Override - public String toString() { - final StringBuffer sb = new StringBuffer("AdditionalHeader{"); - sb.append("username='").append(username).append('\''); - sb.append(", address='").append(address).append('\''); - sb.append(", transport='").append(transport).append('\''); - sb.append('}'); - return sb.toString(); - } - } - -} + } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java index 98462b8025..e052f61cc9 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java @@ -12,11 +12,11 @@ import com.google.common.base.Preconditions; import io.netty.channel.Channel; import io.netty.util.Timer; import io.netty.util.concurrent.Promise; -import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences; import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider; import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener; import org.opendaylight.controller.netconf.util.NetconfUtil; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil; import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -31,7 +31,7 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import java.io.InputStream; -public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory { +public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory { public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml"; @@ -59,8 +59,8 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF } @Override - public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel, - Promise promise) { + public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel, + Promise promise) { long sessionId = idProvider.getNextSessionId(); NetconfServerSessionPreferences proposal = new NetconfServerSessionPreferences(createHelloMessage(sessionId), @@ -74,7 +74,7 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF private static final XPathExpression capabilitiesXPath = XMLNetconfUtil .compileXPath("/netconf:hello/netconf:capabilities"); - private NetconfMessage createHelloMessage(long sessionId) { + private NetconfHelloMessage createHelloMessage(long sessionId) { Document helloMessageTemplate = getHelloTemplateClone(); // change session ID @@ -93,10 +93,10 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF capabilityElement.setTextContent(capability); capabilitiesElement.appendChild(capabilityElement); } - return new NetconfMessage(helloMessageTemplate); + return new NetconfHelloMessage(helloMessageTemplate); } private synchronized Document getHelloTemplateClone() { - return (Document) this.helloMessageTemplate.cloneNode(true); + return (Document) helloMessageTemplate.cloneNode(true); } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java index cc503f60c3..1438515f04 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultCloseSession.java @@ -8,10 +8,8 @@ package org.opendaylight.controller.netconf.impl.mapping.operations; -import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfOperationRouter; -import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation; import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; @@ -19,9 +17,8 @@ import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.w3c.dom.Document; import org.w3c.dom.Element; -public class DefaultCloseSession extends AbstractNetconfOperation implements DefaultNetconfOperation { +public class DefaultCloseSession extends AbstractNetconfOperation { public static final String CLOSE_SESSION = "close-session"; - private NetconfSession netconfSession; public DefaultCloseSession(String netconfSessionIdForReporting) { super(netconfSessionIdForReporting); @@ -48,13 +45,4 @@ public class DefaultCloseSession extends AbstractNetconfOperation implements Def opRouter.close(); return document.createElement(XmlNetconfConstants.OK); } - - @Override - public void setNetconfSession(NetconfSession s) { - this.netconfSession = s; - } - - public NetconfSession getNetconfSession() { - return netconfSession; - } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java index f34529d53f..904f3f613e 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/mapping/operations/DefaultGetSchema.java @@ -11,11 +11,9 @@ package org.opendaylight.controller.netconf.impl.mapping.operations; import java.util.HashMap; import java.util.Map; -import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfOperationRouter; import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider; -import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation; import org.opendaylight.controller.netconf.mapping.api.HandlingPriority; import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; @@ -29,22 +27,19 @@ import org.w3c.dom.Element; import com.google.common.base.Optional; import com.google.common.collect.Maps; -public final class DefaultGetSchema extends AbstractNetconfOperation implements DefaultNetconfOperation { - - private final CapabilityProvider cap; - private NetconfSession netconfSession; +public final class DefaultGetSchema extends AbstractNetconfOperation { + public static final String GET_SCHEMA = "get-schema"; + public static final String IDENTIFIER = "identifier"; + public static final String VERSION = "version"; private static final Logger logger = LoggerFactory.getLogger(DefaultGetSchema.class); + private final CapabilityProvider cap; public DefaultGetSchema(CapabilityProvider cap, String netconfSessionIdForReporting) { super(netconfSessionIdForReporting); this.cap = cap; } - public static final String GET_SCHEMA = "get-schema"; - public static final String IDENTIFIER = "identifier"; - public static final String VERSION = "version"; - @Override protected HandlingPriority canHandle(String netconfOperationName, String namespace) { if (netconfOperationName.equals("get-schema") == false) @@ -117,15 +112,6 @@ public final class DefaultGetSchema extends AbstractNetconfOperation implements } else { version = Optional.absent(); } - } } - - public void setNetconfSession(NetconfSession s) { - this.netconfSession = s; - } - - public NetconfSession getNetconfSession() { - return netconfSession; - } } diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java index d70a15c18b..ece9d47ee9 100644 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java +++ b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java @@ -7,12 +7,18 @@ */ package org.opendaylight.controller.netconf.impl.osgi; -import com.google.common.base.Preconditions; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import org.opendaylight.controller.netconf.api.NetconfSession; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + import org.opendaylight.controller.netconf.api.NetconfDocumentedException; import org.opendaylight.controller.netconf.api.NetconfOperationRouter; +import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer; import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider; import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession; @@ -31,14 +37,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; public class NetconfOperationRouterImpl implements NetconfOperationRouter { @@ -55,24 +56,19 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter { public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot, CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) { - this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot; + this.netconfOperationServiceSnapshot = Preconditions.checkNotNull(netconfOperationServiceSnapshot); + this.capabilityProvider = Preconditions.checkNotNull(capabilityProvider); - this.capabilityProvider = capabilityProvider; - - Set defaultNetconfOperations = Sets.newHashSet(); - defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, netconfOperationServiceSnapshot - .getNetconfSessionIdForReporting())); - defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot - .getNetconfSessionIdForReporting())); - defaultNetconfOperations.add(new DefaultStartExi(netconfOperationServiceSnapshot - .getNetconfSessionIdForReporting())); - defaultNetconfOperations.add(new DefaultStopExi(netconfOperationServiceSnapshot - .getNetconfSessionIdForReporting())); + final String sessionId = netconfOperationServiceSnapshot.getNetconfSessionIdForReporting(); + final Set defaultNetconfOperations = Sets.newHashSet(); + defaultNetconfOperations.add(new DefaultGetSchema(capabilityProvider, sessionId)); + defaultNetconfOperations.add(new DefaultCloseSession(sessionId)); + defaultNetconfOperations.add(new DefaultStartExi(sessionId)); + defaultNetconfOperations.add(new DefaultStopExi(sessionId)); allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot); - DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider, - netconfOperationServiceSnapshot.getNetconfSessionIdForReporting()); + DefaultCommit defaultCommit = new DefaultCommit(commitNotifier, capabilityProvider, sessionId); Set defaultFilters = Sets. newHashSet(defaultCommit); allSortedFilters = getAllNetconfFilters(defaultFilters, netconfOperationServiceSnapshot); } @@ -238,10 +234,6 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter { private class NetconfOperationExecution implements NetconfOperationFilterChain { private final NetconfOperation operationWithHighestPriority; - private NetconfOperationExecution(NetconfOperation operationWithHighestPriority) { - this.operationWithHighestPriority = operationWithHighestPriority; - } - public NetconfOperationExecution(TreeMap> sortedPriority, HandlingPriority highestFoundPriority) { operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next(); diff --git a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java b/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java deleted file mode 100644 index 5c630dd343..0000000000 --- a/opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/util/AdditionalHeaderUtil.java +++ /dev/null @@ -1,41 +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.impl.util; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiator.AdditionalHeader; - -import com.google.common.base.Preconditions; - -public class AdditionalHeaderUtil { - - private static final Pattern pattern = Pattern - .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+)[^\\]]+\\]"); - private static final Pattern customHeaderPattern = Pattern - .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+);(?[a-z]+)[^\\]]+\\]"); - - public static AdditionalHeader fromString(String additionalHeader) { - additionalHeader = additionalHeader.trim(); - Matcher matcher = pattern.matcher(additionalHeader); - Matcher matcher2 = customHeaderPattern.matcher(additionalHeader); - Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s", - additionalHeader, pattern); - String username = matcher.group("username"); - String address = matcher.group("address"); - String transport = matcher.group("transport"); - String sessionIdentifier = "client"; - if (matcher2.matches()) { - sessionIdentifier = matcher2.group("sessionIdentifier"); - } - return new AdditionalHeader(username, address, transport, sessionIdentifier); - } - -} diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java index 97d9a98b57..c2dcd67921 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/AdditionalHeaderParserTest.java @@ -10,15 +10,15 @@ package org.opendaylight.controller.netconf.impl; import junit.framework.Assert; import org.junit.Test; -import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; public class AdditionalHeaderParserTest { @Test public void testParsing() throws Exception { String s = "[netconf;10.12.0.102:48528;ssh;;;;;;]"; - NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s); - Assert.assertEquals("netconf", header.getUsername()); + NetconfHelloMessageAdditionalHeader header = NetconfHelloMessageAdditionalHeader.fromString(s); + Assert.assertEquals("netconf", header.getUserName()); Assert.assertEquals("10.12.0.102", header.getAddress()); Assert.assertEquals("ssh", header.getTransport()); } @@ -26,8 +26,8 @@ public class AdditionalHeaderParserTest { @Test public void testParsing2() throws Exception { String s = "[tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]"; - NetconfServerSessionNegotiator.AdditionalHeader header = AdditionalHeaderUtil.fromString(s); - Assert.assertEquals("tomas", header.getUsername()); + NetconfHelloMessageAdditionalHeader header = NetconfHelloMessageAdditionalHeader.fromString(s); + Assert.assertEquals("tomas", header.getUserName()); Assert.assertEquals("10.0.0.0", header.getAddress()); Assert.assertEquals("tcp", header.getTransport()); } @@ -35,6 +35,6 @@ public class AdditionalHeaderParserTest { @Test(expected = IllegalArgumentException.class) public void testParsingNoUsername() throws Exception { String s = "[10.12.0.102:48528;ssh;;;;;;]"; - AdditionalHeaderUtil.fromString(s); + NetconfHelloMessageAdditionalHeader.fromString(s); } } diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java index 0ef2c285e4..c0d52ad85e 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/ConcurrentClientsTest.java @@ -37,6 +37,7 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperation; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; import org.opendaylight.controller.netconf.util.test.XmlFileLoader; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; @@ -100,7 +101,8 @@ public class ConcurrentClientsTest { } nettyGroup = new NioEventLoopGroup(); - netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, 5000); + NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp", "client"); + netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, additionalHeader, 5000); NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl(); factoriesListener.onAddNetconfOperationServiceFactory(mockOpF()); 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 954da5f487..fce3f70e73 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,12 +8,33 @@ package org.opendaylight.controller.netconf.it; -import ch.ethz.ssh2.Connection; -import ch.ethz.ssh2.Session; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import static java.util.Collections.emptyList; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import io.netty.channel.ChannelFuture; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.management.ManagementFactory; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +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 junit.framework.Assert; + import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -52,26 +73,11 @@ import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.SAXException; -import javax.management.ObjectName; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.InputStream; -import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.Session; -import static java.util.Collections.emptyList; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertTrue; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; public class NetconfITTest extends AbstractNetconfConfigTest { @@ -85,7 +91,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { private static final String PASSWORD = "netconf"; private NetconfMessage getConfig, getConfigCandidate, editConfig, - closeSession, startExi, stopExi; + closeSession, startExi, stopExi; private DefaultCommitNotificationProducer commitNot; private NetconfServerDispatcher dispatch; @@ -304,7 +310,7 @@ public class NetconfITTest extends AbstractNetconfConfigTest { } } - */ + */ @Test public void testCloseSession() throws Exception { @@ -350,12 +356,12 @@ public class NetconfITTest extends AbstractNetconfConfigTest { assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName()); } - private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException { + private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException { return assertGetConfigWorks(netconfClient, this.getConfig); } private Document assertGetConfigWorks(final NetconfClient netconfClient, final NetconfMessage getConfigMessage) - throws InterruptedException { + throws InterruptedException, ExecutionException, TimeoutException { final NetconfMessage rpcReply = netconfClient.sendMessage(getConfigMessage); assertNotNull(rpcReply); assertEquals("data", XmlElement.fromDomDocument(rpcReply.getDocument()).getOnlyChildElement().getName()); @@ -423,19 +429,20 @@ public class NetconfITTest extends AbstractNetconfConfigTest { sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes()); new Thread(){ - public void run(){ - while (true){ - byte[] bytes = new byte[1024]; - int c = 0; - try { - c = sess.getStdout().read(bytes); - } catch (IOException e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - logger.info("got data:"+bytes); - if (c == 0) break; - } - } + @Override + public void run(){ + while (true){ + byte[] bytes = new byte[1024]; + int c = 0; + try { + c = sess.getStdout().read(bytes); + } catch (IOException e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } + logger.info("got data:"+bytes); + if (c == 0) break; + } + } }.join(); } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java index 5b4b3d02ea..0910d9403a 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java @@ -13,21 +13,44 @@ import io.netty.util.concurrent.Promise; import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory; +import org.opendaylight.controller.netconf.util.handler.NetconfHelloMessageToXMLEncoder; import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator; -import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder; -import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder; +import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder; import org.opendaylight.controller.netconf.util.messages.FramingMechanism; -public abstract class AbstractChannelInitializer { +public abstract class AbstractChannelInitializer { - public void initialize(SocketChannel ch, Promise promise){ - ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM)); - ch.pipeline().addLast(new NetconfXMLToMessageDecoder()); - initializeAfterDecoder(ch, promise); - ch.pipeline().addLast("frameEncoder", FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM)); - ch.pipeline().addLast(new NetconfMessageToXMLEncoder()); + public static final String NETCONF_MESSAGE_DECODER = "netconfMessageDecoder"; + public static final String NETCONF_MESSAGE_AGGREGATOR = "aggregator"; + public static final String NETCONF_MESSAGE_ENCODER = "netconfMessageEncoder"; + public static final String NETCONF_MESSAGE_FRAME_ENCODER = "frameEncoder"; + public static final String NETCONF_SESSION_NEGOTIATOR = "negotiator"; + + public void initialize(SocketChannel ch, Promise promise) { + ch.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfMessageAggregator(FramingMechanism.EOM)); + initializeMessageDecoder(ch); + ch.pipeline().addLast(NETCONF_MESSAGE_FRAME_ENCODER, FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM)); + initializeMessageEncoder(ch); + + initializeSessionNegotiator(ch, promise); + } + + protected void initializeMessageEncoder(SocketChannel 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) { + // 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()); } - protected abstract void initializeAfterDecoder(SocketChannel ch, Promise promise); + /** + * 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); } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java index a485a4ea94..9986b82bd8 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java @@ -8,46 +8,50 @@ package org.opendaylight.controller.netconf.util; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.ssl.SslHandler; -import io.netty.util.Timeout; -import io.netty.util.Timer; -import io.netty.util.TimerTask; -import io.netty.util.concurrent.Future; -import io.netty.util.concurrent.GenericFutureListener; -import io.netty.util.concurrent.Promise; +import java.util.concurrent.TimeUnit; + +import org.opendaylight.controller.netconf.api.AbstractNetconfSession; import org.opendaylight.controller.netconf.api.NetconfMessage; -import org.opendaylight.controller.netconf.api.NetconfSession; +import org.opendaylight.controller.netconf.api.NetconfSessionListener; import org.opendaylight.controller.netconf.api.NetconfSessionPreferences; import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory; +import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator; import org.opendaylight.controller.netconf.util.handler.NetconfMessageChunkDecoder; +import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncoder; +import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder; import org.opendaylight.controller.netconf.util.messages.FramingMechanism; -import org.opendaylight.controller.netconf.util.xml.XmlElement; -import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.opendaylight.protocol.framework.AbstractSessionNegotiator; -import org.opendaylight.protocol.framework.SessionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; -import java.util.concurrent.TimeUnit; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.ssl.SslHandler; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import io.netty.util.concurrent.Promise; -public abstract class AbstractNetconfSessionNegotiator

- extends AbstractSessionNegotiator { +public abstract class AbstractNetconfSessionNegotiator

, L extends NetconfSessionListener> +extends AbstractSessionNegotiator { private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSessionNegotiator.class); public static final String NAME_OF_EXCEPTION_HANDLER = "lastExceptionHandler"; + public static final String CHUNK_DECODER_CHANNEL_HANDLER_KEY = "chunkDecoder"; protected final P sessionPreferences; - private final SessionListener sessionListener; + private final L sessionListener; private Timeout timeout; /** @@ -62,7 +66,7 @@ public abstract class AbstractNetconfSessionNegotiator

promise, Channel channel, Timer timer, - SessionListener sessionListener, long connectionTimeoutMillis) { + L sessionListener, long connectionTimeoutMillis) { super(promise, channel); this.sessionPreferences = sessionPreferences; this.timer = timer; @@ -145,20 +149,21 @@ public abstract class AbstractNetconfSessionNegotiator

+ * Hello message with header example: + *

+ * + *

+ * {@code
+ * [tomas;10.0.0.0/10000;tcp;1000;1000;;/home/tomas;;]
+ * 
+ * 
+ * urn:ietf:params:netconf:base:1.0
+ * 
+ * 
+ * }
+ * 
+ */ +public final class NetconfHelloMessageToXMLEncoder extends NetconfMessageToXMLEncoder { + + @Override + protected ByteBuffer encodeMessage(NetconfMessage msg) { + Preconditions.checkState(msg instanceof NetconfHelloMessage, "Netconf message of type %s expected, was %s", + NetconfHelloMessage.class, msg.getClass()); + Optional headerOptional = ((NetconfHelloMessage) msg) + .getAdditionalHeader(); + + // If additional header present, serialize it along with netconf hello + // message + if (headerOptional.isPresent()) { + byte[] bytesFromHeader = headerOptional.get().toFormattedString().getBytes(Charsets.UTF_8); + byte[] bytesFromMessage = xmlToString(msg.getDocument()).getBytes(Charsets.UTF_8); + + ByteBuffer byteBuffer = ByteBuffer.allocate(bytesFromHeader.length + bytesFromMessage.length) + .put(bytesFromHeader).put(bytesFromMessage); + byteBuffer.flip(); + return byteBuffer; + } + + return super.encodeMessage(msg); + } +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java index 31a4225fc8..df0f7ef46a 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageToXMLEncoder.java @@ -24,7 +24,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import com.google.common.base.Optional; -public final class NetconfMessageToXMLEncoder extends MessageToByteEncoder { +public class NetconfMessageToXMLEncoder extends MessageToByteEncoder { private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToXMLEncoder.class); private final Optional clientId; @@ -47,21 +47,17 @@ public final class NetconfMessageToXMLEncoder extends MessageToByteEncoder POSSIBLE_ENDS = ImmutableList.of( + new byte[] { ']', '\n' }, + new byte[] { ']', '\r', '\n' }); + private static final List POSSIBLE_STARTS = ImmutableList.of( + new byte[] { '[' }, + new byte[] { '\r', '\n', '[' }, + new byte[] { '\n', '[' }); + + private String additionalHeaderCache; + + @Override + protected byte[] preprocessMessageBytes(byte[] bytes) { + // Extract bytes containing header with additional metadata + + if (startsWithAdditionalHeader(bytes)) { + // Auth information containing username, ip address... extracted for monitoring + int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes); + if (endOfAuthHeader > -1) { + byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2); + additionalHeaderCache = additionalHeaderToString(additionalHeaderBytes); + bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length); + } + } + + return bytes; + } + + @Override + protected void cleanUpAfterDecode() { + additionalHeaderCache = null; + } + + @Override + protected NetconfMessage buildNetconfMessage(Document doc) { + return new NetconfHelloMessage(doc, additionalHeaderCache == null ? null + : NetconfHelloMessageAdditionalHeader.fromString(additionalHeaderCache)); + } + + private int getAdditionalHeaderEndIndex(byte[] bytes) { + for (byte[] possibleEnd : POSSIBLE_ENDS) { + int idx = findByteSequence(bytes, possibleEnd); + + if (idx != -1) { + return idx; + } + } + + return -1; + } + + private static int findByteSequence(final byte[] bytes, final byte[] sequence) { + if (bytes.length < sequence.length) { + throw new IllegalArgumentException("Sequence to be found is longer than the given byte array."); + } + if (bytes.length == sequence.length) { + if (Arrays.equals(bytes, sequence)) { + return 0; + } else { + return -1; + } + } + int j = 0; + for (int i = 0; i < bytes.length; i++) { + if (bytes[i] == sequence[j]) { + j++; + if (j == sequence.length) { + return i - j + 1; + } + } else { + j = 0; + } + } + return -1; + } + + private boolean startsWithAdditionalHeader(byte[] bytes) { + for (byte[] possibleStart : POSSIBLE_STARTS) { + int i = 0; + for (byte b : possibleStart) { + if(bytes[i++] != b) + break; + + if(i == possibleStart.length) + return true; + } + } + + return false; + } + + private String additionalHeaderToString(byte[] bytes) { + return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString(); + } + +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java index 2eefb91724..b697edfb05 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java @@ -7,15 +7,8 @@ */ package org.opendaylight.controller.netconf.util.handler; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; - import java.io.ByteArrayInputStream; -import java.io.IOException; import java.nio.ByteBuffer; -import java.util.Arrays; import java.util.List; import org.opendaylight.controller.netconf.api.NetconfDeserializerException; @@ -24,22 +17,17 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; -import org.xml.sax.SAXException; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; -import com.google.common.collect.ImmutableList; -public final class NetconfXMLToMessageDecoder extends ByteToMessageDecoder { - private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class); +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; - private static final List POSSIBLE_ENDS = ImmutableList.of( - new byte[] { ']', '\n' }, - new byte[] { ']', '\r', '\n' }); - private static final List POSSIBLE_STARTS = ImmutableList.of( - new byte[] { '[' }, - new byte[] { '\r', '\n', '[' }, - new byte[] { '\n', '[' }); +public class NetconfXMLToMessageDecoder extends ByteToMessageDecoder { + private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class); @Override @VisibleForTesting @@ -57,93 +45,35 @@ public final class NetconfXMLToMessageDecoder extends ByteToMessageDecoder { logMessage(bytes); - String additionalHeader = null; - - // FIXME: this has to be moved into the negotiator and explained as to what the heck - // is going on. This is definitely not specified in NETCONF and has no place here. It - // requires reading all data and incurs inefficiency by being unable to pipe the ByteBuf - // directly into the XML decoder. - if (startsWithAdditionalHeader(bytes)) { - // Auth information containing username, ip address... extracted for monitoring - int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes); - if (endOfAuthHeader > -1) { - byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2); - additionalHeader = additionalHeaderToString(additionalHeaderBytes); - bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length); - } - } + bytes = preprocessMessageBytes(bytes); NetconfMessage message; try { Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes)); - message = new NetconfMessage(doc, additionalHeader); - } catch (final SAXException | IOException | IllegalStateException e) { + message = buildNetconfMessage(doc); + } catch (Exception e) { throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e); } out.add(message); } finally { in.discardReadBytes(); + cleanUpAfterDecode(); } } - private int getAdditionalHeaderEndIndex(byte[] bytes) { - for (byte[] possibleEnd : POSSIBLE_ENDS) { - int idx = findByteSequence(bytes, possibleEnd); - - if (idx != -1) { - return idx; - } - } + protected void cleanUpAfterDecode() {} - return -1; + protected NetconfMessage buildNetconfMessage(Document doc) { + return new NetconfMessage(doc); } - private static int findByteSequence(final byte[] bytes, final byte[] sequence) { - if (bytes.length < sequence.length) { - throw new IllegalArgumentException("Sequence to be found is longer than the given byte array."); - } - if (bytes.length == sequence.length) { - if (Arrays.equals(bytes, sequence)) { - return 0; - } else { - return -1; - } - } - int j = 0; - for (int i = 0; i < bytes.length; i++) { - if (bytes[i] == sequence[j]) { - j++; - if (j == sequence.length) { - return i - j + 1; - } - } else { - j = 0; - } - } - return -1; + protected byte[] preprocessMessageBytes(byte[] bytes) { + return bytes; } - private boolean startsWithAdditionalHeader(byte[] bytes) { - for (byte[] possibleStart : POSSIBLE_STARTS) { - int i = 0; - for (byte b : possibleStart) { - if(bytes[i] != b) - break; - - return true; - } - } - - return false; - }; - private void logMessage(byte[] bytes) { String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString(); LOG.debug("Parsing message \n{}", s); } - private String additionalHeaderToString(byte[] bytes) { - return Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString(); - } - } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java new file mode 100644 index 0000000000..249f894340 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java @@ -0,0 +1,53 @@ +/* + * 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.util.messages; + +import org.opendaylight.controller.netconf.api.NetconfMessage; +import org.opendaylight.controller.netconf.util.xml.XmlElement; +import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.w3c.dom.Document; + +import com.google.common.base.Optional; + +/** + * NetconfMessage that can carry additional header with session metadata. See {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader} + */ +public final class NetconfHelloMessage extends NetconfMessage { + + public static final String HELLO_TAG = "hello"; + + private final NetconfHelloMessageAdditionalHeader additionalHeader; + + public NetconfHelloMessage(Document doc, NetconfHelloMessageAdditionalHeader additionalHeader) { + super(doc); + checkHelloMessage(doc); + this.additionalHeader = additionalHeader; + } + + public NetconfHelloMessage(Document doc) { + this(doc, null); + } + + public Optional getAdditionalHeader() { + return additionalHeader== null ? Optional.absent() : Optional.of(additionalHeader); + } + + private static void checkHelloMessage(Document doc) { + try { + XmlElement.fromDomElementWithExpected(doc.getDocumentElement(), HELLO_TAG, + XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0); + + } catch (IllegalArgumentException | IllegalStateException e) { + throw new IllegalArgumentException(String.format( + "Hello message invalid format, should contain %s tag from namespace %s, but is: %s", HELLO_TAG, + XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlUtil.toString(doc)), e); + } + } +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeader.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeader.java new file mode 100644 index 0000000000..f3ca30d2c4 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessageAdditionalHeader.java @@ -0,0 +1,121 @@ +/* + * 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.util.messages; + +import com.google.common.base.Preconditions; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Additional header can be used with hello message to carry information about + * session's connection. Provided information can be reported via netconf + * monitoring. + *
+ * It has pattern "[username; host-address:port; transport; session-identifier;]"
+ * username - name of account on a remote
+ * host-address - client's IP address
+ * port - port number
+ * transport - tcp, ssh
+ * session-identifier - persister, client
+ * Session-identifier is optional, others mandatory.
+ * 
+ * This header is inserted in front of a netconf hello message followed by a newline. + */ +public class NetconfHelloMessageAdditionalHeader { + + private static final String SC = ";"; + + private final String userName; + private final String hostAddress; + private final String port; + private final String transport; + private final String sessionIdentifier; + + public NetconfHelloMessageAdditionalHeader(String userName, String hostAddress, String port, String transport, String sessionIdentifier) { + this.userName = userName; + this.hostAddress = hostAddress; + this.port = port; + this.transport = transport; + this.sessionIdentifier = sessionIdentifier; + } + + public String getUserName() { + return userName; + } + + public String getAddress() { + return hostAddress; + } + + public String getPort() { + return port; + } + + public String getTransport() { + return transport; + } + + public String getSessionIdentifier() { + return sessionIdentifier; + } + + /** + * Format additional header into a string suitable as a prefix for netconf hello message + */ + public String toFormattedString() { + Preconditions.checkNotNull(userName); + Preconditions.checkNotNull(hostAddress); + Preconditions.checkNotNull(port); + Preconditions.checkNotNull(transport); + Preconditions.checkNotNull(sessionIdentifier); + return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + sessionIdentifier + SC + "]" + + System.lineSeparator(); + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("NetconfHelloMessageAdditionalHeader{"); + sb.append("userName='").append(userName).append('\''); + sb.append(", hostAddress='").append(hostAddress).append('\''); + sb.append(", port='").append(port).append('\''); + sb.append(", transport='").append(transport).append('\''); + sb.append(", sessionIdentifier='").append(sessionIdentifier).append('\''); + sb.append('}'); + return sb.toString(); + } + + // TODO IPv6 + private static final Pattern pattern = Pattern + .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+)[^\\]]+\\]"); + private static final Pattern customHeaderPattern = Pattern + .compile("\\[(?[^;]+);(?
[0-9\\.]+)[:/](?[0-9]+);(?[a-z]+);(?[a-z]+)[^\\]]+\\]"); + + /** + * Parse additional header from a formatted string + */ + public static NetconfHelloMessageAdditionalHeader fromString(String additionalHeader) { + additionalHeader = additionalHeader.trim(); + Matcher matcher = pattern.matcher(additionalHeader); + Matcher matcher2 = customHeaderPattern.matcher(additionalHeader); + Preconditions.checkArgument(matcher.matches(), "Additional header in wrong format %s, expected %s", + additionalHeader, pattern); + + String username = matcher.group("username"); + String address = matcher.group("address"); + String port = matcher.group("port"); + String transport = matcher.group("transport"); + String sessionIdentifier = "client"; + if (matcher2.matches()) { + sessionIdentifier = matcher2.group("sessionIdentifier"); + } + return new NetconfHelloMessageAdditionalHeader(username, address, port, transport, sessionIdentifier); + } + +} diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java deleted file mode 100644 index 457e226e01..0000000000 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageAdditionalHeader.java +++ /dev/null @@ -1,42 +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.util.messages; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; - -/** - * Additional header can be used with hello message to carry information about - * session's connection. Provided information can be reported via netconf - * monitoring. - *
- * It has pattern "[username; host-address:port; transport; session-identifier;]"
- * username - name of account on a remote
- * host-address - client's IP address
- * port - port number
- * transport - tcp, ssh
- * session-identifier - persister, client
- * Session-identifier is optional, others mandatory.
- * 
- */ -public class NetconfMessageAdditionalHeader { - - private static final String SC = ";"; - - public static String toString(String userName, String hostAddress, String port, String transport, - Optional sessionIdentifier) { - Preconditions.checkNotNull(userName); - Preconditions.checkNotNull(hostAddress); - Preconditions.checkNotNull(port); - Preconditions.checkNotNull(transport); - String identifier = sessionIdentifier.isPresent() ? sessionIdentifier.get() : ""; - return "[" + userName + SC + hostAddress + ":" + port + SC + transport + SC + identifier + SC + "]" - + System.lineSeparator(); - } -} diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java index c405d9bcb5..6b7bffcd86 100644 --- a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.List; import org.junit.Test; +import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder; import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder; import com.google.common.io.Files; @@ -22,7 +23,7 @@ import com.google.common.io.Files; public class NetconfMessageFactoryTest { @Test public void testAuth() throws Exception { - NetconfXMLToMessageDecoder parser = new NetconfXMLToMessageDecoder(); + NetconfXMLToMessageDecoder parser = new NetconfXMLToHelloMessageDecoder(); File authHelloFile = new File(getClass().getResource("/netconfMessages/client_hello_with_auth.xml").getFile()); final List out = new ArrayList<>(); diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java index d60bcab8b3..aa60f91174 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java @@ -407,9 +407,9 @@ public class SecureMessageReadWriteService implements IMessageReadWrite { this.myAppData = ByteBuffer .allocate(session.getApplicationBufferSize()); this.peerAppData = ByteBuffer.allocate(session - .getApplicationBufferSize() * 2); + .getApplicationBufferSize() * 20); this.myNetData = ByteBuffer.allocate(session.getPacketBufferSize()); - this.peerNetData = ByteBuffer.allocate(session.getPacketBufferSize() * 2); + this.peerNetData = ByteBuffer.allocate(session.getPacketBufferSize() * 20); } @Override diff --git a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/AuthenticatedUser.java b/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/AuthenticatedUser.java index 94200e66e0..809ca134f7 100644 --- a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/AuthenticatedUser.java +++ b/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/AuthenticatedUser.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.usermanager; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -47,7 +48,7 @@ public class AuthenticatedUser implements Serializable { } public List getUserRoles() { - return userRoles; + return userRoles == null ? Collections. emptyList() : new ArrayList(userRoles); } public void addUserRole(String string) { diff --git a/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthenticatedUserTest.java b/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthenticatedUserTest.java index b8a1a98769..d32799e3eb 100644 --- a/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthenticatedUserTest.java +++ b/opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthenticatedUserTest.java @@ -8,15 +8,15 @@ package org.opendaylight.controller.usermanager; +import java.util.Arrays; +import java.util.List; + import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.sal.authorization.UserLevel; import org.springframework.security.core.GrantedAuthority; -import java.util.Arrays; -import java.util.List; - public class AuthenticatedUserTest { static String[] roleArray; @@ -33,7 +33,7 @@ public class AuthenticatedUserTest { user = new AuthenticatedUser("auser"); Assert.assertFalse(user.getAccessDate().isEmpty()); - Assert.assertNull(user.getUserRoles()); + Assert.assertNotNull(user.getUserRoles()); } @Test diff --git a/opendaylight/web/flows/src/main/resources/js/page.js b/opendaylight/web/flows/src/main/resources/js/page.js index 094562fac0..ab8301bf73 100644 --- a/opendaylight/web/flows/src/main/resources/js/page.js +++ b/opendaylight/web/flows/src/main/resources/js/page.js @@ -457,7 +457,8 @@ one.f.flows = { var editButton = one.lib.dashlet.button.single("Edit Flow", one.f.flows.id.dashlet.edit, "btn-primary", "btn-mini"); var $editButton = one.lib.dashlet.button.button(editButton); $editButton.click(function() { - var $modal = one.f.flows.modal.initialize(true); + var install = flow['flow']['installInHw']; + var $modal = one.f.flows.modal.initialize(true,install); $modal.modal().on('shown',function(){ var $port = $('#'+one.f.flows.id.modal.form.port); $('#'+one.f.flows.id.modal.form.nodes).trigger("change"); @@ -550,7 +551,7 @@ one.f.flows = { return $p; } }, - initialize : function(edit) { + initialize : function(edit,install) { var h3; if(edit) { h3 = "Edit Flow Entry"; @@ -571,7 +572,7 @@ one.f.flows = { if (edit) { // bind edit flow button $('#'+one.f.flows.id.modal.edit, $modal).click(function() { - one.f.flows.modal.save($modal, 'true', true); + one.f.flows.modal.save($modal, install, true); }); } else { // bind add flow button diff --git a/opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java b/opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java index 36b5043dd9..04fbf846b7 100644 --- a/opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java +++ b/opendaylight/web/troubleshoot/src/main/java/org/opendaylight/controller/troubleshoot/web/Troubleshoot.java @@ -41,6 +41,7 @@ import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.reader.FlowOnNode; import org.opendaylight.controller.sal.reader.NodeConnectorStatistics; +import org.opendaylight.controller.sal.reader.NodeDescription; import org.opendaylight.controller.sal.utils.EtherTypes; import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.HexEncode; @@ -101,6 +102,30 @@ public class Troubleshoot implements IDaylightWeb { return userLevel.ordinal() <= AUTH_LEVEL.ordinal(); } + @RequestMapping(value = "/nodeInfo", method = RequestMethod.GET) + @ResponseBody + public NodeDescription getNodeInfo(HttpServletRequest request, @RequestParam(required = false) String container, + @RequestParam(required = true) String nodeId) { + List> lines = new ArrayList>(); + String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container; + + // Derive the privilege this user has on the current container + String userName = request.getUserPrincipal().getName(); + Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this); + + if (privilege != Privilege.NONE) { + IStatisticsManager statisticsManager = (IStatisticsManager) ServiceHelper + .getInstance(IStatisticsManager.class, containerName, this); + if(statisticsManager != null){ + Node node = Node.fromString(nodeId); + NodeDescription nodeDesc = statisticsManager.getNodeDescription(node); + return nodeDesc; + } + } + + return new NodeDescription(); + } + @RequestMapping(value = "/existingNodes", method = RequestMethod.GET) @ResponseBody public TroubleshootingJsonBean getExistingNodes(HttpServletRequest request, @RequestParam(required = false) String container) { diff --git a/opendaylight/web/troubleshoot/src/main/resources/js/page.js b/opendaylight/web/troubleshoot/src/main/resources/js/page.js index 4bc4c76fc4..09c4666d44 100644 --- a/opendaylight/web/troubleshoot/src/main/resources/js/page.js +++ b/opendaylight/web/troubleshoot/src/main/resources/js/page.js @@ -1,8 +1,8 @@ -/* - * 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, +/* + * 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 * */ @@ -63,13 +63,13 @@ $(one.f.menu.right.bottom).each(function(index, value) { /**Troubleshoot modules*/ one.f.troubleshooting = { rootUrl: "/controller/web/troubleshoot", - rightBottomDashlet: { + rightBottomDashlet: { get: function() { var $rightBottomDashlet = $("#right-bottom").find(".dashlet"); return $rightBottomDashlet; }, setDashletHeader: function(label) { - $("#right-bottom li a")[0].innerHTML = label; + $("#right-bottom li a")[0].innerHTML = label; } }, createTable: function(columnNames, body) { @@ -92,8 +92,11 @@ one.f.troubleshooting.existingNodes = { portsDataGrid: "one_f_troubleshooting_existingNodes_id_portsDataGrid", flowsDataGrid: "one_f_troubleshooting_existingNodes_id_flowsDataGrid", refreshFlowsButton:"one_f_troubleshooting_existingNodes_id_refreshFlowsButton", - refreshPortsButton:"one_f_troubleshooting_existingNodes_id_refreshPortsButton" - + refreshPortsButton:"one_f_troubleshooting_existingNodes_id_refreshPortsButton", + modal : { + nodeInfo : "one_f_troubleshooting_existingNodes_id_modal_nodeInfo", + cancelButton : "one_f_troubleshooting_existingNodes_id_modal_cancelButton", + } }, load: { main: function($dashlet) { @@ -171,7 +174,7 @@ one.f.troubleshooting.existingNodes = { $("#" + one.f.troubleshooting.existingNodes.id.portsDataGrid).datagrid({dataSource: dataSource}); }); } catch(e) {} - } + } }, ajax : function(url, callback) { $.getJSON(url, function(data) { @@ -204,7 +207,9 @@ one.f.troubleshooting.existingNodes = { data: data.nodeData, formatter: function(items) { $.each(items, function(index, item) { - item["statistics"] = "Flows" + + item.nodeName = "" + item.nodeName + "" + item["statistics"] = "Flows" + " Ports"; }); }, @@ -461,6 +466,46 @@ one.f.troubleshooting.existingNodes = { result.push(tr); }); return result; + }, + nodeInfo : function(nodeId){ + $.getJSON(one.main.constants.address.prefix + "/troubleshoot/nodeInfo?nodeId=" + nodeId, function(content) { + var h3 = 'Node Information' + + var headers = [ 'Description','Specification']; + + var attributes = ['table-striped', 'table-bordered', 'table-condensed']; + var $table = one.lib.dashlet.table.table(attributes); + var $thead = one.lib.dashlet.table.header(headers); + $table.append($thead); + + var footer = []; + + var cancelButton = one.lib.dashlet.button.single("Cancel", + one.f.troubleshooting.existingNodes.id.modal.nodeInfo, "", ""); + var $cancelButton = one.lib.dashlet.button.button(cancelButton); + footer.push($cancelButton); + + var body = [] + $.each(content, function(key, value) { + var tr = {}; + var entry = []; + + entry.push(key); + entry.push(value); + + tr.entry = entry; + body.push(tr); + }); + var $tbody = one.lib.dashlet.table.body(body); + $table.append($tbody); + + var $modal = one.lib.modal.spawn(one.f.troubleshooting.existingNodes.id.modal.nodeInfo, h3, $table , footer); + $modal.modal(); + + $('#'+one.f.troubleshooting.existingNodes.id.modal.nodeInfo, $modal).click(function() { + $modal.modal('hide'); + }); + }); } } }; @@ -488,7 +533,7 @@ one.f.troubleshooting.uptime = { $("#" + one.f.troubleshooting.uptime.id.datagrid).datagrid({dataSource: dataSource}); }); }, - + ajax : { main : function(url, requestData, callback) { $.getJSON(url, requestData, function(data) { @@ -496,7 +541,7 @@ one.f.troubleshooting.uptime = { }); } }, - + data: { uptimeDataGrid: function(data) { var source = new StaticDataSource({ @@ -548,7 +593,7 @@ one.f.troubleshooting.statistics = { var $p = $(document.createElement('p')); $p.text('Please select a Flow or Ports statistics'); $p.addClass('text-center').addClass('text-info'); - + $dashlet.append($none) .append($p); }