*/
package org.opendaylight.protocol.pcep.impl;
-import java.util.ArrayList;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.UnpooledByteBufAllocator;
+
+import java.util.Arrays;
import java.util.List;
import org.opendaylight.protocol.framework.DeserializerException;
import org.opendaylight.protocol.framework.DocumentedException;
import org.opendaylight.protocol.framework.ProtocolMessageFactory;
import org.opendaylight.protocol.pcep.PCEPDeserializerException;
-import org.opendaylight.protocol.pcep.spi.RawMessage;
+import org.opendaylight.protocol.pcep.PCEPDocumentedException;
+import org.opendaylight.protocol.pcep.spi.HandlerRegistry;
+import org.opendaylight.protocol.pcep.spi.MessageSerializer;
+import org.opendaylight.protocol.util.ByteArray;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
+import com.google.common.primitives.UnsignedBytes;
/**
* A PCEP message parser which also does validation.
*/
public final class PCEPMessageFactory implements ProtocolMessageFactory<Message> {
- private static final RawPCEPMessageFactory rawFactory = new RawPCEPMessageFactory();
+
+ private final static Logger logger = LoggerFactory.getLogger(PCEPMessageFactory.class);
+
+ private final static int TYPE_SIZE = 1; // bytes
+
+ private final static int LENGTH_SIZE = 2; // bytes
+
+ public final static int COMMON_HEADER_LENGTH = 4; // bytes
+
+ /**
+ * Current supported version of PCEP.
+ */
+ public static final int PCEP_VERSION = 1;
+
+ private static final int VERSION_SF_LENGTH = 3;
+
+ private final HandlerRegistry registry;
+
+ private static final int VER_FLAGS_MF_LENGTH = 1;
+ private static final int TYPE_F_LENGTH = 1;
+ private static final int LENGTH_F_LENGTH = 2;
+
+ private static final int VER_FLAGS_MF_OFFSET = 0;
+ private static final int TYPE_F_OFFSET = VER_FLAGS_MF_LENGTH + VER_FLAGS_MF_OFFSET;
+ private static final int LENGTH_F_OFFSET = TYPE_F_LENGTH + TYPE_F_OFFSET;
+
+ public PCEPMessageFactory() {
+ this.registry = HandlerRegistryImpl.INSTANCE;
+ }
@Override
public List<Message> parse(final byte[] bytes) throws DeserializerException, DocumentedException {
- final List<Message> parsed = rawFactory.parse(bytes);
- final List<Message> validated = new ArrayList<>(parsed.size());
-
- for (final Message msg : parsed) {
- Preconditions.checkState(msg instanceof RawMessage);
- final RawMessage raw = (RawMessage) msg;
-
- try {
- validated.addAll(PCEPMessageValidator.getValidator(raw.getMsgType()).validate(raw.getAllObjects()));
- } catch (final PCEPDeserializerException e) {
- // FIXME: at validation time we may want to terminate with:
- // logger.error("Malformed message, terminating. ", e);
- // this.terminate(Reason.MALFORMED_MSG);
- throw e;
- }
+ Preconditions.checkArgument(bytes != null, "Bytes may not be null");
+ Preconditions.checkArgument(bytes.length != 0, "Bytes may not be empty");
+
+ logger.trace("Attempt to parse message from bytes: {}", ByteArray.bytesToHexString(bytes));
+
+ final int type = UnsignedBytes.toInt(bytes[1]);
+
+ final int msgLength = ByteArray.bytesToInt(ByteArray.subByte(bytes, TYPE_SIZE + 1, LENGTH_SIZE));
+
+ final byte[] msgBody = ByteArray.cutBytes(bytes, TYPE_SIZE + 1 + LENGTH_SIZE);
+
+ if (msgBody.length != msgLength - COMMON_HEADER_LENGTH) {
+ throw new DeserializerException("Body size " + msgBody.length + " does not match header size "
+ + (msgLength - COMMON_HEADER_LENGTH));
}
- return validated;
+ Message msg = null;
+
+ try {
+ msg = this.registry.getMessageParser(type).parseMessage(msgBody);
+ } catch (final PCEPDeserializerException e) {
+ logger.debug("Unexpected deserializer problem", e);
+ throw new DeserializerException(e.getMessage(), e);
+ } catch (final PCEPDocumentedException e) {
+ logger.debug("Documented deserializer problem", e);
+ throw new DocumentedException(e.getMessage(), e);
+ }
+ logger.debug("Message was parsed. {}", msg);
+ return Arrays.asList(msg);
}
@Override
public byte[] put(final Message msg) {
- return rawFactory.put(msg);
+ if (msg == null) {
+ throw new IllegalArgumentException("PCEPMessage is mandatory.");
+ }
+
+ final ByteBuf buf = new UnpooledByteBufAllocator(false).buffer();
+
+ final MessageSerializer serializer = this.registry.getMessageSerializer(msg);
+
+ serializer.serializeMessage(msg, buf);
+
+ final byte[] msgBody = buf.array();
+
+ final byte[] headerBytes = new byte[COMMON_HEADER_LENGTH];
+
+ // msgVer_Flag
+ headerBytes[VER_FLAGS_MF_OFFSET] = (byte) (PCEP_VERSION << (Byte.SIZE - VERSION_SF_LENGTH));
+
+ // msgType
+ headerBytes[TYPE_F_OFFSET] = (byte) serializer.getMessageType();
+
+ // msgLength
+ System.arraycopy(ByteArray.intToBytes(msgBody.length), Integer.SIZE / Byte.SIZE - LENGTH_F_LENGTH, headerBytes, LENGTH_F_OFFSET,
+ LENGTH_F_LENGTH);
+
+ final byte[] retBytes = new byte[headerBytes.length + msgBody.length];
+
+ ByteArray.copyWhole(headerBytes, retBytes, 0);
+ ByteArray.copyWhole(msgBody, retBytes, PCEPMessageHeader.COMMON_HEADER_LENGTH);
+
+ return retBytes;
}
}