<java.version.target>1.7</java.version.target>
<!-- enforcer version -->
<enforcer.version>1.3.1</enforcer.version>
+ <exi.version>0.9.2</exi.version>
</properties>
<dependencyManagement>
<artifactId>org.openflow.openflowj</artifactId>
<version>1.0.2</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.thirdparty</groupId>
+ <artifactId>exificient</artifactId>
+ <version>${exi.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller.thirdparty</groupId>
<artifactId>com.sun.jersey.jersey-servlet</artifactId>
<artifactId>config-persister-impl</artifactId>
<version>${netconf.version}</version>
</dependency>
-
+ <dependency>
+ <groupId>org.opendaylight.controller.thirdparty</groupId>
+ <artifactId>exificient</artifactId>
+ <version>${exi.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.xerces</artifactId>
+ <version>2.11.0_1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.birt.runtime.3_7_1</groupId>
+ <artifactId>org.apache.xml.resolver</artifactId>
+ <version>1.2.0</version>
+ </dependency>
<!-- toaster example I'm pretty sure we should trim -->
-
<dependency>
<groupId>org.opendaylight.controller.samples</groupId>
<artifactId>sample-toaster</artifactId>
package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
-import com.google.common.base.Optional;
-import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
import org.opendaylight.controller.config.yang.store.api.YangStoreException;
import org.opendaylight.controller.config.yang.store.api.YangStoreService;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.yangtools.yang.model.api.Module;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
/**
* Manages life cycle of {@link YangStoreSnapshot}.
javax.management,
org.opendaylight.controller.config.api.jmx,
org.opendaylight.protocol.framework,
- org.w3c.dom
+ io.netty.channel,
+ io.netty.util.concurrent,
+ org.w3c.dom,
+ org.slf4j
</Import-Package>
<Export-Package>
org.opendaylight.controller.netconf.api,
</Export-Package>
</instructions>
</configuration>
- </plugin>
+ </plugin>
</plugins>
</build>
public interface NetconfOperationRouter extends AutoCloseable {
- Document onNetconfMessage(Document message) throws NetconfDocumentedException;
+ Document onNetconfMessage(Document message, NetconfSession session)
+ throws NetconfDocumentedException;
@Override
void close();
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.controller.netconf.api;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+
+import java.io.IOException;
+import java.util.Map;
+
import org.opendaylight.protocol.framework.AbstractProtocolSession;
+import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
+import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
+import org.opendaylight.protocol.framework.SessionListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public abstract class NetconfSession extends AbstractProtocolSession<NetconfMessage> {
- public abstract void sendMessage(NetconfMessage netconfMessage);
+ private ChannelHandler exiEncoder;
+ private String exiEncoderName;
+ private String removeAfterMessageSentname;
+ private String pmeName,pmdName;
+ private final Channel channel;
+ private final SessionListener sessionListener;
+ private final long sessionId;
+ private boolean up = false;
+ private static final Logger logger = LoggerFactory.getLogger(NetconfSession.class);
+ private static final int T = 0;
+
+ protected NetconfSession(SessionListener sessionListener, Channel channel, long sessionId) {
+ this.sessionListener = sessionListener;
+ this.channel = channel;
+ this.sessionId = sessionId;
+ logger.debug("Session {} created", toString());
+
+ ChannelHandler pmd = channel.pipeline().get(ProtocolMessageDecoder.class);
+ ChannelHandler pme = channel.pipeline().get(ProtocolMessageEncoder.class);
+
+ for (Map.Entry<String, ChannelHandler> entry:channel.pipeline().toMap().entrySet()){
+ if (entry.getValue().equals(pmd)){
+ pmdName = entry.getKey();
+ }
+ if (entry.getValue().equals(pme)){
+ pmeName = entry.getKey();
+ }
+ }
+ }
+ @Override
+ public void close() {
+ channel.close();
+ sessionListener.onSessionTerminated(this, new NetconfTerminationReason("Session closed"));
+ }
+
+ @Override
+ protected void handleMessage(NetconfMessage netconfMessage) {
+ logger.debug("handlign incomming message");
+ sessionListener.onMessage(this, netconfMessage);
+ }
+
+ public void sendMessage(NetconfMessage netconfMessage) {
+ channel.writeAndFlush(netconfMessage);
+ if (exiEncoder!=null){
+ if (channel.pipeline().get(exiEncoderName)== null){
+ channel.pipeline().addBefore(pmeName, exiEncoderName, exiEncoder);
+ }
+ }
+ if (removeAfterMessageSentname!=null){
+ channel.pipeline().remove(removeAfterMessageSentname);
+ removeAfterMessageSentname = null;
+ }
+ }
+
+ @Override
+ protected void endOfInput() {
+ logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
+ : "initialized");
+ if (isUp()) {
+ this.sessionListener.onSessionDown(this, new IOException("End of input detected. Close the session."));
+ }
+ }
+
+ @Override
+ protected void sessionUp() {
+ logger.debug("Session {} up", toString());
+ sessionListener.onSessionUp(this);
+ this.up = true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("ServerNetconfSession{");
+ sb.append("sessionId=").append(sessionId);
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public boolean isUp() {
+ return up;
+ }
+
+ public long getSessionId() {
+ return sessionId;
+ }
+
+ public <T extends ChannelHandler> T remove(Class<T> handlerType) {
+ return channel.pipeline().remove(handlerType);
+ }
+
+ public <T extends ChannelHandler> T getHandler(Class<T> handlerType) {
+ return channel.pipeline().get(handlerType);
+ }
+
+ public void addFirst(ChannelHandler handler, String name){
+ channel.pipeline().addFirst(name, handler);
+ }
+ public void addLast(ChannelHandler handler, String name){
+ channel.pipeline().addLast(name, handler);
+ }
+
+ public void addExiDecoder(String name,ChannelHandler handler){
+ if (channel.pipeline().get(name)== null){
+ channel.pipeline().addBefore(pmdName, name, handler);
+ }
+ }
+ public void addExiEncoderAfterMessageSent(String name, ChannelHandler handler){
+ this.exiEncoder = handler;
+ this.exiEncoderName = name;
+ }
+
+ public void addExiEncoder(String name, ChannelHandler handler){
+ channel.pipeline().addBefore(pmeName, name, handler);
+ }
+
+ public void removeAfterMessageSent(String handlerName){
+ this.removeAfterMessageSentname = handlerName;
+ }
+
}
+
package org.opendaylight.controller.netconf.client;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GlobalEventExecutor;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.protocol.framework.NeverReconnectStrategy;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.TimedReconnectStrategy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.protocol.framework.NeverReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.TimedReconnectStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+
public class NetconfClient implements Closeable {
private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
Preconditions.checkState(clientSession != null, "Client was not initialized successfully");
return Sets.newHashSet(clientSession.getServerCapabilities());
}
+
+ public NetconfClientSession getClientSession() {
+ return clientSession;
+ }
}
package org.opendaylight.controller.netconf.client;
import io.netty.channel.Channel;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
+
+import java.util.Collection;
+
import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.util.Collection;
-
public class NetconfClientSession extends NetconfSession {
- private final SessionListener sessionListener;
- private final long sessionId;
- private final Channel channel;
-
private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class);
private final Collection<String> capabilities;
- private boolean up;
public NetconfClientSession(SessionListener sessionListener, Channel channel, long sessionId,
Collection<String> capabilities) {
- this.sessionListener = sessionListener;
- this.channel = channel;
- this.sessionId = sessionId;
+ super(sessionListener,channel,sessionId);
this.capabilities = capabilities;
logger.debug("Client Session {} created", toString());
}
- @Override
- public void close() {
- channel.close();
- sessionListener.onSessionTerminated(this, new NetconfTerminationReason("Client Session closed"));
- }
-
- @Override
- protected void handleMessage(NetconfMessage netconfMessage) {
- logger.debug("Client Session {} received message {}", toString(),
- XmlUtil.toString(netconfMessage.getDocument()));
- sessionListener.onMessage(this, netconfMessage);
- }
-
- @Override
- public void sendMessage(NetconfMessage netconfMessage) {
- channel.writeAndFlush(netconfMessage);
- }
-
- @Override
- protected void endOfInput() {
- logger.debug("Client Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
- : "initialized");
- if (isUp()) {
- this.sessionListener.onSessionDown(this, new IOException("End of input detected. Close the session."));
- }
- }
-
- @Override
- protected void sessionUp() {
- logger.debug("Client Session {} up", toString());
- sessionListener.onSessionUp(this);
- this.up = true;
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("ClientNetconfSession{");
- sb.append("sessionId=").append(sessionId);
- sb.append('}');
- return sb.toString();
- }
-
- public boolean isUp() {
- return up;
- }
-
- public long getSessionId() {
- return sessionId;
- }
-
public Collection<String> getServerCapabilities() {
return capabilities;
}
+
}
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>urn:ietf:params:netconf:base:1.0</capability>
+ <capability>urn:ietf:params:netconf:capability:exi:1.0</capability>
</capabilities>
</hello>
\ No newline at end of file
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
-
<!-- test dependencies -->
<dependency>
<groupId>org.opendaylight.bgpcep</groupId>
io.netty.channel.socket,
io.netty.util,
io.netty.util.concurrent,
+ io.netty.buffer,
+ io.netty.handler.codec,
javax.management,
javax.net.ssl,
javax.xml.namespace,
org.opendaylight.controller.netconf.util.mapping,
org.opendaylight.controller.netconf.util.osgi,
org.opendaylight.controller.netconf.util.xml,
+ org.opendaylight.controller.netconf.util.handler,
org.opendaylight.protocol.framework,
org.osgi.framework,
org.osgi.util.tracker,
org.w3c.dom,
org.xml.sax,
org.opendaylight.controller.netconf.util.messages,
- org.opendaylight.controller.config.stat
+ org.opendaylight.controller.config.stat,
+ com.siemens.ct.exi.exceptions
</Import-Package>
</instructions>
</configuration>
package org.opendaylight.controller.netconf.impl;
import io.netty.channel.Channel;
-import org.opendaylight.controller.netconf.api.NetconfMessage;
+
import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.protocol.framework.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-
public class NetconfServerSession extends NetconfSession {
- private final SessionListener sessionListener;
- private final Channel channel;
-
private static final Logger logger = LoggerFactory.getLogger(NetconfServerSession.class);
- private final long sessionId;
- private boolean up = false;
public NetconfServerSession(SessionListener sessionListener, Channel channel, long sessionId) {
- this.sessionListener = sessionListener;
- this.channel = channel;
- this.sessionId = sessionId;
+ super(sessionListener,channel,sessionId);
logger.debug("Session {} created", toString());
}
-
- @Override
- public void close() {
- channel.close();
- sessionListener.onSessionTerminated(this, new NetconfTerminationReason("Session closed"));
- }
-
- @Override
- protected void handleMessage(NetconfMessage netconfMessage) {
- logger.debug("Session {} received message {}", toString(), XmlUtil.toString(netconfMessage.getDocument()));
- sessionListener.onMessage(this, netconfMessage);
- }
-
- public void sendMessage(NetconfMessage netconfMessage) {
- channel.writeAndFlush(netconfMessage);
- }
-
- @Override
- protected void endOfInput() {
- logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
- : "initialized");
- if (isUp()) {
- this.sessionListener.onSessionDown(this, new IOException("End of input detected. Close the session."));
- }
- }
-
- @Override
- protected void sessionUp() {
- logger.debug("Session {} up", toString());
- sessionListener.onSessionUp(this);
- this.up = true;
- }
-
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("ServerNetconfSession{");
- sb.append("sessionId=").append(sessionId);
- sb.append('}');
- return sb.toString();
- }
-
- public boolean isUp() {
- return up;
- }
-
- public long getSessionId() {
- return sessionId;
- }
}
package org.opendaylight.controller.netconf.impl;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import static com.google.common.base.Preconditions.checkState;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouterImpl;
import org.opendaylight.controller.netconf.util.messages.SendErrorExceptionUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
-import static com.google.common.base.Preconditions.checkState;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
public class NetconfServerSessionListener implements
SessionListener<NetconfMessage, NetconfServerSession, NetconfTerminationReason> {
Preconditions.checkState(operationRouter != null, "Cannot handle message, session up was not yet received");
// FIXME: there is no validation since the document may contain yang
// schemas
- final NetconfMessage message = processDocument(netconfMessage);
+ final NetconfMessage message = processDocument(netconfMessage,
+ session);
logger.debug("Respondign with message {}", XmlUtil.toString(message.getDocument()));
session.sendMessage(message);
logger.info("Session {} closed successfully", session.getSessionId());
}
- private NetconfMessage processDocument(final NetconfMessage netconfMessage) throws NetconfDocumentedException {
+ private NetconfMessage processDocument(final NetconfMessage netconfMessage,
+ NetconfSession session) throws NetconfDocumentedException {
final Document incommingDocument = netconfMessage.getDocument();
final Node rootNode = incommingDocument.getDocumentElement();
- if (rootNode.getNodeName().equals(XmlNetconfConstants.RPC_KEY)) {
+ if (rootNode.getLocalName().equals(XmlNetconfConstants.RPC_KEY)) {
final String messageId = rootNode.getAttributes().getNamedItem(MESSAGE_ID).getTextContent();
checkState(messageId != null);
final Document responseDocument = XmlUtil.newDocument();
- Document rpcReply = operationRouter.onNetconfMessage(incommingDocument);
+ Document rpcReply = operationRouter.onNetconfMessage(
+ incommingDocument, session);
responseDocument.appendChild(responseDocument.importNode(rpcReply.getDocumentElement(), true));
return new NetconfMessage(responseDocument);
} else {
private final SessionIdProvider idProvider;
public NetconfServerSessionListenerFactory(NetconfOperationServiceFactoryListener factoriesListener,
- DefaultCommitNotificationProducer commitNotifier, SessionIdProvider idProvider) {
+ DefaultCommitNotificationProducer commitNotifier,
+ SessionIdProvider idProvider) {
this.factoriesListener = factoriesListener;
this.commitNotifier = commitNotifier;
this.idProvider = idProvider;
CapabilityProvider capabilityProvider = new CapabilityProviderImpl(netconfOperationServiceSnapshot);
- NetconfOperationRouterImpl operationRouter = new NetconfOperationRouterImpl(netconfOperationServiceSnapshot,
- capabilityProvider, commitNotifier);
+ NetconfOperationRouterImpl operationRouter = new NetconfOperationRouterImpl(
+ netconfOperationServiceSnapshot, capabilityProvider,
+ commitNotifier);
return new NetconfServerSessionListener(operationRouter);
}
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.netconf.impl.mapping;\r
+\r
+import io.netty.buffer.ByteBuf;\r
+import io.netty.channel.ChannelHandlerContext;\r
+import io.netty.handler.codec.ByteToMessageDecoder;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.controller.netconf.util.xml.ExiParameters;\r
+import org.opendaylight.controller.netconf.util.xml.ExiUtil;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+public class ExiDecoderHandler extends ByteToMessageDecoder {\r
+\r
+ public static final String HANDLER_NAME;\r
+\r
+ static {\r
+ HANDLER_NAME = "exiDecoder";\r
+ }\r
+\r
+ private final static Logger logger = LoggerFactory\r
+ .getLogger(ExiDecoderHandler.class);\r
+\r
+ private ExiParameters parameters;\r
+\r
+ public ExiDecoderHandler(ExiParameters parameters) {\r
+ this.parameters = parameters;\r
+ }\r
+\r
+ @Override\r
+ protected void decode(ChannelHandlerContext ctx, ByteBuf in,\r
+ List<Object> out) {\r
+ try {\r
+ ExiUtil.decode(in, out, this.parameters);\r
+ } catch (Exception e) {\r
+ throw new IllegalStateException("Unable to decode exi message.");\r
+ }\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.netconf.impl.mapping;\r
+\r
+import io.netty.buffer.ByteBuf;\r
+import io.netty.channel.ChannelHandlerContext;\r
+import io.netty.handler.codec.MessageToByteEncoder;\r
+\r
+import org.opendaylight.controller.netconf.util.xml.ExiParameters;\r
+import org.opendaylight.controller.netconf.util.xml.ExiUtil;\r
+\r
+public class ExiEncoderHandler extends MessageToByteEncoder<Object> {\r
+\r
+ public static final String HANDLER_NAME;\r
+ static {\r
+ HANDLER_NAME = "exiEncoder";\r
+ }\r
+\r
+ private ExiParameters parameters;\r
+\r
+ public ExiEncoderHandler(ExiParameters parameters) {\r
+ this.parameters = parameters;\r
+ }\r
+\r
+ @Override\r
+ protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out)\r
+ throws Exception {\r
+ try {\r
+ ExiUtil.encode(msg, out, this.parameters);\r
+ } catch (Exception e) {\r
+ throw new IllegalStateException("Unable to encode exi message.");\r
+ }\r
+ }\r
+}\r
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
+import org.opendaylight.controller.netconf.api.NetconfSession;
+import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-public class DefaultCloseSession extends AbstractNetconfOperation {
+public class DefaultCloseSession extends AbstractNetconfOperation implements DefaultNetconfOperation {
public static final String CLOSE_SESSION = "close-session";
+ private NetconfSession netconfSession;
public DefaultCloseSession(String netconfSessionIdForReporting) {
super(netconfSessionIdForReporting);
opRouter.close();
return document.createElement(XmlNetconfConstants.OK);
}
+
+ @Override
+ public void setNetconfSession(NetconfSession s) {
+ this.netconfSession = s;
+ }
+
+ public NetconfSession getNetconfSession() {
+ return netconfSession;
+ }
}
package org.opendaylight.controller.netconf.impl.mapping.operations;
-import com.google.common.collect.Maps;
+import java.io.InputStream;
+import java.util.Map;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.io.InputStream;
-import java.util.Map;
+import com.google.common.collect.Maps;
public class DefaultCommit implements NetconfOperationFilter {
}
@Override
- public int getSoringOrder() {
+ public int getSortingOrder() {
return 0;
}
@Override
public int compareTo(NetconfOperationFilter o) {
- return Integer.compare(getSoringOrder(), o.getSoringOrder());
+ return Integer.compare(getSortingOrder(), o.getSortingOrder());
}
private boolean canHandle(OperationNameAndNamespace operationNameAndNamespace) {
}
private Element getConfigSnapshot(NetconfOperationRouter opRouter) throws NetconfDocumentedException {
- final Document responseDocument = opRouter.onNetconfMessage(getConfigMessage);
+ final Document responseDocument = opRouter.onNetconfMessage(
+ getConfigMessage, null);
XmlElement dataElement;
try {
package org.opendaylight.controller.netconf.impl.mapping.operations;
-import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
+import java.util.HashMap;
+import java.util.Map;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
+import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
+import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import java.util.HashMap;
-import java.util.Map;
+import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
-public final class DefaultGetSchema extends AbstractNetconfOperation {
+public final class DefaultGetSchema extends AbstractNetconfOperation implements DefaultNetconfOperation {
private final CapabilityProvider cap;
+ private NetconfSession netconfSession;
private static final Logger logger = LoggerFactory.getLogger(DefaultGetSchema.class);
}
}
+
+ public void setNetconfSession(NetconfSession s) {
+ this.netconfSession = s;
+ }
+
+ public NetconfSession getNetconfSession() {
+ return netconfSession;
+ }
}
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\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.NetconfOperationRouter;\r
+import org.opendaylight.controller.netconf.api.NetconfSession;\r
+import org.opendaylight.controller.netconf.impl.mapping.ExiDecoderHandler;\r
+import org.opendaylight.controller.netconf.impl.mapping.ExiEncoderHandler;\r
+import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;\r
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;\r
+import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;\r
+import org.opendaylight.controller.netconf.util.xml.ExiParameters;\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 org.w3c.dom.Document;\r
+import org.w3c.dom.Element;\r
+\r
+import com.siemens.ct.exi.exceptions.EXIException;\r
+\r
+public class DefaultStartExi extends AbstractNetconfOperation implements DefaultNetconfOperation {\r
+\r
+ public static final String START_EXI = "start-exi";\r
+\r
+ private static NetconfSession netconfSession;\r
+\r
+ private static final Logger logger = LoggerFactory.getLogger(DefaultStartExi.class);\r
+\r
+ public DefaultStartExi(String netconfSessionIdForReporting) {\r
+ super(netconfSessionIdForReporting);\r
+ }\r
+\r
+ @Override\r
+ protected HandlingPriority canHandle(String operationName,\r
+ String netconfOperationNamespace) {\r
+ if (operationName.equals(START_EXI) == false)\r
+ return HandlingPriority.CANNOT_HANDLE;\r
+ if (netconfOperationNamespace\r
+ .equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0) == false)\r
+ return HandlingPriority.CANNOT_HANDLE;\r
+\r
+ return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;\r
+ }\r
+\r
+ @Override\r
+ protected Element handle(Document document, XmlElement operationElement,\r
+ NetconfOperationRouter opRouter) throws NetconfDocumentedException {\r
+\r
+\r
+ Element getSchemaResult = document\r
+ .createElement(XmlNetconfConstants.OK);\r
+ XmlUtil.addNamespaceAttr(getSchemaResult,\r
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);\r
+\r
+\r
+ try {\r
+ ExiParameters exiParams = new ExiParameters();\r
+ exiParams.setParametersFromXmlElement(operationElement);\r
+\r
+ netconfSession.addExiDecoder(ExiDecoderHandler.HANDLER_NAME, new ExiDecoderHandler(exiParams));\r
+ netconfSession.addExiEncoderAfterMessageSent(ExiEncoderHandler.HANDLER_NAME,new ExiEncoderHandler(exiParams));\r
+\r
+ } catch (EXIException e) {\r
+ getSchemaResult = document\r
+ .createElement(XmlNetconfConstants.RPC_ERROR);\r
+ }\r
+\r
+ logger.info("{} operation successful", START_EXI);\r
+ logger.debug("received start-exi message {} ", XmlUtil.toString(document));\r
+ return getSchemaResult;\r
+\r
+ }\r
+\r
+ @Override\r
+ public void setNetconfSession(NetconfSession s) {\r
+ netconfSession = s;\r
+ }\r
+\r
+ public NetconfSession getNetconfSession() {\r
+ return netconfSession;\r
+ }\r
+\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\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.NetconfOperationRouter;\r
+import org.opendaylight.controller.netconf.api.NetconfSession;\r
+import org.opendaylight.controller.netconf.impl.mapping.ExiDecoderHandler;\r
+import org.opendaylight.controller.netconf.impl.mapping.ExiEncoderHandler;\r
+import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;\r
+import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;\r
+import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation;\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 org.w3c.dom.Document;\r
+import org.w3c.dom.Element;\r
+\r
+public class DefaultStopExi extends AbstractNetconfOperation implements DefaultNetconfOperation {\r
+\r
+ public static final String STOP_EXI = "stop-exi";\r
+ private NetconfSession netconfSession;\r
+\r
+ private static final Logger logger = LoggerFactory\r
+ .getLogger(DefaultStartExi.class);\r
+\r
+ public DefaultStopExi(String netconfSessionIdForReporting) {\r
+ super(netconfSessionIdForReporting);\r
+ }\r
+\r
+ @Override\r
+ protected HandlingPriority canHandle(String operationName,\r
+ String netconfOperationNamespace) {\r
+ if (operationName.equals(STOP_EXI) == false)\r
+ return HandlingPriority.CANNOT_HANDLE;\r
+ if (netconfOperationNamespace\r
+ .equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0) == false)\r
+ return HandlingPriority.CANNOT_HANDLE;\r
+\r
+ return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;\r
+ }\r
+\r
+ @Override\r
+ protected Element handle(Document document, XmlElement operationElement,\r
+ NetconfOperationRouter opRouter) throws NetconfDocumentedException {\r
+\r
+ netconfSession.remove(ExiDecoderHandler.class);\r
+ netconfSession.removeAfterMessageSent(ExiEncoderHandler.HANDLER_NAME);\r
+\r
+ Element getSchemaResult = document.createElement(XmlNetconfConstants.OK);\r
+ XmlUtil.addNamespaceAttr(getSchemaResult,\r
+ XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0);\r
+ logger.info("{} operation successful", STOP_EXI);\r
+ logger.debug("received stop-exi message {} ", XmlUtil.toString(document));\r
+ return getSchemaResult;\r
+ }\r
+\r
+ @Override\r
+ public void setNetconfSession(NetconfSession s) {\r
+ this.netconfSession = s;\r
+ }\r
+\r
+ public NetconfSession getNetconfSession() {\r
+ return netconfSession;\r
+ }\r
+}
\ No newline at end of file
*/
package org.opendaylight.controller.netconf.impl.osgi;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
+import org.opendaylight.controller.netconf.api.NetconfSession;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCommit;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultGetSchema;
+import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStartExi;
+import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultStopExi;
+import org.opendaylight.controller.netconf.mapping.api.DefaultNetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
public class NetconfOperationRouterImpl implements NetconfOperationRouter {
private final CapabilityProvider capabilityProvider;
+
public NetconfOperationRouterImpl(NetconfOperationServiceSnapshot netconfOperationServiceSnapshot,
- CapabilityProvider capabilityProvider, DefaultCommitNotificationProducer commitNotifier) {
+ CapabilityProvider capabilityProvider,
+ DefaultCommitNotificationProducer commitNotifier) {
this.netconfOperationServiceSnapshot = netconfOperationServiceSnapshot;
.getNetconfSessionIdForReporting()));
defaultNetconfOperations.add(new DefaultCloseSession(netconfOperationServiceSnapshot
.getNetconfSessionIdForReporting()));
+ defaultNetconfOperations.add(new DefaultStartExi(
+ netconfOperationServiceSnapshot
+ .getNetconfSessionIdForReporting()));
+ defaultNetconfOperations.add(new DefaultStopExi(
+ netconfOperationServiceSnapshot
+ .getNetconfSessionIdForReporting()));
allNetconfOperations = getAllNetconfOperations(defaultNetconfOperations, netconfOperationServiceSnapshot);
}
@Override
- public synchronized Document onNetconfMessage(Document message) throws NetconfDocumentedException {
- NetconfOperationExecution netconfOperationExecution = getNetconfOperationWithHighestPriority(message);
+ public synchronized Document onNetconfMessage(Document message,
+ NetconfSession session) throws NetconfDocumentedException {
+ NetconfOperationExecution netconfOperationExecution = getNetconfOperationWithHighestPriority(
+ message, session);
logger.debug("Forwarding netconf message {} to {}", XmlUtil.toString(message),
netconfOperationExecution.operationWithHighestPriority);
return chain.getFirst().execute(message, this);
}
- private NetconfOperationExecution getNetconfOperationWithHighestPriority(Document message) {
+ private NetconfOperationExecution getNetconfOperationWithHighestPriority(
+ Document message, NetconfSession session) {
// TODO test
- TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = getSortedNetconfOperationsWithCanHandle(message);
+ TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = getSortedNetconfOperationsWithCanHandle(
+ message, session);
Preconditions.checkState(sortedPriority.isEmpty() == false, "No %s available to handle message %s",
NetconfOperation.class.getName(), XmlUtil.toString(message));
return new NetconfOperationExecution(sortedPriority, highestFoundPriority);
}
- private TreeMap<HandlingPriority, Set<NetconfOperation>> getSortedNetconfOperationsWithCanHandle(Document message) {
+ private TreeMap<HandlingPriority, Set<NetconfOperation>> getSortedNetconfOperationsWithCanHandle(
+ Document message, NetconfSession session) {
TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority = Maps.newTreeMap();
for (NetconfOperation netconfOperation : allNetconfOperations) {
final HandlingPriority handlingPriority = netconfOperation.canHandle(message);
-
+ if (netconfOperation instanceof DefaultNetconfOperation) {
+ ((DefaultNetconfOperation) netconfOperation)
+ .setNetconfSession(session);
+ }
if (handlingPriority.equals(HandlingPriority.CANNOT_HANDLE) == false) {
Set<NetconfOperation> netconfOperations = sortedPriority.get(handlingPriority);
netconfOperations = checkIfNoOperationsOnPriority(sortedPriority, handlingPriority, netconfOperations);
return "NetconfOperationRouterImpl{" + "netconfOperationServiceSnapshot=" + netconfOperationServiceSnapshot
+ '}';
}
+
+
+
}
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>urn:ietf:params:netconf:base:1.0</capability>
+ <capability>urn:ietf:params:netconf:capability:exi:1.0</capability>
</capabilities>
<session-id>1</session-id>
</hello>
--- /dev/null
+package org.opendaylight.controller.netconf.impl;\r
+\r
+import static junit.framework.Assert.assertNotNull;\r
+import io.netty.buffer.ByteBuf;\r
+import io.netty.buffer.Unpooled;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.junit.Test;\r
+import org.opendaylight.controller.netconf.api.NetconfMessage;\r
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;\r
+import org.opendaylight.controller.netconf.util.xml.ExiParameters;\r
+import org.opendaylight.controller.netconf.util.xml.ExiUtil;\r
+import org.opendaylight.controller.netconf.util.xml.XmlElement;\r
+\r
+\r
+\r
+public class ExiEncodeDecodeTest {\r
+ @Test\r
+ public void encodeExi() throws Exception{\r
+\r
+ String startExiString = XmlFileLoader.xmlFileToString("netconfMessages/startExi.xml");\r
+ assertNotNull(startExiString);\r
+\r
+ NetconfMessage startExiMessage = XmlFileLoader.xmlFileToNetconfMessage(("netconfMessages/startExi.xml"));\r
+ assertNotNull(startExiMessage);\r
+\r
+ ExiParameters exiParams = new ExiParameters();\r
+ exiParams.setParametersFromXmlElement(XmlElement.fromDomElement(startExiMessage.getDocument().getDocumentElement()));\r
+ assertNotNull(exiParams);\r
+\r
+ ByteBuf encodedBuf = Unpooled.buffer();\r
+ ByteBuf sourceBuf = Unpooled.copiedBuffer(startExiString.getBytes());\r
+ ExiUtil.encode(sourceBuf, encodedBuf, exiParams);\r
+\r
+ List<Object> newOut = new ArrayList<Object>();\r
+ ExiUtil.decode(encodedBuf, newOut, exiParams);\r
+\r
+ ByteBuf decodedBuf = (ByteBuf)newOut.get(0);\r
+ String decodedString = new String(decodedBuf.array(),"UTF-8");\r
+ assertNotNull(decodedString);\r
+ }\r
+}\r
import org.opendaylight.controller.netconf.impl.NetconfServerSessionListenerFactory;
import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
import org.opendaylight.controller.netconf.impl.SessionIdProvider;
+import org.opendaylight.controller.netconf.impl.mapping.ExiDecoderHandler;
+import org.opendaylight.controller.netconf.impl.mapping.ExiEncoderHandler;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.netconf.util.xml.ExiParameters;
import org.opendaylight.controller.netconf.util.xml.XmlElement;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
// private static final Logger logger =
// LoggerFactory.getLogger(NetconfITTest.class);
//
+
private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023);
- private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession;
+ private NetconfMessage getConfig, getConfigCandidate, editConfig,
+ closeSession, startExi, stopExi;
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatch;
this.editConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/edit_config.xml");
this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
this.getConfigCandidate = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig_candidate.xml");
+ this.startExi = XmlFileLoader
+ .xmlFileToNetconfMessage("netconfMessages/startExi.xml");
+ this.stopExi = XmlFileLoader
+ .xmlFileToNetconfMessage("netconfMessages/stopExi.xml");
this.closeSession = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/closeSession.xml");
}
final Element rpcReply = message.getDocument().getDocumentElement();
final XmlElement resultElement = XmlElement.fromDomElement(rpcReply).getOnlyChildElement();
assertEquals("result", resultElement.getName());
+
final String namespace = resultElement.getNamespaceAttribute();
assertEquals(expectedNamespace, namespace);
}
});
}
+ @Test
+// @Ignore
+ public void testStartExi() throws Exception {
+ try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
+
+
+ Document rpcReply = netconfClient.sendMessage(this.startExi)
+ .getDocument();
+ assertIsOK(rpcReply);
+
+ ExiParameters exiParams = new ExiParameters();
+ exiParams.setParametersFromXmlElement(XmlElement.fromDomDocument(this.startExi.getDocument()));
+
+ netconfClient.getClientSession().addExiDecoder(ExiDecoderHandler.HANDLER_NAME, new ExiDecoderHandler(exiParams));
+ netconfClient.getClientSession().addExiEncoder(ExiEncoderHandler.HANDLER_NAME, new ExiEncoderHandler(exiParams));
+
+ rpcReply = netconfClient.sendMessage(this.editConfig)
+ .getDocument();
+ assertIsOK(rpcReply);
+
+ rpcReply = netconfClient.sendMessage(this.stopExi)
+ .getDocument();
+ assertIsOK(rpcReply);
+
+ }
+ }
+
@Test
public void testCloseSession() throws Exception {
try (NetconfClient netconfClient = createSession(tcpAddress, "1")) {
// edit config
- Document rpcReply = netconfClient.sendMessage(this.editConfig).getDocument();
+ Document rpcReply = netconfClient.sendMessage(this.editConfig)
+ .getDocument();
assertIsOK(rpcReply);
- rpcReply = netconfClient.sendMessage(this.closeSession).getDocument();
+ rpcReply = netconfClient.sendMessage(this.closeSession)
+ .getDocument();
assertIsOK(rpcReply);
}
}
private void assertIsOK(final Document rpcReply) {
- assertEquals("rpc-reply", rpcReply.getDocumentElement().getTagName());
+ assertEquals("rpc-reply", rpcReply.getDocumentElement().getLocalName());
assertEquals("ok", XmlElement.fromDomDocument(rpcReply).getOnlyChildElement().getName());
}
private NetconfClient createSession(final InetSocketAddress address, final String expected) throws Exception {
final NetconfClient netconfClient = new NetconfClient("test " + address.toString(), address, 5000, NETCONF_CLIENT_DISPATCHER);
-
assertEquals(expected, Long.toString(netconfClient.getSessionId()));
-
return netconfClient;
}
--- /dev/null
+package org.opendaylight.controller.netconf.mapping.api;\r
+\r
+import org.opendaylight.controller.netconf.api.NetconfSession;\r
+\r
+public interface DefaultNetconfOperation {\r
+ void setNetconfSession(NetconfSession s);\r
+}\r
Document doFilter(Document message, NetconfOperationRouter operationRouter, NetconfOperationFilterChain filterChain)
throws NetconfDocumentedException;
- int getSoringOrder();
+ int getSortingOrder();
}
<artifactId>netty-handler</artifactId>
<version>${netconf.netty.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.siemens.ct.exi</groupId>
+ <artifactId>exificient</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller.thirdparty</groupId>
<artifactId>ganymed</artifactId>
org.opendaylight.controller.netconf.util.osgi,
org.opendaylight.controller.netconf.util.mapping,
org.opendaylight.controller.netconf.util.messages,
+ org.opendaylight.controller.netconf.util.handler,
</Export-Package>
<Import-Package>
org.opendaylight.controller.config.stat,
javax.xml.transform.stream,
javax.xml.validation,
javax.xml.xpath,
+ javax.xml.transform.sax,
org.opendaylight.controller.netconf.api,
org.opendaylight.controller.netconf.mapping.api,
org.opendaylight.protocol.framework,
org.slf4j,
org.w3c.dom,
org.xml.sax,
+ com.siemens.ct.exi,
+ com.siemens.ct.exi.api.sax,
+ com.siemens.ct.exi.grammars,
+ com.siemens.ct.exi.helpers,
+ com.siemens.ct.exi.exceptions,
+ com.siemens.ct.exi.api.dom,
+ org.xml.sax.helpers,
</Import-Package>
</instructions>
</configuration>
package org.opendaylight.controller.netconf.util.handler;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
import java.util.List;
import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import io.netty.buffer.ByteBuf;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.ByteToMessageDecoder;
-
public class NetconfMessageAggregator extends ByteToMessageDecoder {
private final static Logger logger = LoggerFactory.getLogger(NetconfMessageAggregator.class);
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
int index = indexOfSequence(in, eom);
if (index == -1) {
- logger.debug("Message is not complete, read agian.");
+ logger.debug("Message is not complete, read again.");
ctx.read();
} else {
ByteBuf msg = in.readBytes(index);
package org.opendaylight.controller.netconf.util.mapping;
-import java.util.Map;
-
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import java.util.Map;
public abstract class AbstractNetconfOperation implements NetconfOperation {
private final String netconfSessionIdForReporting;
Map<String, Attr> attributes = requestElement.getAttributes();
Element response = handle(document, operationElement, opRouter);
-
Element rpcReply = document.createElementNS(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0,
XmlNetconfConstants.RPC_REPLY_KEY);
- rpcReply.appendChild(response);
- for (String attrName : attributes.keySet()) {
- rpcReply.setAttribute(attrName, attributes.get(attrName).getNodeValue());
+ if(XmlElement.fromDomElement(response).hasNamespace()) {
+ rpcReply.appendChild(response);
+ } else {
+ Element responseNS = document.createElementNS(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, response.getNodeName());
+ NodeList list = response.getChildNodes();
+ while(list.getLength()!=0) {
+ responseNS.appendChild(list.item(0));
+ }
+ rpcReply.appendChild(responseNS);
}
+ for (String attrName : attributes.keySet()) {
+ rpcReply.setAttributeNode((Attr) document.importNode(attributes.get(attrName), true));
+ }
document.appendChild(rpcReply);
return document;
}
--- /dev/null
+package org.opendaylight.controller.netconf.util.xml;\r
+\r
+import com.siemens.ct.exi.CodingMode;\r
+import com.siemens.ct.exi.FidelityOptions;\r
+import com.siemens.ct.exi.GrammarFactory;\r
+import com.siemens.ct.exi.exceptions.EXIException;\r
+import com.siemens.ct.exi.grammars.Grammars;\r
+\r
+public class ExiParameters {\r
+\r
+ private static final String EXI_PARAMETER_ALIGNMENT = "alignment";\r
+ private static final String EXI_PARAMETER_BYTE_ALIGNED = "byte-aligned";\r
+ private static final String EXI_PARAMETER_COMPRESSED = "compressed";\r
+\r
+ private static final String EXI_PARAMETER_FIDELITY = "fidelity";\r
+ private static final String EXI_FIDELITY_DTD = "dtd";\r
+ private static final String EXI_FIDELITY_LEXICAL_VALUES = "lexical-values";\r
+ private static final String EXI_FIDELITY_COMMENTS = "comments";\r
+ private static final String EXI_FIDELITY_PIS = "pis";\r
+ private static final String EXI_FIDELITY_PREFIXES = "prefixes";\r
+\r
+ private static final String EXI_PARAMETER_SCHEMA = "schema";\r
+ private static final String EXI_PARAMETER_SCHEMA_NONE = "none";\r
+ private static final String EXI_PARAMETER_SCHEMA_BUILT_IN = "builtin";\r
+ private static final String EXI_PARAMETER_SCHEMA_BASE_1_1 = "base:1.1";\r
+\r
+ private static final String NETCONF_XSD_LOCATION = "";\r
+\r
+ private FidelityOptions fidelityOptions;\r
+ private Grammars grammars;\r
+ private CodingMode codingMode = CodingMode.BIT_PACKED;\r
+\r
+ public void setParametersFromXmlElement(XmlElement operationElement)\r
+ throws EXIException {\r
+\r
+ if (operationElement.getElementsByTagName(EXI_PARAMETER_ALIGNMENT)\r
+ .getLength() > 0) {\r
+\r
+ if (operationElement.getElementsByTagName(\r
+ EXI_PARAMETER_BYTE_ALIGNED)\r
+ .getLength() > 0) {\r
+ this.codingMode = CodingMode.BYTE_PACKED;\r
+ }\r
+\r
+ if (operationElement.getElementsByTagName(\r
+ EXI_PARAMETER_BYTE_ALIGNED).getLength() > 0) {\r
+ this.codingMode = CodingMode.BYTE_PACKED;\r
+ }\r
+ if (operationElement.getElementsByTagName(EXI_PARAMETER_COMPRESSED)\r
+ .getLength() > 0) {\r
+ this.codingMode = CodingMode.COMPRESSION;\r
+ }\r
+ }\r
+\r
+ if (operationElement.getElementsByTagName(EXI_PARAMETER_FIDELITY)\r
+ .getLength() > 0) {\r
+\r
+ this.fidelityOptions = FidelityOptions.createDefault();\r
+\r
+ if (operationElement.getElementsByTagName(EXI_FIDELITY_DTD)\r
+ .getLength() > 0) {\r
+ this.fidelityOptions.setFidelity(FidelityOptions.FEATURE_DTD,\r
+ true);\r
+ }\r
+ if (operationElement.getElementsByTagName(\r
+ EXI_FIDELITY_LEXICAL_VALUES)\r
+ .getLength() > 0) {\r
+ this.fidelityOptions.setFidelity(\r
+ FidelityOptions.FEATURE_LEXICAL_VALUE, true);\r
+ }\r
+\r
+ if (operationElement.getElementsByTagName(EXI_FIDELITY_COMMENTS)\r
+ .getLength() > 0) {\r
+ this.fidelityOptions.setFidelity(\r
+ FidelityOptions.FEATURE_COMMENT, true);\r
+ }\r
+\r
+ if (operationElement.getElementsByTagName(EXI_FIDELITY_PIS)\r
+ .getLength() > 0) {\r
+ this.fidelityOptions.setFidelity(FidelityOptions.FEATURE_PI,\r
+ true);\r
+ }\r
+\r
+ if (operationElement.getElementsByTagName(EXI_FIDELITY_PREFIXES)\r
+ .getLength() > 0) {\r
+ this.fidelityOptions.setFidelity(\r
+ FidelityOptions.FEATURE_PREFIX, true);\r
+ }\r
+\r
+ }\r
+\r
+ if (operationElement.getElementsByTagName(EXI_PARAMETER_SCHEMA)\r
+ .getLength() > 0) {\r
+\r
+ GrammarFactory grammarFactory = GrammarFactory.newInstance();\r
+ if (operationElement\r
+ .getElementsByTagName(EXI_PARAMETER_SCHEMA_NONE)\r
+ .getLength() > 0) {\r
+ this.grammars = grammarFactory.createSchemaLessGrammars();\r
+ }\r
+\r
+ if (operationElement.getElementsByTagName(\r
+ EXI_PARAMETER_SCHEMA_BUILT_IN).getLength() > 0) {\r
+ this.grammars = grammarFactory.createXSDTypesOnlyGrammars();\r
+ }\r
+\r
+ if (operationElement.getElementsByTagName(\r
+ EXI_PARAMETER_SCHEMA_BASE_1_1).getLength() > 0) {\r
+ this.grammars = grammarFactory\r
+ .createGrammars(NETCONF_XSD_LOCATION);\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ public FidelityOptions getFidelityOptions() {\r
+ return fidelityOptions;\r
+ }\r
+\r
+ public Grammars getGrammars() {\r
+ return grammars;\r
+ }\r
+\r
+ public CodingMode getCodingMode() {\r
+ return codingMode;\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.opendaylight.controller.netconf.util.xml;\r
+\r
+import io.netty.buffer.ByteBuf;\r
+import io.netty.buffer.EmptyByteBuf;\r
+import io.netty.buffer.Unpooled;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.util.List;\r
+\r
+import javax.xml.parsers.ParserConfigurationException;\r
+\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+import org.w3c.dom.Document;\r
+import org.xml.sax.SAXException;\r
+\r
+import com.siemens.ct.exi.EXIFactory;\r
+import com.siemens.ct.exi.api.dom.DOMBuilder;\r
+import com.siemens.ct.exi.api.dom.DOMWriter;\r
+import com.siemens.ct.exi.exceptions.EXIException;\r
+import com.siemens.ct.exi.helpers.DefaultEXIFactory;\r
+\r
+public class ExiUtil {\r
+\r
+ private final static Logger logger = LoggerFactory.getLogger(ExiUtil.class);\r
+\r
+\r
+\r
+ public static void encode(final Object msg, final ByteBuf out,\r
+ ExiParameters parameters)\r
+ throws EXIException, IOException, SAXException {\r
+ final byte[] bytes = toExi(msg, parameters);\r
+ out.writeBytes(bytes);\r
+ }\r
+\r
+ public static void decode(ByteBuf in, List<Object> out,\r
+ ExiParameters parameters) throws ParserConfigurationException, EXIException, IOException\r
+ {\r
+ if (in instanceof EmptyByteBuf){\r
+ return;\r
+ }\r
+\r
+ EXIFactory exiFactory = DefaultEXIFactory.newInstance();\r
+ if (parameters.getGrammars() != null) {\r
+ exiFactory.setGrammars(parameters.getGrammars());\r
+ }\r
+\r
+ if (parameters.getFidelityOptions() != null) {\r
+ exiFactory.setFidelityOptions(parameters.getFidelityOptions());\r
+ }\r
+\r
+ exiFactory.setCodingMode(parameters.getCodingMode());\r
+ try (ByteArrayInputStream exiIS = new ByteArrayInputStream(((ByteBuf)in).readBytes(((ByteBuf)in).readableBytes()).array())){\r
+ DOMBuilder domBuilder = new DOMBuilder(exiFactory);\r
+ ByteBuf result = Unpooled.copiedBuffer(XmlUtil.toString(domBuilder.parse(exiIS)).getBytes());\r
+ exiIS.close();\r
+ out.add(result);\r
+ }\r
+ }\r
+\r
+ private static byte[] toExi(Object msg, ExiParameters parameters) throws EXIException, IOException,\r
+ SAXException {\r
+\r
+ if (!(msg instanceof ByteBuf)){\r
+ return Unpooled.EMPTY_BUFFER.array();\r
+ }\r
+\r
+ EXIFactory exiFactory = DefaultEXIFactory.newInstance();\r
+ if (parameters.getGrammars() != null) {\r
+ exiFactory.setGrammars(parameters.getGrammars());\r
+ }\r
+\r
+ if (parameters.getFidelityOptions() != null) {\r
+ exiFactory.setFidelityOptions(parameters.getFidelityOptions());\r
+ }\r
+\r
+ Document doc = XmlUtil.readXmlToDocument(new String( ((ByteBuf)msg).readBytes(((ByteBuf)msg).readableBytes()).array(),"UTF-8"));\r
+ exiFactory.setCodingMode(parameters.getCodingMode());\r
+\r
+ try (ByteArrayOutputStream exiOS = new ByteArrayOutputStream()){\r
+ DOMWriter domWriter = new DOMWriter(exiFactory);\r
+ domWriter.setOutput(exiOS);\r
+ domWriter.encode(doc) ;\r
+ exiOS.close();\r
+ return exiOS.toByteArray();\r
+ }\r
+ }\r
+\r
+}\r
}
public String getName() {
+ if (element.getLocalName()!=null && !element.getLocalName().equals("")){
+ return element.getLocalName();
+ }
return element.getTagName();
}
return element.getAttributeNS(namespace, attributeName);
}
+ public NodeList getElementsByTagName(String name) {
+ return element.getElementsByTagName(name);
+ }
+
public void appendChild(Element element) {
this.element.appendChild(element);
// Element newElement = (Element) element.cloneNode(true);
public String getNamespaceAttribute() {
String attribute = element.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY);
- Preconditions.checkState(attribute != null && !attribute.equals(""), "Element %s must specify a %s attribute",
- toString(), XmlUtil.XMLNS_ATTRIBUTE_KEY);
+ Preconditions.checkState(attribute != null && !attribute.equals(""), "Element %s must specify namespace",
+ toString());
return attribute;
}
return element.hashCode();
}
+ public boolean hasNamespace() {
+ try {
+ getNamespaceAttribute();
+ } catch (IllegalStateException e) {
+ try {
+ getNamespace();
+ } catch (IllegalStateException e1) {
+ return false;
+ }
+ return true;
+ }
+ return true;
+ }
+
private static interface ElementFilteringStrategy {
boolean accept(Element e);
}
//
public static final String RFC4741_TARGET_NAMESPACE = "urn:ietf:params:xml:ns:netconf:base:1.0";
public static final String URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0 = "urn:ietf:params:xml:ns:netconf:base:1.0";
+
public static final String URN_IETF_PARAMS_XML_NS_YANG_IETF_NETCONF_MONITORING = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring";
// TODO where to store namespace of config ?
public static final String URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG = "urn:opendaylight:params:xml:ns:yang:controller:config";
package org.opendaylight.controller.netconf.util.xml;
-import com.google.common.base.Charsets;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.xml.sax.SAXException;
+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.validation.SchemaFactory;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
-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 org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+import com.google.common.base.Charsets;
public class XmlUtil {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setCoalescing(true);
- // factory.setValidating(true);
factory.setIgnoringElementContentWhitespace(true);
factory.setIgnoringComments(true);
return factory;
package org.opendaylight.controller.netconf.util.test;
-import com.google.common.base.Charsets;
-import com.google.common.base.Preconditions;
-import com.google.common.io.CharStreams;
-import com.google.common.io.InputSupplier;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import javax.xml.parsers.ParserConfigurationException;
+
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+import com.google.common.io.CharStreams;
+import com.google.common.io.InputSupplier;
public class XmlFileLoader {
--- /dev/null
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" a="64" message-id="a">\r
+<start-exi>\r
+<alignment>pre-compression</alignment>\r
+<fidelity>\r
+<dtd/>\r
+<lexical-values/>\r
+</fidelity>\r
+</start-exi>\r
+</rpc>
\ No newline at end of file
--- /dev/null
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">\r
+ <stop-exi/>\r
+</rpc>
\ No newline at end of file
<module>netconf-mapping-api</module>
<module>netconf-client</module>
<module>../../third-party/ganymed</module>
+ <module>../../third-party/com.siemens.ct.exi</module>
</modules>
<profiles>
<maven.bundle.version>2.3.7</maven.bundle.version>
<slf4j.version>1.7.2</slf4j.version>
<netconf.netty.version>4.0.10.Final</netconf.netty.version>
+ <ct.exi.version>0.9.2</ct.exi.version>
</properties>
<dependencies>
<artifactId>logback-config</artifactId>
<version>${config.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.siemens.ct.exi</groupId>
+ <artifactId>exificient</artifactId>
+ <version>${ct.exi.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
--- /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/maven-v4_0_0.xsd">
+ <!-- Get some common settings for the project we are using it in -->
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.thirdparty</artifactId>
+ <version>1.1.1-SNAPSHOT</version>
+ <relativePath>../commons/thirdparty</relativePath>
+ </parent>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+ <tag>HEAD</tag>
+ </scm>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.opendaylight.controller.thirdparty</groupId>
+ <artifactId>exificient</artifactId>
+ <version>0.9.2</version>
+ <packaging>bundle</packaging>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.3.6</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Embed-Dependency>*;scope=!provided;type=!pom;inline=false</Embed-Dependency>
+ <Embed-Transitive>false</Embed-Transitive>
+ <Export-Package>
+ com.siemens.ct.exi.*,
+ </Export-Package>
+ <Import-Package>
+ javax.xml.namespace,
+ javax.xml.parsers,
+ javax.xml.stream,
+ javax.xml.stream.events,
+ javax.xml.transform.sax,
+ org.apache.xerces.impl.xs,
+ org.apache.xerces.impl.xs.models,
+ org.apache.xerces.xni,
+ org.apache.xerces.xni.grammars,
+ org.apache.xerces.xni.parser,
+ org.apache.xerces.xs,
+ org.w3c.dom,
+ org.xml.sax,
+ org.xml.sax.ext,
+ org.xml.sax.helpers
+ </Import-Package>
+ </instructions>
+ <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>com.siemens.ct.exi</groupId>
+ <artifactId>exificient</artifactId>
+ <version>0.9.2</version>
+ </dependency>
+ </dependencies>
+
+</project>