@Immutable
public final class HexDumpBGPFileParser {
private static final int MINIMAL_LENGTH = 19;
- private static final Logger logger = LoggerFactory.getLogger(HexDumpBGPFileParser.class);
+ private static final Logger LOG = LoggerFactory.getLogger(HexDumpBGPFileParser.class);
private static final String FF_16 = Strings.repeat("FF", 16);
private HexDumpBGPFileParser() {
// search for 16 FFs
final List<byte[]> messages = Lists.newLinkedList();
- int idx = 0;
- while ((idx = content.indexOf(FF_16, idx)) > -1) {
+ int idx = content.indexOf(FF_16, 0);
+ while (idx > -1) {
// next 2 bytes are length
final int lengthIdx = idx + 16 * 2;
final int messageIdx = lengthIdx + 4;
}
messages.add(message);
idx = messageEndIdx;
+ idx = content.indexOf(FF_16, idx);
}
- logger.info("Succesfully extracted {} messages", messages.size());
+ LOG.info("Succesfully extracted {} messages", messages.size());
return messages;
}
static String clearWhiteSpaceToUpper(final String line) {
return line.replaceAll("\\s", "").toUpperCase();
}
-
}
--- /dev/null
+Received PCEP Open message. Length:28.
+
+20 01 00 1c 01 10 00 18 20 1e 78 03 00 10 00 04
+00 00 00 05 00 1a 00 04 00 00 00 b4
+
+Received PCEP Keepalive message. Length:4.
+
+20 02 00 04
+
+Received PCEPReport message. Length:12.
+
+20 0a 00 0c 20 10 00 08 00 00 00 00
+
+Received PCEPReport message. Length:56.
+
+20 0a 00 38 20 10 00 34 00 00 50 01 00 11 00 28
+74 75 6e 6e 65 6c 5f 66 72 6f 6d 5f 4f 66 2d 39
+6b 2d 30 32 5f 74 6f 5f 4f 66 2d 39 6b 2d 30 33
+4f 66 2d 39 6b 2d 30 32
+
+Received PCEPReport message. Length:120.
+
+20 0a 00 78 20 10 00 44 00 00 50 05 00 11 00 28
+74 75 6e 6e 65 6c 5f 66 72 6f 6d 5f 4f 66 2d 39
+6b 2d 30 32 5f 74 6f 5f 4f 66 2d 39 6b 2d 30 33
+4f 66 2d 39 6b 2d 30 32 00 12 00 0c 2a 2a 2a 2a
+00 00 00 04 2a 2a 2a 2a 07 10 00 14 01 08 c6 14
+a0 2b 20 00 01 08 2b 2b 2b 2b 20 00 09 10 00 14
+00 00 00 00 00 00 00 00 00 00 00 00 07 07 00 00
+05 20 00 08 00 00 00 00
+
+Received PCEPReport message. Length:56.
+
+20 0a 00 38 20 10 00 34 00 00 50 0c 00 11 00 28
+74 75 6e 6e 65 6c 5f 66 72 6f 6d 5f 4f 66 2d 39
+6b 2d 30 32 5f 74 6f 5f 4f 66 2d 39 6b 2d 30 33
+4f 66 2d 39 6b 2d 30 32
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Open;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.OpenBuilder;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
public final class DefaultPCEPSessionNegotiator extends AbstractPCEPSessionNegotiator {
}
@Override
- protected PCEPSessionImpl createSession(final Timer timer, final Channel channel, final Open localPrefs, final Open remotePrefs) {
+ @VisibleForTesting
+ public PCEPSessionImpl createSession(final Timer timer, final Channel channel, final Open localPrefs, final Open remotePrefs) {
return new PCEPSessionImpl(timer, this.listener, this.maxUnknownMessages, channel, localPrefs, remotePrefs);
}
}
@Override
- protected void sessionUp() {
+ @VisibleForTesting
+ public void sessionUp() {
this.listener.onSessionUp(this);
}
<groupId>${project.groupId}</groupId>
<artifactId>mockito-configuration</artifactId>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>pcep-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
</dependencies>
<build>
import io.netty.util.concurrent.FutureListener;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.OperationResult;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.PccSyncState;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.RemoveLspArgs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.TopologyTypes1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.TopologyTypes1Builder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.UpdateLspArgs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClient;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.PathComputationClientBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLsps;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.ReportedLspsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev131024.topology.pcep.type.TopologyPcepBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypesBuilder;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
/**
*
*/
-final class ServerSessionManager implements SessionListenerFactory<PCEPSessionListener> {
+final class ServerSessionManager implements SessionListenerFactory<PCEPSessionListener>, AutoCloseable {
private static String createNodeId(final InetAddress addr) {
return "pcc://" + addr.getHostAddress();
}
final DataModificationTransaction trans = ServerSessionManager.this.dataProvider.beginTransaction();
// The session went down. Undo all the Topology changes we have done.
- trans.removeRuntimeData(this.topologyAugment);
+ trans.removeOperationalData(this.topologyAugment);
if (this.ownsTopology) {
- trans.removeRuntimeData(this.topologyNode);
+ trans.removeOperationalData(this.topologyNode);
}
- Futures.addCallback(JdkFutureAdapters.listenInPoolThread(trans.commit()),
- new FutureCallback<RpcResult<TransactionStatus>>() {
+ Futures.addCallback(JdkFutureAdapters.listenInPoolThread(trans.commit()), new FutureCallback<RpcResult<TransactionStatus>>() {
@Override
public void onSuccess(final RpcResult<TransactionStatus> result) {
// Nothing to do
}
private InstanceIdentifier<ReportedLsps> lspIdentifier(final SymbolicPathName name) {
- return InstanceIdentifier.builder(this.topologyAugment).
- child(PathComputationClient.class).
- child(ReportedLsps.class, new ReportedLspsKey(name.getPathName())).toInstance();
+ return InstanceIdentifier.builder(this.topologyAugment).child(PathComputationClient.class).child(ReportedLsps.class,
+ new ReportedLspsKey(name.getPathName())).toInstance();
}
@Override
if (lsp.isRemove()) {
final SymbolicPathName name = this.lsps.remove(id);
if (name != null) {
- trans.removeRuntimeData(lspIdentifier(name));
+ trans.removeOperationalData(lspIdentifier(name));
}
LOG.debug("LSP {} removed", lsp);
// TODO: what should we do here?
continue;
}
+ this.lsps.put(id, name);
}
final SymbolicPathName name = this.lsps.get(id);
}
}
- Futures.addCallback(JdkFutureAdapters.listenInPoolThread(trans.commit()),
- new FutureCallback<RpcResult<TransactionStatus>>() {
+ Futures.addCallback(JdkFutureAdapters.listenInPoolThread(trans.commit()), new FutureCallback<RpcResult<TransactionStatus>>() {
@Override
public void onSuccess(final RpcResult<TransactionStatus> result) {
// Nothing to do
public ServerSessionManager(final DataProviderService dataProvider, final InstanceIdentifier<Topology> topology) {
this.dataProvider = Preconditions.checkNotNull(dataProvider);
this.topology = Preconditions.checkNotNull(topology);
+
+ // Make sure the topology does not exist
+ final Object c = dataProvider.readOperationalData(topology);
+ Preconditions.checkArgument(c == null, "Topology %s already exists", topology);
+
+ // Now create the base topology
+ final TopologyKey k = InstanceIdentifier.keyOf(topology);
+ final DataModificationTransaction t = dataProvider.beginTransaction();
+ t.putOperationalData(
+ topology,
+ new TopologyBuilder().setKey(k).setTopologyId(k.getTopologyId()).setTopologyTypes(
+ new TopologyTypesBuilder().addAugmentation(TopologyTypes1.class,
+ new TopologyTypes1Builder().setTopologyPcep(new TopologyPcepBuilder().build()).build()).build()).setNode(
+ new ArrayList<Node>()).build());
+
+ // FIXME: attach to the future to notify of failures
+ t.commit();
+
}
@Override
}
// Make sure there is no such LSP
- final InstanceIdentifier<ReportedLsps> lsp = InstanceIdentifier.builder(l.topologyAugment).
- child(PathComputationClient.class).
- child(ReportedLsps.class, new ReportedLspsKey(input.getName())).toInstance();
+ final InstanceIdentifier<ReportedLsps> lsp = InstanceIdentifier.builder(l.topologyAugment).child(PathComputationClient.class).child(
+ ReportedLsps.class, new ReportedLspsKey(input.getName())).toInstance();
if (this.dataProvider.readOperationalData(lsp) != null) {
LOG.debug("Node {} already contains lsp {} at {}", input.getNode(), input.getName(), lsp);
return Futures.immediateFuture(OPERATION_UNSENT);
}
// Make sure the LSP exists, we need it for PLSP-ID
- final InstanceIdentifier<ReportedLsps> lsp = InstanceIdentifier.builder(l.topologyAugment).
- child(PathComputationClient.class).
- child(ReportedLsps.class, new ReportedLspsKey(input.getName())).toInstance();
+ final InstanceIdentifier<ReportedLsps> lsp = InstanceIdentifier.builder(l.topologyAugment).child(PathComputationClient.class).child(
+ ReportedLsps.class, new ReportedLspsKey(input.getName())).toInstance();
final ReportedLsps rep = (ReportedLsps) this.dataProvider.readOperationalData(lsp);
if (rep == null) {
LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
}
// Make sure the LSP exists
- final InstanceIdentifier<ReportedLsps> lsp = InstanceIdentifier.builder(l.topologyAugment).
- child(PathComputationClient.class).
- child(ReportedLsps.class, new ReportedLspsKey(input.getName())).toInstance();
+ final InstanceIdentifier<ReportedLsps> lsp = InstanceIdentifier.builder(l.topologyAugment).child(PathComputationClient.class).child(
+ ReportedLsps.class, new ReportedLspsKey(input.getName())).toInstance();
final ReportedLsps rep = (ReportedLsps) this.dataProvider.readOperationalData(lsp);
if (rep == null) {
LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
return Futures.immediateFuture(OPERATION_UNSENT);
}
}
+
+ @Override
+ public void close() throws InterruptedException, ExecutionException {
+ final DataModificationTransaction t = this.dataProvider.beginTransaction();
+ t.removeOperationalData(this.topology);
+ t.commit().get();
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.bgpcep.pcep.topology.provider;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelPipeline;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.concurrent.Promise;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.protocol.pcep.impl.DefaultPCEPSessionNegotiator;
+import org.opendaylight.protocol.pcep.impl.PCEPSessionImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Pcrpt;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.PcrptBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.PlspId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.SymbolicPathName;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.object.LspBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Open;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.OpenBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.open.TlvsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrpt.message.PcrptMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrpt.message.pcrpt.message.Reports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcrpt.message.pcrpt.message.ReportsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.stateful.capability.tlv.StatefulBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.symbolic.path.name.tlv.SymbolicPathNameBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+public class ParserToSalTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ParserToSalTest.class);
+
+ private List<Notification> receivedMsgs;
+
+ private PCEPSessionImpl session;
+
+ @Mock
+ private Channel clientListener;
+
+ @Mock
+ private ChannelPipeline pipeline;
+
+ @Mock
+ DataProviderService providerService;
+
+ @Mock
+ DataModificationTransaction mockedTransaction;
+
+ private final Open localPrefs = new OpenBuilder().setDeadTimer((short) 30).setKeepalive((short) 10).setTlvs(
+ new TlvsBuilder().setStateful(new StatefulBuilder().build()).build()).build();
+
+ private Pcrpt rptmsg;
+
+ @Before
+ public void setUp() throws IOException {
+ MockitoAnnotations.initMocks(this);
+
+ doAnswer(new Answer<Object>() {
+ @Override
+ public Object answer(final InvocationOnMock invocation) {
+ final Object[] args = invocation.getArguments();
+ ParserToSalTest.this.receivedMsgs.add((Notification) args[0]);
+ return mock(ChannelFuture.class);
+ }
+ }).when(this.clientListener).writeAndFlush(any(Notification.class));
+ doReturn("TestingChannel").when(this.clientListener).toString();
+ doReturn(this.pipeline).when(this.clientListener).pipeline();
+ doReturn(this.pipeline).when(this.pipeline).replace(any(ChannelHandler.class), any(String.class), any(ChannelHandler.class));
+ doReturn(true).when(this.clientListener).isActive();
+ final SocketAddress sa = new InetSocketAddress("127.0.0.1", 4189);
+ doReturn(sa).when(this.clientListener).remoteAddress();
+ doReturn(mock(ChannelFuture.class)).when(this.clientListener).close();
+
+ Mockito.doReturn(this.mockedTransaction).when(this.providerService).beginTransaction();
+ Mockito.doReturn(new Future<RpcResult<TransactionStatus>>() {
+ int i = 0;
+
+ @Override
+ public boolean cancel(final boolean mayInterruptIfRunning) {
+ LOG.debug("Cancel.");
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ LOG.debug("Is cancelled.");
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ this.i++;
+ LOG.debug("Done. {}", this.i);
+ return true;
+ }
+
+ @Override
+ public RpcResult<TransactionStatus> get() throws InterruptedException, ExecutionException {
+ return null;
+ }
+
+ @Override
+ public RpcResult<TransactionStatus> get(final long timeout, final TimeUnit unit) throws InterruptedException,
+ ExecutionException, TimeoutException {
+ return null;
+ }
+ }).when(this.mockedTransaction).commit();
+
+ final HashMap<Object, Object> data = new HashMap<>();
+
+ Mockito.doAnswer(new Answer<Object>() {
+ @Override
+ public Object answer(final InvocationOnMock invocation) throws Throwable {
+ final Object[] args = invocation.getArguments();
+ LOG.debug("Get key {}", args[0]);
+ return data.get(args[0]);
+ }
+
+ }).when(this.mockedTransaction).readOperationalData(Matchers.any(InstanceIdentifier.class));
+
+ Mockito.doAnswer(new Answer<Object>() {
+ @Override
+ public Object answer(final InvocationOnMock invocation) throws Throwable {
+ final Object[] args = invocation.getArguments();
+ LOG.debug("Get key {}", args[0]);
+ return data.get(args[0]);
+ }
+
+ }).when(this.providerService).readOperationalData(Matchers.any(InstanceIdentifier.class));
+
+ Mockito.doAnswer(new Answer<String>() {
+ @Override
+ public String answer(final InvocationOnMock invocation) throws Throwable {
+ final Object[] args = invocation.getArguments();
+ LOG.debug("Put key {} value {}", args[0]);
+ LOG.debug("Put value {}", args[1]);
+ data.put(args[0], args[1]);
+ return null;
+ }
+
+ }).when(this.mockedTransaction).putOperationalData(Matchers.any(InstanceIdentifier.class), Matchers.any(DataObject.class));
+
+ final ServerSessionManager manager = new ServerSessionManager(this.providerService, InstanceIdentifier.builder(
+ NetworkTopology.class).child(Topology.class, new TopologyKey(new TopologyId("testtopo"))).toInstance());
+ final DefaultPCEPSessionNegotiator neg = new DefaultPCEPSessionNegotiator(new HashedWheelTimer(), mock(Promise.class), this.clientListener, manager.getSessionListener(), (short) 1, 5, this.localPrefs);
+ this.session = neg.createSession(new HashedWheelTimer(), this.clientListener, this.localPrefs, this.localPrefs);
+
+ final List<Reports> reports = Lists.newArrayList(new ReportsBuilder().setLsp(
+ new LspBuilder().setPlspId(new PlspId(5L)).setSync(false).setRemove(false).setTlvs(
+ new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.lsp.object.lsp.TlvsBuilder().setSymbolicPathName(
+ new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(new byte[] { 22, 34 })).build()).build()).build()).build());
+ this.rptmsg = new PcrptBuilder().setPcrptMessage(new PcrptMessageBuilder().setReports(reports).build()).build();
+ }
+
+ @Test
+ public void testUnknownLsp() {
+ this.session.sessionUp();
+ this.session.handleMessage(this.rptmsg);
+ Mockito.verify(this.mockedTransaction, Mockito.times(4)).putOperationalData(Matchers.any(InstanceIdentifier.class),
+ Matchers.any(DataObject.class));
+ Mockito.verify(this.mockedTransaction, Mockito.times(3)).commit();
+ }
+}
<artifactId>commons-codec</artifactId>
<version>${commonscodec.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
<!-- Testing dependencies -->
<dependency>
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.io.CharStreams;
+
+/**
+ * Parses PCEP messages from a text file. Messages need to follow this formatting:
+ *
+ * Received PCEP Open message. Length:28.
+ *
+ * 20 01 00 1c 01 10 00 18 20 1e 78 03 00 10 00 04 00 00 00 05 00 1a 00 04 00 00 00 b4
+ *
+ */
+public class PCEPHexDumpParser {
+ private static final int MINIMAL_LENGTH = 4;
+ private static final Logger LOG = LoggerFactory.getLogger(PCEPHexDumpParser.class);
+ private static final String LENGTH = "LENGTH:";
+
+ private PCEPHexDumpParser() {
+
+ }
+
+ public static List<byte[]> parseMessages(final File file) throws IOException {
+ Preconditions.checkArgument(file != null, "Filename cannot be null");
+ return parseMessages(new FileInputStream(file));
+ }
+
+ public static List<byte[]> parseMessages(final InputStream is) throws IOException {
+ Preconditions.checkNotNull(is);
+ try (InputStreamReader isr = new InputStreamReader(is)) {
+ return parseMessages(CharStreams.toString(isr));
+ } finally {
+ is.close();
+ }
+ }
+
+ private static List<byte[]> parseMessages(final String c) {
+ final String content = clearWhiteSpaceToUpper(c);
+
+ final List<byte[]> messages = Lists.newLinkedList();
+ int idx = content.indexOf(LENGTH, 0);
+ while (idx > -1) {
+ // next chars are final length, ending with '.'
+ final int lengthIdx = idx + LENGTH.length();
+ final int messageIdx = content.indexOf('.', lengthIdx);
+
+ final int length = Integer.valueOf(content.substring(lengthIdx, messageIdx));
+ final int messageEndIdx = idx + length * 2;
+
+ // Assert that message is longer than minimum 4(header.length == 4)
+ // If length in PCEP message would be 0, loop would never end
+ Preconditions.checkArgument(length >= MINIMAL_LENGTH, "Invalid message at index " + idx + ", length atribute is lower than "
+ + MINIMAL_LENGTH);
+
+ final String hexMessage = content.substring(idx, messageEndIdx);
+ byte[] message = null;
+ try {
+ message = Hex.decodeHex(hexMessage.toCharArray());
+ } catch (final DecoderException e) {
+ new RuntimeException(e);
+ }
+ messages.add(message);
+ idx = messageEndIdx;
+ idx = content.indexOf(LENGTH, idx);
+ }
+ LOG.info("Succesfully extracted {} messages", messages.size());
+ return messages;
+ }
+
+ private static String clearWhiteSpaceToUpper(final String line) {
+ return line.replaceAll("\\s", "").toUpperCase();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.List;
+
+import org.junit.Test;
+
+public class PCEPHexDumpParserTest {
+
+ public static final String hexDumpFileName = "/pcep-hex.txt";
+ private final int expectedSize = 6;
+
+ @Test
+ public void testParsing() throws Exception {
+ final List<byte[]> result = PCEPHexDumpParser.parseMessages(getClass().getResourceAsStream(PCEPHexDumpParserTest.hexDumpFileName));
+ assertEquals(this.expectedSize, result.size());
+ }
+
+ @Test
+ public void testParsingInvalidFile() throws Exception {
+ try {
+ PCEPHexDumpParser.parseMessages(new File("bad file name"));
+ fail("Exception should have occured.");
+ } catch (final FileNotFoundException e) {
+ assertThat(e.getMessage(), containsString("bad file name (No such file or directory)"));
+ }
+ }
+}
--- /dev/null
+Received PCEP Open message. Length:28.
+
+20 01 00 1c 01 10 00 18 20 1e 78 03 00 10 00 04
+00 00 00 05 00 1a 00 04 00 00 00 b4
+
+Received PCEP Keepalive message. Length:4.
+
+20 02 00 04
+
+Received PCEPReport message. Length:12.
+
+20 0a 00 0c 20 10 00 08 00 00 00 00
+
+Received PCEPReport message. Length:56.
+
+20 0a 00 38 20 10 00 34 00 00 50 01 00 11 00 28
+74 75 6e 6e 65 6c 5f 66 72 6f 6d 5f 4f 66 2d 39
+6b 2d 30 32 5f 74 6f 5f 4f 66 2d 39 6b 2d 30 33
+4f 66 2d 39 6b 2d 30 32
+
+Received PCEPReport message. Length:120.
+
+20 0a 00 78 20 10 00 44 00 00 50 05 00 11 00 28
+74 75 6e 6e 65 6c 5f 66 72 6f 6d 5f 4f 66 2d 39
+6b 2d 30 32 5f 74 6f 5f 4f 66 2d 39 6b 2d 30 33
+4f 66 2d 39 6b 2d 30 32 00 12 00 0c 2a 2a 2a 2a
+00 00 00 04 2a 2a 2a 2a 07 10 00 14 01 08 c6 14
+a0 2b 20 00 01 08 2b 2b 2b 2b 20 00 09 10 00 14
+00 00 00 00 00 00 00 00 00 00 00 00 07 07 00 00
+05 20 00 08 00 00 00 00
+
+Received PCEPReport message. Length:56.
+
+20 0a 00 38 20 10 00 34 00 00 50 0c 00 11 00 28
+74 75 6e 6e 65 6c 5f 66 72 6f 6d 5f 4f 66 2d 39
+6b 2d 30 32 5f 74 6f 5f 4f 66 2d 39 6b 2d 30 33
+4f 66 2d 39 6b 2d 30 32