2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.bgp.parser.spi.pojo;
10 import com.google.common.base.Preconditions;
11 import io.netty.buffer.ByteBuf;
12 import java.util.ArrayList;
13 import java.util.LinkedHashMap;
14 import java.util.List;
16 import java.util.Map.Entry;
17 import java.util.TreeMap;
18 import java.util.concurrent.atomic.AtomicReference;
19 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
20 import org.opendaylight.protocol.bgp.parser.BGPError;
21 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
22 import org.opendaylight.protocol.bgp.parser.spi.AttributeParser;
23 import org.opendaylight.protocol.bgp.parser.spi.AttributeRegistry;
24 import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer;
25 import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
26 import org.opendaylight.protocol.concepts.AbstractRegistration;
27 import org.opendaylight.protocol.concepts.HandlerRegistry;
28 import org.opendaylight.protocol.util.BitArray;
29 import org.opendaylight.protocol.util.ByteArray;
30 import org.opendaylight.protocol.util.Values;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AttributesBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.UnrecognizedAttributes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.UnrecognizedAttributesBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.UnrecognizedAttributesKey;
36 import org.opendaylight.yangtools.yang.binding.DataContainer;
37 import org.opendaylight.yangtools.yang.binding.DataObject;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 final class SimpleAttributeRegistry implements AttributeRegistry {
43 private static final class RawAttribute {
44 private final AttributeParser parser;
45 private final ByteBuf buffer;
47 public RawAttribute(final AttributeParser parser, final ByteBuf buffer) {
48 this.parser = Preconditions.checkNotNull(parser);
49 this.buffer = Preconditions.checkNotNull(buffer);
53 private static final Logger LOG = LoggerFactory.getLogger(SimpleAttributeRegistry.class);
54 private static final int OPTIONAL_BIT = 0;
55 private static final int TRANSITIVE_BIT = 1;
56 private static final int PARTIAL_BIT = 2;
57 private static final int EXTENDED_LENGTH_BIT = 3;
58 private final HandlerRegistry<DataContainer, AttributeParser, AttributeSerializer> handlers = new HandlerRegistry<>();
59 private final Map<AbstractRegistration, AttributeSerializer> serializers = new LinkedHashMap<>();
60 private final AtomicReference<Iterable<AttributeSerializer>> roSerializers =
61 new AtomicReference<>(this.serializers.values());
62 private final List<UnrecognizedAttributes> unrecognizedAttributes = new ArrayList<>();
65 AutoCloseable registerAttributeParser(final int attributeType, final AttributeParser parser) {
66 Preconditions.checkArgument(attributeType >= 0 && attributeType <= Values.UNSIGNED_BYTE_MAX_VALUE);
67 return this.handlers.registerParser(attributeType, parser);
70 synchronized AutoCloseable registerAttributeSerializer(final Class<? extends DataObject> paramClass, final AttributeSerializer serializer) {
71 final AbstractRegistration reg = this.handlers.registerSerializer(paramClass, serializer);
73 this.serializers.put(reg, serializer);
74 return new AbstractRegistration() {
76 protected void removeRegistration() {
77 synchronized (SimpleAttributeRegistry.this) {
78 SimpleAttributeRegistry.this.serializers.remove(reg);
79 SimpleAttributeRegistry.this.roSerializers.set(SimpleAttributeRegistry.this.serializers.values());
86 private void addAttribute(final ByteBuf buffer, final Map<Integer, RawAttribute> attributes)
87 throws BGPDocumentedException {
88 final BitArray flags = BitArray.valueOf(buffer.readByte());
89 final int type = buffer.readUnsignedByte();
90 final int len = (flags.get(EXTENDED_LENGTH_BIT)) ? buffer.readUnsignedShort() : buffer.readUnsignedByte();
91 if (!attributes.containsKey(type)) {
92 final AttributeParser parser = this.handlers.getParser(type);
94 processUnrecognized(flags, type, buffer, len);
96 attributes.put(type, new RawAttribute(parser, buffer.readSlice(len)));
99 LOG.debug("Ignoring duplicate attribute type {}", type);
103 private void processUnrecognized(final BitArray flags, final int type, final ByteBuf buffer, final int len) throws BGPDocumentedException {
104 if (!flags.get(OPTIONAL_BIT)) {
105 throw new BGPDocumentedException("Well known attribute not recognized.", BGPError.WELL_KNOWN_ATTR_NOT_RECOGNIZED);
107 final UnrecognizedAttributes unrecognizedAttribute = new UnrecognizedAttributesBuilder()
108 .setKey(new UnrecognizedAttributesKey((short) type))
109 .setPartial(flags.get(PARTIAL_BIT))
110 .setTransitive(flags.get(TRANSITIVE_BIT))
111 .setType((short) type)
112 .setValue(ByteArray.readBytes(buffer, len)).build();
113 this.unrecognizedAttributes.add(unrecognizedAttribute);
114 LOG.debug("Unrecognized attribute were parsed: {}", unrecognizedAttribute);
118 public Attributes parseAttributes(final ByteBuf buffer) throws BGPDocumentedException, BGPParsingException {
119 return parseAttributes(buffer, null);
123 public Attributes parseAttributes(final ByteBuf buffer, final PeerSpecificParserConstraint constraint)
124 throws BGPDocumentedException, BGPParsingException {
125 final Map<Integer, RawAttribute> attributes = new TreeMap<>();
126 while (buffer.isReadable()) {
127 addAttribute(buffer, attributes);
130 * TreeMap guarantees that we will be invoking the parser in the order
131 * of increasing attribute type.
133 final AttributesBuilder builder = new AttributesBuilder();
134 for (final Entry<Integer, RawAttribute> e : attributes.entrySet()) {
135 LOG.debug("Parsing attribute type {}", e.getKey());
137 final RawAttribute a = e.getValue();
138 a.parser.parseAttribute(a.buffer, builder, constraint);
140 builder.setUnrecognizedAttributes(this.unrecognizedAttributes);
141 return builder.build();
145 public void serializeAttribute(final DataObject attribute,final ByteBuf byteAggregator) {
146 for (final AttributeSerializer serializer : this.roSerializers.get()) {
147 serializer.serializeAttribute(attribute, byteAggregator);