*.iws
.idea
xtend-gen
+yang-gen-config
+yang-gen-sal
classes
out/
.externalToolBuilders
</scm>
<artifactId>clustering.services-implementation</artifactId>
- <version>0.4.2-SNAPSHOT</version>
+ <version>0.4.3-SNAPSHOT</version>
<packaging>bundle</packaging>
<properties>
<!-- Sonar properties using jacoco to retrieve integration test results -->
*
</DynamicImport-Package>
<Embed-Dependency>
- infinispan-core,jgroups,jboss-marshalling-river,jboss-marshalling,jboss-logging,staxmapper,narayana-jta;type=!pom;inline=false
+ infinispan-core,infinispan-commons,jgroups,jboss-marshalling-river,jboss-marshalling,jboss-logging,staxmapper,narayana-jta;type=!pom;inline=false
</Embed-Dependency>
<Embed-Transitive>
true
<exclude>org.infinispan:infinispan-core:*</exclude>
</excludes>
<includes>
- <include>org.infinispan:infinispan-core:[5.3.0.Final]</include>
+ <include>org.infinispan:infinispan-core:[6.0.2.Final]</include>
</includes>
</bannedDependencies>
</rules>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
- <version>5.3.0.Final</version>
+ <version>6.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
+++ /dev/null
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2009 Red Hat Inc. and/or its affiliates and other
- * contributors as indicated by the @author tags. All rights reserved.
- * See the copyright.txt in the distribution for a full listing of
- * individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.infinispan.interceptors.distribution;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.infinispan.CacheException;
-import org.infinispan.commands.FlagAffectedCommand;
-import org.infinispan.commands.remote.ClusteredGetCommand;
-import org.infinispan.commands.write.DataWriteCommand;
-import org.infinispan.commands.write.WriteCommand;
-import org.infinispan.container.entries.InternalCacheEntry;
-import org.infinispan.container.entries.InternalCacheValue;
-import org.infinispan.context.InvocationContext;
-import org.infinispan.context.impl.TxInvocationContext;
-import org.infinispan.distribution.DistributionManager;
-import org.infinispan.factories.annotations.Inject;
-import org.infinispan.interceptors.ClusteringInterceptor;
-import org.infinispan.interceptors.locking.ClusteringDependentLogic;
-import org.infinispan.remoting.responses.ClusteredGetResponseValidityFilter;
-import org.infinispan.remoting.responses.ExceptionResponse;
-import org.infinispan.remoting.responses.Response;
-import org.infinispan.remoting.responses.SuccessfulResponse;
-import org.infinispan.remoting.rpc.ResponseFilter;
-import org.infinispan.remoting.rpc.ResponseMode;
-import org.infinispan.remoting.rpc.RpcOptions;
-import org.infinispan.remoting.transport.Address;
-import org.infinispan.transaction.xa.GlobalTransaction;
-import org.infinispan.util.logging.Log;
-import org.infinispan.util.logging.LogFactory;
-
-
-/**
- * Base class for distribution of entries across a cluster.
- *
- * @author Manik Surtani
- * @author Mircea.Markus@jboss.com
- * @author Pete Muir
- * @author Dan Berindei <dan@infinispan.org>
- * @since 4.0
- */
-public abstract class BaseDistributionInterceptor extends ClusteringInterceptor {
-
- protected DistributionManager dm;
-
- protected ClusteringDependentLogic cdl;
-
- private static final Log log = LogFactory.getLog(BaseDistributionInterceptor.class);
-
- @Override
- protected Log getLog() {
- return log;
- }
-
- @Inject
- public void injectDependencies(DistributionManager distributionManager, ClusteringDependentLogic cdl) {
- this.dm = distributionManager;
- this.cdl = cdl;
- }
-
- @Override
- protected final InternalCacheEntry retrieveFromRemoteSource(Object key, InvocationContext ctx, boolean acquireRemoteLock, FlagAffectedCommand command) throws Exception {
- GlobalTransaction gtx = acquireRemoteLock ? ((TxInvocationContext)ctx).getGlobalTransaction() : null;
- ClusteredGetCommand get = cf.buildClusteredGetCommand(key, command.getFlags(), acquireRemoteLock, gtx);
-
- List<Address> targets = new ArrayList<Address>(stateTransferManager.getCacheTopology().getReadConsistentHash().locateOwners(key));
- // if any of the recipients has left the cluster since the command was issued, just don't wait for its response
- targets.retainAll(rpcManager.getTransport().getMembers());
- ResponseFilter filter = new ClusteredGetResponseValidityFilter(targets, rpcManager.getAddress());
- RpcOptions options = rpcManager.getRpcOptionsBuilder(ResponseMode.WAIT_FOR_VALID_RESPONSE, false)
- .responseFilter(filter).build();
- Map<Address, Response> responses = rpcManager.invokeRemotely(targets, get, options);
-
- if (!responses.isEmpty()) {
- for (Response r : responses.values()) {
- if (r instanceof SuccessfulResponse) {
- InternalCacheValue cacheValue = (InternalCacheValue) ((SuccessfulResponse) r).getResponseValue();
- return cacheValue.toInternalCacheEntry(key);
- }
- }
- }
-
- // TODO If everyone returned null, and the read CH has changed, retry the remote get.
- // Otherwise our get command might be processed by the old owners after they have invalidated their data
- // and we'd return a null even though the key exists on
- return null;
- }
-
- protected final Object handleNonTxWriteCommand(InvocationContext ctx, DataWriteCommand command) throws Throwable {
- if (ctx.isInTxScope()) {
- throw new CacheException("Attempted execution of non-transactional write command in a transactional invocation context");
- }
-
- RecipientGenerator recipientGenerator = new SingleKeyRecipientGenerator(command.getKey());
-
- // see if we need to load values from remote sources first
- remoteGetBeforeWrite(ctx, command, recipientGenerator);
-
- // if this is local mode then skip distributing
- if (isLocalModeForced(command)) {
- return invokeNextInterceptor(ctx, command);
- }
-
- boolean isSync = isSynchronous(command);
- if (!ctx.isOriginLocal()) {
- Object returnValue = invokeNextInterceptor(ctx, command);
- Address primaryOwner = cdl.getPrimaryOwner(command.getKey());
- if (primaryOwner.equals(rpcManager.getAddress())) {
- if (command.isConditional() && !command.isSuccessful()) {
- log.tracef(
- "Skipping the replication of the conditional command as it did not succeed on primary owner (%s).",
- command);
- return returnValue;
- }
- rpcManager.invokeRemotely(recipientGenerator.generateRecipients(), command,
- rpcManager.getDefaultRpcOptions(isSync));
- } else {
- log.tracef("Didn't invoke RPC because primaryOwner (%s) didn't match this node (%s)", primaryOwner,
- rpcManager.getAddress());
- log.tracef("Hashcode is (%s) for Key (%s)",
- command.getKey().hashCode(), command.getKey());
- }
- return returnValue;
- } else {
- Address primaryOwner = cdl.getPrimaryOwner(command.getKey());
- if (primaryOwner.equals(rpcManager.getAddress())) {
- Object result = invokeNextInterceptor(ctx, command);
- if (command.isConditional() && !command.isSuccessful()) {
- log.tracef("Skipping the replication of the conditional command as it did not succeed on primary owner (%s).", command);
- return result;
- }
- List<Address> recipients = recipientGenerator.generateRecipients();
- log.tracef("I'm the primary owner, sending the command to all (%s) the recipients in order to be applied.", recipients);
- // check if a single owner has been configured and the target for the key is the local address
- boolean isSingleOwnerAndLocal = cacheConfiguration.clustering().hash().numOwners() == 1
- && recipients != null
- && recipients.size() == 1
- && recipients.get(0).equals(rpcManager.getTransport().getAddress());
- if (!isSingleOwnerAndLocal) {
- rpcManager.invokeRemotely(recipients, command, rpcManager.getDefaultRpcOptions(isSync));
- }
- return result;
- } else {
- log.tracef("I'm not the primary owner, so sending the command to the primary owner(%s) in order to be forwarded", primaryOwner);
- log.tracef("Hashcode is (%s) for Key (%s)", command.getKey().hashCode(), command.getKey());
-
- Object localResult = invokeNextInterceptor(ctx, command);
- boolean isSyncForwarding = isSync || isNeedReliableReturnValues(command);
- Map<Address, Response> addressResponseMap = rpcManager.invokeRemotely(Collections.singletonList(primaryOwner), command,
- rpcManager.getDefaultRpcOptions(isSyncForwarding));
- if (!isSyncForwarding) return localResult;
-
- return getResponseFromPrimaryOwner(primaryOwner, addressResponseMap);
- }
- }
- }
-
- private Object getResponseFromPrimaryOwner(Address primaryOwner, Map<Address, Response> addressResponseMap) {
- Response fromPrimaryOwner = addressResponseMap.get(primaryOwner);
- if (fromPrimaryOwner == null) {
- log.tracef("Primary owner %s returned null", primaryOwner);
- return null;
- }
- if (!fromPrimaryOwner.isSuccessful()) {
- Throwable cause = fromPrimaryOwner instanceof ExceptionResponse ? ((ExceptionResponse)fromPrimaryOwner).getException() : null;
- throw new CacheException("Got unsuccessful response from primary owner: " + fromPrimaryOwner, cause);
- } else {
- return ((SuccessfulResponse) fromPrimaryOwner).getResponseValue();
- }
- }
-
- protected abstract void remoteGetBeforeWrite(InvocationContext ctx, WriteCommand command, RecipientGenerator keygen) throws Throwable;
-
- interface RecipientGenerator {
-
- Collection<Object> getKeys();
-
- List<Address> generateRecipients();
- }
-
- class SingleKeyRecipientGenerator implements RecipientGenerator {
- private final Object key;
- private final Set<Object> keys;
- private List<Address> recipients = null;
-
- SingleKeyRecipientGenerator(Object key) {
- this.key = key;
- keys = Collections.singleton(key);
- }
-
- @Override
- public List<Address> generateRecipients() {
- if (recipients == null) {
- recipients = cdl.getOwners(key);
- }
- return recipients;
- }
-
- @Override
- public Collection<Object> getKeys() {
- return keys;
- }
- }
-
- class MultipleKeysRecipientGenerator implements RecipientGenerator {
-
- private final Collection<Object> keys;
- private List<Address> recipients = null;
-
- MultipleKeysRecipientGenerator(Collection<Object> keys) {
- this.keys = keys;
- }
-
- @Override
- public List<Address> generateRecipients() {
- if (recipients == null) {
- recipients = cdl.getOwners(keys);
- }
- return recipients;
- }
-
- @Override
- public Collection<Object> getKeys() {
- return keys;
- }
- }
-}
-<infinispan xsi:schemaLocation="urn:infinispan:config:5.3 http://www.infinispan.org/schemas/infinispan-config-5.3.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:infinispan:config:5.3">
+<infinispan>
<global>
<transport>
<properties>
jmxDomain="org.infinispan"
cacheManagerName="SampleCacheManager"/>
</global>
- <default>
- <!-- Configure a synchronous replication cache -->
- <clustering mode="replication">
- <sync/>
- </clustering>
- <!--
- Used to register JMX statistics in any available MBean server
- -->
+
+ <default>
<jmxStatistics enabled="true"/>
- </default>
- <!-- transactionManagerLookupClass="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup" -->
- <namedCache name="transactional-type">
+ <clustering mode="replication">
+ <sync/>
+ </clustering>
+ </default>
+ <namedCache name="transactional-type">
<transaction
transactionManagerLookupClass="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup"
syncRollbackPhase="true"
use1PcForAutoCommitTransactions="true"
autoCommit="true"
lockingMode="OPTIMISTIC"
+ useEagerLocking="true"
useSynchronization="true"
transactionMode="TRANSACTIONAL"
/>
+ <clustering mode="replication">
+ <sync/>
+ </clustering>
</namedCache>
+
</infinispan>
<commons.io.version>2.4</commons.io.version>
<bundlescanner.version>0.4.2-SNAPSHOT</bundlescanner.version>
<usermanager.version>0.4.2-SNAPSHOT</usermanager.version>
- <forwardingrulesmanager.version>0.5.1-SNAPSHOT</forwardingrulesmanager.version>
+ <forwardingrulesmanager.version>0.6.0-SNAPSHOT</forwardingrulesmanager.version>
<statisticsmanager.version>0.5.1-SNAPSHOT</statisticsmanager.version>
<clustering.services.version>0.5.1-SNAPSHOT</clustering.services.version>
<configuration.version>0.4.3-SNAPSHOT</configuration.version>
<topologymanager.version>0.4.2-SNAPSHOT</topologymanager.version>
<protocol_plugin.stub.version>0.4.2-SNAPSHOT</protocol_plugin.stub.version>
<clustering.stub.version>0.4.2-SNAPSHOT</clustering.stub.version>
+ <clustering.services_implementation.version>0.4.3-SNAPSHOT</clustering.services_implementation.version>
<!-- Third party version -->
<jersey-servlet.version>1.17</jersey-servlet.version>
<corsfilter.version>7.0.42</corsfilter.version>
<!-- enforcer version -->
<enforcer.version>1.3.1</enforcer.version>
<xtend.version>2.4.3</xtend.version>
- <xtend.dstdir>${project.build.directory}/generated-sources/xtend-gen</xtend.dstdir>
+ <xtend.dstdir>src/main/xtend-gen</xtend.dstdir>
+ <jmxGeneratorPath>src/main/yang-gen-config</jmxGeneratorPath>
+ <salGeneratorPath>src/main/yang-gen-sal</salGeneratorPath>
</properties>
<dependencyManagement>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services-implementation</artifactId>
- <version>${controller.version}</version>
+ <version>${clustering.services_implementation.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<sourceDirectory>${project.basedir}</sourceDirectory>
<includes>**\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat</includes>
- <excludes>**\/target\/,**\/bin\/,**\/target-ide\/</excludes>
+ <excludes>**\/target\/,**\/bin\/,**\/target-ide\/,**\/${jmxGeneratorPath}\/,**\/${salGeneratorPath}\/</excludes>
</configuration>
</plugin>
<plugin>
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ </plugin>
</plugins>
<pluginManagement>
<plugins>
</execution>
</executions>
</plugin>
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <configuration>
+ <filesets>
+ <fileset>
+ <directory>${xtend.dstdir}</directory>
+ <includes>
+ <include>**</include>
+ </includes>
+ </fileset>
+ <fileset>
+ <directory>${jmxGeneratorPath}</directory>
+ <includes>
+ <include>**</include>
+ </includes>
+ </fileset>
+ <fileset>
+ <directory>${salGeneratorPath}</directory>
+ <includes>
+ <include>**</include>
+ </includes>
+ </fileset>
+ </filesets>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>${jmxGeneratorPath}</source>
+ <source>${salGeneratorPath}</source>
+ <source>${xtend.dstdir}</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</pluginManagement>
</build>
<maven>3.0.4</maven>
</prerequisites>
- <properties>
- <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
- <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
- </properties>
-
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<packaging>bundle</packaging>
<properties>
- <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
- <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
<config.version>${config-api-version}</config.version>
<yangtools.version>${yang-maven-plugin-version}</yangtools.version>
<maven.bundle.version>${maven-bundle-plugin-version}</maven.bundle.version>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${jmxGeneratorPath}</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<maven>3.0.4</maven>
</prerequisites>
- <properties>
- <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
- </properties>
-
<build>
<pluginManagement>
<plugins>
</dependency>
</dependencies>
</plugin>
-
- <!-- tell eclipse about generated source folders -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${jmxGeneratorPath}</source>
- <source>${salGeneratorPath}</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</pluginManagement>
</build>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
</plugin>
+
</plugins>
</build>
</project>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
</plugin>
-
-
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<osgi.version>5.0.0</osgi.version>
<jacoco.version>0.6.2.201302030002</jacoco.version>
<slf4j.version>1.7.2</slf4j.version>
- <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
</properties>
<dependencies>
</dependency>
</dependencies>
</plugin>
- <!-- tell eclipse about generated source folders -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${salGeneratorPath}</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
osgi.noShutdown=true
# Clean any cached data on restart of the framework
osgi.clean=true
+
+# https://bugs.eclipse.org/bugs/show_bug.cgi?id=325578
# Extend the framework to avoid the resources to be presented with
# a URL of type bundleresource: but to be presented as file:
osgi.hook.configurators.include=org.eclipse.virgo.kernel.equinox.extensions.hooks.ExtensionsHookConfigurator
+
# Directory from where the fileinstall will monitor for new bundles
felix.fileinstall.dir=./plugins
# Immediately learn new bundles at startup
SET debugport=8000
SET consoleport=2400
SET jmxport=1088
+SET jvmMaxMemory=
SET extraJVMOpts=
SET consoleOpts=-console -consoleLog
SET PID=
)
GOTO :EOF
)
+ IF "!CARG:~0,4!"=="-Xmx" (
+ SET jvmMaxMemory=!CARG!
+ SHIFT
+ GOTO :LOOP
+ )
IF "!CARG:~0,2!"=="-D" (
SET extraJVMOpts=%extraJVMOpts% !CARG!
SHIFT
REM ECHO "DEBUG enabled suspended"
SET extraJVMOpts=%extraJVMOpts% -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=%debugport%
)
+
+IF "%jvmMaxMemory%"=="" (
+ SET jvmMaxMemory=-Xmx1G
+ ECHO *****************************************************************
+ ECHO JVM maximum memory was not defined. Setting maximum memory to 1G.
+ ECHO To define the maximum memory, specify the -Xmx setting on the
+ ECHO command line.
+ ECHO e.g. run.bat -Xmx1G
+ ECHO *****************************************************************"
+)
+
+SET extraJVMOpts=%extraJVMOpts% %jvmMaxMemory%
+
IF "%jmxEnabled%" NEQ "" (
REM ECHO "JMX enabled "
SET extraJVMOpts=%extraJVMOpts% -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=%jmxport% -Dcom.sun.management.jmxremote
statusdaemon=0
consolestart=1
dohelp=0
+jvmMaxMemory=""
extraJVMOpts=""
agentPath=""
unknown_option=0
-status) statusdaemon=1; shift ;;
-console) shift ;;
-help) dohelp=1; shift;;
+ -Xmx*) jvmMaxMemory="$1"; shift;;
-D*) extraJVMOpts="${extraJVMOpts} $1"; shift;;
-X*) extraJVMOpts="${extraJVMOpts} $1"; shift;;
-agentpath:*) agentPath="$1"; shift;;
usage
fi
+if [ "${jvmMaxMemory}" == "" ]; then
+ jvmMaxMemory="-Xmx1G"
+ echo "*****************************************************************"
+ echo "JVM maximum memory was not defined. Setting maximum memory to 1G."
+ echo "To define the maximum memory, specify the -Xmx setting on the"
+ echo "command line. "
+ echo " e.g. ./run.sh -Xmx1G"
+ echo "*****************************************************************"
+fi
+
+extraJVMOpts="${extraJVMOpts} ${jvmMaxMemory}"
+
# Validate debug port
if [[ "${debugport}" -lt 1024 ]] || [[ "${debugport}" -gt 65535 ]]; then
echo "Debug Port not in the range [1024,65535] ${debugport}"
</scm>
<artifactId>forwardingrulesmanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
+ <version>0.6.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<build>
*/
public Status addStaticFlow(FlowConfig config);
+ /**
+ * Add a flow specified by the {@code FlowConfig} object on the current
+ * container, through an asynchronous call.
+ *
+ * @param config
+ * the {@code FlowConfig} object representing the static flow
+ * @return the {@code Status} object indicating the result of this action.
+ */
+ public Status addStaticFlowAsync(FlowConfig config);
+
/**
* Remove a flow specified by the {@code FlowConfig} object on the current
* container
*/
public Status removeStaticFlow(FlowConfig config);
+ /**
+ * Remove a flow specified by the {@code FlowConfig} object on the current
+ * container, through an asynchronous call.
+ *
+ * @param config
+ * the {@code FlowConfig} object representing the static flow
+ * @return the {@code Status} object indicating the result of this action
+ */
+ public Status removeStaticFlowAsync(FlowConfig config);
+
/**
* Replace the flow identified by the {@code FlowConfig.name} name for the
* {@code FlowConfig.node} network node with the new flow specified by
*
* @param config
* the {@code FlowConfig} object
- * @returnthe {@code Status} object indicating the result of this action
+ * @return the {@code Status} object indicating the result of this action
*/
public Status modifyStaticFlow(FlowConfig config);
*/
public Status removeStaticFlow(String name, Node node);
+ /**
+ * Remove the flow specified by name on the passed network node via an
+ * asynchronous call
+ *
+ * @param name
+ * for the static flow
+ * @param node
+ * on which the flow is attached
+ * @return the {@code Status} object indicating the result of this action
+ */
+ public Status removeStaticFlowAsync(String name, Node node);
+
/**
* Toggle the installation status of the specified configured flow If the
* flow configuration status is active, this call will change the flow
@Override
public Status addStaticFlow(FlowConfig config) {
+ return addStaticFlow(config, false);
+ }
+
+ private Status addStaticFlow(FlowConfig config, boolean async) {
// Configuration object validation
Status status = config.validate();
if (!status.isSuccess()) {
config.setStatus(error);
return new Status(StatusCode.BADREQUEST, error);
}
- return addStaticFlowInternal(config, false);
+ return addStaticFlowInternal(config, async, false);
+ }
+
+
+ @Override
+ public Status addStaticFlowAsync(FlowConfig config) {
+ return addStaticFlow(config, true);
}
/**
* installation on the network node was successful
* @return The status of this request
*/
- private Status addStaticFlowInternal(FlowConfig config, boolean restore) {
+ private Status addStaticFlowInternal(FlowConfig config, boolean async, boolean restore) {
boolean multipleFlowPush = false;
String error;
Status status;
// Program hw
if (config.installInHw()) {
FlowEntry entry = config.getFlowEntry();
- status = this.installFlowEntry(entry);
+ status = async ? this.installFlowEntryAsync(entry) : this.installFlowEntry(entry);
if (!status.isSuccess()) {
config.setStatus(status.getDescription());
if (!restore) {
@Override
public Status removeStaticFlow(FlowConfig config) {
+ return removeStaticFlow(config, false);
+ }
+
+ @Override
+ public Status removeStaticFlowAsync(FlowConfig config) {
+ return removeStaticFlow(config, true);
+ }
+
+ private Status removeStaticFlow(FlowConfig config, boolean async) {
/*
* No config.isInternal() check as NB does not take this path and GUI
* cannot issue a delete on an internal generated flow. We need this
}
// Program the network node
- Status status = this.uninstallFlowEntry(config.getFlowEntry());
+ Status status = async ? this.uninstallFlowEntryAsync(config.getFlowEntry()) : this.uninstallFlowEntry(config
+ .getFlowEntry());
// Update configuration database if programming was successful
if (status.isSuccess()) {
@Override
public Status removeStaticFlow(String name, Node node) {
+ return removeStaticFlow(name, node, false);
+ }
+
+ @Override
+ public Status removeStaticFlowAsync(String name, Node node) {
+ return removeStaticFlow(name, node, true);
+ }
+
+ private Status removeStaticFlow(String name, Node node, boolean async) {
// Look for the target configuration entry
Integer key = 0;
FlowConfig target = null;
}
// Program the network node
- Status status = this.removeEntry(target.getFlowEntry(), false);
+ Status status = this.removeEntry(target.getFlowEntry(), async);
// Update configuration database if programming was successful
if (status.isSuccess()) {
}
for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, STATIC_FLOWS_FILE_NAME)) {
- addStaticFlowInternal((FlowConfig) conf, true);
+ addStaticFlowInternal((FlowConfig) conf, false, true);
}
}
// check if the frm really needs to act on the notification.
// this is to check against duplicate notifications
if(programInternalFlow(proactive, fc)) {
- Status status = (proactive) ? addStaticFlowInternal(fc, false) : removeStaticFlow(fc);
+ Status status = (proactive) ? addStaticFlowInternal(fc, false, false) : removeStaticFlow(fc);
if (status.isSuccess()) {
log.trace("{} Proactive Static flow: {}", (proactive ? "Installed" : "Removed"), fc.getName());
} else {
if ((staticFlow.getNode().equals(node)) && (staticFlow.getPortGroup().equals(config.getName()))) {
for (Short port : data.getPorts()) {
FlowConfig derivedFlow = getDerivedFlowConfig(staticFlow, config.getName(), port);
- addStaticFlowInternal(derivedFlow, false);
+ addStaticFlowInternal(derivedFlow, false, false);
}
}
}
}
return list;
}
+
}
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
</plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- </plugin>
</plugins>
</build>
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
</plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- </plugin>
</plugins>
</build>
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
</plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- </plugin>
</plugins>
</build>
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
</plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- </plugin>
</plugins>
</build>
</project>
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.7</version>
- <executions>
- <execution>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>target/generated-sources/sal</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</build>
<!--module>test/sal-rest-connector-it</modulei -->
</modules>
</profile>
- <profile>
- <id>IDE</id>
- <activation>
- <property>
- <name>m2e.version</name>
- </property>
- </activation>
- <build>
- <!-- Put the IDE's build output in a folder other than target,
- so that IDE builds don't interact with Maven builds -->
- <directory>target-ide</directory>
- </build>
- </profile>
</profiles>
<properties>
- <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Plugin Versions -->
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
<version>${xtend.version}</version>
- <executions>
- <execution>
- <goals>
- <goal>compile</goal>
- </goals>
- <configuration>
- <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- <version>${maven.clean.plugin.version}</version>
- <configuration>
- <filesets>
- <fileset>
- <directory>${basedir}/src/main/xtend-gen</directory>
- <includes>
- <include>**</include>
- </includes>
- </fileset>
- </filesets>
- </configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${project.build.directory}/generated-sources/config</source>
- <source>${project.build.directory}/generated-sources/sal</source>
- <source>src/main/xtend-gen</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<codeGeneratorClass>
org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
</codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+ <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
<additionalConfiguration>
<namespaceToPackage1>
urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
-
-
- </goals>
- <configuration>
- <sources>
- <source>${project.build.directory}/generated-sources/config</source>
- <source>src/main/xtend-gen</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
</plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- </plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
.toNormalizedNode(path, data);
org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey();
- try {
- List<PathArgument> currentArguments = new ArrayList<>();
- DataNormalizationOperation<?> currentOp = codec.getDataNormalizer().getRootOperation();
- Iterator<PathArgument> iterator = normalizedPath.getPath().iterator();
- while (iterator.hasNext()) {
- PathArgument currentArg = iterator.next();
+ List<PathArgument> currentArguments = new ArrayList<>();
+ DataNormalizationOperation<?> currentOp = codec.getDataNormalizer().getRootOperation();
+ Iterator<PathArgument> iterator = normalizedPath.getPath().iterator();
+ while (iterator.hasNext()) {
+ PathArgument currentArg = iterator.next();
+ try {
currentOp = currentOp.getChild(currentArg);
- currentArguments.add(currentArg);
- org.opendaylight.yangtools.yang.data.api.InstanceIdentifier currentPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
- currentArguments);
- boolean isPresent = writeTransaction.read(store, currentPath).get().isPresent();
- if (isPresent == false && iterator.hasNext()) {
- writeTransaction.put(store, currentPath, currentOp.createDefault(currentArg));
- }
+ } catch (DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Invalid child encountered in path %s", path), e);
+ }
+ currentArguments.add(currentArg);
+ org.opendaylight.yangtools.yang.data.api.InstanceIdentifier currentPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
+ currentArguments);
+
+ final Optional<NormalizedNode<?, ?>> d;
+ try {
+ d = writeTransaction.read(store, currentPath).get();
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error("Failed to read pre-existing data from store {} path {}", store, currentPath, e);
+ throw new IllegalStateException("Failed to read pre-existing data", e);
+ }
+
+ if (!d.isPresent() && iterator.hasNext()) {
+ writeTransaction.put(store, currentPath, currentOp.createDefault(currentArg));
}
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
}
//LOG .info("Tx: {} : Putting data {}",getDelegate().getIdentifier(),normalized.getKey());
writeTransaction.put(store, normalized.getKey(), normalized.getValue());
-
}
protected void doMerge(final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType store,
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.codegen;
+
+import com.google.common.base.Objects;
+import java.lang.reflect.Field;
+import java.util.Map;
+import org.eclipse.xtext.xbase.lib.Exceptions;
+import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+@SuppressWarnings("all")
+public class RuntimeCodeHelper {
+ /**
+ * Helper method to return delegate from ManagedDirectedProxy with use of reflection.
+ *
+ * Note: This method uses reflection, but access to delegate field should be
+ * avoided and called only if neccessary.
+ */
+ public static <T extends RpcService> T getDelegate(final RpcService proxy) {
+ try {
+ Class<? extends RpcService> _class = proxy.getClass();
+ final Field field = _class.getField(RuntimeCodeSpecification.DELEGATE_FIELD);
+ boolean _equals = Objects.equal(field, null);
+ if (_equals) {
+ UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException("Unable to get delegate from proxy");
+ throw _unsupportedOperationException;
+ }
+ try {
+ Object _get = field.get(proxy);
+ return ((T) _get);
+ } catch (Throwable _e) {
+ throw Exceptions.sneakyThrow(_e);
+ }
+ } catch (Throwable _e_1) {
+ throw Exceptions.sneakyThrow(_e_1);
+ }
+ }
+
+ /**
+ * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
+ *
+ * Note: This method uses reflection, but setting delegate field should not occur too much
+ * to introduce any significant performance hits.
+ */
+ public static void setDelegate(final RpcService proxy, final RpcService delegate) {
+ try {
+ Class<? extends RpcService> _class = proxy.getClass();
+ final Field field = _class.getField(RuntimeCodeSpecification.DELEGATE_FIELD);
+ boolean _equals = Objects.equal(field, null);
+ if (_equals) {
+ UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException("Unable to set delegate to proxy");
+ throw _unsupportedOperationException;
+ }
+ boolean _or = false;
+ boolean _equals_1 = Objects.equal(delegate, null);
+ if (_equals_1) {
+ _or = true;
+ } else {
+ Class<? extends Object> _type = field.getType();
+ Class<? extends RpcService> _class_1 = delegate.getClass();
+ boolean _isAssignableFrom = _type.isAssignableFrom(_class_1);
+ _or = (_equals_1 || _isAssignableFrom);
+ }
+ if (_or) {
+ field.set(proxy, delegate);
+ } else {
+ IllegalArgumentException _illegalArgumentException = new IllegalArgumentException("delegate class is not assignable to proxy");
+ throw _illegalArgumentException;
+ }
+ } catch (Throwable _e) {
+ throw Exceptions.sneakyThrow(_e);
+ }
+ }
+
+ /**
+ * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
+ *
+ * Note: This method uses reflection, but setting delegate field should not occur too much
+ * to introduce any significant performance hits.
+ */
+ public static void setDelegate(final Object proxy, final Object delegate) {
+ try {
+ Class<? extends Object> _class = proxy.getClass();
+ final Field field = _class.getField(RuntimeCodeSpecification.DELEGATE_FIELD);
+ boolean _equals = Objects.equal(field, null);
+ if (_equals) {
+ UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException("Unable to set delegate to proxy");
+ throw _unsupportedOperationException;
+ }
+ boolean _or = false;
+ boolean _equals_1 = Objects.equal(delegate, null);
+ if (_equals_1) {
+ _or = true;
+ } else {
+ Class<? extends Object> _type = field.getType();
+ Class<? extends Object> _class_1 = delegate.getClass();
+ boolean _isAssignableFrom = _type.isAssignableFrom(_class_1);
+ _or = (_equals_1 || _isAssignableFrom);
+ }
+ if (_or) {
+ field.set(proxy, delegate);
+ } else {
+ IllegalArgumentException _illegalArgumentException = new IllegalArgumentException("delegate class is not assignable to proxy");
+ throw _illegalArgumentException;
+ }
+ } catch (Throwable _e) {
+ throw Exceptions.sneakyThrow(_e);
+ }
+ }
+
+ public static Map<InstanceIdentifier<? extends Object>,? extends RpcService> getRoutingTable(final RpcService target, final Class<? extends BaseIdentity> tableClass) {
+ try {
+ Class<? extends RpcService> _class = target.getClass();
+ String _routingTableField = RuntimeCodeSpecification.getRoutingTableField(tableClass);
+ final Field field = _class.getField(_routingTableField);
+ boolean _equals = Objects.equal(field, null);
+ if (_equals) {
+ UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException(
+ "Unable to get routing table. Table field does not exists");
+ throw _unsupportedOperationException;
+ }
+ try {
+ Object _get = field.get(target);
+ return ((Map<InstanceIdentifier<? extends Object>,? extends RpcService>) _get);
+ } catch (Throwable _e) {
+ throw Exceptions.sneakyThrow(_e);
+ }
+ } catch (Throwable _e_1) {
+ throw Exceptions.sneakyThrow(_e_1);
+ }
+ }
+
+ public static void setRoutingTable(final RpcService target, final Class<? extends BaseIdentity> tableClass, final Map<InstanceIdentifier<? extends Object>,? extends RpcService> routingTable) {
+ try {
+ Class<? extends RpcService> _class = target.getClass();
+ String _routingTableField = RuntimeCodeSpecification.getRoutingTableField(tableClass);
+ final Field field = _class.getField(_routingTableField);
+ boolean _equals = Objects.equal(field, null);
+ if (_equals) {
+ UnsupportedOperationException _unsupportedOperationException = new UnsupportedOperationException(
+ "Unable to set routing table. Table field does not exists");
+ throw _unsupportedOperationException;
+ }
+ field.set(target, routingTable);
+ } catch (Throwable _e) {
+ throw Exceptions.sneakyThrow(_e);
+ }
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.codegen
-
-import java.util.Map
-
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-import org.opendaylight.yangtools.yang.binding.RpcService
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-
-import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
-
-class RuntimeCodeHelper {
- /**
- * Helper method to return delegate from ManagedDirectedProxy with use of reflection.
- *
- * Note: This method uses reflection, but access to delegate field should be
- * avoided and called only if neccessary.
- *
- */
- public static def <T extends RpcService> getDelegate(RpcService proxy) {
- val field = proxy.class.getField(DELEGATE_FIELD)
- if (field == null) throw new UnsupportedOperationException("Unable to get delegate from proxy");
- return field.get(proxy) as T
- }
-
- /**
- * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
- *
- * Note: This method uses reflection, but setting delegate field should not occur too much
- * to introduce any significant performance hits.
- *
- */
- public static def void setDelegate(RpcService proxy, RpcService delegate) {
- val field = proxy.class.getField(DELEGATE_FIELD)
- if (field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
- if (delegate == null || field.type.isAssignableFrom(delegate.class)) {
- field.set(proxy, delegate)
- } else
- throw new IllegalArgumentException("delegate class is not assignable to proxy");
- }
-
- /**
- * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
- *
- * Note: This method uses reflection, but setting delegate field should not occur too much
- * to introduce any significant performance hits.
- *
- */
- public static def void setDelegate(Object proxy, Object delegate) {
- val field = proxy.class.getField(DELEGATE_FIELD)
- if (field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
- if (delegate == null || field.type.isAssignableFrom(delegate.class)) {
- field.set(proxy, delegate)
- } else
- throw new IllegalArgumentException("delegate class is not assignable to proxy");
- }
-
-
- public static def Map<InstanceIdentifier<?>, ? extends RpcService> getRoutingTable(RpcService target,
- Class<? extends BaseIdentity> tableClass) {
- val field = target.class.getField(tableClass.routingTableField)
- if (field == null) throw new UnsupportedOperationException(
- "Unable to get routing table. Table field does not exists");
- return field.get(target) as Map<InstanceIdentifier<? extends Object>, ? extends RpcService>;
- }
-
- public static def void setRoutingTable(RpcService target, Class<? extends BaseIdentity> tableClass,
- Map<InstanceIdentifier<?>, ? extends RpcService> routingTable) {
- val field = target.class.getField(tableClass.routingTableField)
- if (field == null) throw new UnsupportedOperationException(
- "Unable to set routing table. Table field does not exists");
- field.set(target,routingTable);
- }
-
-}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+
+package org.opendaylight.controller.sal.binding.codegen;
+
+import java.lang.reflect.Method;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+@SuppressWarnings("all")
+public class YangtoolsMappingHelper {
+ public static boolean isNotificationCallback(final Method it) {
+ return it.getName().startsWith("on") && (it.getParameterTypes().length == 1) &&
+ Notification.class.isAssignableFrom(it.getParameterTypes()[0]);
+ }
+
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.codegen
-
-import java.lang.reflect.Method
-import org.opendaylight.yangtools.yang.binding.Notification
-
-public static class YangtoolsMappingHelper {
-
- public static def boolean isNotificationCallback(Method it) {
- return name.startsWith("on") && parameterTypes.size === 1 &&
- Notification.isAssignableFrom(parameterTypes.get(0))
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import org.eclipse.xtext.xbase.lib.Exceptions;
+
+@SuppressWarnings("all")
+public class BrokerImplClassLoader extends ClassLoader {
+ private final ClassLoader spiClassLoader;
+
+ public BrokerImplClassLoader(final ClassLoader model, final ClassLoader spi) {
+ super(model);
+ this.spiClassLoader = spi;
+ }
+
+ public Class<? extends Object> loadClass(final String name) throws ClassNotFoundException {
+ try {
+ return super.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ return this.spiClassLoader.loadClass(name);
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.codegen.impl
-
-import java.lang.ClassLoader
-
-class BrokerImplClassLoader extends ClassLoader {
-
- val ClassLoader spiClassLoader
-
- public new(ClassLoader model, ClassLoader spi) {
- super(model)
- spiClassLoader = spi;
- }
-
- override public loadClass(String name) throws ClassNotFoundException {
- try {
- return super.loadClass(name);
- } catch (ClassNotFoundException e) {
- return spiClassLoader.loadClass(name);
- }
- }
-
-}
* 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;\r
-\r
+package org.opendaylight.controller.sal.binding.impl;
+
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter;
import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
-import org.opendaylight.controller.sal.binding.impl.util.BindingAwareDataReaderRouter;
+import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.util.DataObjectReadingUtil;
import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Maps;
-\r
-\r
-public class DataBrokerImpl extends AbstractDataBroker<InstanceIdentifier<? extends DataObject>, DataObject, DataChangeListener> //\r
- implements DataProviderService, AutoCloseable {\r
-\r
+
+public class DataBrokerImpl extends
+ AbstractDataBroker<InstanceIdentifier<? extends DataObject>, DataObject, DataChangeListener> //
+ implements DataProviderService, AutoCloseable {
+
private final static class ContainsWildcarded implements Predicate<InstanceIdentifier<? extends DataObject>> {
- private final InstanceIdentifier<? extends DataObject> key;
+ private final InstanceIdentifier<? extends DataObject> key;
- public ContainsWildcarded(InstanceIdentifier<? extends DataObject> key) {
+ public ContainsWildcarded(final InstanceIdentifier<? extends DataObject> key) {
this.key = key;
}
@Override
- public boolean apply(InstanceIdentifier<? extends DataObject> input) {
+ public boolean apply(final InstanceIdentifier<? extends DataObject> input) {
return key.containsWildcarded(input);
}
}
private final static class IsContainedWildcarded implements Predicate<InstanceIdentifier<? extends DataObject>> {
- private final InstanceIdentifier<? extends DataObject> key;
+ private final InstanceIdentifier<? extends DataObject> key;
- public IsContainedWildcarded(InstanceIdentifier<? extends DataObject> key) {
+ public IsContainedWildcarded(final InstanceIdentifier<? extends DataObject> key) {
this.key = key;
}
@Override
- public boolean apply(InstanceIdentifier<? extends DataObject> input) {
+ public boolean apply(final InstanceIdentifier<? extends DataObject> input) {
return input.containsWildcarded(key);
}
}
- private final AtomicLong nextTransaction = new AtomicLong();\r
- private final AtomicLong createdTransactionsCount = new AtomicLong();\r
-\r
- public AtomicLong getCreatedTransactionsCount() {\r
- return createdTransactionsCount;\r
- }\r
-\r
- public DataBrokerImpl() {\r
- setDataReadRouter(new BindingAwareDataReaderRouter());\r
- }\r
-\r
- @Override\r
- public DataTransactionImpl beginTransaction() {\r
- String transactionId = "BA-" + nextTransaction.getAndIncrement();\r
- createdTransactionsCount.getAndIncrement();\r
- return new DataTransactionImpl(transactionId,this);\r
- }\r
-\r
- @Override\r
- public void close() {\r
-\r
+ private final AtomicLong nextTransaction = new AtomicLong();
+ private final AtomicLong createdTransactionsCount = new AtomicLong();
+ private final DelegatingDataReadRouter router = new DelegatingDataReadRouter();
+ private DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> rootCommitHandler;
+
+ public DataBrokerImpl() {
+ setDataReadRouter(router);
+ }
+
+ public void setDataReadDelegate(final DataReader<InstanceIdentifier<? extends DataObject>, DataObject> delegate) {
+ router.setDelegate(delegate);
+ }
+
+ public AtomicLong getCreatedTransactionsCount() {
+ return createdTransactionsCount;
+ }
+
+ @Override
+ public DataTransactionImpl beginTransaction() {
+ String transactionId = "BA-" + nextTransaction.getAndIncrement();
+ createdTransactionsCount.getAndIncrement();
+ return new DataTransactionImpl(transactionId, this);
}
@Override
- protected Predicate<InstanceIdentifier<? extends DataObject>> createContainsPredicate(final
- InstanceIdentifier<? extends DataObject> key) {
+ public void close() {
+
+ }
+
+ @Override
+ protected Predicate<InstanceIdentifier<? extends DataObject>> createContainsPredicate(
+ final InstanceIdentifier<? extends DataObject> key) {
return new ContainsWildcarded(key);
}
@Override
- protected Predicate<InstanceIdentifier<? extends DataObject>> createIsContainedPredicate(final
- InstanceIdentifier<? extends DataObject> key) {
+ protected Predicate<InstanceIdentifier<? extends DataObject>> createIsContainedPredicate(
+ final InstanceIdentifier<? extends DataObject> key) {
return new IsContainedWildcarded(key);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected Map<InstanceIdentifier<? extends DataObject>, DataObject> deepGetBySubpath(
- Map<InstanceIdentifier<? extends DataObject>, DataObject> dataSet,
- InstanceIdentifier<? extends DataObject> path) {
+ final Map<InstanceIdentifier<? extends DataObject>, DataObject> dataSet,
+ final InstanceIdentifier<? extends DataObject> path) {
Builder<InstanceIdentifier<? extends DataObject>, DataObject> builder = ImmutableMap.builder();
- Map<InstanceIdentifier<? extends DataObject>, DataObject> potential = Maps.filterKeys(dataSet, createIsContainedPredicate(path));
- for(Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : potential.entrySet()) {
+ Map<InstanceIdentifier<? extends DataObject>, DataObject> potential = Maps.filterKeys(dataSet,
+ createIsContainedPredicate(path));
+ for (Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry : potential.entrySet()) {
try {
- builder.putAll(DataObjectReadingUtil.readData(entry.getValue(),(InstanceIdentifier)entry.getKey(),path));
+ builder.putAll(DataObjectReadingUtil.readData(entry.getValue(), (InstanceIdentifier) entry.getKey(),
+ path));
} catch (Exception e) {
// FIXME : Log exception;
}
return builder.build();
}
-\r
+
+ public class DelegatingDataReadRouter extends
+ AbstractDataReadRouter<InstanceIdentifier<? extends DataObject>, DataObject> {
+
+ private DataReader<InstanceIdentifier<? extends DataObject>, DataObject> delegate;
+
+ @Override
+ public DataObject readConfigurationData(final InstanceIdentifier<? extends DataObject> path) {
+ return delegate.readConfigurationData(path);
+ }
+
+ public void setDelegate(final DataReader<InstanceIdentifier<? extends DataObject>, DataObject> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public DataObject readOperationalData(final InstanceIdentifier<? extends DataObject> path) {
+ return delegate.readOperationalData(path);
+ }
+
+ @Override
+ protected DataObject merge(final InstanceIdentifier<? extends DataObject> path, final Iterable<DataObject> data) {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ @Override
+ public Registration<DataReader<InstanceIdentifier<? extends DataObject>, DataObject>> registerConfigurationReader(
+ final InstanceIdentifier<? extends DataObject> path,
+ final DataReader<InstanceIdentifier<? extends DataObject>, DataObject> reader) {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ @Override
+ public Registration<DataReader<InstanceIdentifier<? extends DataObject>, DataObject>> registerOperationalReader(
+ final InstanceIdentifier<? extends DataObject> path,
+ final DataReader<InstanceIdentifier<? extends DataObject>, DataObject> reader) {
+ throw new UnsupportedOperationException("Not supported");
+ }
+ }
+
+ @Override
+ protected ImmutableList<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> affectedCommitHandlers(
+ final Set<InstanceIdentifier<? extends DataObject>> paths) {
+ ImmutableList.Builder<DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject>> handlersBuilder = ImmutableList.builder();
+ return handlersBuilder //
+ .add(rootCommitHandler) //
+ .addAll(super.affectedCommitHandlers(paths)) //
+ .build();
+ }
+
+ public void setRootCommitHandler(final DataCommitHandler<InstanceIdentifier<? extends DataObject>, DataObject> commitHandler) {
+ rootCommitHandler = commitHandler;
+ }
+
}
super(rpcRegistry, notificationBroker, dataBroker);
this.identifier = identifier;
}
+
+ // Needed only for BI Connector
+ public DataBrokerImpl getDataBrokerImpl() {
+ return (DataBrokerImpl) getDataBroker();
+ }
@Override
public InstanceIdentifier<?> getIdentifier() {
override publish(Notification notification, ExecutorService service) {\r
val allTypes = notification.notificationTypes\r
\r
- var Iterable<NotificationListener<?>> listenerToNotify = Collections.emptySet();\r
+ var Iterable<NotificationListener<? extends Object>> listenerToNotify = Collections.emptySet();\r
for (type : allTypes) {\r
listenerToNotify = listenerToNotify + listeners.get(type as Class<? extends Notification>)\r
}\r
--- /dev/null
+/*
+ * 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.yangtools.yang.binding.RpcService;
+import org.osgi.framework.ServiceRegistration;
+
+@SuppressWarnings("all")
+public class RpcProxyContext {
+ public RpcProxyContext(final Class<? extends RpcService> proxyClass) {
+ this.proxyClass = proxyClass;
+ }
+
+ protected final Class<? extends RpcService> proxyClass;
+
+ protected RpcService _proxy;
+
+ public RpcService getProxy() {
+ return this._proxy;
+ }
+
+ public void setProxy(final RpcService proxy) {
+ this._proxy = proxy;
+ }
+
+ protected ServiceRegistration<? extends RpcService> _registration;
+
+ public ServiceRegistration<? extends RpcService> getRegistration() {
+ return this._registration;
+ }
+
+ public void setRegistration(final ServiceRegistration<? extends RpcService> registration) {
+ this._registration = registration;
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.yangtools.yang.binding.RpcService
-import org.osgi.framework.ServiceRegistration
-
-class RpcProxyContext {
-
- new(Class<? extends RpcService> proxyClass) {
- this.proxyClass = proxyClass
- }
-
- protected val Class<? extends RpcService> proxyClass;
-
- @Property
- protected var RpcService proxy;
-
- @Property
- protected var ServiceRegistration<? extends RpcService> registration;
-}
\ No newline at end of file
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.controller.md.sal.common.api.data.DataReader;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider;
import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
+import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
+import org.opendaylight.controller.sal.binding.impl.MountPointManagerImpl.BindingMountPointImpl;
import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl;
import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.GlobalRpcRegistrationListener;
import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
public class BindingIndependentConnector implements //
RuntimeDataProvider, //
private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class);
- @SuppressWarnings("deprecation")
- private static final InstanceIdentifier<? extends DataObject> ROOT = InstanceIdentifier.builder().toInstance();
private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
.builder().toInstance();
};
- private Registration<DataReader<InstanceIdentifier<? extends DataObject>, DataObject>> baDataReaderRegistration;
-
private boolean rpcForwarding = false;
private boolean dataForwarding = false;
dataForwarding = true;
return;
}
- checkState(!dataForwarding, "Connector is already forwarding data.");
- baDataReaderRegistration = baDataService.registerDataReader(ROOT, this);
- baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler);
- biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
- baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
+
+ final DataProviderService baData;
+ if (baDataService instanceof BindingMountPointImpl) {
+ baData = ((BindingMountPointImpl)baDataService).getDataBrokerImpl();
+ LOG.debug("Extracted BA Data provider {} from mount point {}", baData, baDataService);
+ } else {
+ baData = baDataService;
+ }
+
+ if (baData instanceof DataBrokerImpl) {
+ checkState(!dataForwarding, "Connector is already forwarding data.");
+ ((DataBrokerImpl) baData).setDataReadDelegate(this);
+ ((DataBrokerImpl) baData).setRootCommitHandler(bindingToDomCommitHandler);
+ biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler);
+ baDataService.registerCommitHandlerListener(domToBindingCommitHandler);
+ }
+
dataForwarding = true;
}
}
}
+
@Override
- public RpcResult<CompositeNode> invokeRpc(final QName rpc, final CompositeNode domInput) {
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode domInput) {
checkArgument(rpc != null);
checkArgument(domInput != null);
RpcService rpcService = baRpcRegistry.getRpcService(rpcType);
checkState(rpcService != null);
CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input"));
+
try {
- return resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput);
+ return Futures.immediateFuture(resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput));
} catch (Exception e) {
- throw new IllegalStateException(e);
+ return Futures.immediateFailedFuture(e);
}
}
}
@Override
- public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
- if(biRpcRegistry != null) {
- CompositeNode xml = mappingService.toDataDom(input);
- CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
- RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
- Object baResultValue = null;
- if (result.getResult() != null) {
- baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult());
- }
- RpcResult<?> baResult = Rpcs.getRpcResult(result.isSuccessful(), baResultValue, result.getErrors());
- return Futures.<RpcResult<?>> immediateFuture(baResult);
+ public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
+ if(biRpcRegistry == null) {
+ return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
}
- return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
- }
+ CompositeNode xml = mappingService.toDataDom(input);
+ CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc, ImmutableList.<Node<?>> of(xml));
+
+ return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml), new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
+ @Override
+ public RpcResult<?> apply(RpcResult<CompositeNode> input) {
+ Object baResultValue = null;
+ if (input.getResult() != null) {
+ baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), input.getResult());
+ }
+ return Rpcs.getRpcResult(input.isSuccessful(), baResultValue, input.getErrors());
+ }
+ });
+ }
}
private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy {
}
@Override
- public Future<RpcResult<?>> forwardToDomBroker(final DataObject input) {
- if(biRpcRegistry != null) {
- CompositeNode xml = mappingService.toDataDom(input);
- CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
- RpcResult<CompositeNode> result = biRpcRegistry.invokeRpc(rpc, wrappedXml);
- Object baResultValue = null;
- RpcResult<?> baResult = Rpcs.<Void>getRpcResult(result.isSuccessful(), null, result.getErrors());
- return Futures.<RpcResult<?>>immediateFuture(baResult);
+ public ListenableFuture<RpcResult<?>> forwardToDomBroker(final DataObject input) {
+ if(biRpcRegistry == null) {
+ return Futures.<RpcResult<?>> immediateFuture(Rpcs.getRpcResult(false));
}
- return Futures.<RpcResult<?>>immediateFuture(Rpcs.getRpcResult(false));
- }
+ CompositeNode xml = mappingService.toDataDom(input);
+ CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.<Node<?>>of(xml));
+
+ return Futures.transform(biRpcRegistry.invokeRpc(rpc, wrappedXml), new Function<RpcResult<CompositeNode>, RpcResult<?>>() {
+ @Override
+ public RpcResult<?> apply(RpcResult<CompositeNode> input) {
+ return Rpcs.<Void>getRpcResult(input.isSuccessful(), null, input.getErrors());
+ }
+ });
+ }
}
public boolean isRpcForwarding() {
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.binding.impl.util;
+
+import java.util.Iterator;
+import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@SuppressWarnings("all")
+public class BindingAwareDataReaderRouter extends AbstractDataReadRouter<InstanceIdentifier<? extends DataObject>,DataObject> {
+ protected DataObject merge(final InstanceIdentifier<? extends DataObject> path, final Iterable<DataObject> data) {
+ return data.iterator().next();
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.impl.util
-
-import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.DataObject
-
-class BindingAwareDataReaderRouter extends AbstractDataReadRouter<InstanceIdentifier<? extends DataObject>, DataObject> {
-
- override protected merge(InstanceIdentifier<? extends DataObject> path, Iterable<DataObject> data) {
- return data.iterator.next;
- }
-
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.binding.impl.util;
+
+import com.google.common.collect.Multimap;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map.Entry;
+import org.opendaylight.yangtools.concepts.Path;
+
+@SuppressWarnings("all")
+public class MapUtils {
+ public static <P extends Path<P>, V extends Object> Collection<Entry<? extends P,? extends V>> getAllChildren(final Multimap<? extends P,? extends V> map, final P path) {
+ HashSet<Entry<? extends P,? extends V>> _hashSet = new HashSet<Entry<? extends P, ? extends V>>();
+ final HashSet<Entry<? extends P,? extends V>> ret = _hashSet;
+ final Collection<? extends Entry<? extends P,? extends V>> entries = map.entries();
+ for (final Entry<? extends P,? extends V> entry : entries) {
+ {
+ final P currentPath = entry.getKey();
+ if (path.contains(currentPath)) {
+ ret.add(entry);
+ } else if (currentPath.contains(path)){
+ ret.add(entry);
+ }
+ }
+ }
+ return ret;
+ }
+}
+
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.binding.impl.util
-
-import com.google.common.collect.Multimap
-import java.util.Collection
-import java.util.HashSet
-import java.util.Map.Entry
-import org.opendaylight.yangtools.concepts.Path
-
-class MapUtils {
-
- public static def <P extends Path<P>, V> Collection<Entry<? extends P, ? extends V>> getAllChildren(
- Multimap<? extends P, ? extends V> map, P path) {
- val ret = new HashSet();
- val entries = map.entries;
-
- for (entry : entries) {
- val currentPath = entry.key;
- // If the registered reader processes nested elements
- if (path.contains(currentPath)) {
- ret.add(entry);
- } else if(currentPath.contains(path)) {
- // If the registered reader is parent of entry
- ret.add(entry);
- }
- }
-
- return ret;
- }
-}
import static org.mockito.Mockito.verify;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import javassist.ClassPool;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
public class RuntimeCodeGeneratorTest {
}
- private void verifyRouting(RpcRouter<FooService> product) {
+ private void verifyRouting(final RpcRouter<FooService> product) {
assertNotNull("Routing table should be initialized", product.getRoutingTable(BaseIdentity.class));
RpcRoutingTable<BaseIdentity, FooService> routingTable = product.getRoutingTable(BaseIdentity.class);
verify(service[1]).simple(instance_1_input[0]);
}
- private InstanceIdentifier<?>[][] identifiers(int serviceSize, int instancesPerService) {
+ private InstanceIdentifier<?>[][] identifiers(final int serviceSize, final int instancesPerService) {
InstanceIdentifier<?>[][] ret = new InstanceIdentifier[serviceSize][];
int service = 0;
for (int i = 0; i < serviceSize; i++) {
return ret;
}
- private InstanceIdentifier<?> referencableIdentifier(int i) {
- ReferencableObjectKey key = new ReferencableObjectKey(i);
- IdentifiableItem<ReferencableObject, ReferencableObjectKey> pathArg = new IdentifiableItem<>(
- ReferencableObject.class, key);
- return new InstanceIdentifier<ReferencableObject>(Arrays.<PathArgument> asList(pathArg),
- ReferencableObject.class);
+ private InstanceIdentifier<?> referencableIdentifier(final int i) {
+ return InstanceIdentifier.builder(ReferencableObject.class, new ReferencableObjectKey(i)).build();
}
private static class SimpleInputImpl implements SimpleInput {
private final InstanceIdentifier<?> identifier;
- public SimpleInputImpl(InstanceIdentifier<?> _identifier) {
+ public SimpleInputImpl(final InstanceIdentifier<?> _identifier) {
this.identifier = _identifier;
}
@Override
- public <E extends Augmentation<SimpleInput>> E getAugmentation(Class<E> augmentationType) {
+ public <E extends Augmentation<SimpleInput>> E getAugmentation(final Class<E> augmentationType) {
return null;
}
List<FooUpdate> receivedFoos = new ArrayList<>();
@Override
- public void onFooUpdate(FooUpdate notification) {
+ public void onFooUpdate(final FooUpdate notification) {
receivedFoos.add(notification);
}
List<FlowDelete> receivedDeletes = new ArrayList<>();
@Override
- public void onBarUpdate(BarUpdate notification) {
+ public void onBarUpdate(final BarUpdate notification) {
receivedBars.add(notification);
}
@Override
- public void onFlowDelete(FlowDelete notification) {
+ public void onFlowDelete(final FlowDelete notification) {
receivedDeletes.add(notification);
}
*/
package org.opendaylight.controller.sal.binding.test.mock;
+import org.opendaylight.yangtools.yang.binding.ChildOf;
import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
import org.opendaylight.yangtools.yang.binding.Identifiable;
-public interface ReferencableObject extends DataObject,Identifiable<ReferencableObjectKey> {
+public interface ReferencableObject extends DataObject,
+ Identifiable<ReferencableObjectKey>,ChildOf<DataRoot>{
}
private void startDomBroker() {
checkState(executor != null);
biBrokerImpl = new BrokerImpl();
- biBrokerImpl.setExecutor(executor);
biBrokerImpl.setRouter(new SchemaAwareRpcBroker("/", this));
}
<codeGeneratorClass>
org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
</codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+ <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
<additionalConfiguration>
<namespaceToPackage1>
urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${project.build.directory}/generated-sources/config</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</build>
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
</plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- </plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
public class CrossBrokerRpcTest {
public static final NodeId NODE_B = new NodeId("b");
public static final NodeId NODE_C = new NodeId("c");
public static final NodeId NODE_D = new NodeId("d");
-
+
private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow");
public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_C_ID = createBINodeIdentifier(NODE_C);
public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_D_ID = createBINodeIdentifier(NODE_D);
-
+
@Before
public void setup() {
}
@Test
- public void bindingRoutedRpcProvider_DomInvokerTest() {
+ public void bindingRoutedRpcProvider_DomInvokerTest() throws Exception {
flowService//
.registerPath(NodeContext.class, BA_NODE_A_ID) //
CompositeNode addFlowDom = toDomRpc(ADD_FLOW_QNAME, addFlowA);
assertNotNull(addFlowDom);
- RpcResult<CompositeNode> domResult = biRpcInvoker.invokeRpc(ADD_FLOW_QNAME, addFlowDom);
+ RpcResult<CompositeNode> domResult = biRpcInvoker.invokeRpc(ADD_FLOW_QNAME, addFlowDom).get();
assertNotNull(domResult);
assertTrue("DOM result is successful.", domResult.isSuccessful());
assertTrue("Bidning Add Flow RPC was captured.", flowService.getReceivedAddFlows().containsKey(BA_NODE_A_ID));
final AddFlowOutput output = builder.build();
org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration registration = biRpcRegistry.addRoutedRpcImplementation(ADD_FLOW_QNAME, new RpcImplementation() {
@Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
- CompositeNode result = testContext.getBindingToDomMappingService().toDataDom(output);
- return Rpcs.getRpcResult(true, result, ImmutableList.<RpcError>of());
+ public Set<QName> getSupportedRpcs() {
+ return ImmutableSet.of(ADD_FLOW_QNAME);
}
@Override
- public Set<QName> getSupportedRpcs() {
- return ImmutableSet.of(ADD_FLOW_QNAME);
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
+ CompositeNode result = testContext.getBindingToDomMappingService().toDataDom(output);
+ return Futures.immediateFuture(Rpcs.getRpcResult(true, result, ImmutableList.<RpcError>of()));
}
});
registration.registerPath(NodeContext.QNAME, BI_NODE_C_ID);
-
+
SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class);
Future<RpcResult<AddFlowOutput>> baResult = baFlowInvoker.addFlow(addFlow(BA_NODE_C_ID).setPriority(500).build());
assertNotNull(baResult);
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.common.impl.util.compat;
+
+public class DataNormalizationException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public DataNormalizationException(String message) {
+ super(message);
+ }
+
+ public DataNormalizationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
package org.opendaylight.controller.md.sal.common.impl.util.compat;
import static com.google.common.base.Preconditions.checkArgument;
return Collections.singleton(identifier.getNodeType());
}
- public abstract DataNormalizationOperation<?> getChild(final PathArgument child);
+ public abstract DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException;
- public abstract DataNormalizationOperation<?> getChild(QName child);
+ public abstract DataNormalizationOperation<?> getChild(QName child) throws DataNormalizationException;
public abstract NormalizedNode<?, ?> normalize(Node<?> legacyData);
Set<DataNormalizationOperation<?>> usedMixins = new HashSet<>();
for (Node<?> childLegacy : compositeNode.getValue()) {
- DataNormalizationOperation childOp = getChild(childLegacy.getNodeType());
+ final DataNormalizationOperation childOp;
+
+ try {
+ childOp = getChild(childLegacy.getNodeType());
+ } catch (DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Failed to normalize data %s", compositeNode.getValue()), e);
+ }
// We skip unknown nodes if this node is mixin since
// it's nodes and parent nodes are interleaved
if (childOp.isMixin()) {
if (usedMixins.contains(childOp)) {
// We already run / processed that mixin, so to avoid
- // dupliciry we are
- // skiping next nodes.
+ // duplicity we are skipping next nodes.
continue;
}
builder.addChild(childOp.normalize(compositeNode));
}
@Override
- public DataNormalizationOperation<?> getChild(final PathArgument child) {
+ public DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException {
DataNormalizationOperation<?> potential = byArg.get(child);
if (potential != null) {
return potential;
}
@Override
- public DataNormalizationOperation<?> getChild(final QName child) {
+ public DataNormalizationOperation<?> getChild(final QName child) throws DataNormalizationException {
DataNormalizationOperation<?> potential = byQName.get(child);
if (potential != null) {
return potential;
}
}
- public static DataNormalizationOperation<?> fromSchemaAndPathArgument(final DataNodeContainer schema,
- final QName child) {
+ private static DataNormalizationOperation<?> fromSchemaAndPathArgument(final DataNodeContainer schema,
+ final QName child) throws DataNormalizationException {
DataSchemaNode potential = schema.getDataChildByName(child);
if (potential == null) {
Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices = FluentIterable.from(
schema.getChildNodes()).filter(org.opendaylight.yangtools.yang.model.api.ChoiceNode.class);
potential = findChoice(choices, child);
}
- checkArgument(potential != null, "Supplied QName %s is not valid according to schema %s", child, schema);
+
+ if (potential == null) {
+ throw new DataNormalizationException(String.format("Supplied QName %s is not valid according to schema %s", child, schema));
+ }
+
if ((schema instanceof DataSchemaNode) && !((DataSchemaNode) schema).isAugmenting() && potential.isAugmenting()) {
return fromAugmentation(schema, (AugmentationTarget) schema, potential);
}
}
}
- private static DataNormalizationOperation<?> fromSchema(final DataNodeContainer schema, final PathArgument child) {
+ private static DataNormalizationOperation<?> fromSchema(final DataNodeContainer schema, final PathArgument child) throws DataNormalizationException {
if (child instanceof AugmentationIdentifier) {
return fromSchemaAndPathArgument(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
.iterator().next());
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
package org.opendaylight.controller.md.sal.common.impl.util.compat;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.Iterator;
import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
DataNormalizationOperation<?> currentOp = operation;
Iterator<PathArgument> arguments = legacy.getPath().iterator();
- while ( arguments.hasNext() ) {
- PathArgument legacyArg = arguments.next();
- currentOp = currentOp.getChild(legacyArg);
- checkArgument(currentOp != null, "Legacy Instance Identifier %s is not correct. Normalized Instance Identifier so far %s",legacy,normalizedArgs.build());
- while (currentOp.isMixin()) {
- normalizedArgs.add(currentOp.getIdentifier());
- currentOp = currentOp.getChild(legacyArg.getNodeType());
- }
- if(arguments.hasNext() || (!currentOp.isKeyedEntry() || legacyArg instanceof NodeIdentifierWithPredicates || legacyArg instanceof NodeWithValue)) {
- normalizedArgs.add(legacyArg);
+
+ try {
+ while ( arguments.hasNext() ) {
+ PathArgument legacyArg = arguments.next();
+ currentOp = currentOp.getChild(legacyArg);
+ checkArgument(currentOp != null, "Legacy Instance Identifier %s is not correct. Normalized Instance Identifier so far %s",legacy,normalizedArgs.build());
+ while (currentOp.isMixin()) {
+ normalizedArgs.add(currentOp.getIdentifier());
+ currentOp = currentOp.getChild(legacyArg.getNodeType());
+ }
+ if(arguments.hasNext() || (!currentOp.isKeyedEntry() || legacyArg instanceof NodeIdentifierWithPredicates || legacyArg instanceof NodeWithValue)) {
+ normalizedArgs.add(legacyArg);
+ }
}
+ } catch (DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Failed to normalize path %s", legacy), e);
}
+
return new InstanceIdentifier(normalizedArgs.build());
}
DataNormalizationOperation<?> currentOp = operation;
for (PathArgument arg : normalizedPath.getPath()) {
- currentOp = currentOp.getChild(arg);
+ try {
+ currentOp = currentOp.getChild(arg);
+ } catch (DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Failed to validate normalized path %s", normalizedPath), e);
+ }
}
- // Write Augmentaiton data resolution
+
+ // Write Augmentation data resolution
if (legacyData.getChildren().size() == 1) {
- DataNormalizationOperation<?> potentialOp = currentOp.getChild(legacyData.getChildren().get(0)
- .getNodeType());
+ final DataNormalizationOperation<?> potentialOp;
+
+ try {
+ final QName childType = legacyData.getChildren().get(0).getNodeType();
+ potentialOp = currentOp.getChild(childType);
+ } catch (DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Failed to get child operation for %s", legacyData), e);
+ }
+
if(potentialOp.getIdentifier() instanceof AugmentationIdentifier) {
currentOp = potentialOp;
ArrayList<PathArgument> reworkedArgs = new ArrayList<>(normalizedPath.getPath());
<codeGeneratorClass>
org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
</codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+ <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
<additionalConfiguration>
<namespaceToPackage1>
urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${project.build.directory}/generated-sources/config</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</build>
<dependencies>
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
package org.opendaylight.controller.sal.core.api;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import com.google.common.util.concurrent.ListenableFuture;
+
public interface RoutedRpcDefaultImplementation {
- public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input);
+ ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input);
}
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import com.google.common.util.concurrent.ListenableFuture;
+
/**
* {@link Provider}'s implementation of an RPC.
*
* {@link RpcResult}
* <li> {@link Broker} returns the {@link RpcResult} to {@link Consumer}
* </ol>
- *
- *
*/
public interface RpcImplementation extends Provider.ProviderFunctionality {
Set<QName> getSupportedRpcs();
/**
- * Invokes a implementation of specified rpc.
- *
+ * Invokes a implementation of specified RPC asynchronously.
*
* @param rpc
- * Rpc to be invoked
+ * RPC to be invoked
* @param input
- * Input data for rpc.
+ * Input data for the RPC.
*
* @throws IllegalArgumentException
* <ul>
* <li>If input is not <code>null</code> and
* <code>false == rpc.equals(input.getNodeType)</code>
* </ul>
- * @return RpcResult containing the output of rpc if was executed
- * successfully, the list of errors otherwise.
+ * @return Future promising an RpcResult containing the output of
+ * the RPC if was executed successfully, the list of errors
+ * otherwise.
*/
- RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input);
-
+ ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input);
}
<codeGeneratorClass>
org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
</codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+ <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
<additionalConfiguration>
<namespaceToPackage1>
urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
</instructions>
</configuration>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${project.build.directory}/generated-sources/config</source>
- <source>src/main/xtend-gen</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
<plugin>
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
package org.opendaylight.controller.md.sal.dom.broker.impl.compat;
import static com.google.common.base.Preconditions.checkNotNull;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
Iterator<PathArgument> iterator = normalizedPath.getPath().iterator();
while(iterator.hasNext()) {
PathArgument currentArg = iterator.next();
- currentOp = currentOp.getChild(currentArg);
+ try {
+ currentOp = currentOp.getChild(currentArg);
+ } catch (DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Invalid child encountered in path %s", normalizedPath), e);
+ }
currentArguments.add(currentArg);
InstanceIdentifier currentPath = new InstanceIdentifier(currentArguments);
boolean isPresent = getDelegate().read(store, currentPath).get().isPresent();
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerRegistrationNode;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Walker;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
private static final DOMImmutableDataChangeEvent NO_CHANGE = builder().build();
private final ImmutableList.Builder<ChangeListenerNotifyTask> tasks = ImmutableList.builder();
private InstanceIdentifier rootPath;
- private ListenerRegistrationNode listenerRoot;
+ private ListenerTree listenerRoot;
private NodeModification modificationRoot;
private Optional<StoreMetadataNode> beforeRoot;
private Optional<StoreMetadataNode> afterRoot;
return this;
}
- protected ListenerRegistrationNode getListenerRoot() {
+ protected ListenerTree getListenerRoot() {
return listenerRoot;
}
- protected DataChangeEventResolver setListenerRoot(final ListenerRegistrationNode listenerRoot) {
+ protected DataChangeEventResolver setListenerRoot(final ListenerTree listenerRoot) {
this.listenerRoot = listenerRoot;
return this;
}
}
public Iterable<ChangeListenerNotifyTask> resolve() {
- LOG.trace("Resolving events for {}" ,modificationRoot);
- resolveAnyChangeEvent(rootPath, Optional.of(listenerRoot), modificationRoot, beforeRoot, afterRoot);
- return tasks.build();
+ LOG.trace("Resolving events for {}", modificationRoot);
+
+ try (final Walker w = listenerRoot.getWalker()) {
+ resolveAnyChangeEvent(rootPath, Optional.of(w.getRootNode()), modificationRoot, beforeRoot, afterRoot);
+ return tasks.build();
+ }
}
private DOMImmutableDataChangeEvent resolveAnyChangeEvent(final InstanceIdentifier path,
- final Optional<ListenerRegistrationNode> listeners, final NodeModification modification,
+ final Optional<ListenerTree.Node> listeners, final NodeModification modification,
final Optional<StoreMetadataNode> before, final Optional<StoreMetadataNode> after) {
// No listeners are present in listener registration subtree
// no before and after state is present
* @return
*/
private DOMImmutableDataChangeEvent resolveCreateEvent(final InstanceIdentifier path,
- final Optional<ListenerRegistrationNode> listeners, final StoreMetadataNode afterState) {
+ final Optional<ListenerTree.Node> listeners, final StoreMetadataNode afterState) {
final NormalizedNode<?, ?> node = afterState.getData();
Builder builder = builder().setAfter(node).addCreated(path, node);
for (StoreMetadataNode child : afterState.getChildren()) {
PathArgument childId = child.getIdentifier();
- Optional<ListenerRegistrationNode> childListeners = getChild(listeners, childId);
+ Optional<ListenerTree.Node> childListeners = getChild(listeners, childId);
InstanceIdentifier childPath = StoreUtils.append(path, childId);
builder.merge(resolveCreateEvent(childPath, childListeners, child));
}
private DOMImmutableDataChangeEvent resolveDeleteEvent(final InstanceIdentifier path,
- final Optional<ListenerRegistrationNode> listeners, final StoreMetadataNode beforeState) {
+ final Optional<ListenerTree.Node> listeners, final StoreMetadataNode beforeState) {
final NormalizedNode<?, ?> node = beforeState.getData();
Builder builder = builder().setBefore(node).addRemoved(path, node);
for (StoreMetadataNode child : beforeState.getChildren()) {
PathArgument childId = child.getIdentifier();
- Optional<ListenerRegistrationNode> childListeners = getChild(listeners, childId);
+ Optional<ListenerTree.Node> childListeners = getChild(listeners, childId);
InstanceIdentifier childPath = StoreUtils.append(path, childId);
builder.merge(resolveDeleteEvent(childPath, childListeners, child));
}
}
private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final InstanceIdentifier path,
- final Optional<ListenerRegistrationNode> listeners, final NodeModification modification,
+ final Optional<ListenerTree.Node> listeners, final NodeModification modification,
final StoreMetadataNode before, final StoreMetadataNode after) {
Builder one = builder().setBefore(before.getData()).setAfter(after.getData());
for (NodeModification childMod : modification.getModifications()) {
PathArgument childId = childMod.getIdentifier();
InstanceIdentifier childPath = append(path, childId);
- Optional<ListenerRegistrationNode> childListen = getChild(listeners, childId);
+ Optional<ListenerTree.Node> childListen = getChild(listeners, childId);
Optional<StoreMetadataNode> childBefore = before.getChild(childId);
Optional<StoreMetadataNode> childAfter = after.getChild(childId);
}
private DOMImmutableDataChangeEvent resolveReplacedEvent(final InstanceIdentifier path,
- final Optional<ListenerRegistrationNode> listeners, final NodeModification modification,
+ final Optional<ListenerTree.Node> listeners, final NodeModification modification,
final StoreMetadataNode before, final StoreMetadataNode after) {
// FIXME Add task
return builder().build();
}
- private DOMImmutableDataChangeEvent addNotifyTask(final Optional<ListenerRegistrationNode> listeners, final DOMImmutableDataChangeEvent event) {
+ private DOMImmutableDataChangeEvent addNotifyTask(final Optional<ListenerTree.Node> listeners, final DOMImmutableDataChangeEvent event) {
if (listeners.isPresent()) {
final Collection<DataChangeListenerRegistration<?>> l = listeners.get().getListeners();
if (!l.isEmpty()) {
return event;
}
- private void addNotifyTask(final ListenerRegistrationNode listenerRegistrationNode, final DataChangeScope scope,
+ private void addNotifyTask(final ListenerTree.Node listenerRegistrationNode, final DataChangeScope scope,
final DOMImmutableDataChangeEvent event) {
Collection<DataChangeListenerRegistration<?>> potential = listenerRegistrationNode.getListeners();
if(!potential.isEmpty()) {
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerRegistrationNode;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerRegistrationNode.DataChangeListenerRegistration;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
private final ListeningExecutorService executor;
private final String name;
private final AtomicLong txCounter = new AtomicLong(0);
- private final ListenerRegistrationNode listenerTree;
+ private final ListenerTree listenerTree;
private final AtomicReference<DataAndMetadataSnapshot> snapshot;
private ModificationApplyOperation operationTree;
public InMemoryDOMDataStore(final String name, final ListeningExecutorService executor) {
this.name = Preconditions.checkNotNull(name);
this.executor = Preconditions.checkNotNull(executor);
- this.listenerTree = ListenerRegistrationNode.createRoot();
+ this.listenerTree = ListenerTree.create();
this.snapshot = new AtomicReference<DataAndMetadataSnapshot>(DataAndMetadataSnapshot.createEmpty());
this.operationTree = new AlwaysFailOperation();
}
final DataChangeListenerRegistration<L> reg;
synchronized (this) {
LOG.debug("{}: Registering data change listener {} for {}",name,listener,path);
- ListenerRegistrationNode listenerNode = listenerTree;
- for(PathArgument arg : path.getPath()) {
- listenerNode = listenerNode.ensureChild(arg);
- }
- reg = listenerNode.registerDataChangeListener(path, listener, scope);
+ reg = listenerTree.registerDataChangeListener(path, listener, scope);
Optional<StoreMetadataNode> currentState = snapshot.get().read(path);
if (currentState.isPresent()) {
import static com.google.common.base.Preconditions.checkState;
import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+/*
+ * FIXME: the thread safety of concurrent write/delete/read/seal operations
+ * needs to be evaluated.
+ */
class MutableDataTree {
-
- private static final Logger log = LoggerFactory.getLogger(MutableDataTree.class);
-
- final DataAndMetadataSnapshot snapshot;
- final NodeModification rootModification;
- final ModificationApplyOperation strategyTree;
-
- private boolean sealed = false;
+ private static final Logger LOG = LoggerFactory.getLogger(MutableDataTree.class);
+ private final AtomicBoolean sealed = new AtomicBoolean();
+ private final ModificationApplyOperation strategyTree;
+ private final DataAndMetadataSnapshot snapshot;
+ private final NodeModification rootModification;
private MutableDataTree(final DataAndMetadataSnapshot snapshot, final ModificationApplyOperation strategyTree) {
this.snapshot = snapshot;
return NormalizedNodeUtils.findNode(modification.getKey(), data, path);
}
return Optional.absent();
-
}
private Optional<StoreMetadataNode> resolveSnapshot(
return resolveModificationStrategy(path).apply(modification, modification.getOriginal(),
StoreUtils.increase(snapshot.getMetadataTree().getSubtreeVersion()));
} catch (Exception e) {
- log.error("Could not create snapshot for {}", path,e);
+ LOG.error("Could not create snapshot for {}", path,e);
throw e;
}
}
private ModificationApplyOperation resolveModificationStrategy(final InstanceIdentifier path) {
- log.trace("Resolving modification apply strategy for {}", path);
+ LOG.trace("Resolving modification apply strategy for {}", path);
return TreeNodeUtils.findNodeChecked(strategyTree, path);
}
}
public void seal() {
- sealed = true;
+ final boolean success = sealed.compareAndSet(false, true);
+ Preconditions.checkState(success, "Attempted to seal an already-sealed Data Tree.");
rootModification.seal();
}
private void checkSealed() {
- checkState(!sealed, "Data Tree is sealed. No further modifications allowed.");
+ checkState(!sealed.get(), "Data Tree is sealed. No further modifications allowed.");
}
protected NodeModification getRootModification() {
public String toString() {
return "MutableDataTree [modification=" + rootModification + "]";
}
-
-
}
public final class StoreUtils {
private final static Function<Identifiable<Object>, Object> EXTRACT_IDENTIFIER = new Function<Identifiable<Object>, Object>() {
-
@Override
public Object apply(final Identifiable<Object> input) {
return input.getIdentifier();
return new InitialDataChangeEvent(path, data.getData());
}
+ /*
+ * Suppressing warnings here allows us to fool the compiler enough
+ * such that we can reuse a single function for all applicable types
+ * and present it in a type-safe manner to our users.
+ */
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <V> Function<Identifiable<V>, V> identifierExtractor() {
return (Function) EXTRACT_IDENTIFIER;
public NormalizedNode<?, ?> getUpdatedSubtree() {
return data;
}
-
}
public static <V> Set<V> toIdentifierSet(final Iterable<? extends Identifiable<V>> children) {
StringBuilder builder = new StringBuilder();
toStringTree(builder, metaNode, 0);
return builder.toString();
-
}
private static void toStringTree(final StringBuilder builder, final StoreMetadataNode metaNode, final int offset) {
builder.append(prefix).append(toStringTree(metaNode.getIdentifier()));
NormalizedNode<?, ?> dataNode = metaNode.getData();
if (dataNode instanceof NormalizedNodeContainer<?, ?, ?>) {
- builder.append(" {").append("\n");
+ builder.append(" {\n");
for (StoreMetadataNode child : metaNode.getChildren()) {
toStringTree(builder, child, offset + 4);
}
- builder.append(prefix).append("}");
+ builder.append(prefix).append('}');
} else {
- builder.append(" ").append(dataNode.getValue());
+ builder.append(' ').append(dataNode.getValue());
}
- builder.append("\n");
+ builder.append('\n');
}
private static String toStringTree(final PathArgument identifier) {
+++ /dev/null
-package org.opendaylight.controller.md.sal.dom.store.impl.tree;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Optional;
-
-public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrationNode>, Identifiable<PathArgument> {
-
- private static final Logger LOG = LoggerFactory.getLogger(ListenerRegistrationNode.class);
-
- private final ListenerRegistrationNode parent;
- private final Map<PathArgument, ListenerRegistrationNode> children;
- private final PathArgument identifier;
- private final HashSet<DataChangeListenerRegistration<?>> listeners;
-
- private ListenerRegistrationNode(final PathArgument identifier) {
- this(null, identifier);
- }
-
- private ListenerRegistrationNode(final ListenerRegistrationNode parent, final PathArgument identifier) {
- this.parent = parent;
- this.identifier = identifier;
- children = new HashMap<>();
- listeners = new HashSet<>();
- }
-
- public final static ListenerRegistrationNode createRoot() {
- return new ListenerRegistrationNode(null);
- }
-
- @Override
- public PathArgument getIdentifier() {
- return identifier;
- }
-
- /**
- * Return the list of current listeners. Any caller wishing to use this method
- * has to make sure the collection remains unchanged while it's executing. This
- * means the caller has to synchronize externally both the registration and
- * unregistration process.
- *
- * @return the list of current listeners
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public Collection<org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<?>> getListeners() {
- return (Collection) listeners;
- }
-
- @Override
- public synchronized Optional<ListenerRegistrationNode> getChild(final PathArgument child) {
- return Optional.fromNullable(children.get(child));
- }
-
- public synchronized ListenerRegistrationNode ensureChild(final PathArgument child) {
- ListenerRegistrationNode potential = (children.get(child));
- if (potential == null) {
- potential = new ListenerRegistrationNode(this, child);
- children.put(child, potential);
- }
- return potential;
- }
-
- /**
- * Registers listener on this node.
- *
- * @param path Full path on which listener is registered.
- * @param listener Listener
- * @param scope Scope of triggering event.
- * @return
- */
- public synchronized <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> DataChangeListenerRegistration<L> registerDataChangeListener(final InstanceIdentifier path,
- final L listener, final DataChangeScope scope) {
-
- DataChangeListenerRegistration<L> listenerReg = new DataChangeListenerRegistration<L>(path,listener, scope, this);
- listeners.add(listenerReg);
- LOG.debug("Listener {} registered", listener);
- return listenerReg;
- }
-
- private synchronized void removeListener(final DataChangeListenerRegistration<?> listener) {
- listeners.remove(listener);
- LOG.debug("Listener {} unregistered", listener);
- removeThisIfUnused();
- }
-
- private void removeThisIfUnused() {
- if (parent != null && listeners.isEmpty() && children.isEmpty()) {
- parent.removeChildIfUnused(this);
- }
- }
-
- public boolean isUnused() {
- return (listeners.isEmpty() && children.isEmpty()) || areChildrenUnused();
- }
-
- private boolean areChildrenUnused() {
- for (ListenerRegistrationNode child : children.values()) {
- if (!child.isUnused()) {
- return false;
- }
- }
- return true;
- }
-
- private void removeChildIfUnused(final ListenerRegistrationNode listenerRegistrationNode) {
- // FIXME Remove unnecessary
- }
-
- public static class DataChangeListenerRegistration<T extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>>
- extends AbstractObjectRegistration<T> implements
- org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<T> {
-
- private final DataChangeScope scope;
- private ListenerRegistrationNode node;
- private final InstanceIdentifier path;
-
- public DataChangeListenerRegistration(final InstanceIdentifier path,final T listener, final DataChangeScope scope,
- final ListenerRegistrationNode node) {
- super(listener);
- this.path = path;
- this.scope = scope;
- this.node = node;
- }
-
- @Override
- public DataChangeScope getScope() {
- return scope;
- }
-
- @Override
- protected void removeRegistration() {
- node.removeListener(this);
- node = null;
- }
-
- @Override
- public InstanceIdentifier getPath() {
- return path;
- }
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.store.impl.tree;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+public final class ListenerTree {
+ private static final Logger LOG = LoggerFactory.getLogger(ListenerTree.class);
+ private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
+ private final Node rootNode = new Node(null, null);
+
+ private ListenerTree() {
+
+ }
+
+ public static ListenerTree create() {
+ return new ListenerTree();
+ }
+
+ /**
+ * Registers listener on this node.
+ *
+ * @param path Full path on which listener is registered.
+ * @param listener Listener
+ * @param scope Scope of triggering event.
+ * @return Listener registration
+ */
+ public <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> DataChangeListenerRegistration<L> registerDataChangeListener(final InstanceIdentifier path,
+ final L listener, final DataChangeScope scope) {
+
+ // Take the write lock
+ rwLock.writeLock().lock();
+
+ try {
+ Node walkNode = rootNode;
+ for (final PathArgument arg : path.getPath()) {
+ walkNode = walkNode.ensureChild(arg);
+ }
+
+ final Node node = walkNode;
+ DataChangeListenerRegistration<L> reg = new DataChangeListenerRegistrationImpl<L>(listener) {
+ @Override
+ public DataChangeScope getScope() {
+ return scope;
+ }
+
+ @Override
+ public InstanceIdentifier getPath() {
+ return path;
+ }
+
+ @Override
+ protected void removeRegistration() {
+ /*
+ * TODO: Here's an interesting problem. The way the datastore works, it
+ * enqueues requests towards the listener, so the listener will be
+ * notified at some point in the future. Now if the registration is
+ * closed, we will prevent any new events from being delivered, but
+ * we have no way to purge that queue.
+ *
+ * While this does not directly violate the ListenerRegistration
+ * contract, it is probably not going to be liked by the users.
+ */
+
+ // Take the write lock
+ ListenerTree.this.rwLock.writeLock().lock();
+ try {
+ node.removeListener(this);
+ } finally {
+ // Always release the lock
+ ListenerTree.this.rwLock.writeLock().unlock();
+ }
+ }
+ };
+
+ node.addListener(reg);
+ return reg;
+ } finally {
+ // Always release the lock
+ rwLock.writeLock().unlock();
+ }
+ }
+
+ public Walker getWalker() {
+ /*
+ * TODO: The only current user of this method is local to the datastore.
+ * Since this class represents a read-lock, losing a reference to
+ * it is a _major_ problem, as the registration process will get
+ * wedged, eventually grinding the system to a halt. Should an
+ * external user exist, make the Walker a phantom reference, which
+ * will cleanup the lock if not told to do so.
+ */
+ final Walker ret = new Walker(rwLock.readLock(), rootNode);
+ rwLock.readLock().lock();
+ return ret;
+ }
+
+ public static final class Walker implements AutoCloseable {
+ private final Lock lock;
+ private final Node node;
+
+ @GuardedBy("this")
+ private boolean valid = true;
+
+ private Walker(final Lock lock, final Node node) {
+ this.lock = Preconditions.checkNotNull(lock);
+ this.node = Preconditions.checkNotNull(node);
+ }
+
+ public Node getRootNode() {
+ return node;
+ }
+
+ @Override
+ public synchronized void close() {
+ if (valid) {
+ lock.unlock();
+ valid = false;
+ }
+ }
+ }
+
+ /**
+ * This is a single node within the listener tree. Note that the data returned from
+ * and instance of this class is guaranteed to have any relevance or consistency
+ * only as long as the {@link Walker} instance through which it is reached remains
+ * unclosed.
+ */
+ public static final class Node implements StoreTreeNode<Node>, Identifiable<PathArgument> {
+ private final Collection<DataChangeListenerRegistration<?>> listeners = new ArrayList<>();
+ private final Map<PathArgument, Node> children = new HashMap<>();
+ private final PathArgument identifier;
+ private final Reference<Node> parent;
+
+ private Node(final Node parent, final PathArgument identifier) {
+ this.parent = new WeakReference<>(parent);
+ this.identifier = identifier;
+ }
+
+ @Override
+ public PathArgument getIdentifier() {
+ return identifier;
+ }
+
+ @Override
+ public Optional<Node> getChild(final PathArgument child) {
+ return Optional.fromNullable(children.get(child));
+ }
+
+ /**
+ * Return the list of current listeners. This collection is guaranteed
+ * to be immutable only while the walker, through which this node is
+ * reachable remains unclosed.
+ *
+ * @return the list of current listeners
+ */
+ public Collection<DataChangeListenerRegistration<?>> getListeners() {
+ return listeners;
+ }
+
+ private Node ensureChild(final PathArgument child) {
+ Node potential = children.get(child);
+ if (potential == null) {
+ potential = new Node(this, child);
+ children.put(child, potential);
+ }
+ return potential;
+ }
+
+ private void addListener(final DataChangeListenerRegistration<?> listener) {
+ listeners.add(listener);
+ LOG.debug("Listener {} registered", listener);
+ }
+
+ private void removeListener(final DataChangeListenerRegistrationImpl<?> listener) {
+ listeners.remove(listener);
+ LOG.debug("Listener {} unregistered", listener);
+
+ // We have been called with the write-lock held, so we can perform some cleanup.
+ removeThisIfUnused();
+ }
+
+ private void removeThisIfUnused() {
+ final Node p = parent.get();
+ if (p != null && listeners.isEmpty() && children.isEmpty()) {
+ p.removeChild(identifier);
+ }
+ }
+
+ private void removeChild(final PathArgument arg) {
+ children.remove(arg);
+ removeThisIfUnused();
+ }
+ }
+
+ private abstract static class DataChangeListenerRegistrationImpl<T extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> extends AbstractListenerRegistration<T> //
+ implements DataChangeListenerRegistration<T> {
+ public DataChangeListenerRegistrationImpl(final T listener) {
+ super(listener);
+ }
+ }
+}
import java.util.LinkedHashMap;
import java.util.Map;
+import javax.annotation.concurrent.GuardedBy;
+
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
private final Map<PathArgument, NodeModification> childModification;
+ @GuardedBy("this")
private boolean sealed = false;
protected NodeModification(final PathArgument identifier, final Optional<StoreMetadataNode> original) {
this.value = value;
}
+ @GuardedBy("this")
private void checkSealed() {
checkState(!sealed, "Node Modification is sealed. No further changes allowed.");
}
return !childModification.isEmpty();
}
- public void updateModificationType(final ModificationType type) {
+ @GuardedBy("this")
+ private void updateModificationType(final ModificationType type) {
modificationType = type;
clearSnapshot();
}
public static <T extends StoreTreeNode<T>> T findNodeChecked(final T tree, final InstanceIdentifier path) {
T current = tree;
- List<PathArgument> nested = new ArrayList<>(path.getPath());
+ List<PathArgument> nested = new ArrayList<>(path.getPath().size());
for(PathArgument pathArg : path.getPath()) {
Optional<T> potential = current.getChild(pathArg);
nested.add(pathArg);
final InstanceIdentifier currentPath = new InstanceIdentifier(path.getPath().subList(0, nesting));
return new SimpleEntry<InstanceIdentifier,T>(currentPath,current.get());
}
- // Nesting minus one is safe, since current is allways present when nesting = 0
- // so this prat of code is never triggered, in cases nesting == 0;
+
+ /*
+ * Subtracting 1 from nesting level at this point is safe, because we
+ * cannot reach here with nesting == 0: that would mean the above check
+ * for current.isPresent() failed, which it cannot, as current is always
+ * present. At any rate we check state just to be on the safe side.
+ */
+ Preconditions.checkState(nesting > 0);
final InstanceIdentifier parentPath = new InstanceIdentifier(path.getPath().subList(0, nesting - 1));
- return new SimpleEntry<InstanceIdentifier,T>(parentPath,parent.get());
+ return new SimpleEntry<InstanceIdentifier,T>(parentPath,parent.get());
}
public static <T extends StoreTreeNode<T>> Optional<T> getChild(final Optional<T> parent,final PathArgument child) {
*/
package org.opendaylight.controller.sal.dom.broker;
+import com.google.common.util.concurrent.ListenableFuture
import java.util.Collections
import java.util.HashSet
import java.util.Set
-import java.util.concurrent.Callable
-import java.util.concurrent.ExecutorService
-import java.util.concurrent.Executors
-import java.util.concurrent.Future
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
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 org.opendaylight.controller.sal.core.api.RpcRegistrationListener
import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry
import org.opendaylight.controller.sal.core.api.RpcImplementation
-import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener
import org.opendaylight.controller.sal.core.api.RpcRoutingContext
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation
private val Set<ProviderContextImpl> providerSessions = Collections.synchronizedSet(
new HashSet<ProviderContextImpl>());
- // Implementation specific
- @Property
- private var ExecutorService executor = Executors.newFixedThreadPool(5);
@Property
private var BundleContext bundleContext;
-
+
@Property
private var AutoCloseable deactivator;
return session;
}
- protected def Future<RpcResult<CompositeNode>> invokeRpcAsync(QName rpc, CompositeNode input) {
- val result = executor.submit([|router.invokeRpc(rpc, input)] as Callable<RpcResult<CompositeNode>>);
- return result;
+ protected def ListenableFuture<RpcResult<CompositeNode>> invokeRpcAsync(QName rpc, CompositeNode input) {
+ return router.invokeRpc(rpc, input);
}
// Validation
sessions.remove(consumerContextImpl);
providerSessions.remove(consumerContextImpl);
}
-
+
override close() throws Exception {
deactivator?.close();
}
-
+
override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException {
router.addRpcImplementation(rpcType,implementation);
}
-
+
override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
router.addRoutedRpcImplementation(rpcType,implementation);
}
override addRpcRegistrationListener(RpcRegistrationListener listener) {
return router.addRpcRegistrationListener(listener);
}
-
+
override <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> registerRouteChangeListener(L listener) {
return router.registerRouteChangeListener(listener);
}
- override invokeRpc(QName rpc,CompositeNode input){
- return router.invokeRpc(rpc,input)
- }
-
override getSupportedRpcs() {
return router.getSupportedRpcs();
}
-
+
+ override invokeRpc(QName rpc, CompositeNode input) {
+ return router.invokeRpc(rpc,input)
+ }
+
}
return rpcs.getSupportedRpcs();
}
-
@Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
return rpcs.invokeRpc(rpc, input);
}
return rpcs.addRpcRegistrationListener(listener);
}
-
@Override
public ListenableFuture<RpcResult<CompositeNode>> rpc(QName type, CompositeNode input) {
return null;
L listener) {
return rpcs.registerRouteChangeListener(listener);
}
-
-
}
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.ListenableFuture;
public class SchemaAwareRpcBroker implements RpcRouter, Identifiable<String>, RoutedRpcDefaultImplementation {
this.schemaProvider = schemaProvider;
}
- public RoutedRpcDefaultImplementation getRoutedRpcDefaultDelegate() {
- return defaultDelegate;
- }
+ public RoutedRpcDefaultImplementation getRoutedRpcDefaultDelegate() {
+ return defaultDelegate;
+ }
@Override
- public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultDelegate) {
- this.defaultDelegate = defaultDelegate;
- }
+ public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultDelegate) {
+ this.defaultDelegate = defaultDelegate;
+ }
- @Override
+ @Override
public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) {
checkArgument(rpcType != null, "RPC Type should not be null");
checkArgument(implementation != null, "RPC Implementatoin should not be null");
}
@Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
return findRpcImplemention(rpc).invokeRpc(rpc, input);
}
}
@Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
checkState(defaultDelegate != null);
return defaultDelegate.invokeRpc(rpc, identifier, input);
}
}
@Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
CompositeNode inputContainer = input.getFirstCompositeByName(QName.create(rpc,"input"));
checkArgument(inputContainer != null, "Rpc payload must contain input element");
SimpleNode<?> routeContainer = inputContainer.getFirstSimpleByName(strategy.getLeaf());
package org.opendaylight.controller.sal.dom.broker.osgi;
+import java.util.Set;
+
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.sal.core.api.*;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.osgi.framework.ServiceReference;
-import java.util.Set;
+import com.google.common.util.concurrent.ListenableFuture;
public class RpcProvisionRegistryProxy extends AbstractBrokerServiceProxy<RpcProvisionRegistry>
implements RpcProvisionRegistry {
return getDelegate().addRoutedRpcImplementation(rpcType, implementation);
}
- @Override
- public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) {
- getDelegate().setRoutedRpcDefaultDelegate(defaultImplementation);
- }
+ @Override
+ public void setRoutedRpcDefaultDelegate(RoutedRpcDefaultImplementation defaultImplementation) {
+ getDelegate().setRoutedRpcDefaultDelegate(defaultImplementation);
+ }
- @Override
+ @Override
public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(L listener) {
return getDelegate().registerRouteChangeListener(listener);
}
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return getDelegate().getSupportedRpcs();
+ }
- @Override
- public Set<QName> getSupportedRpcs() {
- return getDelegate().getSupportedRpcs();
- }
-
- @Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
- return getDelegate().invokeRpc(rpc,input);
- }
+ @Override
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
+ return getDelegate().invokeRpc(rpc, input);
+ }
}
package org.opendaylight.controller.sal.dom.broker.spi;
import java.util.Map;
-import java.util.Set;
import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
import org.opendaylight.controller.sal.core.api.RpcImplementation;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
public interface RoutedRpcProcessor extends RpcImplementation {
- public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation);
+ RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation);
- public Set<QName> getSupportedRpcs();
-
- public QName getRpcType();
-
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input);
+ QName getRpcType();
Map<InstanceIdentifier,RpcImplementation> getRoutes();
-
+
RpcImplementation getDefaultRoute();
}
import org.opendaylight.controller.sal.core.api.RpcImplementation;
import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
public interface RpcRouter extends RpcProvisionRegistry, RpcImplementation {
@Override
public Set<QName> getSupportedRpcs();
-
- @Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input);
}
<codeGeneratorClass>
org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
</codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+ <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
<additionalConfiguration>
<namespaceToPackage1>
urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${project.build.directory}/generated-sources/config</source>
- <source>src/main/xtend-gen</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
<plugin>
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class InventoryUtils {
-
+ private static final Logger LOG = LoggerFactory.getLogger(InventoryUtils.class);
private static final URI INVENTORY_NAMESPACE = URI.create("urn:opendaylight:inventory");
private static final URI NETCONF_INVENTORY_NAMESPACE = URI.create("urn:opendaylight:netconf-node-inventory");
private static final Date INVENTORY_REVISION = dateFromString("2013-08-19");
.toInstance();
public static final QName NETCONF_INVENTORY_MOUNT = null;
+ private InventoryUtils() {
+ throw new UnsupportedOperationException("Utility class cannot be instantiated");
+ }
+
/**
* Converts date in string format yyyy-MM-dd to java.util.Date.
- *
+ *
* @return java.util.Date conformant to string formatted date yyyy-MM-dd.
*/
private static Date dateFromString(final String date) {
+ // We do not reuse the formatter because it's not thread-safe
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
try {
return formatter.parse(date);
} catch (ParseException e) {
- e.printStackTrace();
+ LOG.error("Failed to parse date {}", date, e);
+ return null;
}
- return null;
}
}
import java.io.InputStream
import java.net.InetSocketAddress
import java.net.URI
+import java.util.ArrayList
+import java.util.Collection
import java.util.Collections
import java.util.List
import java.util.Set
import java.util.concurrent.ExecutorService
-import java.util.concurrent.Future
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler
import org.opendaylight.controller.md.sal.common.api.data.DataModification
import org.opendaylight.controller.md.sal.common.api.data.DataReader
-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.xml.XmlUtil
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession
+import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration
import org.opendaylight.controller.sal.core.api.Provider
import org.opendaylight.controller.sal.core.api.RpcImplementation
import org.opendaylight.controller.sal.core.api.data.DataBrokerService
import org.opendaylight.yangtools.yang.model.api.SchemaContext
import org.opendaylight.yangtools.yang.model.util.repo.AbstractCachingSchemaSourceProvider
import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider
-import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProviders
import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl
import org.opendaylight.yangtools.yang.parser.impl.util.YangSourceContext
import org.slf4j.Logger
import static extension org.opendaylight.controller.sal.connect.netconf.NetconfMapping.*
-class NetconfDevice implements Provider, //
+class NetconfDevice implements Provider, //
DataReader<InstanceIdentifier, CompositeNode>, //
DataCommitHandler<InstanceIdentifier, CompositeNode>, //
RpcImplementation, //
AutoCloseable {
- var NetconfClient client;
-
@Property
var InetSocketAddress socketAddress;
Registration<DataReader<InstanceIdentifier, CompositeNode>> operReaderReg
Registration<DataReader<InstanceIdentifier, CompositeNode>> confReaderReg
Registration<DataCommitHandler<InstanceIdentifier, CompositeNode>> commitHandlerReg
+ List<RpcRegistration> rpcReg
+ @Property
val String name
- MountProvisionService mountService
- int messegeRetryCount = 5;
-
- int messageTimeoutCount = 5 * 1000;
-
- Set<QName> cachedCapabilities
+ MountProvisionService mountService
@Property
var NetconfClientDispatcher dispatcher
@Property
var SchemaSourceProvider<InputStream> remoteSourceProvider
-
+
DataBrokerService dataBroker
+ var NetconfDeviceListener listener;
+
public new(String name) {
- this.name = name;
+ this._name = name;
this.logger = LoggerFactory.getLogger(NetconfDevice.name + "#" + name);
this.path = InstanceIdentifier.builder(INVENTORY_PATH).nodeWithKey(INVENTORY_NODE,
Collections.singletonMap(INVENTORY_ID, name)).toInstance;
checkState(schemaSourceProvider != null, "Schema Source Provider must be set.")
checkState(eventExecutor != null, "Event executor must be set.");
- val listener = new NetconfDeviceListener(this);
- val task = startClientTask(dispatcher, listener)
- return processingExecutor.submit(task) as Future<Void>;
+ listener = new NetconfDeviceListener(this);
+
+ logger.info("Starting NETCONF Client {} for address {}", name, socketAddress);
+ dispatcher.createClient(socketAddress, listener, reconnectStrategy);
}
def Optional<SchemaContext> getSchemaContext() {
return deviceContextProvider.currentContext;
}
- private def Runnable startClientTask(NetconfClientDispatcher dispatcher, NetconfDeviceListener listener) {
- return [ |
- try {
- logger.info("Starting Netconf Client on: {}", socketAddress);
- client = NetconfClient.clientFor(name, socketAddress, reconnectStrategy, dispatcher, listener);
- logger.debug("Initial capabilities {}", initialCapabilities);
- var SchemaSourceProvider<String> delegate;
- if (NetconfRemoteSchemaSourceProvider.isSupportedFor(initialCapabilities)) {
- delegate = new NetconfRemoteSchemaSourceProvider(this);
- } else if(client.capabilities.contains(NetconfRemoteSchemaSourceProvider.IETF_NETCONF_MONITORING.namespace.toString)) {
- delegate = new NetconfRemoteSchemaSourceProvider(this);
- } else {
- logger.info("Netconf server {} does not support IETF Netconf Monitoring", socketAddress);
- delegate = SchemaSourceProviders.<String>noopProvider();
- }
- remoteSourceProvider = schemaSourceProvider.createInstanceFor(delegate);
- deviceContextProvider = new NetconfDeviceSchemaContextProvider(this, remoteSourceProvider);
- deviceContextProvider.createContextFromCapabilities(initialCapabilities);
- if (mountInstance != null && schemaContext.isPresent) {
- mountInstance.schemaContext = schemaContext.get();
- val operations = schemaContext.get().operations;
- for (rpc : operations) {
- mountInstance.addRpcImplementation(rpc.QName, this);
- }
- }
- updateDeviceState()
- if (mountInstance != null && confReaderReg == null && operReaderReg == null) {
- confReaderReg = mountInstance.registerConfigurationReader(ROOT_PATH, this);
- operReaderReg = mountInstance.registerOperationalReader(ROOT_PATH, this);
- commitHandlerReg = mountInstance.registerCommitHandler(ROOT_PATH, this);
- }
- } catch (Exception e) {
- logger.error("Netconf client NOT started. ", e)
+ def bringDown() {
+ if (rpcReg != null) {
+ for (reg : rpcReg) {
+ reg.close()
}
- ]
+ rpcReg = null
+ }
+ confReaderReg?.close()
+ confReaderReg = null
+ operReaderReg?.close()
+ operReaderReg = null
+ commitHandlerReg?.close()
+ commitHandlerReg = null
+
+ updateDeviceState(false, Collections.emptySet())
}
- private def updateDeviceState() {
+ def bringUp(SchemaSourceProvider<String> delegate, Set<QName> capabilities) {
+ remoteSourceProvider = schemaSourceProvider.createInstanceFor(delegate);
+ deviceContextProvider = new NetconfDeviceSchemaContextProvider(this, remoteSourceProvider);
+ deviceContextProvider.createContextFromCapabilities(capabilities);
+ if (mountInstance != null && schemaContext.isPresent) {
+ mountInstance.schemaContext = schemaContext.get();
+ }
+
+ updateDeviceState(true, capabilities)
+
+ if (mountInstance != null) {
+ confReaderReg = mountInstance.registerConfigurationReader(ROOT_PATH, this);
+ operReaderReg = mountInstance.registerOperationalReader(ROOT_PATH, this);
+ commitHandlerReg = mountInstance.registerCommitHandler(ROOT_PATH, this);
+
+ val rpcs = new ArrayList<RpcRegistration>();
+ for (rpc : mountInstance.schemaContext.operations) {
+ rpcs.add(mountInstance.addRpcImplementation(rpc.QName, this));
+ }
+ rpcReg = rpcs
+ }
+ }
+
+ private def updateDeviceState(boolean up, Set<QName> capabilities) {
val transaction = dataBroker.beginTransaction
val it = ImmutableCompositeNode.builder
setQName(INVENTORY_NODE)
addLeaf(INVENTORY_ID, name)
- addLeaf(INVENTORY_CONNECTED, client.clientSession.up)
+ addLeaf(INVENTORY_CONNECTED, up)
- logger.debug("Client capabilities {}", client.capabilities)
- for (capability : client.capabilities) {
+ logger.debug("Client capabilities {}", capabilities)
+ for (capability : capabilities) {
addLeaf(NETCONF_INVENTORY_INITIAL_CAPABILITY, capability)
}
logger.debug("Update device state transaction " + transaction.identifier + " putting operational data started.")
+ transaction.removeOperationalData(path)
transaction.putOperationalData(path, it.toInstance)
logger.debug("Update device state transaction " + transaction.identifier + " putting operational data ended.")
+
+ // FIXME: this has to be asynchronous
val transactionStatus = transaction.commit.get;
if (transactionStatus.successful) {
override readConfigurationData(InstanceIdentifier path) {
val result = invokeRpc(NETCONF_GET_CONFIG_QNAME,
- wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, path.toFilterStructure()));
+ wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, path.toFilterStructure())).get();
val data = result.result.getFirstCompositeByName(NETCONF_DATA_QNAME);
return data?.findNode(path) as CompositeNode;
}
override readOperationalData(InstanceIdentifier path) {
- val result = invokeRpc(NETCONF_GET_QNAME, wrap(NETCONF_GET_QNAME, path.toFilterStructure()));
+ val result = invokeRpc(NETCONF_GET_QNAME, wrap(NETCONF_GET_QNAME, path.toFilterStructure())).get();
val data = result.result.getFirstCompositeByName(NETCONF_DATA_QNAME);
return data?.findNode(path) as CompositeNode;
}
Collections.emptySet;
}
- def createSubscription(String streamName) {
- val it = ImmutableCompositeNode.builder()
- QName = NETCONF_CREATE_SUBSCRIPTION_QNAME
- addLeaf("stream", streamName);
- invokeRpc(QName, toInstance())
- }
-
override invokeRpc(QName rpc, CompositeNode input) {
- try {
- val message = rpc.toRpcMessage(input,schemaContext);
- val result = sendMessageImpl(message, messegeRetryCount, messageTimeoutCount);
- return result.toRpcResult(rpc, schemaContext);
-
- } catch (Exception e) {
- logger.error("Rpc was not processed correctly.", e)
- throw e;
- }
- }
-
- def NetconfMessage sendMessageImpl(NetconfMessage message, int retryCount, int timeout) {
- logger.debug("Send message {}",XmlUtil.toString(message.document))
- val result = client.sendMessage(message, retryCount, timeout);
- NetconfMapping.checkValidReply(message, result)
- return result;
+ return listener.sendRequest(rpc.toRpcMessage(input,schemaContext));
}
override getProviderFunctionality() {
return null;
} else if (current instanceof CompositeNode) {
val currentComposite = (current as CompositeNode);
-
+
current = currentComposite.getFirstCompositeByName(arg.nodeType);
if(current == null) {
current = currentComposite.getFirstCompositeByName(arg.nodeType.withoutRevision());
}
override requestCommit(DataModification<InstanceIdentifier, CompositeNode> modification) {
- val twoPhaseCommit = new NetconfDeviceTwoPhaseCommitTransaction(this, modification);
+ val twoPhaseCommit = new NetconfDeviceTwoPhaseCommitTransaction(this, modification, true);
twoPhaseCommit.prepare()
return twoPhaseCommit;
}
- def getInitialCapabilities() {
- val capabilities = client?.capabilities;
- if (capabilities == null) {
- return null;
- }
- if (cachedCapabilities == null) {
- cachedCapabilities = FluentIterable.from(capabilities).filter[
+ def getCapabilities(Collection<String> capabilities) {
+ return FluentIterable.from(capabilities).filter[
contains("?") && contains("module=") && contains("revision=")].transform [
val parts = split("\\?");
val namespace = parts.get(0);
}
return QName.create(namespace, revision, moduleName);
].toSet();
- }
- return cachedCapabilities;
}
override close() {
- confReaderReg?.close()
- operReaderReg?.close()
- client?.close()
+ bringDown()
}
-
}
package class NetconfDeviceSchemaContextProvider {
*/
package org.opendaylight.controller.sal.connect.netconf;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.FutureListener;
+
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Queue;
+import java.util.Set;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.client.AbstractNetconfClientNotifySessionListener;
+import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
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.common.util.Rpcs;
import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
+import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProviders;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+class NetconfDeviceListener implements NetconfClientSessionListener {
+ private static final class Request {
+ final UncancellableFuture<RpcResult<CompositeNode>> future;
+ final NetconfMessage request;
+
+ private Request(UncancellableFuture<RpcResult<CompositeNode>> future, NetconfMessage request) {
+ this.future = future;
+ this.request = request;
+ }
+ }
-class NetconfDeviceListener extends AbstractNetconfClientNotifySessionListener {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceListener.class);
+ private final Queue<Request> requests = new ArrayDeque<>();
private final NetconfDevice device;
+ private NetconfClientSession session;
public NetconfDeviceListener(final NetconfDevice device) {
this.device = Preconditions.checkNotNull(device);
}
- /**
- * Method intended to customize notification processing.
- *
- * @param session
- * {@see
- * NetconfClientSessionListener#onMessage(NetconfClientSession,
- * NetconfMessage)}
- * @param message
- * {@see
- * 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;
- if (message != null) {
- domNotification = NetconfMapping.toNotificationNode(message, device.getSchemaContext());
- }
- if (domNotification != null) {
- MountProvisionInstance _mountInstance = null;
- if (this.device != null) {
- _mountInstance = this.device.getMountInstance();
+ public synchronized void onSessionUp(final NetconfClientSession session) {
+ LOG.debug("Session with {} established as address {} session-id {}",
+ device.getName(), device.getSocketAddress(), session.getSessionId());
+
+ final Set<QName> caps = device.getCapabilities(session.getServerCapabilities());
+ LOG.trace("Server {} advertized capabilities {}", device.getName(), caps);
+
+ // Select the appropriate provider
+ final SchemaSourceProvider<String> delegate;
+ if (NetconfRemoteSchemaSourceProvider.isSupportedFor(caps)) {
+ delegate = new NetconfRemoteSchemaSourceProvider(device);
+ } else if(caps.contains(NetconfRemoteSchemaSourceProvider.IETF_NETCONF_MONITORING.getNamespace().toString())) {
+ delegate = new NetconfRemoteSchemaSourceProvider(device);
+ } else {
+ LOG.info("Netconf server {} does not support IETF Netconf Monitoring", device.getName());
+ delegate = SchemaSourceProviders.<String>noopProvider();
+ }
+
+ device.bringUp(delegate, caps);
+
+ this.session = session;
+ }
+
+ private synchronized void tearDown(final Exception e) {
+ session = null;
+
+ /*
+ * Walk all requests, check if they have been executing
+ * or cancelled and remove them from the queue.
+ */
+ final Iterator<Request> it = requests.iterator();
+ while (it.hasNext()) {
+ final Request r = it.next();
+ if (r.future.isUncancellable()) {
+ // FIXME: add a RpcResult instead?
+ r.future.setException(e);
+ it.remove();
+ } else if (r.future.isCancelled()) {
+ // This just does some house-cleaning
+ it.remove();
}
- if (_mountInstance != null) {
- _mountInstance.publish(domNotification);
+ }
+
+ device.bringDown();
+ }
+
+ @Override
+ public void onSessionDown(final NetconfClientSession session, final Exception e) {
+ LOG.debug("Session with {} went down", device.getName(), e);
+ tearDown(e);
+ }
+
+ @Override
+ public void onSessionTerminated(final NetconfClientSession session, final NetconfTerminationReason reason) {
+ LOG.debug("Session with {} terminated {}", session, reason);
+ tearDown(new RuntimeException(reason.getErrorMessage()));
+ }
+
+ @Override
+ public void onMessage(final NetconfClientSession session, final NetconfMessage message) {
+ /*
+ * Dispatch between notifications and messages. Messages need to be processed
+ * with lock held, notifications do not.
+ */
+ if (isNotification(message)) {
+ processNotification(message);
+ } else {
+ processMessage(message);
+ }
+ }
+
+ private synchronized void processMessage(final NetconfMessage message) {
+ final Request r = requests.peek();
+ if (r.future.isUncancellable()) {
+ requests.poll();
+ LOG.debug("Matched {} to {}", r.request, message);
+
+ // FIXME: this can throw exceptions, which should result
+ // in the future failing
+ NetconfMapping.checkValidReply(r.request, message);
+ r.future.set(Rpcs.getRpcResult(true, NetconfMapping.toNotificationNode(message, device.getSchemaContext()),
+ Collections.<RpcError>emptyList()));
+ } else {
+ LOG.warn("Ignoring unsolicited message", message);
+ }
+ }
+
+ synchronized ListenableFuture<RpcResult<CompositeNode>> sendRequest(final NetconfMessage message) {
+ if (session == null) {
+ LOG.debug("Session to {} is disconnected, failing RPC request {}", device.getName(), message);
+ return Futures.<RpcResult<CompositeNode>>immediateFuture(new RpcResult<CompositeNode>() {
+ @Override
+ public boolean isSuccessful() {
+ return false;
+ }
+
+ @Override
+ public CompositeNode getResult() {
+ return null;
+ }
+
+ @Override
+ public Collection<RpcError> getErrors() {
+ // FIXME: indicate that the session is down
+ return Collections.emptySet();
+ }
+ });
+ }
+
+ final Request req = new Request(new UncancellableFuture<RpcResult<CompositeNode>>(true), message);
+ requests.add(req);
+
+ session.sendMessage(req.request).addListener(new FutureListener<Void>() {
+ @Override
+ public void operationComplete(final Future<Void> future) throws Exception {
+ if (!future.isSuccess()) {
+ // We expect that a session down will occur at this point
+ LOG.debug("Failed to send request {}", req.request, future.cause());
+ req.future.setException(future.cause());
+ } else {
+ LOG.trace("Finished sending request {}", req.request);
+ }
}
+ });
+
+ return req.future;
+ }
+
+ /**
+ * Process an incoming notification.
+ *
+ * @param notification Notification message
+ */
+ private void processNotification(final NetconfMessage notification) {
+ this.device.logger.debug("Received NETCONF notification.", notification);
+ CompositeNode domNotification = NetconfMapping.toNotificationNode(notification, device.getSchemaContext());
+ if (domNotification == null) {
+ return;
+ }
+
+ MountProvisionInstance mountInstance = this.device.getMountInstance();
+ if (mountInstance != null) {
+ mountInstance.publish(domNotification);
}
}
+
+ private static boolean isNotification(final NetconfMessage message) {
+ final XmlElement xmle = XmlElement.fromDomDocument(message.getDocument());
+ return XmlNetconfConstants.NOTIFICATION_ELEMENT_NAME.equals(xmle.getName()) ;
+ }
}
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_RUNNING_QNAME;
import static org.opendaylight.controller.sal.connect.netconf.NetconfMapping.NETCONF_TARGET_QNAME;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
import org.opendaylight.controller.md.sal.common.api.data.DataModification;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.Node;
import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
-public class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
-
- private final NetconfDevice device;
+class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceTwoPhaseCommitTransaction.class);
private final DataModification<InstanceIdentifier, CompositeNode> modification;
- private final boolean candidateSupported = true;
+ private final NetconfDevice device;
+ private final boolean candidateSupported;
public NetconfDeviceTwoPhaseCommitTransaction(NetconfDevice device,
- DataModification<InstanceIdentifier, CompositeNode> modification) {
- super();
- this.device = device;
- this.modification = modification;
+ DataModification<InstanceIdentifier, CompositeNode> modification,
+ boolean candidateSupported) {
+ this.device = Preconditions.checkNotNull(device);
+ this.modification = Preconditions.checkNotNull(modification);
+ this.candidateSupported = candidateSupported;
}
- public void prepare() {
+ void prepare() throws InterruptedException, ExecutionException {
for (InstanceIdentifier toRemove : modification.getRemovedConfigurationData()) {
sendDelete(toRemove);
}
for(Entry<InstanceIdentifier, CompositeNode> toUpdate : modification.getUpdatedConfigurationData().entrySet()) {
sendMerge(toUpdate.getKey(),toUpdate.getValue());
}
-
}
- private void sendMerge(InstanceIdentifier key, CompositeNode value) {
+ private void sendMerge(InstanceIdentifier key, CompositeNode value) throws InterruptedException, ExecutionException {
sendEditRpc(createEditStructure(key, Optional.<String>absent(), Optional.of(value)));
}
- private void sendDelete(InstanceIdentifier toDelete) {
+ private void sendDelete(InstanceIdentifier toDelete) throws InterruptedException, ExecutionException {
sendEditRpc(createEditStructure(toDelete, Optional.of("delete"), Optional.<CompositeNode> absent()));
}
- private void sendEditRpc(CompositeNode editStructure) {
+ private void sendEditRpc(CompositeNode editStructure) throws InterruptedException, ExecutionException {
CompositeNodeBuilder<ImmutableCompositeNode> builder = configurationRpcBuilder();
builder.setQName(NETCONF_EDIT_CONFIG_QNAME);
builder.add(editStructure);
- RpcResult<CompositeNode> rpcResult = device.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, builder.toInstance());
+ RpcResult<CompositeNode> rpcResult = device.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, builder.toInstance()).get();
Preconditions.checkState(rpcResult.isSuccessful(),"Rpc Result was unsuccessful");
-
}
private CompositeNodeBuilder<ImmutableCompositeNode> configurationRpcBuilder() {
public RpcResult<Void> finish() {
CompositeNodeBuilder<ImmutableCompositeNode> commitInput = ImmutableCompositeNode.builder();
commitInput.setQName(NETCONF_COMMIT_QNAME);
- RpcResult<?> rpcResult = device.invokeRpc(NetconfMapping.NETCONF_COMMIT_QNAME, commitInput.toInstance());
- return (RpcResult<Void>) rpcResult;
+ try {
+ final RpcResult<?> rpcResult = device.invokeRpc(NetconfMapping.NETCONF_COMMIT_QNAME, commitInput.toInstance()).get();
+ return new RpcResult<Void>() {
+
+ @Override
+ public boolean isSuccessful() {
+ return rpcResult.isSuccessful();
+ }
+
+ @Override
+ public Void getResult() {
+ return null;
+ }
+
+ @Override
+ public Collection<RpcError> getErrors() {
+ return rpcResult.getErrors();
+ }
+ };
+ } catch (final InterruptedException | ExecutionException e) {
+ LOG.warn("Failed to finish operation", e);
+ return new RpcResult<Void>() {
+ @Override
+ public boolean isSuccessful() {
+ return false;
+ }
+
+ @Override
+ public Void getResult() {
+ return null;
+ }
+
+ @Override
+ public Collection<RpcError> getErrors() {
+ // FIXME: wrap the exception
+ return Collections.emptySet();
+ }
+ };
+ }
}
@Override
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
public class NetconfInventoryUtils {
-
-
public static final QName NETCONF_MOUNT = null;
public static final QName NETCONF_ENDPOINT = null;
public static final QName NETCONF_ENDPOINT_ADDRESS = null;
public static final QName NETCONF_ENDPOINT_PORT = null;
+ private NetconfInventoryUtils() {
+ throw new UnsupportedOperationException("Utility class cannot be instantiated");
+ }
public static String getEndpointAddress(CompositeNode node) {
return node.getCompositesByName(NETCONF_ENDPOINT).get(0).getFirstSimpleByName(NETCONF_ENDPOINT_ADDRESS).getValue().toString();
}
-
+
public static String getEndpointPort(CompositeNode node) {
return node.getCompositesByName(NETCONF_ENDPOINT).get(0).getFirstSimpleByName(NETCONF_ENDPOINT_PORT).getValue().toString();
}
public static val NETCONF_URI = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0")
public static val NETCONF_MONITORING_URI = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
public static val NETCONF_NOTIFICATION_URI = URI.create("urn:ietf:params:xml:ns:netconf:notification:1.0")
-
-
+
+
public static val NETCONF_QNAME = QName.create(NETCONF_URI, null, "netconf");
public static val NETCONF_RPC_QNAME = QName.create(NETCONF_QNAME, "rpc");
public static val NETCONF_GET_QNAME = QName.create(NETCONF_QNAME, "get");
public static val NETCONF_DELETE_CONFIG_QNAME = QName.create(NETCONF_QNAME, "delete-config");
public static val NETCONF_OPERATION_QNAME = QName.create(NETCONF_QNAME, "operation");
public static val NETCONF_COMMIT_QNAME = QName.create(NETCONF_QNAME, "commit");
-
+
public static val NETCONF_CONFIG_QNAME = QName.create(NETCONF_QNAME, "config");
public static val NETCONF_SOURCE_QNAME = QName.create(NETCONF_QNAME, "source");
public static val NETCONF_TARGET_QNAME = QName.create(NETCONF_QNAME, "target");
-
+
public static val NETCONF_CANDIDATE_QNAME = QName.create(NETCONF_QNAME, "candidate");
public static val NETCONF_RUNNING_QNAME = QName.create(NETCONF_QNAME, "running");
-
-
+
+
public static val NETCONF_RPC_REPLY_QNAME = QName.create(NETCONF_QNAME, "rpc-reply");
public static val NETCONF_OK_QNAME = QName.create(NETCONF_QNAME, "ok");
public static val NETCONF_DATA_QNAME = QName.create(NETCONF_QNAME, "data");
if(identifier.path.empty) {
return null;
}
-
+
for (component : identifier.path.reverseView) {
val Node<?> current = component.toNode(previous);
previous = current;
}
static def CompositeNode toCompositeNode(NetconfMessage message,Optional<SchemaContext> ctx) {
- //TODO: implement general normalization to normalize incoming Netconf Message
+ //TODO: implement general normalization to normalize incoming Netconf Message
// for Schema Context counterpart
return null
}
-
+
static def CompositeNode toNotificationNode(NetconfMessage message,Optional<SchemaContext> ctx) {
if (ctx.present) {
val schemaContext = ctx.get
w3cPayload.documentElement.setAttribute("message-id", "m-" + messageId.andIncrement)
return new NetconfMessage(w3cPayload);
}
-
+
def static flattenInput(CompositeNode node) {
val inputQName = QName.create(node.nodeType,"input");
val input = node.getFirstCompositeByName(inputQName);
if(input == null) return node;
if(input instanceof CompositeNode) {
-
+
val nodes = ImmutableList.builder() //
.addAll(input.children) //
.addAll(node.children.filter[nodeType != inputQName]) //
.build()
return ImmutableCompositeNode.create(node.nodeType,nodes);
- }
-
+ }
+
}
static def RpcResult<CompositeNode> toRpcResult(NetconfMessage message,QName rpc,Optional<SchemaContext> context) {
var CompositeNode rawRpc;
if(context.present) {
if(isDataRetrievalReply(rpc)) {
-
+
val xmlData = message.document.dataSubtree
val dataNodes = XmlDocumentUtils.toDomNodes(xmlData, Optional.of(context.get.dataDefinitions))
-
+
val it = ImmutableCompositeNode.builder()
setQName(NETCONF_RPC_REPLY_QNAME)
add(ImmutableCompositeNode.create(NETCONF_DATA_QNAME, dataNodes));
-
+
rawRpc = it.toInstance;
//sys(xmlData)
} else {
val rpcSchema = context.get.operations.findFirst[QName == rpc]
rawRpc = message.document.toCompositeNode() as CompositeNode;
}
-
-
-
} else {
rawRpc = message.document.toCompositeNode() as CompositeNode;
}
//rawRpc.
return Rpcs.getRpcResult(true, rawRpc, Collections.emptySet());
}
-
+
def static Element getDataSubtree(Document doc) {
doc.getElementsByTagNameNS(NETCONF_URI.toString,"data").item(0) as Element
}
-
+
def static boolean isDataRetrievalReply(QName it) {
- return NETCONF_URI == namespace && ( localName == NETCONF_GET_CONFIG_QNAME.localName || localName == NETCONF_GET_QNAME.localName)
+ return NETCONF_URI == namespace && ( localName == NETCONF_GET_CONFIG_QNAME.localName || localName == NETCONF_GET_QNAME.localName)
}
static def wrap(QName name, Node<?> node) {
public static def Node<?> toCompositeNode(Document document) {
return XmlDocumentUtils.toDomNode(document) as Node<?>
}
-
+
public static def checkValidReply(NetconfMessage input, NetconfMessage output) {
val inputMsgId = input.document.documentElement.getAttribute("message-id")
val outputMsgId = output.document.documentElement.getAttribute("message-id")
Preconditions.checkState(inputMsgId == outputMsgId,"Rpc request and reply message IDs must be same.");
-
+
}
-
+
}
*/
package org.opendaylight.controller.sal.connect.netconf;
-import java.util.Set;
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.model.util.repo.SchemaSourceProvider;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
class NetconfRemoteSchemaSourceProvider implements SchemaSourceProvider<String> {
public static final QName GET_SCHEMA_QNAME = QName.create(IETF_NETCONF_MONITORING, "get-schema");
public static final QName GET_DATA_QNAME = QName.create(IETF_NETCONF_MONITORING, "data");
- NetconfDevice device;
+ private final NetconfDevice device;
public NetconfRemoteSchemaSourceProvider(NetconfDevice device) {
- super();
- this.device = device;
+ this.device = Preconditions.checkNotNull(device);
}
@Override
}
device.logger.trace("Loading YANG schema source for {}:{}", moduleName, revision);
- RpcResult<CompositeNode> schemaReply = device.invokeRpc(GET_SCHEMA_QNAME, request.toInstance());
- if (schemaReply.isSuccessful()) {
- String schemaBody = getSchemaFromRpc(schemaReply.getResult());
- if (schemaBody != null) {
- device.logger.trace("YANG Schema successfully retrieved from remote for {}:{}", moduleName, revision);
- return Optional.of(schemaBody);
+ try {
+ RpcResult<CompositeNode> schemaReply = device.invokeRpc(GET_SCHEMA_QNAME, request.toInstance()).get();
+ if (schemaReply.isSuccessful()) {
+ String schemaBody = getSchemaFromRpc(schemaReply.getResult());
+ if (schemaBody != null) {
+ device.logger.trace("YANG Schema successfully retrieved from remote for {}:{}", moduleName, revision);
+ return Optional.of(schemaBody);
+ }
}
+ device.logger.warn("YANG shcema was not successfully retrieved.");
+ } catch (InterruptedException | ExecutionException e) {
+ device.logger.warn("YANG shcema was not successfully retrieved.", e);
}
- device.logger.warn("YANG shcema was not successfully retrieved.");
return Optional.absent();
}
return null;
}
- public static final boolean isSupportedFor(Set<QName> capabilities) {
+ public static final boolean isSupportedFor(Collection<QName> capabilities) {
return capabilities.contains(IETF_NETCONF_MONITORING);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.connect.netconf;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.AbstractFuture;
+
+final class UncancellableFuture<V> extends AbstractFuture<V> {
+ @GuardedBy("this")
+ private boolean uncancellable = false;
+
+ public UncancellableFuture(boolean uncancellable) {
+ this.uncancellable = uncancellable;
+ }
+
+ public synchronized boolean setUncancellable() {
+ if (isCancelled()) {
+ return false;
+ }
+
+ uncancellable = true;
+ return true;
+ }
+
+ public synchronized boolean isUncancellable() {
+ return uncancellable;
+ }
+
+ @Override
+ public synchronized boolean cancel(boolean mayInterruptIfRunning) {
+ if (uncancellable) {
+ return false;
+ }
+
+ return super.cancel(mayInterruptIfRunning);
+ }
+
+ @Override
+ public synchronized boolean set(@Nullable V value) {
+ Preconditions.checkState(uncancellable == true);
+ return super.set(value);
+ }
+
+ @Override
+ protected boolean setException(Throwable throwable) {
+ Preconditions.checkState(uncancellable == true);
+ return super.setException(throwable);
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.connect.netconf;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.opendaylight.yangtools.concepts.Delegator;
-import org.opendaylight.yangtools.yang.common.QName;
-
-import com.google.common.base.Charsets;
-
-/**
- *
- *
- */
-public class YangModelInputStreamAdapter extends InputStream implements Delegator<InputStream> {
-
- final String source;
- final QName moduleIdentifier;
- final InputStream delegate;
-
- private YangModelInputStreamAdapter(String source, QName moduleIdentifier, InputStream delegate) {
- super();
- this.source = source;
- this.moduleIdentifier = moduleIdentifier;
- this.delegate = delegate;
- }
-
- @Override
- public int read() throws IOException {
- return delegate.read();
- }
-
- @Override
- public int hashCode() {
- return delegate.hashCode();
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- return delegate.read(b);
- }
-
- @Override
- public boolean equals(Object obj) {
- return delegate.equals(obj);
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- return delegate.read(b, off, len);
- }
-
- @Override
- public long skip(long n) throws IOException {
- return delegate.skip(n);
- }
-
- @Override
- public int available() throws IOException {
- return delegate.available();
- }
-
- @Override
- public void close() throws IOException {
- delegate.close();
- }
-
- @Override
- public void mark(int readlimit) {
- delegate.mark(readlimit);
- }
-
- @Override
- public void reset() throws IOException {
- delegate.reset();
- }
-
- @Override
- public boolean markSupported() {
- return delegate.markSupported();
- }
-
- @Override
- public InputStream getDelegate() {
- return delegate;
- }
-
- @Override
- public String toString() {
- return "YangModelInputStreamAdapter [moduleIdentifier=" + moduleIdentifier + ", delegate=" + delegate + "]";
- }
-
- public static YangModelInputStreamAdapter create(QName name, String module) {
- return new YangModelInputStreamAdapter(null, name, new ByteArrayInputStream(module.getBytes(Charsets.UTF_8)));
- }
-}
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${project.build.directory}/generated-sources/</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</build>
</project>
<codeGeneratorClass>
org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
</codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+ <outputBaseDir>${jmxGeneratorPath}</outputBaseDir>
<additionalConfiguration>
<namespaceToPackage1>
urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
package org.opendaylight.controller.sal.connector.remoterpc;
-import com.google.common.base.Optional;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+
import org.opendaylight.controller.sal.common.util.RpcErrors;
import org.opendaylight.controller.sal.common.util.Rpcs;
import org.opendaylight.controller.sal.connector.api.RpcRouter;
import org.slf4j.LoggerFactory;
import org.zeromq.ZMQ;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeUnit;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
/**
* An implementation of {@link RpcImplementation} that makes
private final Logger _logger = LoggerFactory.getLogger(ClientImpl.class);
- private ZMQ.Context context = ZMQ.context(1);
- private ClientRequestHandler handler;
+ private final ZMQ.Context context = ZMQ.context(1);
+ private final ClientRequestHandler handler;
private RoutingTableProvider routingTableProvider;
public ClientImpl(){
return routingTableProvider;
}
+ @Override
public void setRoutingTableProvider(RoutingTableProvider routingTableProvider) {
this.routingTableProvider = routingTableProvider;
}
* @param input payload for the remote service
* @return
*/
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
RouteIdentifierImpl routeId = new RouteIdentifierImpl();
routeId.setType(rpc);
* payload
* @return
*/
- public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
RouteIdentifierImpl routeId = new RouteIdentifierImpl();
routeId.setType(rpc);
return sendMessage(input, routeId, address);
}
- private RpcResult<CompositeNode> sendMessage(CompositeNode input, RouteIdentifierImpl routeId, String address) {
+ private ListenableFuture<RpcResult<CompositeNode>> sendMessage(CompositeNode input, RouteIdentifierImpl routeId, String address) {
Message request = new Message.MessageBuilder()
.type(Message.MessageType.REQUEST)
.sender(Context.getInstance().getLocalUri())
}
}
- return Rpcs.getRpcResult(true, payload, errors);
+ return Futures.immediateFuture(Rpcs.getRpcResult(true, payload, errors));
} catch (Exception e){
collectErrors(e, errors);
- return Rpcs.getRpcResult(false, null, errors);
+ return Futures.immediateFuture(Rpcs.<CompositeNode>getRpcResult(false, null, errors));
}
}
package org.opendaylight.controller.sal.connector.remoterpc;
-import com.google.common.base.Optional;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.sal.connector.api.RpcRouter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
public class RemoteRpcProvider implements
RpcImplementation,
AutoCloseable,
Provider {
- private Logger _logger = LoggerFactory.getLogger(RemoteRpcProvider.class);
+ private final Logger _logger = LoggerFactory.getLogger(RemoteRpcProvider.class);
private final ServerImpl server;
private final ClientImpl client;
}
@Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input) {
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, CompositeNode input) {
return client.invokeRpc(rpc, input);
}
@Override
- public RpcResult<CompositeNode> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(QName rpc, InstanceIdentifier identifier, CompositeNode input) {
return client.invokeRpc(rpc, identifier, input);
}
return routeIdSet;
}
-
-
}
-
}
e = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e1) {
_logger.error("Failed to get list of interfaces", e1);
- //throw new RuntimeException("Failed to acquire list of interfaces", e1);
return null;
}
while (e.hasMoreElements()) {
while (ee.hasMoreElements()) {
InetAddress i = (InetAddress) ee.nextElement();
_logger.debug("Trying address {}", i);
- if ((i instanceof Inet4Address) && (i.isSiteLocalAddress())) {
+ if ((i instanceof Inet4Address) && (!i.isLoopbackAddress())) {
String hostAddress = i.getHostAddress();
_logger.debug("Settled on host address {}", hostAddress);
return hostAddress;
*/
package org.opendaylight.controller.sal.connector.remoterpc;
-import com.google.common.base.Optional;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
import junit.framework.Assert;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.sal.common.util.Rpcs;
import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RouteChangeListener;
import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
-import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
-import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
import org.opendaylight.controller.sal.connector.remoterpc.dto.Message;
import org.opendaylight.controller.sal.connector.remoterpc.utils.MessagingUtil;
-import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import java.io.IOException;
-import java.util.*;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import com.google.common.base.Optional;
/**
*
when(mockHandler.handle(any(Message.class))).
thenReturn(MessagingUtil.createEmptyMessage());
- RpcResult<CompositeNode> result = client.invokeRpc(null, null);
+ RpcResult<CompositeNode> result = client.invokeRpc(null, null).get();
Assert.assertTrue(result.isSuccessful());
Assert.assertTrue(result.getErrors().isEmpty());
when(mockHandler.handle(any(Message.class))).
thenThrow(new IOException());
- RpcResult<CompositeNode> result = client.invokeRpc(null, null);
+ RpcResult<CompositeNode> result = client.invokeRpc(null, null).get();
Assert.assertFalse(result.isSuccessful());
Assert.assertFalse(result.getErrors().isEmpty());
+ "\" cannot contain \"null\" value as a key."
)
}
- keyValues.addKeyValue(listNode.getDataChildByName(key), uriKeyValue);
+ keyValues.addKeyValue(listNode.getDataChildByName(key), uriKeyValue, mountPoint);
i = i + 1;
}
consumed = consumed + i;
}
}
- private def void addKeyValue(HashMap<QName, Object> map, DataSchemaNode node, String uriValue) {
+ private def void addKeyValue(HashMap<QName, Object> map, DataSchemaNode node, String uriValue, MountInstance mountPoint) {
checkNotNull(uriValue);
checkArgument(node instanceof LeafSchemaNode);
val urlDecoded = URLDecoder.decode(uriValue);
val typedef = (node as LeafSchemaNode).type;
- var decoded = TypeDefinitionAwareCodec.from(typedef)?.deserialize(urlDecoded)
+ var decoded = RestCodec.from(typedef, mountPoint)?.deserialize(urlDecoded)
var additionalInfo = ""
if(decoded === null) {
var baseType = RestUtil.resolveBaseTypeFrom(typedef)
</instructions>
</configuration>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${project.build.directory}/generated-sources/</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</build>
</project>
org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
</codeGeneratorClass>
<outputBaseDir>
- target/generated-sources/sal
+ ${salGeneratorPath}
</outputBaseDir>
</generator>
<generator>
<properties>
<sal-binding-api.version>1.1-SNAPSHOT</sal-binding-api.version>
- <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
-
</properties>
<build>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${jmxGeneratorPath}</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</build>
<properties>
- <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
<sal-binding-api.version>1.1-SNAPSHOT</sal-binding-api.version>
</properties>
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
- <executions>
- <execution>
- <id>add-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${jmxGeneratorPath}</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</build>
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.7</version>
- <executions>
- <execution>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>target/generated-sources/sal</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
<pluginManagement>
<plugins>
</instructions>
</configuration>
</plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- </plugin>
</plugins>
</build>
</project>
<plugin>
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>compile</goal>
- </goals>
- <configuration>
- <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- <configuration>
- <filesets>
- <fileset>
- <directory>${basedir}/src/main/xtend-gen</directory>
- <includes>
- <include>**</include>
- </includes>
- </fileset>
- </filesets>
- </configuration>
</plugin>
</plugins>
</build>
<groupId>org.eclipse.xtend</groupId>
<artifactId>xtend-maven-plugin</artifactId>
</plugin>
- <plugin>
- <artifactId>maven-clean-plugin</artifactId>
- </plugin>
</plugins>
</build>
</project>
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
@Mock
NetconfOperationRouter netconfOperationRouter;
@Mock
- NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
+ NetconfOperationServiceSnapshotImpl netconfOperationServiceSnapshot;
private TransactionProvider transactionProvider;
import com.google.common.annotations.VisibleForTesting;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
import org.opendaylight.controller.netconf.persist.impl.ConfigPusher;
import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
+import org.opendaylight.controller.netconf.util.CloseableUtil;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
public class ConfigPersisterActivator implements BundleActivator {
private static final Logger logger = LoggerFactory.getLogger(ConfigPersisterActivator.class);
+ private static final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
public static final String MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY = "maxWaitForCapabilitiesMillis";
private static final long MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT = TimeUnit.MINUTES.toMillis(2);
public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass";
-
- private static final MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
-
private List<AutoCloseable> autoCloseables;
autoCloseables = new ArrayList<>();
PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context);
-
final PersisterAggregator persisterAggregator = PersisterAggregator.createFromProperties(propertiesProvider);
autoCloseables.add(persisterAggregator);
- final long maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesMillis(propertiesProvider);
- final List<ConfigSnapshotHolder> configs = persisterAggregator.loadLastConfigs();
- final long conflictingVersionTimeoutMillis = getConflictingVersionTimeoutMillis(propertiesProvider);
+ long maxWaitForCapabilitiesMillis = getMaxWaitForCapabilitiesMillis(propertiesProvider);
+ List<ConfigSnapshotHolder> configs = persisterAggregator.loadLastConfigs();
+ long conflictingVersionTimeoutMillis = getConflictingVersionTimeoutMillis(propertiesProvider);
logger.trace("Following configs will be pushed: {}", configs);
- ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory> configNetconfCustomizer = new ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory>() {
- @Override
- public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
- NetconfOperationServiceFactory service = reference.getBundle().getBundleContext().getService(reference);
- final ConfigPusher configPusher = new ConfigPusher(service, maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
- logger.debug("Configuration Persister got %s", service);
- final Thread pushingThread = new Thread(new Runnable() {
- @Override
- public void run() {
- configPusher.pushConfigs(configs);
- logger.info("Configuration Persister initialization completed.");
- ConfigPersisterNotificationHandler jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator);
- synchronized (ConfigPersisterActivator.this) {
- autoCloseables.add(jmxNotificationHandler);
- }
- }
- }, "config-pusher");
- synchronized (ConfigPersisterActivator.this){
- autoCloseables.add(new AutoCloseable() {
- @Override
- public void close() throws Exception {
- pushingThread.interrupt();
- }
- });
- }
- pushingThread.start();
- return service;
- }
- @Override
- public void modifiedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
- }
+ InnerCustomizer innerCustomizer = new InnerCustomizer(configs, maxWaitForCapabilitiesMillis,
+ conflictingVersionTimeoutMillis, persisterAggregator);
+ OuterCustomizer outerCustomizer = new OuterCustomizer(context, innerCustomizer);
+ new ServiceTracker<>(context, NetconfOperationProvider.class, outerCustomizer).open();
+ }
- @Override
- public void removedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
- }
- };
+ private long getConflictingVersionTimeoutMillis(PropertiesProviderBaseImpl propertiesProvider) {
+ String timeoutProperty = propertiesProvider.getProperty(CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY);
+ return timeoutProperty == null ? CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
+ }
- Filter filter = context.createFilter(getFilterString());
+ private long getMaxWaitForCapabilitiesMillis(PropertiesProviderBaseImpl propertiesProvider) {
+ String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY);
+ return timeoutProperty == null ? MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
+ }
- ServiceTracker<NetconfOperationServiceFactory, NetconfOperationServiceFactory> tracker =
- new ServiceTracker<>(context, filter, configNetconfCustomizer);
- tracker.open();
+ @Override
+ public synchronized void stop(BundleContext context) throws Exception {
+ CloseableUtil.closeAll(autoCloseables);
}
")";
}
- private long getConflictingVersionTimeoutMillis(PropertiesProviderBaseImpl propertiesProvider) {
- String timeoutProperty = propertiesProvider.getProperty(CONFLICTING_VERSION_TIMEOUT_MILLIS_PROPERTY);
- return timeoutProperty == null ? CONFLICTING_VERSION_TIMEOUT_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
- }
+ class OuterCustomizer implements ServiceTrackerCustomizer<NetconfOperationProvider, NetconfOperationProvider> {
+ private final BundleContext context;
+ private final InnerCustomizer innerCustomizer;
- private long getMaxWaitForCapabilitiesMillis(PropertiesProviderBaseImpl propertiesProvider) {
- String timeoutProperty = propertiesProvider.getProperty(MAX_WAIT_FOR_CAPABILITIES_MILLIS_PROPERTY);
- return timeoutProperty == null ? MAX_WAIT_FOR_CAPABILITIES_MILLIS_DEFAULT : Long.valueOf(timeoutProperty);
- }
+ OuterCustomizer(BundleContext context, InnerCustomizer innerCustomizer) {
+ this.context = context;
+ this.innerCustomizer = innerCustomizer;
+ }
- @Override
- public synchronized void stop(BundleContext context) throws Exception {
- Exception lastException = null;
- for (AutoCloseable autoCloseable : autoCloseables) {
+ @Override
+ public NetconfOperationProvider addingService(ServiceReference<NetconfOperationProvider> reference) {
+ logger.trace("Got OuterCustomizer.addingService {}", reference);
+ // JMX was registered, track config-netconf-connector
+ Filter filter;
try {
- autoCloseable.close();
- } catch (Exception e) {
- if (lastException == null) {
- lastException = e;
- } else {
- lastException.addSuppressed(e);
+ filter = context.createFilter(getFilterString());
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalStateException(e);
+ }
+ new ServiceTracker<>(context, filter, innerCustomizer).open();
+ return null;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<NetconfOperationProvider> reference, NetconfOperationProvider service) {
+
+ }
+
+ @Override
+ public void removedService(ServiceReference<NetconfOperationProvider> reference, NetconfOperationProvider service) {
+
+ }
+ }
+
+ class InnerCustomizer implements ServiceTrackerCustomizer<NetconfOperationServiceFactory, NetconfOperationServiceFactory> {
+ private final List<ConfigSnapshotHolder> configs;
+ private final PersisterAggregator persisterAggregator;
+ private final long maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis;
+
+
+ InnerCustomizer(List<ConfigSnapshotHolder> configs, long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis,
+ PersisterAggregator persisterAggregator) {
+ this.configs = configs;
+ this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
+ this.conflictingVersionTimeoutMillis = conflictingVersionTimeoutMillis;
+ this.persisterAggregator = persisterAggregator;
+ }
+
+ @Override
+ public NetconfOperationServiceFactory addingService(ServiceReference<NetconfOperationServiceFactory> reference) {
+ logger.trace("Got InnerCustomizer.addingService {}", reference);
+ NetconfOperationServiceFactory service = reference.getBundle().getBundleContext().getService(reference);
+
+ final ConfigPusher configPusher = new ConfigPusher(service, maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
+ logger.debug("Configuration Persister got {}", service);
+ final Thread pushingThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ configPusher.pushConfigs(configs);
+ logger.info("Configuration Persister initialization completed.");
+ ConfigPersisterNotificationHandler jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator);
+ synchronized (ConfigPersisterActivator.this) {
+ autoCloseables.add(jmxNotificationHandler);
+ }
}
+ }, "config-pusher");
+ synchronized (ConfigPersisterActivator.this) {
+ autoCloseables.add(new AutoCloseable() {
+ @Override
+ public void close() throws Exception {
+ pushingThread.interrupt();
+ }
+ });
}
+ pushingThread.start();
+ return service;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
}
- if (lastException != null) {
- throw lastException;
+
+ @Override
+ public void removedService(ServiceReference<NetconfOperationServiceFactory> reference, NetconfOperationServiceFactory service) {
}
+
}
}
+
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
-import javax.management.MBeanServer;
import java.io.IOException;
-import java.lang.management.ManagementFactory;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
private MockedBundleContext ctx;
private ConfigPersisterActivator configPersisterActivator;
- private static final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
private TestingExceptionHandler handler;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.config.persist.api.Persister;
import org.opendaylight.controller.config.persist.api.PropertiesProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.persist.impl.DummyAdapter;
@Mock
private BundleContext context;
@Mock
- private Filter filter;
+ private Filter outerFilter, innerFilter;
@Mock
private ServiceReference<?> serviceReference;
@Mock
MockitoAnnotations.initMocks(this);
doReturn(null).when(context).getProperty(anyString());
initContext(maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
- doReturn(filter).when(context).createFilter(ConfigPersisterActivator.getFilterString());
- String filterString = "filter";
- doReturn(filterString).when(filter).toString();
- doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(filterString));
+
+ String outerFilterString = "(objectClass=org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider)";
+ doReturn(outerFilter).when(context).createFilter(outerFilterString);
+ doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(outerFilterString));
ServiceReference<?>[] toBeReturned = {serviceReference};
- doReturn(toBeReturned).when(context).getServiceReferences((String) null, filterString);
+ doReturn(toBeReturned).when(context).getServiceReferences(NetconfOperationProvider.class.getName(), null);
+
+ String innerFilterString = "innerfilter";
+ doReturn(innerFilterString).when(outerFilter).toString();
+
+ doReturn(innerFilter).when(context).createFilter(ConfigPersisterActivator.getFilterString());
+ doReturn(innerFilterString).when(innerFilter).toString();
+ doNothing().when(context).addServiceListener(any(ServiceListener.class), eq(innerFilterString));
+
+ doReturn(toBeReturned).when(context).getServiceReferences((String) null, innerFilterString);
doReturn(bundle).when(serviceReference).getBundle();
doReturn(context).when(bundle).getBundleContext();
doReturn("").when(serviceReference).toString();
doReturn(service).when(serviceFactory).createService(anyString());
doReturn(Collections.emptySet()).when(service).getCapabilities();
doNothing().when(service).close();
+ doReturn("serviceFactoryMock").when(serviceFactory).toString();
}
public BundleContext getBundleContext() {
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- </plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-maven-plugin</artifactId>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- </plugin>
<plugin>
<groupId>org.apache.felix</groupId>
Document onNetconfMessage(Document message, NetconfSession session)
throws NetconfDocumentedException;
- @Override
- void close();
}
public String getErrorMessage() {
return reason;
}
+
+ @Override
+ public String toString() {
+ return reason;
+ }
}
</instructions>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.4</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
+++ /dev/null
-/*
- * 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 org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
-
-/**
- * Class extending {@link NetconfClientSessionListener} to provide notification capability.
- */
-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.
- * So far let just enable notification capability by extending and let parent class intact.
- */
-
- /**
- * As class purpose is to provide notification capability to session listener
- * onMessage method is not allowed to be further overridden.
- * {@see #onNotification(NetconfClientSession, NetconfMessage)}
- *
- * @param session {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
- * @param message {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
- */
- @Override
- public final void onMessage(NetconfClientSession session, NetconfMessage message) {
- if (isNotification(message)) {
- onNotification(session, message);
- } else {
- super.onMessage(session, message);
- }
- }
-
- /**
- * Method intended to customize notification processing.
- *
- * @param session {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
- * @param message {@see NetconfClientSessionListener#onMessage(NetconfClientSession, NetconfMessage)}
- */
- public abstract void onNotification(NetconfClientSession session, NetconfMessage message);
-
- private boolean isNotification(NetconfMessage message) {
- XmlElement xmle = XmlElement.fromDomDocument(message.getDocument());
- return XmlNetconfConstants.NOTIFICATION_ELEMENT_NAME.equals(xmle.getName()) ;
- }
-}
+++ /dev/null
-/*
- * 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 java.io.Closeable;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-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);
-
- public static final int DEFAULT_CONNECT_TIMEOUT = 5000;
- private final NetconfClientDispatcher dispatch;
- private final String label;
- private final NetconfClientSession clientSession;
- private final NetconfClientSessionListener sessionListener;
- private final long sessionId;
- private final InetSocketAddress address;
-
- // TODO test reconnecting constructor
- public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectionAttempts,
- int attemptMsTimeout, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this(clientLabelForLogging, address, getReconnectStrategy(connectionAttempts, attemptMsTimeout),
- netconfClientDispatcher);
- }
-
- private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this.label = clientLabelForLogging;
- dispatch = netconfClientDispatcher;
- sessionListener = new SimpleNetconfClientSessionListener();
- Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
- this.address = address;
- clientSession = get(clientFuture);
- this.sessionId = clientSession.getSessionId();
- }
-
- private NetconfClientSession get(Future<NetconfClientSession> clientFuture) throws InterruptedException {
- try {
- return clientFuture.get();
- } catch (CancellationException e) {
- throw new RuntimeException("Cancelling " + this, e);
- } catch (ExecutionException e) {
- throw new IllegalStateException("Unable to create " + this, e);
- }
- }
-
- public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher);
- }
-
- public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address,
- ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException {
- return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher,listener);
- }
-
- public NetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
- NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this(clientLabelForLogging, address,
- new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, connectTimeoutMs), netconfClientDispatcher);
- }
-
- public NetconfClient(String clientLabelForLogging, InetSocketAddress address,
- NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
- this(clientLabelForLogging, address, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
- DEFAULT_CONNECT_TIMEOUT), netconfClientDispatcher);
- }
-
- public NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy,
- NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException{
- this.label = clientLabelForLogging;
- dispatch = netconfClientDispatcher;
- sessionListener = listener;
- Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strategy);
- this.address = address;
- clientSession = get(clientFuture);
- this.sessionId = clientSession.getSessionId();
- }
-
- public Future<NetconfMessage> 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);
- }
-
- /**
- * @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()));
- final Stopwatch stopwatch = new Stopwatch().start();
-
- try {
- return sendRequest(message).get(attempts * attemptMsDelay, TimeUnit.MILLISECONDS);
- } finally {
- stopwatch.stop();
- logger.debug("Total time spent waiting for response from {}: {} ms", address, stopwatch.elapsed(TimeUnit.MILLISECONDS));
- }
- }
-
- @Override
- public void close() throws IOException {
- clientSession.close();
- }
-
- public NetconfClientDispatcher getNetconfClientDispatcher() {
- return dispatch;
- }
-
- private static ReconnectStrategy getReconnectStrategy(int connectionAttempts, int attemptMsTimeout) {
- return new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, attemptMsTimeout, 1000, 1.0, null,
- Long.valueOf(connectionAttempts), null);
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("NetconfClient{");
- sb.append("label=").append(label);
- sb.append(", sessionId=").append(sessionId);
- sb.append('}');
- return sb.toString();
- }
-
- public long getSessionId() {
- return sessionId;
- }
-
- public Set<String> getCapabilities() {
- Preconditions.checkState(clientSession != null, "Client was not initialized successfully");
- return Sets.newHashSet(clientSession.getServerCapabilities());
- }
-
- public NetconfClientSession getClientSession() {
- return clientSession;
- }
-}
if(this.additionalHeader.isPresent()) {
helloMessage = new NetconfHelloMessage(helloMessage.getDocument(), additionalHeader.get());
- } else
+ } else {
helloMessage = new NetconfHelloMessage(helloMessage.getDocument());
+ }
NetconfSessionPreferences proposal = new NetconfSessionPreferences(helloMessage);
return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
}
}
- final synchronized Future<NetconfMessage> sendRequest(NetconfMessage message) {
+ public final synchronized Future<NetconfMessage> sendRequest(NetconfMessage message) {
final RequestEntry req = new RequestEntry(GlobalEventExecutor.INSTANCE.<NetconfMessage>newPromise(), message);
requests.add(req);
+++ /dev/null
-/*
- * 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.channel.nio.NioEventLoopGroup;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.opendaylight.controller.netconf.util.handler.ssh.authentication.LoginPassword;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-@Ignore
-public class SSHNetconfClientLiveTest {
- private static final Logger logger = LoggerFactory.getLogger(SSHNetconfClientLiveTest.class);
-
- NioEventLoopGroup nettyThreadgroup;
- NetconfSshClientDispatcher netconfClientDispatcher;
- InetSocketAddress address;
- final int connectionAttempts = 10, attemptMsTimeout = 1000;
- final int connectionTimeoutMillis = 20000;
-
- @Before
- public void setUp() {
- nettyThreadgroup = new NioEventLoopGroup();
-
- netconfClientDispatcher = new NetconfSshClientDispatcher(new LoginPassword(
- System.getProperty("username"), System.getProperty("password")),
- nettyThreadgroup, nettyThreadgroup, connectionTimeoutMillis);
-
- address = new InetSocketAddress(System.getProperty("host"), Integer.parseInt(System.getProperty("port")));
- }
-
- @Ignore
- @Test
- public void test() throws Exception {
- //runnable.run();
- }
-
- @Test
- public void testInExecutor() throws Exception {
- int threads = 4;
- ExecutorService executorService = Executors.newFixedThreadPool(threads);
- try {
- for (int i= 0;i< threads;i++) {
- InetSocketAddress address = new InetSocketAddress(System.getProperty("host"),
- Integer.parseInt(System.getProperty("port")));
- NetconfRunnable runnable = new NetconfRunnable(address);
- executorService.execute(runnable);
- }
- executorService.shutdown();
- executorService.awaitTermination(1, TimeUnit.MINUTES);
-
-
- } finally {
- executorService.shutdownNow();
- }
- }
-
- class NetconfRunnable implements Runnable {
- private final InetSocketAddress address;
-
- NetconfRunnable(InetSocketAddress address) {
- this.address = address;
- }
-
- @Override
- public void run() {
- try (NetconfClient netconfClient = new NetconfClient(address.toString(), address, connectionAttempts,
- attemptMsTimeout, netconfClientDispatcher);) {
- logger.info("OK {}", address);
- } catch (InterruptedException | IOException e) {
- logger.error("Failed {}", address, e);
- }
- }
- };
-}
--- /dev/null
+/*
+ * 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.test;
+
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GlobalEventExecutor;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientSession;
+import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+
+
+/**
+ * Synchronous netconf client suitable for testing
+ */
+public class TestingNetconfClient implements Closeable {
+
+ public static final int DEFAULT_CONNECT_TIMEOUT = 5000;
+
+ private final String label;
+ private final NetconfClientSession clientSession;
+ private final NetconfClientSessionListener sessionListener;
+ private final long sessionId;
+
+ private TestingNetconfClient(String clientLabel, InetSocketAddress address, ReconnectStrategy strat,
+ NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
+ this.label = clientLabel;
+ sessionListener = new SimpleNetconfClientSessionListener();
+ Future<NetconfClientSession> clientFuture = netconfClientDispatcher.createClient(address, sessionListener, strat);
+ clientSession = get(clientFuture);
+ this.sessionId = clientSession.getSessionId();
+ }
+
+ private NetconfClientSession get(Future<NetconfClientSession> clientFuture) throws InterruptedException {
+ try {
+ return clientFuture.get();
+ } catch (CancellationException e) {
+ throw new RuntimeException("Cancelling " + this, e);
+ } catch (ExecutionException e) {
+ throw new IllegalStateException("Unable to create " + this, e);
+ }
+ }
+
+ public TestingNetconfClient(String clientLabelForLogging, InetSocketAddress address, int connectTimeoutMs,
+ NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
+ this(clientLabelForLogging, address,
+ new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, connectTimeoutMs), netconfClientDispatcher);
+ }
+
+ public TestingNetconfClient(String clientLabelForLogging, InetSocketAddress address,
+ NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
+ this(clientLabelForLogging, address, new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
+ DEFAULT_CONNECT_TIMEOUT), netconfClientDispatcher);
+ }
+
+ public Future<NetconfMessage> sendRequest(NetconfMessage message) {
+ return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message);
+ }
+
+ public NetconfMessage sendMessage(NetconfMessage message, int attemptMsDelay) throws ExecutionException,
+ InterruptedException, TimeoutException {
+ return sendRequest(message).get(attemptMsDelay, TimeUnit.MILLISECONDS);
+ }
+
+ public NetconfMessage sendMessage(NetconfMessage message) throws ExecutionException,
+ InterruptedException, TimeoutException {
+ return sendMessage(message, DEFAULT_CONNECT_TIMEOUT);
+ }
+
+ @Override
+ public void close() throws IOException {
+ clientSession.close();
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("TestingNetconfClient{");
+ sb.append("label=").append(label);
+ sb.append(", sessionId=").append(sessionId);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public long getSessionId() {
+ return sessionId;
+ }
+
+ public Set<String> getCapabilities() {
+ Preconditions.checkState(clientSession != null, "Client was not initialized successfully");
+ return Sets.newHashSet(clientSession.getServerCapabilities());
+ }
+}
\ No newline at end of file
<artifactId>netconf-client</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-client</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>commons.logback_settings</artifactId>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
</plugin>
</plugins>
</build>
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.concurrent.Promise;
-
-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<NetconfServerSession, NetconfServerSessionListener> {
private final ServerChannelInitializer initializer;
public static final String DESERIALIZER_EX_HANDLER_KEY = "deserializerExHandler";
private final NetconfServerSessionNegotiatorFactory negotiatorFactory;
- private final NetconfServerSessionListenerFactory listenerFactory;
- public ServerChannelInitializer(NetconfServerSessionNegotiatorFactory negotiatorFactory,
- NetconfServerSessionListenerFactory listenerFactory) {
+
+ public ServerChannelInitializer(NetconfServerSessionNegotiatorFactory negotiatorFactory) {
this.negotiatorFactory = negotiatorFactory;
- this.listenerFactory = listenerFactory;
+
}
@Override
@Override
protected void initializeSessionNegotiator(SocketChannel ch, Promise<NetconfServerSession> promise) {
- ch.pipeline().addAfter(DESERIALIZER_EX_HANDLER_KEY, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR, negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise));
+ ch.pipeline().addAfter(DESERIALIZER_EX_HANDLER_KEY, AbstractChannelInitializer.NETCONF_SESSION_NEGOTIATOR,
+ negotiatorFactory.getSessionNegotiator(null, ch, promise));
}
}
package org.opendaylight.controller.netconf.impl;
-import static com.google.common.base.Preconditions.checkState;
-
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import static com.google.common.base.Preconditions.checkState;
public class NetconfServerSessionListener implements NetconfSessionListener<NetconfServerSession> {
public static final String MESSAGE_ID = "message-id";
static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionListener.class);
private final SessionMonitoringService monitoringService;
private final NetconfOperationRouter operationRouter;
+ private final AutoCloseable onSessionDownCloseable;
- public NetconfServerSessionListener(NetconfOperationRouter operationRouter, SessionMonitoringService monitoringService) {
+ public NetconfServerSessionListener(NetconfOperationRouter operationRouter, SessionMonitoringService monitoringService,
+ AutoCloseable onSessionDownCloseable) {
this.operationRouter = operationRouter;
this.monitoringService = monitoringService;
+ this.onSessionDownCloseable = onSessionDownCloseable;
}
@Override
}
@Override
- public void onSessionDown(NetconfServerSession netconfNetconfServerSession, Exception e) {
- logger.debug("Session {} down, reason: {}", netconfNetconfServerSession, e.getMessage());
+ public void onSessionDown(NetconfServerSession netconfNetconfServerSession, Exception cause) {
+ logger.debug("Session {} down, reason: {}", netconfNetconfServerSession, cause.getMessage());
+ onDown(netconfNetconfServerSession);
+ }
+
+ public void onDown(NetconfServerSession netconfNetconfServerSession) {
monitoringService.onSessionDown(netconfNetconfServerSession);
- operationRouter.close();
+ try {
+ operationRouter.close();
+ } catch (Exception closingEx) {
+ logger.debug("Ignoring exception while closing operationRouter", closingEx);
+ }
+ try {
+ onSessionDownCloseable.close();
+ } catch(Exception ex){
+ logger.debug("Ignoring exception while closing onSessionDownCloseable", ex);
+ }
}
@Override
NetconfTerminationReason netconfTerminationReason) {
logger.debug("Session {} terminated, reason: {}", netconfNetconfServerSession,
netconfTerminationReason.getErrorMessage());
- monitoringService.onSessionDown(netconfNetconfServerSession);
-
- operationRouter.close();
+ onDown(netconfNetconfServerSession);
}
@Override
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
import org.opendaylight.protocol.framework.SessionListenerFactory;
public class NetconfServerSessionListenerFactory implements SessionListenerFactory<NetconfServerSessionListener> {
- private final NetconfOperationServiceFactoryListener factoriesListener;
-
private final DefaultCommitNotificationProducer commitNotifier;
-
- private final SessionIdProvider idProvider;
-
private final SessionMonitoringService monitor;
+ private final NetconfOperationServiceSnapshot netconfOperationServiceSnapshot;
+ private final CapabilityProvider capabilityProvider;
+
+ public NetconfServerSessionListenerFactory(DefaultCommitNotificationProducer commitNotifier,
+ SessionMonitoringService monitor,
+ NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
+ CapabilityProvider capabilityProvider) {
- public NetconfServerSessionListenerFactory(NetconfOperationServiceFactoryListener factoriesListener,
- DefaultCommitNotificationProducer commitNotifier,
- SessionIdProvider idProvider, SessionMonitoringService monitor) {
- this.factoriesListener = factoriesListener;
this.commitNotifier = commitNotifier;
- this.idProvider = idProvider;
this.monitor = monitor;
+ this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
+ this.capabilityProvider = capabilityProvider;
}
@Override
public NetconfServerSessionListener getSessionListener() {
- NetconfOperationServiceSnapshot netconfOperationServiceSnapshot = factoriesListener.getSnapshot(idProvider
- .getCurrentSessionId());
-
- CapabilityProvider capabilityProvider = new CapabilityProviderImpl(netconfOperationServiceSnapshot);
-
NetconfOperationRouter operationRouter = NetconfOperationRouterImpl.createOperationRouter(
- netconfOperationServiceSnapshot, capabilityProvider,
- commitNotifier);
-
- return new NetconfServerSessionListener(operationRouter, monitor);
+ netconfOperationServiceSnapshot, capabilityProvider, commitNotifier);
+ return new NetconfServerSessionListener(operationRouter, monitor, netconfOperationServiceSnapshot);
}
}
package org.opendaylight.controller.netconf.impl;
-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;
import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
-
-import io.netty.channel.Channel;
-import io.netty.util.Timer;
-import io.netty.util.concurrent.Promise;
+import java.net.InetSocketAddress;
public class NetconfServerSessionNegotiator extends
AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession, NetconfServerSessionListener> {
return new NetconfServerSession(sessionListener, channel, getSessionPreferences().getSessionId(), parsedHeader);
}
- }
+}
import io.netty.util.concurrent.Promise;
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.impl.osgi.SessionMonitoringService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.util.NetconfUtil;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
import javax.xml.xpath.XPathExpression;
import java.io.InputStream;
+import static org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider.NetconfOperationProviderUtil.getNetconfSessionIdForReporting;
+
public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfHelloMessage, NetconfServerSession, NetconfServerSessionListener> {
public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml";
private static final Document helloMessageTemplate = loadHelloMessageTemplate();
private final SessionIdProvider idProvider;
- private final NetconfOperationServiceFactoryListener factoriesListener;
+ private final NetconfOperationProvider netconfOperationProvider;
private final long connectionTimeoutMillis;
+ private final DefaultCommitNotificationProducer commitNotificationProducer;
+ private final SessionMonitoringService monitoringService;
- public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationServiceFactoryListener factoriesListener,
- SessionIdProvider idProvider, long connectionTimeoutMillis) {
+ public NetconfServerSessionNegotiatorFactory(Timer timer, NetconfOperationProvider netconfOperationProvider,
+ SessionIdProvider idProvider, long connectionTimeoutMillis,
+ DefaultCommitNotificationProducer commitNot, SessionMonitoringService monitoringService) {
this.timer = timer;
- this.factoriesListener = factoriesListener;
+ this.netconfOperationProvider = netconfOperationProvider;
this.idProvider = idProvider;
this.connectionTimeoutMillis = connectionTimeoutMillis;
+ this.commitNotificationProducer = commitNot;
+ this.monitoringService = monitoringService;
}
private static Document loadHelloMessageTemplate() {
return NetconfUtil.createMessage(resourceAsStream).getDocument();
}
+ /**
+ *
+ * @param defunctSessionListenerFactory will not be taken into account as session listener factory can
+ * only be created after snapshot is opened, thus this method constructs
+ * proper session listener factory.
+ * @param channel Underlying channel
+ * @param promise Promise to be notified
+ * @return session negotiator
+ */
@Override
- public SessionNegotiator<NetconfServerSession> getSessionNegotiator(SessionListenerFactory<NetconfServerSessionListener> sessionListenerFactory, Channel channel,
- Promise<NetconfServerSession> promise) {
+ public SessionNegotiator<NetconfServerSession> getSessionNegotiator(SessionListenerFactory<NetconfServerSessionListener> defunctSessionListenerFactory,
+ Channel channel, Promise<NetconfServerSession> promise) {
long sessionId = idProvider.getNextSessionId();
+ NetconfOperationServiceSnapshot netconfOperationServiceSnapshot = netconfOperationProvider.openSnapshot(
+ getNetconfSessionIdForReporting(sessionId));
+ CapabilityProvider capabilityProvider = new CapabilityProviderImpl(netconfOperationServiceSnapshot);
+
+ NetconfServerSessionPreferences proposal = new NetconfServerSessionPreferences(
+ createHelloMessage(sessionId, capabilityProvider), sessionId);
+
+ NetconfServerSessionListenerFactory sessionListenerFactory = new NetconfServerSessionListenerFactory(
+ commitNotificationProducer, monitoringService,
+ netconfOperationServiceSnapshot, capabilityProvider);
- NetconfServerSessionPreferences proposal = new NetconfServerSessionPreferences(createHelloMessage(sessionId),
- sessionId);
return new NetconfServerSessionNegotiator(proposal, promise, channel, timer,
sessionListenerFactory.getSessionListener(), connectionTimeoutMillis);
}
private static final XPathExpression capabilitiesXPath = XMLNetconfUtil
.compileXPath("/netconf:hello/netconf:capabilities");
- private NetconfHelloMessage createHelloMessage(long sessionId) {
+ private NetconfHelloMessage createHelloMessage(long sessionId, CapabilityProvider capabilityProvider) {
Document helloMessageTemplate = getHelloTemplateClone();
// change session ID
final Element capabilitiesElement = (Element) XmlUtil.evaluateXPath(capabilitiesXPath, helloMessageTemplate,
XPathConstants.NODE);
- CapabilityProvider capabilityProvider = new CapabilityProviderImpl(factoriesListener.getSnapshot(sessionId));
-
for (String capability : capabilityProvider.getCapabilities()) {
final Element capabilityElement = helloMessageTemplate.createElement(XmlNetconfConstants.CAPABILITY);
capabilityElement.setTextContent(capability);
package org.opendaylight.controller.netconf.impl.mapping.operations;
-import java.util.Collections;
-
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import java.util.Collections;
+
public class DefaultCloseSession extends AbstractSingletonNetconfOperation {
public static final String CLOSE_SESSION = "close-session";
private final AutoCloseable sessionResources;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
-import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
private NetconfOperationServiceFactoryTracker factoriesTracker;
private DefaultCommitNotificationProducer commitNot;
- private NetconfServerDispatcher dispatch;
private NioEventLoopGroup eventLoopGroup;
private HashedWheelTimer timer;
private ServiceRegistration<NetconfMonitoringService> regMonitoring;
SessionIdProvider idProvider = new SessionIdProvider();
timer = new HashedWheelTimer();
long connectionTimeoutMillis = NetconfConfigUtil.extractTimeoutMillis(context);
- NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- timer, factoriesListener, idProvider, connectionTimeoutMillis);
+
commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
- NetconfMonitoringServiceImpl monitoringService = startMonitoringService(context, factoriesListener);
+ SessionMonitoringService monitoringService = startMonitoringService(context, factoriesListener);
- NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
- factoriesListener, commitNot, idProvider, monitoringService);
+ NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
+ timer, factoriesListener, idProvider, connectionTimeoutMillis, commitNot, monitoringService);
eventLoopGroup = new NioEventLoopGroup();
NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
- serverNegotiatorFactory, listenerFactory);
- dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
+ serverNegotiatorFactory);
+ NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
logger.info("Starting TCP netconf server at {}", address);
dispatch.createServer(address);
+ context.registerService(NetconfOperationProvider.class, factoriesListener, null);
+
}
private void startOperationServiceFactoryTracker(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.Capability;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.Yang;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
private static final Logger logger = LoggerFactory.getLogger(NetconfMonitoringServiceImpl.class);
private final Set<NetconfManagementSession> sessions = new ConcurrentSet<>();
- private final NetconfOperationServiceFactoryListener factoriesListener;
+ private final NetconfOperationProvider netconfOperationProvider;
- public NetconfMonitoringServiceImpl(NetconfOperationServiceFactoryListener factoriesListener) {
- this.factoriesListener = factoriesListener;
+ public NetconfMonitoringServiceImpl(NetconfOperationProvider netconfOperationProvider) {
+ this.netconfOperationProvider = netconfOperationProvider;
}
@Override
@Override
public void onSessionDown(NetconfManagementSession session) {
logger.debug("Session {} down", session);
- Preconditions.checkState(sessions.contains(session) == true, "Session %s not present", session);
+ Preconditions.checkState(sessions.contains(session), "Session %s not present", session);
sessions.remove(session);
}
@Override
public Schemas getSchemas() {
- // FIXME, session ID
// capabilities should be split from operations (it will allow to move getSchema operation to monitoring module)
- return transformSchemas(factoriesListener.getSnapshot(0));
+ try (NetconfOperationServiceSnapshot snapshot = netconfOperationProvider.openSnapshot("netconf-monitoring")) {
+ return transformSchemas(snapshot.getServices());
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IllegalStateException("Exception while closing", e);
+ }
}
- private Schemas transformSchemas(NetconfOperationServiceSnapshot snapshot) {
+ private Schemas transformSchemas(Set<NetconfOperationService> services) {
Set<Capability> caps = Sets.newHashSet();
List<Schema> schemas = Lists.newArrayList();
- for (NetconfOperationService netconfOperationService : snapshot.getServices()) {
+
+ for (NetconfOperationService netconfOperationService : services) {
// TODO check for duplicates ? move capability merging to snapshot
// Split capabilities from operations first and delete this duplicate code
caps.addAll(netconfOperationService.getCapabilities());
for (Capability cap : caps) {
SchemaBuilder builder = new SchemaBuilder();
- if(cap.getCapabilitySchema().isPresent() == false)
+ if (cap.getCapabilitySchema().isPresent() == false) {
continue;
+ }
Preconditions.checkState(cap.getModuleNamespace().isPresent());
builder.setNamespace(new Uri(cap.getModuleNamespace().get()));
builder.setFormat(Yang.class);
- builder.setLocation(transformLocations(cap.getLocation().or(Collections.<String> emptyList())));
+ builder.setLocation(transformLocations(cap.getLocation().or(Collections.<String>emptyList())));
builder.setKey(new SchemaKey(Yang.class, identifier, version));
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
String errorMessage = String.format("Unable to handle rpc %s on session %s", messageAsString, session);
Map<String, String> errorInfo = Maps.newHashMap();
- NetconfDocumentedException.ErrorTag tag = null;
+ NetconfDocumentedException.ErrorTag tag;
if (e instanceof IllegalArgumentException) {
errorInfo.put(NetconfDocumentedException.ErrorTag.operation_not_supported.toString(), e.getMessage());
tag = NetconfDocumentedException.ErrorTag.operation_not_supported;
- } else if (e instanceof IllegalStateException) {
+ } else {
errorInfo.put(NetconfDocumentedException.ErrorTag.operation_failed.toString(), e.getMessage());
tag = NetconfDocumentedException.ErrorTag.operation_failed;
}
}
@Override
- public void close() {
+ public void close() throws Exception {
netconfOperationServiceSnapshot.close();
}
void onRemoveNetconfOperationServiceFactory(NetconfOperationServiceFactory service);
- NetconfOperationServiceSnapshot getSnapshot(long sessionId);
+
}
*/
package org.opendaylight.controller.netconf.impl.osgi;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
+
import java.util.HashSet;
import java.util.Set;
-import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-
-public class NetconfOperationServiceFactoryListenerImpl implements NetconfOperationServiceFactoryListener {
+public class NetconfOperationServiceFactoryListenerImpl implements NetconfOperationServiceFactoryListener,
+ NetconfOperationProvider {
private final Set<NetconfOperationServiceFactory> allFactories = new HashSet<>();
@Override
}
@Override
- public synchronized NetconfOperationServiceSnapshot getSnapshot(long sessionId) {
- return new NetconfOperationServiceSnapshot(allFactories, sessionId);
+ public synchronized NetconfOperationServiceSnapshotImpl openSnapshot(String sessionIdForReporting) {
+ return new NetconfOperationServiceSnapshotImpl(allFactories, sessionIdForReporting);
}
}
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.util.CloseableUtil;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-public class NetconfOperationServiceSnapshot implements AutoCloseable {
- private static final Logger logger = LoggerFactory.getLogger(NetconfOperationServiceSnapshot.class);
+public class NetconfOperationServiceSnapshotImpl implements NetconfOperationServiceSnapshot {
private final Set<NetconfOperationService> services;
private final String netconfSessionIdForReporting;
- public NetconfOperationServiceSnapshot(Set<NetconfOperationServiceFactory> factories, long sessionId) {
+ public NetconfOperationServiceSnapshotImpl(Set<NetconfOperationServiceFactory> factories, String sessionIdForReporting) {
Set<NetconfOperationService> services = new HashSet<>();
- netconfSessionIdForReporting = getNetconfSessionIdForReporting(sessionId);
+ netconfSessionIdForReporting = sessionIdForReporting;
for (NetconfOperationServiceFactory factory : factories) {
services.add(factory.createService(netconfSessionIdForReporting));
}
this.services = Collections.unmodifiableSet(services);
}
- private static String getNetconfSessionIdForReporting(long sessionId) {
- return "netconf session id " + sessionId;
- }
+
+ @Override
public String getNetconfSessionIdForReporting() {
return netconfSessionIdForReporting;
}
+ @Override
public Set<NetconfOperationService> getServices() {
return services;
}
@Override
- public void close() {
- RuntimeException firstException = null;
- for (NetconfOperationService service : services) {
- try {
- service.close();
- } catch (RuntimeException e) {
- logger.warn("Got exception while closing {}", service, e);
- if (firstException == null) {
- firstException = e;
- } else {
- firstException.addSuppressed(e);
- }
- }
- }
- if (firstException != null) {
- throw firstException;
- }
+ public void close() throws Exception {
+ CloseableUtil.closeAll(services);
}
@Override
public String toString() {
- return "NetconfOperationServiceSnapshot{" + netconfSessionIdForReporting + '}';
+ return "NetconfOperationServiceSnapshotImpl{" + netconfSessionIdForReporting + '}';
}
}
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.Mock;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doNothing;
-import static org.mockito.MockitoAnnotations.initMocks;
+import static org.mockito.Mockito.mock;
public class ConcurrentClientsTest {
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatch;
- @Mock
- private SessionMonitoringService monitoring;
+
HashedWheelTimer hashedWheelTimer;
+ public static SessionMonitoringService createMockedMonitoringService() {
+ SessionMonitoringService monitoring = mock(SessionMonitoringService.class);
+ doNothing().when(monitoring).onSessionUp(any(NetconfServerSession.class));
+ doNothing().when(monitoring).onSessionDown(any(NetconfServerSession.class));
+ return monitoring;
+ }
+
@Before
public void setUp() throws Exception {
- initMocks(this);
+
nettyGroup = new NioEventLoopGroup();
NetconfHelloMessageAdditionalHeader additionalHeader = new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp", "client");
netconfClientDispatcher = new NetconfClientDispatcher( nettyGroup, nettyGroup, additionalHeader, 5000);
SessionIdProvider idProvider = new SessionIdProvider();
hashedWheelTimer = new HashedWheelTimer();
NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- hashedWheelTimer, factoriesListener, idProvider, 5000);
+ hashedWheelTimer, factoriesListener, idProvider, 5000, commitNot, createMockedMonitoringService());
commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
- doNothing().when(monitoring).onSessionUp(any(NetconfServerSession.class));
- doNothing().when(monitoring).onSessionDown(any(NetconfServerSession.class));
- NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
- factoriesListener, commitNot, idProvider, monitoring);
- NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory, listenerFactory);
+
+ NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory);
dispatch = new NetconfServerDispatcher(serverChannelInitializer, nettyGroup, nettyGroup);
ChannelFuture s = dispatch.createServer(netconfAddress);
@Override
public void run() {
try {
- final NetconfClient netconfClient = new NetconfClient(clientId, netconfAddress, netconfClientDispatcher);
+ final TestingNetconfClient netconfClient = new TestingNetconfClient(clientId, netconfAddress, netconfClientDispatcher);
long sessionId = netconfClient.getSessionId();
logger.info("Client with sessionid {} hello exchanged", sessionId);
final NetconfMessage getMessage = XmlFileLoader
.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
- NetconfMessage result = netconfClient.sendMessage(getMessage);
+ NetconfMessage result = netconfClient.sendRequest(getMessage).get();
logger.info("Client with sessionid {} got result {}", sessionId, result);
netconfClient.close();
logger.info("Client with session id {} ended", sessionId);
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
import java.lang.management.ManagementFactory;
private DefaultCommitNotificationProducer commitNot;
private HashedWheelTimer hashedWheelTimer;
+
@Before
public void setUp() throws Exception {
nettyGroup = new NioEventLoopGroup();
commitNot = new DefaultCommitNotificationProducer(
ManagementFactory.getPlatformMBeanServer());
- NetconfOperationServiceFactoryListener factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+ NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
SessionIdProvider idProvider = new SessionIdProvider();
hashedWheelTimer = new HashedWheelTimer();
NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- hashedWheelTimer, factoriesListener, idProvider, 5000);
+ hashedWheelTimer, factoriesListener, idProvider, 5000, commitNot, ConcurrentClientsTest.createMockedMonitoringService());
- NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
- factoriesListener, commitNot, idProvider, null);
- NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory, listenerFactory);
+ NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(serverNegotiatorFactory);
dispatch = new NetconfServerDispatcher(
serverChannelInitializer, nettyGroup, nettyGroup);
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
+ <properties>
+ <tinybundles.version>2.0.0</tinybundles.version>
+ </properties>
<parent>
<artifactId>netconf-subsystem</artifactId>
<artifactId>netconf-client</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-client</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>config-netconf-connector</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netty-config-api</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>config-manager</artifactId>
<artifactId>netconf-impl</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-impl</artifactId>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-monitoring</artifactId>
<groupId>org.opendaylight.controller</groupId>
<artifactId>commons.logback_settings</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.tinybundles</groupId>
+ <artifactId>tinybundles</artifactId>
+ <version>${tinybundles.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
-import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
SessionIdProvider idProvider = new SessionIdProvider();
NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
- hashedWheelTimer, factoriesListener, idProvider, 5000);
-
- NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
- factoriesListener, commitNotifier, idProvider,
- sessionMonitoringService);
+ hashedWheelTimer, factoriesListener, idProvider, 5000, commitNotifier, sessionMonitoringService);
NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
- serverNegotiatorFactory, listenerFactory);
+ serverNegotiatorFactory);
return new NetconfServerDispatcher(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
}
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.jmx.CommitJMXNotification;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.controller.netconf.client.NetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(NetconfITTest.getModuleFactoriesS().toArray(
new ModuleFactory[0])));
- NetconfMonitoringServiceImpl monitoringService = new NetconfMonitoringServiceImpl(getFactoriesListener());
+ NetconfMonitoringServiceImpl monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
VerifyingNotificationListener notificationVerifier = createCommitNotificationListener();
VerifyingPersister mockedAggregator = mockAggregator();
- try (NetconfClient persisterClient = new NetconfClient("persister", tcpAddress, 4000, clientDispatcher)) {
+ try (TestingNetconfClient persisterClient = new TestingNetconfClient("persister", tcpAddress, 4000, clientDispatcher)) {
try (ConfigPersisterNotificationHandler configPersisterNotificationHandler = new ConfigPersisterNotificationHandler(
platformMBeanServer, mockedAggregator)) {
- try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
NetconfMessage response = netconfClient.sendMessage(loadGetConfigMessage());
assertResponse(response, "<modules");
assertResponse(response, "<services");
}
- public NetconfOperationServiceFactoryListener getFactoriesListener() {
- NetconfOperationServiceFactoryListener factoriesListener = mock(NetconfOperationServiceFactoryListener.class);
- NetconfOperationServiceSnapshot snap = mock(NetconfOperationServiceSnapshot.class);
+ public NetconfOperationProvider getNetconfOperationProvider() {
+ NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
+ NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
NetconfOperationService service = mock(NetconfOperationService.class);
Set<Capability> caps = Sets.newHashSet();
doReturn(caps).when(service).getCapabilities();
Set<NetconfOperationService> services = Sets.newHashSet(service);
doReturn(services).when(snap).getServices();
- doReturn(snap).when(factoriesListener).getSnapshot(anyLong());
+ doReturn(snap).when(factoriesListener).openSnapshot(anyString());
return factoriesListener;
}
import org.junit.Test;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
-import org.opendaylight.controller.netconf.client.NetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
@Test
public void testSecure() throws Exception {
NetconfClientDispatcher dispatch = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
- try (NetconfClient netconfClient = new NetconfClient("tls-client", tlsAddress, 4000, dispatch)) {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("tls-client", tlsAddress, 4000, dispatch)) {
}
}
import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
import org.opendaylight.controller.netconf.StubUserManager;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
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.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
}
static NetconfMonitoringServiceImpl getNetconfMonitoringListenerService() {
- NetconfOperationServiceFactoryListener factoriesListener = mock(NetconfOperationServiceFactoryListener.class);
- NetconfOperationServiceSnapshot snap = mock(NetconfOperationServiceSnapshot.class);
+ NetconfOperationProvider netconfOperationProvider = mock(NetconfOperationProvider.class);
+ NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
doReturn(Collections.<NetconfOperationService>emptySet()).when(snap).getServices();
- doReturn(snap).when(factoriesListener).getSnapshot(anyLong());
- return new NetconfMonitoringServiceImpl(factoriesListener);
+ doReturn(snap).when(netconfOperationProvider).openSnapshot(anyString());
+ return new NetconfMonitoringServiceImpl(netconfOperationProvider);
}
@After
@Test
public void testNetconfClientDemonstration() throws Exception {
- try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", tcpAddress, 4000, clientDispatcher)) {
Set<String> capabilitiesFromNetconfServer = netconfClient.getCapabilities();
long sessionId = netconfClient.getSessionId();
@Test
public void testTwoSessions() throws Exception {
- try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 10000, clientDispatcher)) {
- try (NetconfClient netconfClient2 = new NetconfClient("2", tcpAddress, 10000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("1", tcpAddress, 10000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("2", tcpAddress, 10000, clientDispatcher)) {
}
}
}
@Test
public void rpcReplyContainsAllAttributesTest() throws Exception {
- try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
final String rpc = "<rpc message-id=\"5\" a=\"a\" b=\"44\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+ "<get/>" + "</rpc>";
final Document doc = XmlUtil.readXmlToDocument(rpc);
@Test
public void rpcReplyErrorContainsAllAttributesTest() throws Exception {
- try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
final String rpc = "<rpc message-id=\"1\" a=\"adada\" b=\"4\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
+ "<commit/>" + "</rpc>";
final Document doc = XmlUtil.readXmlToDocument(rpc);
transaction.commit();
- try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
final String expectedNamespace = "urn:opendaylight:params:xml:ns:yang:controller:test:impl";
final String rpc = "<rpc message-id=\"5\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">"
/*
@Test
public void testStartExi() throws Exception {
- try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
Document rpcReply = netconfClient.sendMessage(this.startExi)
@Test
public void testCloseSession() throws Exception {
- try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
// edit config
Document rpcReply = netconfClient.sendMessage(this.editConfig)
@Test
public void testEditConfig() throws Exception {
- try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
// send edit_config.xml
final Document rpcReply = netconfClient.sendMessage(this.editConfig).getDocument();
assertIsOK(rpcReply);
@Test
public void testValidate() throws Exception {
- try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
// begin transaction
Document rpcReply = netconfClient.sendMessage(getConfigCandidate).getDocument();
assertEquals("data", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
}
- private Document assertGetConfigWorks(final NetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException {
+ private Document assertGetConfigWorks(final TestingNetconfClient netconfClient) throws InterruptedException, ExecutionException, TimeoutException {
return assertGetConfigWorks(netconfClient, this.getConfig);
}
- private Document assertGetConfigWorks(final NetconfClient netconfClient, final NetconfMessage getConfigMessage)
+ private Document assertGetConfigWorks(final TestingNetconfClient netconfClient, final NetconfMessage getConfigMessage)
throws InterruptedException, ExecutionException, TimeoutException {
final NetconfMessage rpcReply = netconfClient.sendMessage(getConfigMessage);
assertNotNull(rpcReply);
@Test
public void testGetConfig() throws Exception {
- try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
assertGetConfigWorks(netconfClient);
}
}
@Test
public void createYangTestBasedOnYuma() throws Exception {
- try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+ try (TestingNetconfClient netconfClient = createSession(tcpAddress, "1")) {
Document rpcReply = netconfClient.sendMessage(
XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/editConfig_merge_yang-test.xml"))
.getDocument();
}
}
- private NetconfClient createSession(final InetSocketAddress address, final String expected) throws Exception {
- final NetconfClient netconfClient = new NetconfClient("test " + address.toString(), address, 5000, clientDispatcher);
+ private TestingNetconfClient createSession(final InetSocketAddress address, final String expected) throws Exception {
+ final TestingNetconfClient netconfClient = new TestingNetconfClient("test " + address.toString(), address, 5000, clientDispatcher);
assertEquals(expected, Long.toString(netconfClient.getSessionId()));
return netconfClient;
}
*/
package org.opendaylight.controller.netconf.it;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import com.google.common.base.Charsets;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
import io.netty.channel.ChannelFuture;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
import junit.framework.Assert;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.matchers.JUnitMatchers;
import org.mockito.Mock;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.controller.netconf.client.NetconfClient;
+import org.opendaylight.controller.netconf.client.test.TestingNetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListener;
+import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
-import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
+import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator;
import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import com.google.common.base.Charsets;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
public class NetconfMonitoringITTest extends AbstractNetconfConfigTest {
super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(NetconfITTest.getModuleFactoriesS().toArray(
new ModuleFactory[0])));
- monitoringService = new NetconfMonitoringServiceImpl(getFactoriesListener());
+ monitoringService = new NetconfMonitoringServiceImpl(getNetconfOperationProvider());
NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
@Test
public void testGetResponseFromMonitoring() throws Exception {
- try (NetconfClient netconfClient = new NetconfClient("client-monitoring", tcpAddress, 4000, clientDispatcher)) {
- try (NetconfClient netconfClient2 = new NetconfClient("client-monitoring2", tcpAddress, 4000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("client-monitoring", tcpAddress, 4000, clientDispatcher)) {
+ try (TestingNetconfClient netconfClient2 = new TestingNetconfClient("client-monitoring2", tcpAddress, 4000, clientDispatcher)) {
NetconfMessage response = netconfClient.sendMessage(loadGetMessage());
assertSessionElementsInResponse(response.getDocument(), 2);
}
private void assertSessionElementsInResponse(Document document, int i) {
int elementSize = document.getElementsByTagName("session-id").getLength();
- Assert.assertEquals(i, elementSize);
+ Assert.assertEquals("Incorrect number of session-id tags in " + XmlUtil.toString(document),i, elementSize);
}
private NetconfMessage loadGetMessage() throws Exception {
return XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/get.xml");
}
- public static NetconfOperationServiceFactoryListener getFactoriesListener() {
- NetconfOperationServiceFactoryListener factoriesListener = mock(NetconfOperationServiceFactoryListener.class);
- NetconfOperationServiceSnapshot snap = mock(NetconfOperationServiceSnapshot.class);
+ public static NetconfOperationProvider getNetconfOperationProvider() throws Exception {
+ NetconfOperationProvider factoriesListener = mock(NetconfOperationProvider.class);
+ NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
+ doNothing().when(snap).close();
NetconfOperationService service = mock(NetconfOperationService.class);
Set<Capability> caps = Sets.newHashSet();
caps.add(new Capability() {
doReturn(caps).when(service).getCapabilities();
Set<NetconfOperationService> services = Sets.newHashSet(service);
doReturn(services).when(snap).getServices();
- doReturn(snap).when(factoriesListener).getSnapshot(anyLong());
+ doReturn(snap).when(factoriesListener).openSnapshot(anyString());
return factoriesListener;
}
*/
package org.opendaylight.controller.netconf.it.pax;
+import static org.junit.Assert.fail;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.configMinumumBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.flowCapableModelBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAndMockitoBundles;
+import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+import javax.inject.Inject;
+import javax.xml.parsers.ParserConfigurationException;
+
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import io.netty.channel.nio.NioEventLoopGroup;
import org.junit.matchers.JUnitMatchers;
import org.junit.runner.RunWith;
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.client.test.TestingNetconfClient;
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.options.DefaultCompositeOption;
import org.ops4j.pax.exam.util.Filter;
-import org.w3c.dom.Document;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Constants;
import org.xml.sax.SAXException;
-import javax.inject.Inject;
-import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
-import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
-import static org.junit.Assert.fail;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.baseModelBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.bindingAwareSalBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.configMinumumBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.flowCapableModelBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.junitAndMockitoBundles;
-import static org.opendaylight.controller.test.sal.binding.it.TestHelper.mdSalCoreBundles;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemPackages;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-
@Ignore
@RunWith(PaxExam.class)
public class IdentityRefNetconfTest {
loggingModules(),
mdSalCoreBundles(),
bindingAwareSalBundles(), configMinumumBundles(), baseModelBundles(), flowCapableModelBundles(),
- junitAndMockitoBundles());
+ junitAndMockitoBundles(),
+
+ // Classes from test-jars bundled for pax-exam test
+ streamBundle(TinyBundles.bundle()
+ .add(TestingNetconfClient.class)
+ .add(XmlFileLoader.class)
+
+ .add("/netconfMessages/editConfig_identities.xml",
+ XmlFileLoader.class.getResource("/netconfMessages/editConfig_identities.xml"))
+ .add("/netconfMessages/commit.xml",
+ XmlFileLoader.class.getResource("/netconfMessages/commit.xml"))
+ .add("/netconfMessages/getConfig.xml",
+ XmlFileLoader.class.getResource("/netconfMessages/getConfig.xml"))
+
+ .set(Constants.BUNDLE_SYMBOLICNAME, "TestingClient_bundle")
+ .set(Constants.EXPORT_PACKAGE, "org.opendaylight.controller.netconf.client.test, " +
+ "org.opendaylight.controller.netconf.util.test")
+ .build(TinyBundles.withBnd())));
}
private Option loggingModules() {
private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 18383);
-
@Test
public void testIdRef() throws Exception {
- try {
- Preconditions.checkNotNull(broker, "Controller not initialized");
-
- NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup();
- NetconfClientDispatcher clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup,
- CLIENT_CONNECTION_TIMEOUT_MILLIS);
-
- NetconfMessage edit = xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
- NetconfMessage commit = xmlFileToNetconfMessage("netconfMessages/commit.xml");
- NetconfMessage getConfig = xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
-
- try (NetconfClient netconfClient = new NetconfClient("client", tcpAddress, CLIENT_CONNECTION_TIMEOUT_MILLIS, clientDispatcher)) {
- sendMessage(edit, netconfClient);
- sendMessage(commit, netconfClient);
- sendMessage(getConfig, netconfClient, "id-test",
- "<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</afi>",
- "<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</afi>",
- "<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</safi>",
- "<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</safi>");
- }
+ Preconditions.checkNotNull(broker, "Controller not initialized");
+
+ NioEventLoopGroup nettyThreadgroup = new NioEventLoopGroup();
+ NetconfClientDispatcher clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup,
+ CLIENT_CONNECTION_TIMEOUT_MILLIS);
+
+ NetconfMessage edit = xmlFileToNetconfMessage("netconfMessages/editConfig_identities.xml");
+ NetconfMessage commit = xmlFileToNetconfMessage("netconfMessages/commit.xml");
+ NetconfMessage getConfig = xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
+
+ try (TestingNetconfClient netconfClient = new TestingNetconfClient("client", tcpAddress, CLIENT_CONNECTION_TIMEOUT_MILLIS, clientDispatcher)) {
+ sendMessage(edit, netconfClient);
+ sendMessage(commit, netconfClient);
+ sendMessage(getConfig, netconfClient, "id-test",
+ "<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</afi>",
+ "<afi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</afi>",
+ "<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity2</safi>",
+ "<safi xmlns:prefix=\"urn:opendaylight:params:xml:ns:yang:controller:config:test:types\">prefix:test-identity1</safi>");
clientDispatcher.close();
} catch (Exception e) {
}
}
-
- private void sendMessage(NetconfMessage edit, NetconfClient netconfClient, String... containingResponse)
+ private void sendMessage(NetconfMessage edit, TestingNetconfClient netconfClient, String... containingResponse)
throws ExecutionException, InterruptedException, TimeoutException {
NetconfMessage response = netconfClient.sendRequest(edit).get();
if (containingResponse == null) {
public static NetconfMessage xmlFileToNetconfMessage(final String fileName) throws IOException, SAXException,
ParserConfigurationException {
- return new NetconfMessage(xmlFileToDocument(fileName));
- }
-
- public static Document xmlFileToDocument(final String fileName) throws IOException, SAXException,
- ParserConfigurationException {
- // TODO xml messages from netconf-util test-jar cannot be loaded here(in OSGi), since test jar is not a bundle
- try (InputStream resourceAsStream = IdentityRefNetconfTest.class.getClassLoader().getResourceAsStream(fileName)) {
- Preconditions.checkNotNull(resourceAsStream);
- final Document doc = XmlUtil.readXmlToDocument(resourceAsStream);
- return doc;
- }
+ return XmlFileLoader.xmlFileToNetconfMessage(fileName);
}
}
--- /dev/null
+/*
+ * 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.mapping.api;
+
+public interface NetconfOperationProvider {
+
+ NetconfOperationServiceSnapshot openSnapshot(String sessionIdForReporting);
+
+ public static class NetconfOperationProviderUtil {
+
+ public static String getNetconfSessionIdForReporting(long sessionId) {
+ return "netconf session id " + sessionId;
+ }
+
+ }
+
+}
-
/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.controller.concepts.lang;
+package org.opendaylight.controller.netconf.mapping.api;
+
+import java.util.Set;
+
+public interface NetconfOperationServiceSnapshot extends AutoCloseable {
+ String getNetconfSessionIdForReporting();
-public interface Acceptor<I> {
+ Set<NetconfOperationService> getServices();
- /**
- *
- * @param input
- * @return true if input is accepted.
- */
- boolean isAcceptable(I input);
}
--- /dev/null
+/*
+ * 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;
+
+public class CloseableUtil {
+
+ public static void closeAll(Iterable<? extends AutoCloseable> autoCloseables) throws Exception {
+ Exception lastException = null;
+ for (AutoCloseable autoCloseable : autoCloseables) {
+ try {
+ autoCloseable.close();
+ } catch (Exception e) {
+ if (lastException == null) {
+ lastException = e;
+ } else {
+ lastException.addSuppressed(e);
+ }
+ }
+ }
+ if (lastException != null) {
+ throw lastException;
+ }
+
+ }
+}
<osgi.version>5.0.0</osgi.version>
<maven.bundle.version>2.4.0</maven.bundle.version>
<slf4j.version>1.7.2</slf4j.version>
- <salGeneratorPath>${project.build.directory}/generated-sources/sal</salGeneratorPath>
</properties>
<dependencies>
<artifactId>netconf-impl</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-impl</artifactId>
+ <version>${netconf.version}</version>
+ <type>test-jar</type>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-monitoring</artifactId>
</dependency>
</dependencies>
</plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <version>1.7</version>
- <executions>
- <execution>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>${salGeneratorPath}</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
</plugins>
</pluginManagement>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
- <version>1.8</version>
<executions>
<execution>
<id>attach-artifacts</id>
public List<NodeTableStatistics> readAllNodeTable(String containerName, Node node, boolean cached) {
long sid = (Long) node.getID();
List<OFStatistics> ofList = (cached == true) ?
- statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.FLOW, null);
+ statsMgr.getOFTableStatistics(sid) : statsMgr.queryStatistics(sid, OFStatisticsType.TABLE, null);
List<OFStatistics> filteredList = filterTableListPerContainer(containerName, sid, ofList);
+++ /dev/null
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
- <parent>
- <artifactId>yang-prototype</artifactId>
- <groupId>org.opendaylight.controller</groupId>
- <version>0.5-SNAPSHOT</version>
- </parent>
- <scm>
- <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
- <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
- <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
- </scm>
-
- <properties>
- <releaseplugin.version>2.3.2</releaseplugin.version>
- </properties>
-
- <modelVersion>4.0.0</modelVersion>
- <artifactId>concepts-lang</artifactId>
- <packaging>jar</packaging>
- <name>${project.artifactId}</name>
- <description>${project.artifactId}</description>
- <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-release-plugin</artifactId>
- <version>${releaseplugin.version}</version>
- </plugin>
- </plugins>
- </pluginManagement>
- </build>
-</project>
+++ /dev/null
-/*
- * 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.concepts.lang;
-import java.util.Collection;
-/**
- *
- * @author Tony Tkacik
- *
- * @param <I>
- * @param <P>
- */
-public interface AggregateTransformer<I,P> extends Transformer<I,P> {
-
- Collection<P> transformAll(Collection<? extends I> inputs);
-}
+++ /dev/null
-/*
- * 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.concepts.lang;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-
-/**
- * Transformer which aggregates multiple implementations of
- * {@link InputClassBasedTransformer}.
- *
- * The transformation process is driven by {@link Class} of input. The selection
- * of used {@link InputClassBasedTransformer} is done by using the {@link Class}
- * of input as a key to select the transformer.
- *
- * This approach provides quick resolution of transformer, but does not support
- * registering a super type of input to provide transformation support for all
- * subclasses, one must register a new instance of transformer for each valid
- * input class.
- *
- * If you need more flexible selection of transformation consider using
- * {@link CompositeConditionalTransformer} which is slower but most flexible or
- * {@link RuleBasedTransformer} which provides declarative approach for
- * transformation.
- *
- * See {@link #transform(Object)} for more information about tranformation
- * process.
- *
- * @author Tony Tkacik <ttkacik@cisco.com>
- *
- * @param <I>
- * Input super-type
- * @param <P>
- * Product
- */
-public abstract class CompositeClassBasedTransformer<I, P> implements
- InputClassBasedTransformer<I, I, P>,
- AggregateTransformer<I, P> {
-
- private Map<Class<? extends I>, InputClassBasedTransformer<I, ? extends I, P>> transformers = new ConcurrentHashMap<Class<? extends I>, InputClassBasedTransformer<I, ? extends I, P>>();
-
- /**
- * Transforms an input into instance of Product class.
- *
- * The final registered transformer is the one which match following
- * condition:
- *
- * <code>input.getClass() == transformer.getInputClass()</code>
- *
- * This means that transformers are not resolved by class hierarchy, only
- * selected based on final class of the input. If you need more flexible
- * selection of transformation consider using
- * {@link CompositeConditionalTransformer} which is slower but more
- * flexible.
- *
- */
- @Override
- public P transform(I input) {
- @SuppressWarnings("unchecked")
- InputClassBasedTransformer<I, I, P> transformer = (InputClassBasedTransformer<I, I, P>) transformers
- .get(input.getClass());
- if (transformer == null)
- throw new IllegalArgumentException("Transformation of: " + input
- + " is not supported");
- return transformer.transform(input);
- }
-
- /**
- * Registers a new transformer.
- *
- * The transformer is registered for class returned by
- * {@link InputClassBasedTransformer#getInputClass()}. Only one transformer
- * can be registered for particular input class.
- *
- */
- public void addTransformer(
- InputClassBasedTransformer<I, ? extends I, P> transformer)
- throws IllegalStateException {
- if (transformer == null)
- throw new IllegalArgumentException("Transformer should not be null");
- if (transformer.getInputClass() == null)
- throw new IllegalArgumentException(
- "Transformer should specify input class.");
- transformers.put(transformer.getInputClass(), transformer);
- }
-
- /**
- * Removes an registered transformer.
- *
- * Note: Removal is currently unsupported.
- *
- * @param transformer
- * Tranformer to be removed.
- * @throws IllegalArgumentException
- * If the provided transformer is null or is not registered.
- */
- public void removeTransformer(
- InputClassBasedTransformer<I, ? extends I, P> transformer)
- throws IllegalArgumentException {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-
- @Override
- public Collection<P> transformAll(Collection<? extends I> inputs) {
- Collection<P> ret = new ArrayList<P>();
- for (I i : inputs) {
- ret.add(transform(i));
- }
- return ret;
- }
-
-}
+++ /dev/null
-/*
- * 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.concepts.lang;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Set;
-import java.util.TreeSet;
-
-/**
- * Composite transformer which aggregates multiple implementation and selects
- * the one which accepts the input.
- *
- *
- * @author Tony Tkacik
- *
- * @param <I>
- * Input class for transformation
- * @param <P>
- * Product of transformation
- */
-public class CompositeConditionalTransformer<I, P> implements
- SimpleConditionalTransformer<I, P>,
- AggregateTransformer<I,P> {
-
- private final Comparator<TransformerWithPriority<I, P>> comparator = new Comparator<TransformerWithPriority<I, P>>() {
-
- @Override
- public int compare(TransformerWithPriority<I, P> o1,
- TransformerWithPriority<I, P> o2) {
- return Integer.valueOf(o1.priority).compareTo(Integer.valueOf(o2.priority));
- }
-
- };
- private final Set<TransformerWithPriority<I, P>> transformers;
-
- public CompositeConditionalTransformer() {
- // FIXME: Add Ordering
- transformers = new TreeSet<TransformerWithPriority<I, P>>(comparator);
- }
-
- @Override
- public boolean isAcceptable(I input) {
- for (SimpleConditionalTransformer<I, P> trans : transformers) {
- if (trans.isAcceptable(input)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public P transform(I input) {
- for (SimpleConditionalTransformer<I, P> trans : transformers) {
- if (trans.isAcceptable(input)) {
- return trans.transform(input);
- }
- }
- throw new IllegalStateException(
- "Transformer for provided input is not available.");
- }
-
- public void addTransformer(SimpleConditionalTransformer<I, P> transformer,
- int priority) throws IllegalStateException {
- if (transformer == null) {
- throw new IllegalArgumentException(
- "transformer should not be null.");
- }
- TransformerWithPriority<I, P> withPriority = new TransformerWithPriority<I, P>(
- transformer, priority);
- if (false == transformers.add(withPriority)) {
- throw new IllegalStateException("transformer " + transformer
- + "already registered");
- }
- }
-
- public void removeTransformer(SimpleConditionalTransformer<I, P> transformer)
- throws IllegalArgumentException {
- if (transformer == null) {
- throw new IllegalArgumentException(
- "transformer should not be null.");
- }
- if (false == transformers.remove(transformer)) {
- throw new IllegalStateException("transformer " + transformer
- + "already registered");
- }
- }
-
- @Override
- public Collection<P> transformAll(Collection<? extends I> inputs) {
- Collection<P> ret = new ArrayList<P>();
- for (I i : inputs) {
- ret.add(transform(i));
- }
- return ret;
- }
-
- private static class TransformerWithPriority<I, P> implements
- SimpleConditionalTransformer<I, P> {
- final int priority;
- final SimpleConditionalTransformer<I, P> transformer;
-
- public TransformerWithPriority(
- SimpleConditionalTransformer<I, P> transformer, int priority) {
- this.priority = priority;
- this.transformer = transformer;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((transformer == null) ? 0 : transformer.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;
- TransformerWithPriority<?,?> other = (TransformerWithPriority<?,?>) obj;
- if (transformer == null) {
- if (other.transformer != null)
- return false;
- } else if (!transformer.equals(other.transformer))
- return false;
- return true;
- }
-
- @Override
- public boolean isAcceptable(I input) {
- return transformer.isAcceptable(input);
- }
-
- @Override
- public P transform(I input) {
- return transformer.transform(input);
- }
-
-
-
-
-
- }
-}
+++ /dev/null
-/*
- * 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.concepts.lang;
-/**
- * Input class based transformer
- *
- * {@link Transformer} which accepts / transforms only specific classes of
- * input, and is useful if the selection of transformer should be based on the
- * class of the input and there is one-to-one mapping between input class and
- * transformer.
- *
- *
- * @author Tony Tkacik
- *
- * @param <S>
- * Common supertype of input
- * @param <I>
- * Concrete type of input
- * @param <P>
- * Product
- */
-public interface InputClassBasedTransformer<S, I extends S, P> extends
- Transformer<I, P> {
-
- /**
- * Returns an {@link Class} of input which is acceptable for transformation.
- *
- * @return {@link Class} of input which is acceptable for transformation.
- */
- Class<? extends S> getInputClass();
-}
+++ /dev/null
-/*
- * 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.concepts.lang;
-import java.util.Set;
-
-/**
- * Transformer with set of acceptance rules
- *
- * The transformer provides a set of {@link Acceptor}s, which could be used to
- * verify if the input will produce result using the transformer.
- *
- * The transormer is able to produce result if ANY of associated
- * {@link Acceptor}s accepted result.
- *
- * @author Tony Tkacik
- *
- * @param <I>
- * Input class for transformation
- * @param <P>
- * Product of transformation
- */
-public interface RuleBasedTransformer<I, P> extends Transformer<I, P> {
-
- /**
- * Set of {@link Acceptor}, which could be used to verify if the input is
- * usable by transformer.
- *
- * The transformer is able to produce result if ANY of associated
- * {@link Acceptor}s accepted result.
- *
- * @return Set of input acceptance rules associated to this transformer.
- */
- Set<Acceptor<I>> getRules();
-
-}
+++ /dev/null
-/*
- * 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.concepts.lang;
-/**
- * Simple condition-based transformer
- *
- * The transformer provides {@link #isAcceptable(Object)} method,
- * which could be used to query transformer if the input will produce
- * result.
- *
- * This interface is simplified version of {@link RuleBasedTransformer} - does not
- * provide decoupling of Acceptance rule from transformer, and should be used only
- * for simple use-cases.
- *
- * @author Tony Tkacik
- *
- * @param <I> Input class for transformation
- * @param <P> Product of transformation
- */
-public interface SimpleConditionalTransformer<I,P> extends Transformer<I, P>, Acceptor<I> {
-
-
- /**
- * Checks if the input is acceptable
- * for processing by the transformer.
- *
- * @return true it the input is acceptable for processing by transformer.
- */
- @Override
- public boolean isAcceptable(I input);
-}
+++ /dev/null
-/*
- * 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.concepts.lang;
-/**
- * Factory which produces product based on input object
- *
- * @author Tony Tkacik
- *
- * @param <I> Input
- * @param <P> Product
- */
-public interface Transformer<I,P> {
- /**
- * Transforms input into instance of product.
- *
- * @param input Input which drives transformation
- * @return Instance of product which was created from supplied input.
- */
- P transform(I input);
-}
+++ /dev/null
-<project name="${project.name}">
-
- <skin>
- <groupId>org.apache.maven.skins</groupId>
- <artifactId>maven-fluido-skin</artifactId>
- <version>1.3.0</version>
- </skin>
-
- <body>
- <menu ref="parent"/>
- <menu ref="modules"/>
- <menu ref="reports"/>
- </body>
-
-</project>
-
+++ /dev/null
-SAL
-====================
-
-Project documentation
----------------------
-
-### Description
-
-
-
-### Scope
-
-
-
+++ /dev/null
-/* Javadoc style sheet */
-/*
-Overall document style
-*/
-body {
- background-color:#ffffff;
- color:#353833;
- font-family:Arial, Helvetica, sans-serif;
- font-size:76%;
- margin:0;
-}
-a:link, a:visited {
- text-decoration:none;
- color:#4c6b87;
-}
-a:hover, a:focus {
- text-decoration:none;
- color:#bb7a2a;
-}
-a:active {
- text-decoration:none;
- color:#4c6b87;
-}
-a[name] {
- color:#353833;
-}
-a[name]:hover {
- text-decoration:none;
- color:#353833;
-}
-pre {
- font-size:1.3em;
-}
-h1 {
- font-size:1.8em;
-}
-h2 {
- font-size:1.5em;
-}
-h3 {
- font-size:1.4em;
-}
-h4 {
- font-size:1.3em;
-}
-h5 {
- font-size:1.2em;
-}
-h6 {
- font-size:1.1em;
-}
-ul {
- list-style-type:disc;
-}
-code, tt {
- font-size:1.2em;
-}
-dt code {
- font-size:1.2em;
-}
-table tr td dt code {
- font-size:1.2em;
- vertical-align:top;
-}
-sup {
- font-size:.6em;
-}
-/*
-Document title and Copyright styles
-*/
-.clear {
- clear:both;
- height:0px;
- overflow:hidden;
-}
-.aboutLanguage {
- float:right;
- padding:0px 21px;
- font-size:.8em;
- z-index:200;
- margin-top:-7px;
-}
-.legalCopy {
- margin-left:.5em;
-}
-.bar a, .bar a:link, .bar a:visited, .bar a:active {
- color:#FFFFFF;
- text-decoration:none;
-}
-.bar a:hover, .bar a:focus {
- color:#bb7a2a;
-}
-.tab {
- background-color:#0066FF;
- background-image:url(resources/titlebar.gif);
- background-position:left top;
- background-repeat:no-repeat;
- color:#ffffff;
- padding:8px;
- width:5em;
- font-weight:bold;
-}
-/*
-Navigation bar styles
-*/
-.bar {
- background-image:url(resources/background.gif);
- background-repeat:repeat-x;
- color:#FFFFFF;
- padding:.8em .5em .4em .8em;
- height:auto;/*height:1.8em;*/
- font-size:1em;
- margin:0;
-}
-.topNav {
- background-image:url(resources/background.gif);
- background-repeat:repeat-x;
- color:#FFFFFF;
- float:left;
- padding:0;
- width:100%;
- clear:right;
- height:2.8em;
- padding-top:10px;
- overflow:hidden;
-}
-.bottomNav {
- margin-top:10px;
- background-image:url(resources/background.gif);
- background-repeat:repeat-x;
- color:#FFFFFF;
- float:left;
- padding:0;
- width:100%;
- clear:right;
- height:2.8em;
- padding-top:10px;
- overflow:hidden;
-}
-.subNav {
- background-color:#dee3e9;
- border-bottom:1px solid #9eadc0;
- float:left;
- width:100%;
- overflow:hidden;
-}
-.subNav div {
- clear:left;
- float:left;
- padding:0 0 5px 6px;
-}
-ul.navList, ul.subNavList {
- float:left;
- margin:0 25px 0 0;
- padding:0;
-}
-ul.navList li{
- list-style:none;
- float:left;
- padding:3px 6px;
-}
-ul.subNavList li{
- list-style:none;
- float:left;
- font-size:90%;
-}
-.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited {
- color:#FFFFFF;
- text-decoration:none;
-}
-.topNav a:hover, .bottomNav a:hover {
- text-decoration:none;
- color:#bb7a2a;
-}
-.navBarCell1Rev {
- background-image:url(resources/tab.gif);
- background-color:#a88834;
- color:#FFFFFF;
- margin: auto 5px;
- border:1px solid #c9aa44;
-}
-/*
-Page header and footer styles
-*/
-.header, .footer {
- clear:both;
- margin:0 20px;
- padding:5px 0 0 0;
-}
-.indexHeader {
- margin:10px;
- position:relative;
-}
-.indexHeader span{
- margin-right:15px;
-}
-.indexHeader h1 {
- font-size:1.3em;
-}
-.title {
- color:#2c4557;
- margin:10px 0;
-}
-.subTitle {
- margin:5px 0 0 0;
-}
-.header ul {
- margin:0 0 25px 0;
- padding:0;
-}
-.footer ul {
- margin:20px 0 5px 0;
-}
-.header ul li, .footer ul li {
- list-style:none;
- font-size:1.2em;
-}
-/*
-Heading styles
-*/
-div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 {
- background-color:#dee3e9;
- border-top:1px solid #9eadc0;
- border-bottom:1px solid #9eadc0;
- margin:0 0 6px -8px;
- padding:2px 5px;
-}
-ul.blockList ul.blockList ul.blockList li.blockList h3 {
- background-color:#dee3e9;
- border-top:1px solid #9eadc0;
- border-bottom:1px solid #9eadc0;
- margin:0 0 6px -8px;
- padding:2px 5px;
-}
-ul.blockList ul.blockList li.blockList h3 {
- padding:0;
- margin:15px 0;
-}
-ul.blockList li.blockList h2 {
- padding:0px 0 20px 0;
-}
-/*
-Page layout container styles
-*/
-.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer {
- clear:both;
- padding:10px 20px;
- position:relative;
-}
-.indexContainer {
- margin:10px;
- position:relative;
- font-size:1.0em;
-}
-.indexContainer h2 {
- font-size:1.1em;
- padding:0 0 3px 0;
-}
-.indexContainer ul {
- margin:0;
- padding:0;
-}
-.indexContainer ul li {
- list-style:none;
-}
-.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt {
- font-size:1.1em;
- font-weight:bold;
- margin:10px 0 0 0;
- color:#4E4E4E;
-}
-.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd {
- margin:10px 0 10px 20px;
-}
-.serializedFormContainer dl.nameValue dt {
- margin-left:1px;
- font-size:1.1em;
- display:inline;
- font-weight:bold;
-}
-.serializedFormContainer dl.nameValue dd {
- margin:0 0 0 1px;
- font-size:1.1em;
- display:inline;
-}
-/*
-List styles
-*/
-ul.horizontal li {
- display:inline;
- font-size:0.9em;
-}
-ul.inheritance {
- margin:0;
- padding:0;
-}
-ul.inheritance li {
- display:inline;
- list-style:none;
-}
-ul.inheritance li ul.inheritance {
- margin-left:15px;
- padding-left:15px;
- padding-top:1px;
-}
-ul.blockList, ul.blockListLast {
- margin:10px 0 10px 0;
- padding:0;
-}
-ul.blockList li.blockList, ul.blockListLast li.blockList {
- list-style:none;
- margin-bottom:25px;
-}
-ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList {
- padding:0px 20px 5px 10px;
- border:1px solid #9eadc0;
- background-color:#f9f9f9;
-}
-ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList {
- padding:0 0 5px 8px;
- background-color:#ffffff;
- border:1px solid #9eadc0;
- border-top:none;
-}
-ul.blockList ul.blockList ul.blockList ul.blockList li.blockList {
- margin-left:0;
- padding-left:0;
- padding-bottom:15px;
- border:none;
- border-bottom:1px solid #9eadc0;
-}
-ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast {
- list-style:none;
- border-bottom:none;
- padding-bottom:0;
-}
-table tr td dl, table tr td dl dt, table tr td dl dd {
- margin-top:0;
- margin-bottom:1px;
-}
-/*
-Table styles
-*/
-.contentContainer table, .classUseContainer table, .constantValuesContainer table {
- border-bottom:1px solid #9eadc0;
- width:100%;
-}
-.contentContainer ul li table, .classUseContainer ul li table, .constantValuesContainer ul li table {
- width:100%;
-}
-.contentContainer .description table, .contentContainer .details table {
- border-bottom:none;
-}
-.contentContainer ul li table th.colOne, .contentContainer ul li table th.colFirst, .contentContainer ul li table th.colLast, .classUseContainer ul li table th, .constantValuesContainer ul li table th, .contentContainer ul li table td.colOne, .contentContainer ul li table td.colFirst, .contentContainer ul li table td.colLast, .classUseContainer ul li table td, .constantValuesContainer ul li table td{
- vertical-align:top;
- padding-right:20px;
-}
-.contentContainer ul li table th.colLast, .classUseContainer ul li table th.colLast,.constantValuesContainer ul li table th.colLast,
-.contentContainer ul li table td.colLast, .classUseContainer ul li table td.colLast,.constantValuesContainer ul li table td.colLast,
-.contentContainer ul li table th.colOne, .classUseContainer ul li table th.colOne,
-.contentContainer ul li table td.colOne, .classUseContainer ul li table td.colOne {
- padding-right:3px;
-}
-.overviewSummary caption, .packageSummary caption, .contentContainer ul.blockList li.blockList caption, .summary caption, .classUseContainer caption, .constantValuesContainer caption {
- position:relative;
- text-align:left;
- background-repeat:no-repeat;
- color:#FFFFFF;
- font-weight:bold;
- clear:none;
- overflow:hidden;
- padding:0px;
- margin:0px;
- white-space:pre;
-}
-caption a:link, caption a:hover, caption a:active, caption a:visited {
- color:#FFFFFF;
-}
-.overviewSummary caption span, .packageSummary caption span, .contentContainer ul.blockList li.blockList caption span, .summary caption span, .classUseContainer caption span, .constantValuesContainer caption span {
- white-space:nowrap;
- padding-top:8px;
- padding-left:8px;
- display:block;
- float:left;
- background-image:url(resources/titlebar.gif);
- height:18px;
-}
-.contentContainer ul.blockList li.blockList caption span.activeTableTab span {
- white-space:nowrap;
- padding-top:8px;
- padding-left:8px;
- display:block;
- float:left;
- background-image:url(resources/activetitlebar.gif);
- height:18px;
-}
-.contentContainer ul.blockList li.blockList caption span.tableTab span {
- white-space:nowrap;
- padding-top:8px;
- padding-left:8px;
- display:block;
- float:left;
- background-image:url(resources/titlebar.gif);
- height:18px;
-}
-.contentContainer ul.blockList li.blockList caption span.tableTab, .contentContainer ul.blockList li.blockList caption span.activeTableTab {
- padding-top:0px;
- padding-left:0px;
- background-image:none;
- float:none;
- display:inline;
-}
-.overviewSummary .tabEnd, .packageSummary .tabEnd, .contentContainer ul.blockList li.blockList .tabEnd, .summary .tabEnd, .classUseContainer .tabEnd, .constantValuesContainer .tabEnd {
- width:10px;
- background-image:url(resources/titlebar_end.gif);
- background-repeat:no-repeat;
- background-position:top right;
- position:relative;
- float:left;
-}
-.contentContainer ul.blockList li.blockList .activeTableTab .tabEnd {
- width:10px;
- margin-right:5px;
- background-image:url(resources/activetitlebar_end.gif);
- background-repeat:no-repeat;
- background-position:top right;
- position:relative;
- float:left;
-}
-.contentContainer ul.blockList li.blockList .tableTab .tabEnd {
- width:10px;
- margin-right:5px;
- background-image:url(resources/titlebar_end.gif);
- background-repeat:no-repeat;
- background-position:top right;
- position:relative;
- float:left;
-}
-ul.blockList ul.blockList li.blockList table {
- margin:0 0 12px 0px;
- width:100%;
-}
-.tableSubHeadingColor {
- background-color: #EEEEFF;
-}
-.altColor {
- background-color:#eeeeef;
-}
-.rowColor {
- background-color:#ffffff;
-}
-.overviewSummary td, .packageSummary td, .contentContainer ul.blockList li.blockList td, .summary td, .classUseContainer td, .constantValuesContainer td {
- text-align:left;
- padding:3px 3px 3px 7px;
-}
-th.colFirst, th.colLast, th.colOne, .constantValuesContainer th {
- background:#dee3e9;
- border-top:1px solid #9eadc0;
- border-bottom:1px solid #9eadc0;
- text-align:left;
- padding:3px 3px 3px 7px;
-}
-td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover {
- font-weight:bold;
-}
-td.colFirst, th.colFirst {
- border-left:1px solid #9eadc0;
- white-space:nowrap;
-}
-td.colLast, th.colLast {
- border-right:1px solid #9eadc0;
-}
-td.colOne, th.colOne {
- border-right:1px solid #9eadc0;
- border-left:1px solid #9eadc0;
-}
-table.overviewSummary {
- padding:0px;
- margin-left:0px;
-}
-table.overviewSummary td.colFirst, table.overviewSummary th.colFirst,
-table.overviewSummary td.colOne, table.overviewSummary th.colOne {
- width:25%;
- vertical-align:middle;
-}
-table.packageSummary td.colFirst, table.overviewSummary th.colFirst {
- width:25%;
- vertical-align:middle;
-}
-/*
-Content styles
-*/
-.description pre {
- margin-top:0;
-}
-.deprecatedContent {
- margin:0;
- padding:10px 0;
-}
-.docSummary {
- padding:0;
-}
-/*
-Formatting effect styles
-*/
-.sourceLineNo {
- color:green;
- padding:0 30px 0 0;
-}
-h1.hidden {
- visibility:hidden;
- overflow:hidden;
- font-size:.9em;
-}
-.block {
- display:block;
- margin:3px 0 0 0;
-}
-.strong {
- font-weight:bold;
-}
-
+++ /dev/null
-<project name="${project.name}">
-
- <skin>
- <groupId>org.apache.maven.skins</groupId>
- <artifactId>maven-fluido-skin</artifactId>
- <version>1.3.0</version>
- </skin>
-
- <body>
- <menu ref="parent"/>
- <menu ref="modules"/>
- <menu ref="reports"/>
- <menu name="Overview">
- <item name="Readme" href="readme.html" />
- </menu>
- </body>
-
-</project>
<http pattern="/css/**" security="none" />
<http pattern="/js/**" security="none" />
- <http pattern="/images/**" security="none" />
+ <http pattern="/img/**" security="none" />
<http pattern="/favicon.ico" security="none" />
<http pattern="/controller/web/css/**" security="none" />
<http pattern="/controller/web/js/**" security="none" />
- <http pattern="/controller/web/images/**" security="none" />
+ <http pattern="/controller/web/img/**" security="none" />
<http auto-config="false" authentication-manager-ref="authenticationManager"
<web-resource-collection>
<web-resource-name>free access</web-resource-name>
<url-pattern>/js/*</url-pattern>
- <url-pattern>/images/*</url-pattern>
+ <url-pattern>/img/*</url-pattern>
<url-pattern>/css/*</url-pattern>
<url-pattern>/favicon.ico</url-pattern>
<url-pattern>/versionProperty/*</url-pattern>