<artifactId>akka-remote_${scala.version}</artifactId>
<version>${akka.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.typesafe.akka</groupId>
+ <artifactId>akka-testkit_${scala.version}</artifactId>
+ <version>${akka.version}</version>
+ </dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</plugins>
</build>
</profile>
+ <profile>
+ <id>docs</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>swagger-ui</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ </profile>
</profiles>
</project>
@Override
public void onFlowRemoved(final FlowRemoved notification) {
+ // notified upon remove flow rpc successfully invoked
if (notification == null) {
return;
}
@Override
public void onSwitchFlowRemoved(final SwitchFlowRemoved notification) {
- // FIXME: unfinished?
+ // notified upon remove flow message from device arrives
+ if (notification == null) {
+ return;
+ }
+
+ final NodeRef node = notification.getNode();
+ if (node == null) {
+ LOG.debug("Notification {} has not node, ignoring it", notification);
+ return;
+ }
+
+ Node adNode;
+ try {
+ adNode = NodeMapping.toADNode(notification.getNode());
+ } catch (ConstructionException e) {
+ LOG.warn("Failed to construct AD node for {}, ignoring notification", node, e);
+ return;
+ }
+ flowProgrammerPublisher.flowRemoved(adNode, ToSalConversionsUtils.toFlow(notification, adNode));
}
@Override
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SwitchFlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.GenericFlowAttributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
public static Flow toFlow(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow source, Node node) {
final Flow target = new Flow();
+ genericFlowToAdFlow(source, target);
+
+ target.setMatch(toMatch(source.getMatch()));
+
+ List<Action> actions = getAction(source);
+ if (actions != null) {
+ target.setActions(actionFrom(actions, node));
+ }
+
+ return target;
+ }
+
+ /**
+ * @param source notification, missing instructions
+ * @param node corresponding node where the flow change occured
+ * @return ad-sal node, build from given data
+ */
+ public static Flow toFlow(SwitchFlowRemoved source, Node node) {
+ final Flow target = new Flow();
+ genericFlowToAdFlow(source, target);
+
+ target.setMatch(toMatch(source.getMatch()));
+
+ return target;
+ }
+ /**
+ * @param source
+ * @param target
+ */
+ private static void genericFlowToAdFlow(GenericFlowAttributes source,
+ final Flow target) {
Integer hardTimeout = source.getHardTimeout();
if (hardTimeout != null) {
target.setHardTimeout(hardTimeout.shortValue());
if (priority != null) {
target.setPriority(priority.shortValue());
}
-
- target.setMatch(toMatch(source.getMatch()));
-
- List<Action> actions = getAction(source);
- if (actions != null) {
- target.setActions(actionFrom(actions, node));
- }
-
target.setId(source.getCookie().getValue().longValue());
- return target;
}
-
+
public static List<Action> getAction(
org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow source) {
if (source.getInstructions() != null) {
return nodeConnector;
}
- public static Match toMatch(org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match source) {
+ public static Match toMatch(org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match source) {
Match target = new Match();
if (source != null) {
fillFrom(target, source.getVlanMatch());
<artifactId>akka-remote_${scala.version}</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.typesafe.akka</groupId>
+ <artifactId>akka-testkit_${scala.version}</artifactId>
+ </dependency>
+
<!-- SAL Dependencies -->
<dependency>
<artifactId>org.osgi.core</artifactId>
</dependency>
- <!-- AKKA Dependencies -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</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.cluster.datastore;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+/*
+ * 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.cluster.datastore;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
--- /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.cluster.datastore;
+
+import akka.actor.Address;
+import akka.actor.UntypedActor;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+import org.opendaylight.controller.cluster.datastore.messages.FindPrimary;
+import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The ShardManager has the following jobs,
+ *
+ * - Create all the local shard replicas that belong on this cluster member
+ * - Find the primary replica for any given shard
+ * - Engage in shard replica elections which decide which replica should be the primary
+ *
+ * Creation of Shard replicas
+ * ==========================
+ * When the ShardManager is constructed it reads the cluster configuration to find out which shard replicas
+ * belong on this member. It finds out the name of the current cluster member from the Akka Clustering Service.
+ *
+ * Replica Elections
+ * =================
+ * The Shard Manager uses multiple cues to initiate election.
+ * - When a member of the cluster dies
+ * - When a local shard replica dies
+ * - When a local shard replica comes alive
+ */
+public class ShardManager extends UntypedActor {
+
+ // Stores a mapping between a shard name and the address of the current primary
+ private final Map<String, Address> shardNameToPrimaryAddress = new HashMap<>();
+
+ // Stores a mapping between a member name and the address of the member
+ private final Map<String, Address> memberNameToAddress = new HashMap<>();
+
+ // Stores a mapping between the shard name and all the members on which a replica of that shard are available
+ private final Map<String, List<String>> shardNameToMembers = new HashMap<>();
+
+ LoggingAdapter log = Logging.getLogger(getContext().system(), this);
+
+ @Override
+ public void onReceive(Object message) throws Exception {
+ if(message instanceof FindPrimary ){
+ FindPrimary msg = ((FindPrimary) message);
+ getSender().tell(new PrimaryNotFound(msg.getShardName()), getSelf());
+ }
+ }
+}
+/*
+ * 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.cluster.datastore;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
+/*
+ * 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.cluster.datastore;
import com.google.common.base.Optional;
--- /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.cluster.datastore.messages;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The FindPrimary message is used to locate the primary of any given shard
+ *
+ * TODO : Make this serializable
+ */
+public class FindPrimary{
+ private final String shardName;
+
+ public FindPrimary(String shardName){
+
+ Preconditions.checkNotNull(shardName, "shardName should not be null");
+
+ this.shardName = shardName;
+ }
+
+ public String getShardName() {
+ return shardName;
+ }
+}
--- /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.cluster.datastore.messages;
+
+public class PrimaryFound {
+}
--- /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.cluster.datastore.messages;
+
+import com.google.common.base.Preconditions;
+
+public class PrimaryNotFound {
+
+ private final String shardName;
+
+ public PrimaryNotFound(String shardName){
+
+ Preconditions.checkNotNull(shardName, "shardName should not be null");
+
+ this.shardName = shardName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PrimaryNotFound that = (PrimaryNotFound) o;
+
+ if (shardName != null ? !shardName.equals(that.shardName) : that.shardName != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return shardName != null ? shardName.hashCode() : 0;
+ }
+}
--- /dev/null
+package org.opendaylight.controller.cluster.datastore;
+
+import akka.actor.ActorSystem;
+import akka.actor.Props;
+import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.messages.FindPrimary;
+import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound;
+import scala.concurrent.duration.Duration;
+
+public class ShardManagerTest {
+ private static ActorSystem system;
+
+ @BeforeClass
+ public static void setUp(){
+ system = ActorSystem.create("test");
+ }
+
+ @AfterClass
+ public static void tearDown(){
+ JavaTestKit.shutdownActorSystem(system);
+ system = null;
+ }
+
+ @Test
+ public void testOnReceiveFindPrimary() throws Exception {
+
+ new JavaTestKit(system) {{
+ final Props props = Props.create(ShardManager.class);
+ final TestActorRef<ShardManager> subject = TestActorRef.create(system, props, "test");
+
+ // can also use JavaTestKit “from the outside”
+ final JavaTestKit probe = new JavaTestKit(system);
+
+ // the run() method needs to finish within 3 seconds
+ new Within(duration("3 seconds")) {
+ protected void run() {
+
+ subject.tell(new FindPrimary("inventory"), getRef());
+
+ expectMsgEquals(Duration.Zero(), new PrimaryNotFound("inventory"));
+
+ // Will wait for the rest of the 3 seconds
+ expectNoMsg();
+ }
+ };
+ }};
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.cluster.datastore.messages;
+
+import org.junit.Test;
+
+public class FindPrimaryTest {
+
+ @Test
+ public void testNewBuilderForType() throws Exception {
+
+ }
+
+ @Test
+ public void testToBuilder() throws Exception {
+
+ }
+
+ @Test
+ public void testGetDefaultInstanceForType() throws Exception {
+
+ }
+}
\ No newline at end of file
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Queue;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.client.NetconfClientSession;
import org.opendaylight.controller.netconf.client.NetconfClientSessionListener;
import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.controller.sal.common.util.RpcErrors;
import org.opendaylight.controller.sal.common.util.Rpcs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
private static final Logger logger = LoggerFactory.getLogger(NetconfDeviceCommunicator.class);
- private static final RpcResult<NetconfMessage> FAILED_RPC_RESULT = new FailedRpcResult<>(RpcErrors.getRpcError(
- null, null, null, RpcError.ErrorSeverity.ERROR, "Netconf session disconnected",
- RpcError.ErrorType.PROTOCOL, null));
-
private final RemoteDevice<NetconfSessionCapabilities, NetconfMessage> remoteDevice;
private final RemoteDeviceId id;
+ private final Lock sessionLock = new ReentrantLock();
public NetconfDeviceCommunicator(final RemoteDeviceId id,
final RemoteDevice<NetconfSessionCapabilities, NetconfMessage> remoteDevice) {
private NetconfClientSession session;
@Override
- public synchronized void onSessionUp(final NetconfClientSession session) {
- logger.debug("{}: Session established", id);
- this.session = session;
+ public void onSessionUp(final NetconfClientSession session) {
+ sessionLock.lock();
+ try {
+ logger.debug("{}: Session established", id);
+ this.session = session;
- final NetconfSessionCapabilities netconfSessionCapabilities = NetconfSessionCapabilities.fromNetconfSession(session);
- logger.trace("{}: Session advertised capabilities: {}", id, netconfSessionCapabilities);
+ final NetconfSessionCapabilities netconfSessionCapabilities =
+ NetconfSessionCapabilities.fromNetconfSession(session);
+ logger.trace("{}: Session advertised capabilities: {}", id, netconfSessionCapabilities);
- remoteDevice.onRemoteSessionUp(netconfSessionCapabilities, this);
+ remoteDevice.onRemoteSessionUp(netconfSessionCapabilities, this);
+ }
+ finally {
+ sessionLock.unlock();
+ }
}
public void initializeRemoteConnection(final NetconfClientDispatcher dispatch,
dispatch.createReconnectingClient(config);
}
- private synchronized void tearDown(final Exception e) {
- remoteDevice.onRemoteSessionDown();
- session = null;
+ private void tearDown( String reason ) {
+ List<UncancellableFuture<RpcResult<NetconfMessage>>> futuresToCancel = Lists.newArrayList();
+ sessionLock.lock();
+ try {
+ if( session != null ) {
+ 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()) {
+ futuresToCancel.add( r.future );
+ it.remove();
+ } else if (r.future.isCancelled()) {
+ // This just does some house-cleaning
+ it.remove();
+ }
+ }
- /*
- * 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()) {
- r.future.setException(e);
- it.remove();
- } else if (r.future.isCancelled()) {
- // This just does some house-cleaning
- it.remove();
+ remoteDevice.onRemoteSessionDown();
+ }
+ }
+ finally {
+ sessionLock.unlock();
+ }
+
+ // Notify pending request futures outside of the sessionLock to avoid unnecessarily
+ // blocking the caller.
+ for( UncancellableFuture<RpcResult<NetconfMessage>> future: futuresToCancel ) {
+ if( Strings.isNullOrEmpty( reason ) ) {
+ future.set( createSessionDownRpcResult() );
+ } else {
+ future.set( createErrorRpcResult( RpcError.ErrorType.TRANSPORT, reason ) );
}
}
}
+ private RpcResult<NetconfMessage> createSessionDownRpcResult()
+ {
+ return createErrorRpcResult( RpcError.ErrorType.TRANSPORT,
+ String.format( "The netconf session to %1$s is disconnected", id.getName() ) );
+ }
+
+ private RpcResult<NetconfMessage> createErrorRpcResult( RpcError.ErrorType errorType, String message )
+ {
+ return new FailedRpcResult<NetconfMessage>( RpcErrors.getRpcError( null,
+ NetconfDocumentedException.ErrorTag.operation_failed.getTagValue(),
+ null, RpcError.ErrorSeverity.ERROR, message, errorType, null ) );
+ }
+
@Override
public void onSessionDown(final NetconfClientSession session, final Exception e) {
logger.warn("{}: Session went down", id, e);
- tearDown(e);
+ tearDown( null );
}
@Override
public void onSessionTerminated(final NetconfClientSession session, final NetconfTerminationReason reason) {
logger.warn("{}: Session terminated {}", id, reason);
- tearDown(new RuntimeException(reason.getErrorMessage()));
+ tearDown( reason.getErrorMessage() );
+ }
+
+ @Override
+ public void close() {
+ tearDown( String.format( "The netconf session to %1$s has been closed", id.getName() ) );
}
@Override
}
}
- private synchronized void processMessage(final NetconfMessage message) {
- final Request r = requests.peek();
- if (r.future.isUncancellable()) {
- requests.poll();
+ private void processMessage(final NetconfMessage message) {
+ Request request = null;
+ sessionLock.lock();
+ try {
+ request = requests.peek();
+ if (request.future.isUncancellable()) {
+ requests.poll();
+ }
+ else {
+ request = null;
+ logger.warn("{}: Ignoring unsolicited message {}", id, msgToS(message));
+ }
+ }
+ finally {
+ sessionLock.unlock();
+ }
+
+ if( request != null ) {
logger.debug("{}: Message received {}", id, message);
if(logger.isTraceEnabled()) {
- logger.trace("{}: Matched request: {} to response: {}", id, msgToS(r.request), msgToS(message));
+ logger.trace( "{}: Matched request: {} to response: {}", id,
+ msgToS( request.request ), msgToS( message ) );
}
try {
- NetconfMessageTransformUtil.checkValidReply(r.request, message);
- } catch (final IllegalStateException e) {
- logger.warn("{}: Invalid request-reply match, reply message contains different message-id, request: {}, response: {}", id,
- msgToS(r.request), msgToS(message), e);
- r.future.setException(e);
+ NetconfMessageTransformUtil.checkValidReply( request.request, message );
+ }
+ catch (final NetconfDocumentedException e) {
+ logger.warn( "{}: Invalid request-reply match, reply message contains different message-id, request: {}, response: {}",
+ id, msgToS( request.request ), msgToS( message ), e );
+
+ request.future.set( new FailedRpcResult<NetconfMessage>(
+ NetconfMessageTransformUtil.toRpcError( e ) ) );
return;
}
try {
NetconfMessageTransformUtil.checkSuccessReply(message);
- } catch (NetconfDocumentedException | IllegalStateException e) {
- logger.warn("{}: Error reply from remote device, request: {}, response: {}", id,
- msgToS(r.request), msgToS(message), e);
- r.future.setException(e);
+ }
+ catch( NetconfDocumentedException e ) {
+ logger.warn( "{}: Error reply from remote device, request: {}, response: {}", id,
+ msgToS( request.request ), msgToS( message ), e );
+
+ request.future.set( new FailedRpcResult<NetconfMessage>(
+ NetconfMessageTransformUtil.toRpcError( e ) ) );
return;
}
- r.future.set(Rpcs.getRpcResult(true, message, Collections.<RpcError>emptySet()));
- } else {
- logger.warn("{}: Ignoring unsolicited message {}", id, msgToS(message));
+ request.future.set(Rpcs.getRpcResult( true, message, Collections.<RpcError>emptySet() ) );
}
}
- @Override
- public void close() {
- tearDown(new RuntimeException("Closed"));
- }
-
private static String msgToS(final NetconfMessage msg) {
return XmlUtil.toString(msg.getDocument());
}
@Override
- public synchronized ListenableFuture<RpcResult<NetconfMessage>> sendRequest(final NetconfMessage message, final QName rpc) {
+ public ListenableFuture<RpcResult<NetconfMessage>> sendRequest(
+ final NetconfMessage message, final QName rpc) {
+ sessionLock.lock();
+ try {
+ return sendRequestWithLock( message, rpc );
+ }
+ finally {
+ sessionLock.unlock();
+ }
+ }
+
+ private ListenableFuture<RpcResult<NetconfMessage>> sendRequestWithLock(
+ final NetconfMessage message, final QName rpc) {
if(logger.isTraceEnabled()) {
logger.trace("{}: Sending message {}", id, msgToS(message));
}
if (session == null) {
logger.warn("{}: Session is disconnected, failing RPC request {}", id, message);
- return Futures.immediateFuture(FAILED_RPC_RESULT);
+ return Futures.immediateFuture( createSessionDownRpcResult() );
}
- final Request req = new Request(new UncancellableFuture<RpcResult<NetconfMessage>>(true), message, rpc);
+ final Request req = new Request( new UncancellableFuture<RpcResult<NetconfMessage>>(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()) {
+ if( !future.isSuccess() ) {
// We expect that a session down will occur at this point
- logger.debug("{}: Failed to send request {}", id, XmlUtil.toString(req.request.getDocument()), future.cause());
- req.future.setException(future.cause());
- } else {
- logger.trace("{}: Finished sending request {}", id, req.request);
+ logger.debug( "{}: Failed to send request {}", id,
+ XmlUtil.toString(req.request.getDocument()), future.cause() );
+
+ if( future.cause() != null ) {
+ req.future.set( createErrorRpcResult( RpcError.ErrorType.TRANSPORT,
+ future.cause().getLocalizedMessage() ) );
+ } else {
+ req.future.set( createSessionDownRpcResult() ); // assume session is down
+ }
+ req.future.setException( future.cause() );
+ }
+ else {
+ logger.trace( "Finished sending request {}", req.request );
}
}
});
private static final class Request {
final UncancellableFuture<RpcResult<NetconfMessage>> future;
final NetconfMessage request;
- final QName rpc;
- private Request(final UncancellableFuture<RpcResult<NetconfMessage>> future, final NetconfMessage request, final QName rpc) {
+ private Request(final UncancellableFuture<RpcResult<NetconfMessage>> future,
+ final NetconfMessage request) {
this.future = future;
this.request = request;
- this.rpc = rpc;
}
}
}
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import javax.annotation.Nullable;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.opendaylight.controller.sal.common.util.RpcErrors;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
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 com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
return new CompositeNodeTOImpl(argument.getNodeType(), null, list);
}
- public static void checkValidReply(final NetconfMessage input, final NetconfMessage output) {
+ public static void checkValidReply(final NetconfMessage input, final NetconfMessage output)
+ throws NetconfDocumentedException {
final String inputMsgId = input.getDocument().getDocumentElement().getAttribute("message-id");
final String outputMsgId = output.getDocument().getDocumentElement().getAttribute("message-id");
if(inputMsgId.equals(outputMsgId) == false) {
- final String requestXml = XmlUtil.toString(input.getDocument());
- final String responseXml = XmlUtil.toString(output.getDocument());
- throw new IllegalStateException(String.format("Rpc request and reply message IDs must be same. Request: %s, response: %s", requestXml, responseXml));
+ Map<String,String> errorInfo = ImmutableMap.<String,String>builder()
+ .put( "actual-message-id", outputMsgId )
+ .put( "expected-message-id", inputMsgId )
+ .build();
+
+ throw new NetconfDocumentedException( "Response message contained unknown \"message-id\"",
+ null, NetconfDocumentedException.ErrorType.protocol,
+ NetconfDocumentedException.ErrorTag.bad_attribute,
+ NetconfDocumentedException.ErrorSeverity.error, errorInfo );
}
}
public static void checkSuccessReply(final NetconfMessage output) throws NetconfDocumentedException {
if(NetconfMessageUtil.isErrorMessage(output)) {
- throw new IllegalStateException(String.format("Response contains error: %s", XmlUtil.toString(output.getDocument())));
+ throw NetconfDocumentedException.fromXMLDocument( output.getDocument() );
+ }
+ }
+
+ public static RpcError toRpcError( NetconfDocumentedException ex )
+ {
+ StringBuilder infoBuilder = new StringBuilder();
+ Map<String, String> errorInfo = ex.getErrorInfo();
+ if( errorInfo != null )
+ {
+ for( Entry<String,String> e: errorInfo.entrySet() ) {
+ infoBuilder.append( '<' ).append( e.getKey() ).append( '>' ).append( e.getValue() )
+ .append( "</" ).append( e.getKey() ).append( '>' );
+
+ }
+ }
+
+ return RpcErrors.getRpcError( null, ex.getErrorTag().getTagValue(), infoBuilder.toString(),
+ toRpcErrorSeverity( ex.getErrorSeverity() ), ex.getLocalizedMessage(),
+ toRpcErrorType( ex.getErrorType() ), ex.getCause() );
+ }
+
+ private static ErrorSeverity toRpcErrorSeverity( NetconfDocumentedException.ErrorSeverity severity ) {
+ switch( severity ) {
+ case warning:
+ return RpcError.ErrorSeverity.WARNING;
+ default:
+ return RpcError.ErrorSeverity.ERROR;
+ }
+ }
+
+ private static RpcError.ErrorType toRpcErrorType( NetconfDocumentedException.ErrorType type )
+ {
+ switch( type ) {
+ case protocol:
+ return RpcError.ErrorType.PROTOCOL;
+ case rpc:
+ return RpcError.ErrorType.RPC;
+ case transport:
+ return RpcError.ErrorType.TRANSPORT;
+ default:
+ return RpcError.ErrorType.APPLICATION;
}
}
import org.junit.Test;
import org.mockito.Mockito;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.sal.common.util.Rpcs;
import org.opendaylight.controller.sal.connect.api.MessageTransformer;
import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator;
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications 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.listener;
+
+import io.netty.channel.ChannelFuture;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+
+import java.io.ByteArrayInputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.client.NetconfClientSession;
+import org.opendaylight.controller.sal.connect.api.RemoteDevice;
+import org.opendaylight.controller.sal.connect.api.RemoteDeviceCommunicator;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class NetconfDeviceCommunicatorTest {
+
+ @Mock
+ NetconfClientSession mockSession;
+
+ @Mock
+ RemoteDevice<NetconfSessionCapabilities, NetconfMessage> mockDevice;
+
+ NetconfDeviceCommunicator communicator;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks( this );
+
+ communicator = new NetconfDeviceCommunicator( new RemoteDeviceId( "test" ), mockDevice );
+ }
+
+ @SuppressWarnings("unchecked")
+ void setupSession()
+ {
+ doReturn( Collections.<String>emptySet() ).when( mockSession ).getServerCapabilities();
+ doNothing().when( mockDevice ).onRemoteSessionUp( any( NetconfSessionCapabilities.class ),
+ any( RemoteDeviceCommunicator.class ) );
+ communicator.onSessionUp( mockSession );
+ }
+
+ private ListenableFuture<RpcResult<NetconfMessage>> sendRequest() throws Exception {
+ return sendRequest( UUID.randomUUID().toString() );
+ }
+
+ @SuppressWarnings("unchecked")
+ private ListenableFuture<RpcResult<NetconfMessage>> sendRequest( String messageID ) throws Exception {
+ Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+ Element element = doc.createElement( "request" );
+ element.setAttribute( "message-id", messageID );
+ doc.appendChild( element );
+ NetconfMessage message = new NetconfMessage( doc );
+
+ ChannelFuture mockChannelFuture = mock( ChannelFuture.class );
+ doReturn( mockChannelFuture ).when( mockChannelFuture )
+ .addListener( any( (GenericFutureListener.class ) ) );
+ doReturn( mockChannelFuture ).when( mockSession ).sendMessage( same( message ) );
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture =
+ communicator.sendRequest( message, QName.create( "mock rpc" ) );
+
+ assertNotNull( "ListenableFuture is null", resultFuture );
+ return resultFuture;
+ }
+
+ @Test
+ public void testOnSessionUp() {
+ String testCapability = "urn:opendaylight:params:xml:ns:test?module=test-module&revision=2014-06-02";
+ Collection<String> serverCapabilities =
+ Sets.newHashSet( NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString(),
+ NetconfMessageTransformUtil.IETF_NETCONF_MONITORING.getNamespace().toString(),
+ testCapability );
+ doReturn( serverCapabilities ).when( mockSession ).getServerCapabilities();
+
+ ArgumentCaptor<NetconfSessionCapabilities> netconfSessionCapabilities =
+ ArgumentCaptor.forClass( NetconfSessionCapabilities.class );
+ doNothing().when( mockDevice ).onRemoteSessionUp( netconfSessionCapabilities.capture(), eq( communicator ) );
+
+ communicator.onSessionUp( mockSession );
+
+ verify( mockSession ).getServerCapabilities();
+ verify( mockDevice ).onRemoteSessionUp( netconfSessionCapabilities.capture(), eq( communicator ) );
+
+ NetconfSessionCapabilities actualCapabilites = netconfSessionCapabilities.getValue();
+ assertEquals( "containsCapability", true, actualCapabilites.containsCapability(
+ NetconfMessageTransformUtil.NETCONF_ROLLBACK_ON_ERROR_URI.toString() ) );
+ assertEquals( "containsCapability", true, actualCapabilites.containsCapability( testCapability ) );
+ assertEquals( "getModuleBasedCaps", Sets.newHashSet(
+ QName.create( "urn:opendaylight:params:xml:ns:test", "2014-06-02", "test-module" )),
+ actualCapabilites.getModuleBasedCaps() );
+ assertEquals( "isRollbackSupported", true, actualCapabilites.isRollbackSupported() );
+ assertEquals( "isMonitoringSupported", true, actualCapabilites.isMonitoringSupported() );
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test(timeout=5000)
+ public void testOnSessionDown() throws Exception {
+ setupSession();
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest();
+
+ doNothing().when( mockDevice ).onRemoteSessionDown();
+
+ communicator.onSessionDown( mockSession, new Exception( "mock ex" ) );
+
+ verifyErrorRpcResult( resultFuture1.get(), RpcError.ErrorType.TRANSPORT, "operation-failed" );
+ verifyErrorRpcResult( resultFuture2.get(), RpcError.ErrorType.TRANSPORT, "operation-failed" );
+
+ verify( mockDevice ).onRemoteSessionDown();
+
+ reset( mockDevice );
+
+ communicator.onSessionDown( mockSession, new Exception( "mock ex" ) );
+
+ verify( mockDevice, never() ).onRemoteSessionDown();
+ }
+
+ @Test
+ public void testOnSessionTerminated() throws Exception {
+ setupSession();
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest();
+
+ doNothing().when( mockDevice ).onRemoteSessionDown();
+
+ String reasonText = "testing terminate";
+ NetconfTerminationReason reason = new NetconfTerminationReason( reasonText );
+ communicator.onSessionTerminated( mockSession, reason );
+
+ RpcError rpcError = verifyErrorRpcResult( resultFuture.get(), RpcError.ErrorType.TRANSPORT,
+ "operation-failed" );
+ assertEquals( "RpcError message", reasonText, rpcError.getMessage() );
+
+ verify( mockDevice ).onRemoteSessionDown();
+ }
+
+ @Test
+ public void testClose() throws Exception {
+ communicator.close();
+ verify( mockDevice, never() ).onRemoteSessionDown();
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
+ public void testSendRequest() throws Exception {
+ setupSession();
+
+ NetconfMessage message = new NetconfMessage(
+ DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() );
+ QName rpc = QName.create( "mock rpc" );
+
+ ArgumentCaptor<GenericFutureListener> futureListener =
+ ArgumentCaptor.forClass( GenericFutureListener.class );
+
+ ChannelFuture mockChannelFuture = mock( ChannelFuture.class );
+ doReturn( mockChannelFuture ).when( mockChannelFuture ).addListener( futureListener.capture() );
+ doReturn( mockChannelFuture ).when( mockSession ).sendMessage( same( message ) );
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest( message, rpc );
+
+ verify( mockSession ).sendMessage( same( message ) );
+
+ assertNotNull( "ListenableFuture is null", resultFuture );
+
+ verify( mockChannelFuture ).addListener( futureListener.capture() );
+ Future<Void> operationFuture = mock( Future.class );
+ doReturn( true ).when( operationFuture ).isSuccess();
+ doReturn( true ).when( operationFuture ).isDone();
+ futureListener.getValue().operationComplete( operationFuture );
+
+ try {
+ resultFuture.get( 1, TimeUnit.MILLISECONDS ); // verify it's not cancelled or has an error set
+ }
+ catch( TimeoutException e ) {} // expected
+ }
+
+ @Test
+ public void testSendRequestWithNoSession() throws Exception {
+ NetconfMessage message = new NetconfMessage(
+ DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() );
+ QName rpc = QName.create( "mock rpc" );
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest( message, rpc );
+
+ assertNotNull( "ListenableFuture is null", resultFuture );
+
+ // Should have an immediate result
+ RpcResult<NetconfMessage> rpcResult = resultFuture.get( 3, TimeUnit.MILLISECONDS );
+
+ verifyErrorRpcResult( rpcResult, RpcError.ErrorType.TRANSPORT, "operation-failed" );
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Test
+ public void testSendRequestWithWithSendFailure() throws Exception {
+ setupSession();
+
+ NetconfMessage message = new NetconfMessage(
+ DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() );
+ QName rpc = QName.create( "mock rpc" );
+
+ ArgumentCaptor<GenericFutureListener> futureListener =
+ ArgumentCaptor.forClass( GenericFutureListener.class );
+
+ ChannelFuture mockChannelFuture = mock( ChannelFuture.class );
+ doReturn( mockChannelFuture ).when( mockChannelFuture ).addListener( futureListener.capture() );
+ doReturn( mockChannelFuture ).when( mockSession ).sendMessage( same( message ) );
+
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest( message, rpc );
+
+ assertNotNull( "ListenableFuture is null", resultFuture );
+
+ verify( mockChannelFuture ).addListener( futureListener.capture() );
+
+ Future<Void> operationFuture = mock( Future.class );
+ doReturn( false ).when( operationFuture ).isSuccess();
+ doReturn( true ).when( operationFuture ).isDone();
+ doReturn( new Exception( "mock error" ) ).when( operationFuture ).cause();
+ futureListener.getValue().operationComplete( operationFuture );
+
+ // Should have an immediate result
+ RpcResult<NetconfMessage> rpcResult = resultFuture.get( 3, TimeUnit.MILLISECONDS );
+
+ RpcError rpcError = verifyErrorRpcResult( rpcResult, RpcError.ErrorType.TRANSPORT, "operation-failed" );
+ assertEquals( "RpcError message contains \"mock error\"", true,
+ rpcError.getMessage().contains( "mock error" ) );
+ }
+
+ private NetconfMessage createSuccessResponseMessage( String messageID ) throws ParserConfigurationException {
+ Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+ Element rpcReply = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_REPLY_KEY );
+ rpcReply.setAttribute( "message-id", messageID );
+ Element element = doc.createElementNS( "ns", "data" );
+ element.setTextContent( messageID );
+ rpcReply.appendChild( element );
+ doc.appendChild( rpcReply );
+
+ return new NetconfMessage( doc );
+ }
+
+ @Test
+ public void testOnSuccessfulResponseMessage() throws Exception {
+ setupSession();
+
+ String messageID1 = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest( messageID1 );
+
+ String messageID2 = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest( messageID2 );
+
+ communicator.onMessage( mockSession, createSuccessResponseMessage( messageID1 ) );
+ communicator.onMessage( mockSession, createSuccessResponseMessage( messageID2 ) );
+
+ verifyResponseMessage( resultFuture1.get(), messageID1 );
+ verifyResponseMessage( resultFuture2.get(), messageID2 );
+ }
+
+ @Test
+ public void testOnResponseMessageWithError() throws Exception {
+ setupSession();
+
+ String messageID = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest( messageID );
+
+ communicator.onMessage( mockSession, createErrorResponseMessage( messageID ) );
+
+ RpcError rpcError = verifyErrorRpcResult( resultFuture.get(), RpcError.ErrorType.RPC,
+ "missing-attribute" );
+ assertEquals( "RpcError message", "Missing attribute", rpcError.getMessage() );
+
+ String errorInfo = rpcError.getInfo();
+ assertNotNull( "RpcError info is null", errorInfo );
+ assertEquals( "Error info contains \"foo\"", true,
+ errorInfo.contains( "<bad-attribute>foo</bad-attribute>" ) );
+ assertEquals( "Error info contains \"bar\"", true,
+ errorInfo.contains( "<bad-element>bar</bad-element>" ) );
+ }
+
+ @Test
+ public void testOnResponseMessageWithWrongMessageID() throws Exception {
+ setupSession();
+
+ String messageID = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest( messageID );
+
+ communicator.onMessage( mockSession, createSuccessResponseMessage( UUID.randomUUID().toString() ) );
+
+ RpcError rpcError = verifyErrorRpcResult( resultFuture.get(), RpcError.ErrorType.PROTOCOL,
+ "bad-attribute" );
+ assertEquals( "RpcError message non-empty", true,
+ !Strings.isNullOrEmpty( rpcError.getMessage() ) );
+
+ String errorInfo = rpcError.getInfo();
+ assertNotNull( "RpcError info is null", errorInfo );
+ assertEquals( "Error info contains \"actual-message-id\"", true,
+ errorInfo.contains( "actual-message-id" ) );
+ assertEquals( "Error info contains \"expected-message-id\"", true,
+ errorInfo.contains( "expected-message-id" ) );
+ }
+
+ private NetconfMessage createErrorResponseMessage( String messageID ) throws Exception {
+ String xmlStr =
+ "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"" +
+ " message-id=\"" + messageID + "\">" +
+ " <rpc-error>" +
+ " <error-type>rpc</error-type>" +
+ " <error-tag>missing-attribute</error-tag>" +
+ " <error-severity>error</error-severity>" +
+ " <error-message>Missing attribute</error-message>" +
+ " <error-info>" +
+ " <bad-attribute>foo</bad-attribute>" +
+ " <bad-element>bar</bad-element>" +
+ " </error-info>" +
+ " </rpc-error>" +
+ "</rpc-reply>";
+
+ ByteArrayInputStream bis = new ByteArrayInputStream( xmlStr.getBytes() );
+ Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( bis );
+ return new NetconfMessage( doc );
+ }
+
+ private void verifyResponseMessage( RpcResult<NetconfMessage> rpcResult, String dataText ) {
+ assertNotNull( "RpcResult is null", rpcResult );
+ assertEquals( "isSuccessful", true, rpcResult.isSuccessful() );
+ NetconfMessage messageResult = rpcResult.getResult();
+ assertNotNull( "getResult", messageResult );
+// List<SimpleNode<?>> nodes = messageResult.getSimpleNodesByName(
+// QName.create( URI.create( "ns" ), null, "data" ) );
+// assertNotNull( "getSimpleNodesByName", nodes );
+// assertEquals( "List<SimpleNode<?>> size", 1, nodes.size() );
+// assertEquals( "SimpleNode value", dataText, nodes.iterator().next().getValue() );
+ }
+
+ private RpcError verifyErrorRpcResult( RpcResult<NetconfMessage> rpcResult,
+ RpcError.ErrorType expErrorType, String expErrorTag ) {
+ assertNotNull( "RpcResult is null", rpcResult );
+ assertEquals( "isSuccessful", false, rpcResult.isSuccessful() );
+ assertNotNull( "RpcResult errors is null", rpcResult.getErrors() );
+ assertEquals( "Errors size", 1, rpcResult.getErrors().size() );
+ RpcError rpcError = rpcResult.getErrors().iterator().next();
+ assertEquals( "getErrorSeverity", RpcError.ErrorSeverity.ERROR, rpcError.getSeverity() );
+ assertEquals( "getErrorType", expErrorType, rpcError.getErrorType() );
+ assertEquals( "getErrorTag", expErrorTag, rpcError.getTag() );
+ assertTrue( "getMessage is empty", StringUtils.isNotEmpty( rpcError.getMessage() ) );
+ return rpcError;
+ }
+}
package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml;
import com.google.common.base.Preconditions;
+
import java.util.List;
import java.util.Map;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
public class ObjectNameAttributeReadingStrategy extends AbstractAttributeReadingStrategy {
package org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.toxml;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectNameAttributeMappingStrategy;
import org.opendaylight.controller.netconf.confignetconfconnector.util.Util;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+
import javax.management.ObjectName;
+
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+
import javax.management.ObjectName;
import javax.management.openmbean.OpenType;
+
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeReadingStrategy;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectXmlReader;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package org.opendaylight.controller.netconf.confignetconfconnector.mapping.config;
import com.google.common.base.Optional;
+
import java.util.Date;
import java.util.Map;
+
import javax.management.ObjectName;
+
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditStrategyType;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
+
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.ObjectNameAttributeReadingStrategy;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.management.ObjectName;
+
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+
import java.util.Collection;
import java.util.Map;
import java.util.Set;
+
import javax.management.ObjectName;
+
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
import com.google.common.base.Optional;
+
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package org.opendaylight.controller.netconf.confignetconfconnector.operations;
import com.google.common.base.Optional;
+
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
+
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfigElementResolved;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreSnapshot;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.collect.Multimap;
+
import java.util.Arrays;
import java.util.Map;
+
import org.opendaylight.controller.config.api.ServiceReferenceReadableRegistry;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementDefinition;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleElementResolved;
import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package org.opendaylight.controller.netconf.confignetconfconnector.operations.get;
import com.google.common.collect.Maps;
+
import java.util.List;
import java.util.Map;
import java.util.Set;
+
import javax.management.ObjectName;
+
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.InstanceConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ModuleConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.runtime.InstanceRuntime;
import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.Config;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.config.ServiceRegistryWrapper;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
import org.opendaylight.controller.netconf.util.exception.UnexpectedElementException;
import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
+
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.AttributeMappingStrategy;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.ObjectMapper;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.ObjectName;
import javax.management.openmbean.OpenType;
+
import java.util.Map;
public class RuntimeRpc extends AbstractConfigNetconfOperation {
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
+
import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.ModuleRpcs;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import javax.management.ObjectName;
+
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
import javax.xml.parsers.ParserConfigurationException;
+
import org.custommonkey.xmlunit.AbstractNodeTester;
import org.custommonkey.xmlunit.NodeTest;
import org.custommonkey.xmlunit.NodeTestException;
import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.DiscardChanges;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2;
import org.junit.Test;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Element;
import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.Capability;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.util.NetconfUtil;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
<instructions>
<Private-Package></Private-Package>
<Import-Package>javax.management,
+ javax.xml.parsers,
org.opendaylight.controller.config.api,
org.opendaylight.controller.config.api.jmx,
org.opendaylight.protocol.framework,
com.google.common.base,</Import-Package>
<Export-Package>org.opendaylight.controller.netconf.api,
org.opendaylight.controller.netconf.api.jmx,
+ org.opendaylight.controller.netconf.api.xml,
org.opendaylight.controller.netconf.api.monitoring,</Export-Package>
</instructions>
</configuration>
package org.opendaylight.controller.netconf.api;
-import org.opendaylight.controller.config.api.ConflictingVersionException;
-import org.opendaylight.controller.config.api.ValidationException;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_INFO;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_MESSAGE;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_SEVERITY;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_TAG;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.ERROR_TYPE;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_ERROR;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.RPC_REPLY_KEY;
+import static org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/**
* Checked exception to communicate an error that needs to be sent to the
private static final long serialVersionUID = 1L;
+ private final static Logger LOG = LoggerFactory.getLogger( NetconfDocumentedException.class );
+ private static final DocumentBuilderFactory BUILDER_FACTORY;
+
+ static {
+ BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+ BUILDER_FACTORY.setNamespaceAware(true);
+ BUILDER_FACTORY.setCoalescing(true);
+ BUILDER_FACTORY.setIgnoringElementContentWhitespace(true);
+ BUILDER_FACTORY.setIgnoringComments(true);
+ }
public enum ErrorType {
transport, rpc, protocol, application;
public String getTagValue() {
return name();
}
+
+ public static ErrorType from( String text ) {
+ try {
+ return valueOf( text );
+ }
+ catch( Exception e ) {
+ return application;
+ }
+ }
}
public enum ErrorTag {
- missing_attribute("missing-attribute"), unknown_element("unknown-element"), operation_not_supported(
- "operation-not-supported"), bad_attribute("bad-attribute"), data_missing("data-missing"), operation_failed(
- "operation-failed"), invalid_value("invalid-value"), malformed_message("malformed-message");
+ access_denied("access-denied"),
+ bad_attribute("bad-attribute"),
+ bad_element("bad-element"),
+ data_exists("data-exists"),
+ data_missing("data-missing"),
+ in_use("in-use"),
+ invalid_value("invalid-value"),
+ lock_denied("lock-denied"),
+ malformed_message("malformed-message"),
+ missing_attribute("missing-attribute"),
+ missing_element("missing-element"),
+ operation_failed("operation-failed"),
+ operation_not_supported("operation-not-supported"),
+ resource_denied("resource-denied"),
+ rollback_failed("rollback-failed"),
+ too_big("too-big"),
+ unknown_attribute("unknown-attribute"),
+ unknown_element("unknown-element"),
+ unknown_namespace("unknown-namespace");
private final String tagValue;
public String getTagValue() {
return this.tagValue;
}
+
+ public static ErrorTag from( String text ) {
+ for( ErrorTag e: values() )
+ {
+ if( e.getTagValue().equals( text ) ) {
+ return e;
+ }
+ }
+
+ return operation_failed;
+ }
}
public enum ErrorSeverity {
public String getTagValue() {
return name();
}
+
+ public static ErrorSeverity from( String text ) {
+ try {
+ return valueOf( text );
+ }
+ catch( Exception e ) {
+ return error;
+ }
+ }
}
private final ErrorType errorType;
ErrorSeverity.error, errorInfo);
}
+ public static NetconfDocumentedException fromXMLDocument( Document fromDoc ) {
+
+ ErrorType errorType = ErrorType.application;
+ ErrorTag errorTag = ErrorTag.operation_failed;
+ ErrorSeverity errorSeverity = ErrorSeverity.error;
+ Map<String, String> errorInfo = null;
+ String errorMessage = "";
+
+ Node rpcReply = fromDoc.getDocumentElement();
+
+ // FIXME: BUG? - we only handle one rpc-error.
+
+ NodeList replyChildren = rpcReply.getChildNodes();
+ for( int i = 0; i < replyChildren.getLength(); i++ ) {
+ Node replyChild = replyChildren.item( i );
+ if( RPC_ERROR.equals( replyChild.getNodeName() ) )
+ {
+ NodeList rpcErrorChildren = replyChild.getChildNodes();
+ for( int j = 0; j < rpcErrorChildren.getLength(); j++ )
+ {
+ Node rpcErrorChild = rpcErrorChildren.item( j );
+ if( ERROR_TYPE.equals( rpcErrorChild.getNodeName() ) ) {
+ errorType = ErrorType.from( rpcErrorChild.getTextContent() );
+ }
+ else if( ERROR_TAG.equals( rpcErrorChild.getNodeName() ) ) {
+ errorTag = ErrorTag.from( rpcErrorChild.getTextContent() );
+ }
+ else if( ERROR_SEVERITY.equals( rpcErrorChild.getNodeName() ) ) {
+ errorSeverity = ErrorSeverity.from( rpcErrorChild.getTextContent() );
+ }
+ else if( ERROR_MESSAGE.equals( rpcErrorChild.getNodeName() ) ) {
+ errorMessage = rpcErrorChild.getTextContent();
+ }
+ else if( ERROR_INFO.equals( rpcErrorChild.getNodeName() ) ) {
+ errorInfo = parseErrorInfo( rpcErrorChild );
+ }
+ }
+
+ break;
+ }
+ }
+
+ return new NetconfDocumentedException( errorMessage, errorType, errorTag, errorSeverity, errorInfo );
+ }
+
+ private static Map<String, String> parseErrorInfo( Node node ) {
+ Map<String, String> infoMap = new HashMap<>();
+ NodeList children = node.getChildNodes();
+ for( int i = 0; i < children.getLength(); i++ ) {
+ Node child = children.item( i );
+ if( child.getNodeType() == Node.ELEMENT_NODE ) {
+ infoMap.put( child.getNodeName(), child.getTextContent() );
+ }
+ }
+
+ return infoMap;
+ }
+
public ErrorType getErrorType() {
return this.errorType;
}
return this.errorInfo;
}
+ public Document toXMLDocument() {
+ Document doc = null;
+ try {
+ doc = BUILDER_FACTORY.newDocumentBuilder().newDocument();
+
+ Node rpcReply = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_REPLY_KEY );
+ doc.appendChild( rpcReply );
+
+ Node rpcError = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, RPC_ERROR );
+ rpcReply.appendChild( rpcError );
+
+ rpcError.appendChild( createTextNode( doc, ERROR_TYPE, getErrorType().getTagValue() ) );
+ rpcError.appendChild( createTextNode( doc, ERROR_TAG, getErrorTag().getTagValue() ) );
+ rpcError.appendChild( createTextNode( doc, ERROR_SEVERITY, getErrorSeverity().getTagValue() ) );
+ rpcError.appendChild( createTextNode( doc, ERROR_MESSAGE, getLocalizedMessage() ) );
+
+ Map<String, String> errorInfoMap = getErrorInfo();
+ if( errorInfoMap != null && !errorInfoMap.isEmpty() ) {
+ /*
+ * <error-info>
+ * <bad-attribute>message-id</bad-attribute>
+ * <bad-element>rpc</bad-element>
+ * </error-info>
+ */
+
+ Node errorInfoNode = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, ERROR_INFO );
+ errorInfoNode.setPrefix( rpcReply.getPrefix() );
+ rpcError.appendChild( errorInfoNode );
+
+ for ( Entry<String, String> entry : errorInfoMap.entrySet() ) {
+ errorInfoNode.appendChild( createTextNode( doc, entry.getKey(), entry.getValue() ) );
+ }
+ }
+ }
+ catch( ParserConfigurationException e ) {
+ LOG.error( "Error outputting to XML document", e ); // this shouldn't happen
+ }
+
+ return doc;
+ }
+
+ private Node createTextNode( Document doc, String tag, String textContent ) {
+ Node node = doc.createElementNS( URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, tag );
+ node.setTextContent( textContent );
+ return node;
+ }
+
@Override
public String toString() {
return "NetconfDocumentedException{" + "message=" + getMessage() + ", errorType=" + this.errorType
* 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.xml;
+package org.opendaylight.controller.netconf.api.xml;
public final class XmlNetconfConstants {
public static final String RPC_KEY = "rpc";
public static final String RPC_REPLY_KEY = "rpc-reply";
public static final String RPC_ERROR = "rpc-error";
+ public static final String ERROR_TYPE = "error-type";
+ public static final String ERROR_TAG = "error-tag";
+ public static final String ERROR_SEVERITY = "error-severity";
+ public static final String ERROR_APP_TAG = "error-app-tag";
+ public static final String ERROR_PATH = "error-path";
+ public static final String ERROR_MESSAGE = "error-message";
+ public static final String ERROR_INFO = "error-info";
public static final String NAME_KEY = "name";
public static final String NOTIFICATION_ELEMENT_NAME = "notification";
--- /dev/null
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.google.common.collect.ImmutableMap;
+
+
+/**
+ * Unit tests for NetconfDocumentedException.
+ *
+ * @author Thomas Pantelis
+ */
+public class NetconfDocumentedExceptionTest {
+
+ private XPath xpath;
+
+ @Before
+ public void setUp() throws Exception {
+ XPathFactory xPathfactory = XPathFactory.newInstance();
+ xpath = xPathfactory.newXPath();
+ xpath.setNamespaceContext( new NamespaceContext() {
+ @Override
+ public Iterator<?> getPrefixes( String namespaceURI ) {
+ return Collections.singletonList( "netconf" ).iterator();
+ }
+
+ @Override
+ public String getPrefix( String namespaceURI ) {
+ return "netconf";
+ }
+
+ @Override
+ public String getNamespaceURI( String prefix ) {
+ return XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
+ }
+ } );
+ }
+
+ @Test
+ public void testToAndFromXMLDocument() throws XPathExpressionException {
+ String errorMessage = "mock error message";
+ NetconfDocumentedException ex = new NetconfDocumentedException( errorMessage, null,
+ ErrorType.protocol,
+ ErrorTag.data_exists,
+ ErrorSeverity.warning,
+ ImmutableMap.of( "foo", "bar" ) );
+
+ Document doc = ex.toXMLDocument();
+ assertNotNull( "Document is null", doc );
+
+ Node rootNode = doc.getDocumentElement();
+
+ assertEquals( "getNamespaceURI", "urn:ietf:params:xml:ns:netconf:base:1.0", rootNode.getNamespaceURI() );
+ assertEquals( "getLocalName", "rpc-reply", rootNode.getLocalName() );
+
+ Node rpcErrorNode = getNode( "/netconf:rpc-reply/netconf:rpc-error", rootNode );
+ assertNotNull( "rpc-error not found", rpcErrorNode );
+
+ Node errorTypeNode = getNode( "netconf:error-type", rpcErrorNode );
+ assertNotNull( "error-type not found", errorTypeNode );
+ assertEquals( "error-type", ErrorType.protocol.getTagValue(),
+ errorTypeNode.getTextContent() );
+
+ Node errorTagNode = getNode( "netconf:error-tag", rpcErrorNode );
+ assertNotNull( "error-tag not found", errorTagNode );
+ assertEquals( "error-tag", ErrorTag.data_exists.getTagValue(),
+ errorTagNode.getTextContent() );
+
+ Node errorSeverityNode = getNode( "netconf:error-severity", rpcErrorNode );
+ assertNotNull( "error-severity not found", errorSeverityNode );
+ assertEquals( "error-severity", ErrorSeverity.warning.getTagValue(),
+ errorSeverityNode.getTextContent() );
+
+ Node errorInfoNode = getNode( "netconf:error-info/netconf:foo", rpcErrorNode );
+ assertNotNull( "foo not found", errorInfoNode );
+ assertEquals( "foo", "bar", errorInfoNode.getTextContent() );
+
+ Node errorMsgNode = getNode( "netconf:error-message", rpcErrorNode );
+ assertNotNull( "error-message not found", errorMsgNode );
+ assertEquals( "error-message", errorMessage, errorMsgNode.getTextContent() );
+
+ // Test fromXMLDocument
+
+ ex = NetconfDocumentedException.fromXMLDocument( doc );
+
+ assertNotNull( "NetconfDocumentedException is null", ex );
+ assertEquals( "getErrorSeverity", ErrorSeverity.warning, ex.getErrorSeverity() );
+ assertEquals( "getErrorTag", ErrorTag.data_exists, ex.getErrorTag() );
+ assertEquals( "getErrorType", ErrorType.protocol, ex.getErrorType() );
+ assertEquals( "getLocalizedMessage", errorMessage, ex.getLocalizedMessage() );
+ assertEquals( "getErrorInfo", ImmutableMap.of( "foo", "bar" ), ex.getErrorInfo() );
+ }
+
+ @SuppressWarnings("unchecked")
+ <T> T getNode( String xpathExp, Node node ) throws XPathExpressionException {
+ return (T)xpath.compile( xpathExp ).evaluate( node, XPathConstants.NODE );
+ }
+}
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public final class NetconfClientSession extends AbstractNetconfSession<NetconfClientSession, NetconfClientSessionListener> {
+public class NetconfClientSession extends AbstractNetconfSession<NetconfClientSession, NetconfClientSessionListener> {
private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class);
private final Collection<String> capabilities;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
+
import java.util.Collection;
+
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
+
import org.opendaylight.controller.netconf.api.NetconfClientSessionPreferences;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.nettyutil.AbstractChannelInitializer;
import org.opendaylight.controller.netconf.nettyutil.AbstractNetconfSessionNegotiator;
import org.opendaylight.controller.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
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.Sets;
+
import io.netty.channel.Channel;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
+
import org.opendaylight.controller.netconf.api.NetconfClientSessionPreferences;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.protocol.framework.SessionListenerFactory;
import org.opendaylight.protocol.framework.SessionNegotiator;
import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
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.NetconfSessionListener;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
+
import java.util.Set;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
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.messages.NetconfHelloMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.protocol.framework.SessionListenerFactory;
import org.opendaylight.protocol.framework.SessionNegotiator;
import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
import io.netty.channel.Channel;
import io.netty.util.Timer;
import io.netty.util.concurrent.Promise;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
import java.io.IOException;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package org.opendaylight.controller.netconf.impl.mapping.operations;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
package org.opendaylight.controller.netconf.impl.mapping.operations;
import com.google.common.base.Preconditions;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorSeverity;\r
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorTag;\r
import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorType;\r
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;\r
import org.opendaylight.controller.netconf.api.NetconfMessage;\r
import org.opendaylight.controller.netconf.impl.NetconfServerSession;\r
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;\r
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;\r
import org.opendaylight.controller.netconf.util.xml.XmlElement;\r
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;\r
import org.opendaylight.controller.netconf.util.xml.XmlUtil;\r
import org.slf4j.Logger;\r
import org.slf4j.LoggerFactory;\r
package org.opendaylight.controller.netconf.impl.mapping.operations;\r
\r
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;\r
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;\r
import org.opendaylight.controller.netconf.impl.NetconfServerSession;\r
import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation;\r
import org.opendaylight.controller.netconf.util.xml.XmlElement;\r
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;\r
import org.opendaylight.controller.netconf.util.xml.XmlUtil;\r
import org.slf4j.Logger;\r
import org.slf4j.LoggerFactory;\r
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.HashedWheelTimer;
import io.netty.util.concurrent.GlobalEventExecutor;
+
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
+
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.runners.Parameterized;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.NeverReconnectStrategy;
import org.slf4j.Logger;
package org.opendaylight.controller.netconf.monitoring;
import com.google.common.collect.Maps;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.monitoring.xml.JaxBSerializer;
import org.opendaylight.controller.netconf.monitoring.xml.model.NetconfState;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.openexi.proc.common.EXIOptions;
import org.w3c.dom.Document;
<Import-Package>com.google.common.base, com.google.common.collect, io.netty.channel,
io.netty.util.concurrent, javax.annotation, javax.xml.namespace, javax.xml.parsers, javax.xml.transform,
javax.xml.transform.dom, javax.xml.transform.stream, javax.xml.validation, javax.xml.xpath,
- org.opendaylight.controller.netconf.api, org.opendaylight.controller.netconf.mapping.api,
+ org.opendaylight.controller.netconf.api, org.opendaylight.controller.netconf.api.xml,
+ org.opendaylight.controller.netconf.mapping.api,
org.osgi.framework, org.slf4j, org.w3c.dom, org.xml.sax,io.netty.channel.local</Import-Package>
<Export-Package>org.opendaylight.controller.netconf.util.*</Export-Package>
</instructions>
package org.opendaylight.controller.netconf.util;
import com.google.common.base.Preconditions;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Set;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import javax.annotation.Nullable;
+
import java.util.Collection;
import java.util.List;
package org.opendaylight.controller.netconf.util.messages;
import com.google.common.base.Preconditions;
+
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
+
import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
-import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import java.io.InputStream;
-import java.util.Map.Entry;
public final class SendErrorExceptionUtil {
private static final Logger logger = LoggerFactory.getLogger(SendErrorExceptionUtil.class);
}
}
- private static XPathExpression rpcErrorExpression = XMLNetconfUtil
- .compileXPath("/netconf:rpc-reply/netconf:rpc-error");
- private static XPathExpression errorTypeExpression = XMLNetconfUtil.compileXPath("netconf:error-type");
- private static XPathExpression errorTagExpression = XMLNetconfUtil.compileXPath("netconf:error-tag");
- private static XPathExpression errorSeverityExpression = XMLNetconfUtil.compileXPath("netconf:error-severity");
-
private static Document createDocument(final NetconfDocumentedException sendErrorException) {
-
- final InputStream errIS = SendErrorExceptionUtil.class.getResourceAsStream("server_error.xml");
- Document originalErrorDocument;
- try {
- originalErrorDocument = XmlUtil.readXmlToDocument(errIS);
- } catch (final Exception e) {
- throw new IllegalStateException(e);
- }
-
- final Document errorDocument = XmlUtil.createDocumentCopy(originalErrorDocument);
- final Node rootNode = errorDocument.getFirstChild();
-
- final Node rpcErrorNode = (Node) XmlUtil.evaluateXPath(rpcErrorExpression, rootNode, XPathConstants.NODE);
-
- final Node errorTypeNode = (Node) XmlUtil.evaluateXPath(errorTypeExpression, rpcErrorNode, XPathConstants.NODE);
- errorTypeNode.setTextContent(sendErrorException.getErrorType().getTagValue());
-
- final Node errorTagNode = (Node) XmlUtil.evaluateXPath(errorTagExpression, rpcErrorNode, XPathConstants.NODE);
- errorTagNode.setTextContent(sendErrorException.getErrorTag().getTagValue());
-
- final Node errorSeverityNode = (Node) XmlUtil.evaluateXPath(errorSeverityExpression, rpcErrorNode,
- XPathConstants.NODE);
- errorSeverityNode.setTextContent(sendErrorException.getErrorSeverity().getTagValue());
-
- if (sendErrorException.getErrorInfo() != null && !sendErrorException.getErrorInfo().isEmpty()) {
- /*
- * <error-info> <bad-attribute>message-id</bad-attribute>
- * <bad-element>rpc</bad-element> </error-info>
- */
- final Node errorInfoNode = errorDocument.createElementNS(
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, "error-info");
-
- errorInfoNode.setPrefix(rootNode.getPrefix());
- rpcErrorNode.appendChild(errorInfoNode);
- for (final Entry<String, String> errorInfoEntry : sendErrorException.getErrorInfo().entrySet()) {
- final Node node = errorDocument.createElementNS(
- XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, errorInfoEntry.getKey());
- node.setTextContent(errorInfoEntry.getValue());
- errorInfoNode.appendChild(node);
- }
-
- }
- return errorDocument;
+ return sendErrorException.toXMLDocument();
}
/**
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+
public final class XMLNetconfUtil {
private XMLNetconfUtil() {}
import com.google.common.base.Charsets;
import com.google.common.base.Optional;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
+
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.validation.SchemaFactory;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
+
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<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>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.opendaylight</artifactId>
+ <version>1.4.2-SNAPSHOT</version>
+ <relativePath>../../commons/opendaylight</relativePath>
+ </parent>
+
+ <artifactId>swagger-ui</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <api.dir>${resource.dir}/apis</api.dir>
+ <resource.dir>${project.build.directory}/classes</resource.dir>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>equinoxSDK381</groupId>
+ <artifactId>javax.servlet</artifactId>
+ </dependency>
+ <!-- add dependency on all northbound bundles -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>connectionmanager.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>controllermanager.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>flowprogrammer.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>forwarding.staticrouting.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>hosttracker.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>networkconfig.bridgedomain.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>statistics.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>subnets.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>switchmanager.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>topology.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>usermanager.northbound</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package></Export-Package>
+ <Import-Package>org.slf4j,
+ javax.annotation,
+ javax.naming,
+ javax.servlet,
+ javax.servlet.annotation,
+ javax.servlet.http,
+ com.google.gson,</Import-Package>
+ <Export-Package></Export-Package>
+ <Include-Resource>apis=target/classes/apis,
+ index.html=target/classes/index.html,
+ apilist.json=target/classes/apilist.json,
+ css=target/classes/css,
+ lib=target/classes/lib,
+ swagger-ui.min.js=target/classes/swagger-ui.min.js,
+ swagger-ui.js=target/classes/swagger-ui.js,
+ images=target/classes/images,
+ WEB-INF/web.xml=target/classes/WEB-INF/web.xml</Include-Resource>
+ <Web-ContextPath>/swagger</Web-ContextPath>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.7</version>
+ <dependencies>
+ <dependency>
+ <groupId>ant-contrib</groupId>
+ <artifactId>ant-contrib</artifactId>
+ <version>1.0b3</version>
+ <exclusions>
+ <exclusion>
+ <groupId>ant</groupId>
+ <artifactId>ant</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+ <executions>
+ <execution>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <phase>generate-sources</phase>
+ <configuration>
+ <target>
+ <taskdef classpathref="maven.plugin.classpath" resource="net/sf/antcontrib/antlib.xml"></taskdef>
+ <patternset id="rest.paths">
+ <include name="**/enunciate/generate/swagger/ui/*.json"></include>
+ <exclude name="**/java-client/**"></exclude>
+ <exclude name="**/swagger-ui/**"></exclude>
+ </patternset>
+
+ <echo message="======== Assembling swagger docs ========"></echo>
+ <!-- make api directory -->
+ <mkdir dir="${api.dir}"></mkdir>
+ <!-- copy swagger libs -->
+ <copy todir="${resource.dir}">
+ <fileset dir="../subnets/target/enunciate/generate/swagger/ui">
+ <exclude name="**/*.json"></exclude>
+ <exclude name="**/*.png"></exclude>
+ <exclude name="**/index.html"></exclude>
+ </fileset>
+ </copy>
+ <!-- Copy NorthBound json files into ui directory-->
+ <copy todir="${api.dir}">
+ <fileset dir="${basedir}/../../..">
+ <patternset refid="rest.paths"></patternset>
+ </fileset>
+ <mapper>
+ <regexpmapper from="^(.*)/([^/]+)/*/target/enunciate/generate/swagger/ui/(.*Northbound).*$$" to="\3"></regexpmapper>
+ <regexpmapper from="^(.*)/([^/]+)/*/target/enunciate/generate/swagger/ui/(.*resource-list.json)$$" to="\2-\3"></regexpmapper>
+ </mapper>
+ </copy>
+
+ <!-- Correct base path -->
+ <replaceregexp match="/full" replace="">
+ <fileset dir="${api.dir}">
+ <include name="**/*Northbound"></include>
+ </fileset>
+ </replaceregexp>
+ <!-- Merge Resource list -->
+ <echo append="false" file="${resource.dir}/apilist.json">{
+ "swaggerVersion": "1.1",
+ "basePath": "http://localhost:8080/swagger/apis",
+ "apis": [</echo>
+ <for param="file">
+ <path>
+ <fileset dir="${api.dir}">
+ <include name="**/*resource-list.json"></include>
+ <exclude name="**/neutron*"></exclude>
+ </fileset>
+ </path>
+ <sequential>
+ <echo message="Processing json resource @{file}"></echo>
+ <loadfile property="jsoncontent" srcfile="@{file}">
+ <filterchain>
+ <headfilter lines="10"></headfilter>
+ <tailfilter lines="6"></tailfilter>
+ </filterchain>
+ </loadfile>
+ <echo append="true" file="${resource.dir}/apilist.json" message="${jsoncontent},"></echo>
+ <var name="jsoncontent" unset="true"></var>
+ </sequential>
+ </for>
+ <sequential>
+ <loadfile property="jsoncontent" srcfile="${api.dir}/neutron-resource-list.json">
+ <filterchain>
+ <headfilter lines="46"></headfilter>
+ <tailfilter lines="42"></tailfilter>
+ </filterchain>
+ </loadfile>
+ <echo append="true" file="${resource.dir}/apilist.json" message="${jsoncontent},"></echo>
+ <var name="jsoncontent" unset="true"></var>
+ </sequential>
+ <echo append="true" file="${resource.dir}/apilist.json">{ }
+ ]
+}</echo>
+
+ <!-- Remove .json from api paths -->
+ <replaceregexp file="${resource.dir}/apilist.json" flags="g" match=".json" replace=""></replaceregexp>
+ <replaceregexp file="${resource.dir}/apilist.json" flags="g" match="JAXRS" replace=""></replaceregexp>
+
+ <!-- cleanup resource files as we don't need them -->
+ <delete>
+ <fileset dir="${api.dir}" includes="**/*resource-list.json"></fileset>
+ </delete>
+ <echo message="======== Build successful ========"></echo>
+ </target>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+ </scm>
+</project>
--- /dev/null
+package org.opendaylight.controller.swaggerui;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+/**
+ * Servlet implementation class BasePathModifierServlet
+ */
+public class BasePathModifierServlet extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+ private static final Logger logger = LoggerFactory
+ .getLogger(BasePathModifierServlet.class);
+
+ private static final String API_BASE_PATH_SUFFIX = "/swagger/apis";
+ private static final String BASE_PATH_KEY = "basePath";
+
+ /**
+ * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
+ * response)
+ */
+ @Override
+ protected void doGet(HttpServletRequest request,
+ HttpServletResponse response) throws ServletException, IOException {
+ String resourcePath = request.getRequestURI().substring(
+ request.getContextPath().length());
+ logger.debug("Locating resource : {}.", resourcePath);
+ JsonObject jsonObject = null;
+ try {
+
+ InputStream stream = this.getServletContext().getResourceAsStream(
+ resourcePath);
+ if (stream == null) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND,
+ "API / API Listing not found");
+ return;
+ }
+ BufferedReader streamReader = new BufferedReader(
+ new InputStreamReader(stream, "UTF-8"));
+ StringBuilder responseStrBuilder = new StringBuilder();
+
+ String inputStr;
+ while ((inputStr = streamReader.readLine()) != null)
+ responseStrBuilder.append(inputStr);
+
+ JsonElement jelement = new JsonParser().parse(responseStrBuilder
+ .toString());
+ jsonObject = jelement.getAsJsonObject();
+
+ String basePath = jsonObject.get(BASE_PATH_KEY).getAsString();
+
+ // construct base path
+ StringBuilder requestURL = new StringBuilder();
+
+ requestURL.append(request.isSecure() ? "https://" : "http://")
+ .append(request.getServerName()).append(":")
+ .append(request.getServerPort());
+ if (!basePath.contains(requestURL)) {
+ String endPath = "";
+ if (basePath.contains(API_BASE_PATH_SUFFIX)) {
+ endPath = basePath.substring(basePath
+ .indexOf(API_BASE_PATH_SUFFIX));
+ }
+ basePath = requestURL + endPath;
+ logger.debug("Modified Base Path is {}", basePath);
+ jsonObject.addProperty(BASE_PATH_KEY, basePath);
+ }
+ } catch (Exception ex) {
+ logger.error("Error processing JSON data", ex);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+ "Could not read API Listing or APIs");
+ return;
+ }
+
+ try {
+ response.setContentType("application/json");
+ PrintWriter out = response.getWriter();
+ out.print(jsonObject);
+ out.flush();
+ } catch (Exception ex) {
+ logger.error("Error while writing response", ex);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+ "Internal Error while writing resposne");
+ }
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+ <servlet>
+ <servlet-name>BasePathModifierServlet</servlet-name>
+ <servlet-class>org.opendaylight.controller.swaggerui.BasePathModifierServlet</servlet-class>
+ </servlet>
+ <!-- Mapping for all northbound json files aka apis-->
+ <servlet-mapping>
+ <servlet-name>BasePathModifierServlet</servlet-name>
+ <url-pattern>/apis/*</url-pattern>
+ </servlet-mapping>
+ <!-- Mapping to get list of available NB apis -->
+ <servlet-mapping>
+ <servlet-name>BasePathModifierServlet</servlet-name>
+ <url-pattern>/apilist.json</url-pattern>
+ </servlet-mapping>
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ </welcome-file-list>
+</web-app>
--- /dev/null
+body #header a#logo {
+ font-size: 1.5em;
+ font-weight: bold;
+ text-decoration: none;
+ background: transparent url(../images/logo.png) no-repeat left center;
+ padding: 20px 0 20px 70px;
+ color: white;
+}
+
+div.footer {
+ display: none;
+}
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Swagger UI</title>
+ <link href='//fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
+ <link href='css/highlight.default.css' media='screen' rel='stylesheet' type='text/css'/>
+ <link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
+ <link href='css/custom.css' media='screen' rel='stylesheet' type='text/css'/>
+ <script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
+ <script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
+ <script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
+ <script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
+ <script src='lib/handlebars-1.0.rc.1.js' type='text/javascript'></script>
+ <script src='lib/underscore-min.js' type='text/javascript'></script>
+ <script src='lib/backbone-min.js' type='text/javascript'></script>
+ <script src='lib/swagger.js' type='text/javascript'></script>
+ <script src='swagger-ui.js' type='text/javascript'></script>
+ <script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
+
+ <script type="text/javascript">
+ $(function () {
+ window.swaggerUi = new SwaggerUi({
+ discoveryUrl:"./apilist.json",
+ apiKey:"",
+ dom_id:"swagger-ui-container",
+ supportHeaderParams: false,
+ supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
+ onComplete: function(swaggerApi, swaggerUi){
+ if(console) {
+ console.log("Loaded SwaggerUI")
+ console.log(swaggerApi);
+ console.log(swaggerUi);
+ }
+ $('pre code').each(function(i, e) {hljs.highlightBlock(e)});
+ },
+ onFailure: function(data) {
+ if(console) {
+ console.log("Unable to Load SwaggerUI");
+ console.log(data);
+ }
+ },
+ docExpansion: "none"
+ });
+
+ window.swaggerUi.load();
+ });
+
+ </script>
+</head>
+
+<body>
+ <div id='header'>
+ <div class="swagger-ui-wrap">
+ <a id="logo" href="http://www.opendaylight.org/">ODL NB API</a>
+ <form id='api_selector'>
+ <div class='input'>
+ <input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/>
+ </div>
+ <div class='input'>
+ <input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/>
+ </div>
+ <div class='input'><a id="explore" href="#">Explore</a></div>
+ </form>
+ </div>
+ </div>
+
+ <div id="message-bar" class="swagger-ui-wrap">
+
+ </div>
+
+ <div id="swagger-ui-container" class="swagger-ui-wrap">
+
+ </div>
+
+</body>
+
+</html>
</activation>
<modules>
<module>opendaylight/northbound/java-client</module>
+ <module>opendaylight/northbound/swagger-ui</module>
</modules>
</profile>
</profiles>