Merge "Fixed segment-routing formating."
[bgpcep.git] / bgp / parser-spi / src / main / java / org / opendaylight / protocol / bgp / parser / spi / pojo / SimpleAttributeRegistry.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.bgp.parser.spi.pojo;
9
10 import com.google.common.base.Preconditions;
11
12 import io.netty.buffer.ByteBuf;
13
14 import java.util.LinkedHashMap;
15 import java.util.Map;
16 import java.util.Map.Entry;
17 import java.util.TreeMap;
18 import java.util.concurrent.atomic.AtomicReference;
19
20 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
21 import org.opendaylight.protocol.bgp.parser.BGPError;
22 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
23 import org.opendaylight.protocol.bgp.parser.spi.AttributeParser;
24 import org.opendaylight.protocol.bgp.parser.spi.AttributeRegistry;
25 import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer;
26 import org.opendaylight.protocol.concepts.AbstractRegistration;
27 import org.opendaylight.protocol.concepts.HandlerRegistry;
28 import org.opendaylight.protocol.util.ByteArray;
29 import org.opendaylight.protocol.util.Values;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributesBuilder;
32 import org.opendaylight.yangtools.yang.binding.DataContainer;
33 import org.opendaylight.yangtools.yang.binding.DataObject;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 final class SimpleAttributeRegistry implements AttributeRegistry {
38
39     private static final class RawAttribute {
40         private final AttributeParser parser;
41         private final ByteBuf buffer;
42
43         public RawAttribute(final AttributeParser parser, final ByteBuf buffer) {
44             this.parser = Preconditions.checkNotNull(parser);
45             this.buffer = Preconditions.checkNotNull(buffer);
46         }
47     }
48
49     private static final Logger LOG = LoggerFactory.getLogger(SimpleAttributeRegistry.class);
50     private static final int OPTIONAL_BIT = 0;
51     private static final int TRANSITIVE_BIT = 1;
52     @SuppressWarnings("unused")
53     private static final int PARTIAL_BIT = 2;
54     private static final int EXTENDED_LENGTH_BIT = 3;
55     private final HandlerRegistry<DataContainer, AttributeParser, AttributeSerializer> handlers = new HandlerRegistry<>();
56     private final Map<AbstractRegistration, AttributeSerializer> serializers = new LinkedHashMap<>();
57     private final AtomicReference<Iterable<AttributeSerializer>> roSerializers =
58         new AtomicReference<Iterable<AttributeSerializer>>(this.serializers.values());
59
60     AutoCloseable registerAttributeParser(final int attributeType, final AttributeParser parser) {
61         Preconditions.checkArgument(attributeType >= 0 && attributeType <= Values.UNSIGNED_BYTE_MAX_VALUE);
62         return this.handlers.registerParser(attributeType, parser);
63     }
64
65     synchronized AutoCloseable registerAttributeSerializer(final Class<? extends DataObject> paramClass, final AttributeSerializer serializer) {
66         final AbstractRegistration reg = this.handlers.registerSerializer(paramClass, serializer);
67
68         this.serializers.put(reg, serializer);
69         return new AbstractRegistration() {
70             @Override
71             protected void removeRegistration() {
72                 synchronized (SimpleAttributeRegistry.this) {
73                     SimpleAttributeRegistry.this.serializers.remove(reg);
74                     SimpleAttributeRegistry.this.roSerializers.set(SimpleAttributeRegistry.this.serializers.values());
75                 }
76                 reg.close();
77             }
78         };
79     }
80
81     private void addAttribute(final ByteBuf buffer, final Map<Integer, RawAttribute> attributes) throws BGPDocumentedException {
82         final boolean[] flags = ByteArray.parseBits(buffer.readByte());
83         final int type = buffer.readUnsignedByte();
84         final int len = (flags[EXTENDED_LENGTH_BIT]) ? buffer.readUnsignedShort() : buffer.readUnsignedByte();
85         if (!attributes.containsKey(type)) {
86             final AttributeParser parser = this.handlers.getParser(type);
87             if (parser == null) {
88                 if (!flags[OPTIONAL_BIT]) {
89                     throw new BGPDocumentedException("Well known attribute not recognized.", BGPError.WELL_KNOWN_ATTR_NOT_RECOGNIZED);
90                 }
91                 if (flags[TRANSITIVE_BIT]) {
92                     // FIXME: transitive attributes need to be preserved
93                     LOG.warn("Losing unrecognized transitive attribute {}", type);
94                 } else {
95                     LOG.debug("Ignoring unrecognized attribute type {}", type);
96                 }
97             } else {
98                 attributes.put(type, new RawAttribute(parser, buffer.slice(buffer.readerIndex(), len)));
99                 buffer.skipBytes(len);
100             }
101         } else {
102             LOG.debug("Ignoring duplicate attribute type {}", type);
103         }
104     }
105
106     @Override
107     public PathAttributes parseAttributes(final ByteBuf buffer) throws BGPDocumentedException, BGPParsingException {
108         final TreeMap<Integer, RawAttribute> attributes = new TreeMap<>();
109         while (buffer.isReadable()) {
110             addAttribute(buffer, attributes);
111         }
112         /*
113          * TreeMap guarantees that we will be invoking the parser in the order
114          * of increasing attribute type.
115          */
116         final PathAttributesBuilder builder = new PathAttributesBuilder();
117         for (final Entry<Integer, RawAttribute> e : attributes.entrySet()) {
118             LOG.debug("Parsing attribute type {}", e.getKey());
119
120             final RawAttribute a = e.getValue();
121             a.parser.parseAttribute(a.buffer, builder);
122         }
123         return builder.build();
124     }
125
126     @Override
127     public void serializeAttribute(final DataObject attribute,final ByteBuf byteAggregator) {
128         for (AttributeSerializer serializer : this.roSerializers.get()) {
129             serializer.serializeAttribute(attribute, byteAggregator);
130         }
131     }
132 }