PCEPSessionNegotiatorFactory is not generic
[bgpcep.git] / pcep / impl / src / main / java / org / opendaylight / protocol / pcep / impl / AbstractPCEPSessionNegotiatorFactory.java
index accabad458559d043cbcad6a0807dbe6d3dbe318..1a07ee291cba2ba0e29367f51e657c37f8b5ff8c 100644 (file)
 package org.opendaylight.protocol.pcep.impl;
 
 import io.netty.channel.Channel;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelFutureListener;
 import io.netty.util.concurrent.Promise;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.Comparator;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import javax.annotation.concurrent.GuardedBy;
-
-import org.opendaylight.protocol.framework.AbstractSessionNegotiator;
-import org.opendaylight.protocol.framework.SessionListenerFactory;
-import org.opendaylight.protocol.framework.SessionNegotiator;
-import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
-import org.opendaylight.protocol.pcep.PCEPSessionListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
+import org.opendaylight.protocol.pcep.PCEPSession;
+import org.opendaylight.protocol.pcep.PCEPSessionNegotiatorFactory;
+import org.opendaylight.protocol.pcep.PCEPSessionNegotiatorFactoryDependencies;
+import org.opendaylight.protocol.pcep.SessionNegotiator;
+import org.opendaylight.yangtools.yang.common.Uint8;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-import com.google.common.primitives.UnsignedBytes;
-
 /**
  * SessionNegotiator which takes care of making sure sessions between PCEP peers are kept unique. This needs to be
  * further subclassed to provide either a client or server factory.
  */
-public abstract class AbstractPCEPSessionNegotiatorFactory implements
-               SessionNegotiatorFactory<Message, PCEPSessionImpl, PCEPSessionListener> {
-       private static final Comparator<byte[]> comparator = UnsignedBytes.lexicographicalComparator();
-       private static final Logger logger = LoggerFactory.getLogger(AbstractPCEPSessionNegotiatorFactory.class);
-       private final BiMap<byte[], Closeable> sessions = HashBiMap.create();
-       private final Map<byte[], Short> sessionIds = new WeakHashMap<>();
-
-       /**
-        * Create a new negotiator. This method needs to be implemented by subclasses to actually provide a negotiator.
-        * 
-        * @param promise Session promise to be completed by the negotiator
-        * @param channel Associated channel
-        * @param sessionId Session ID assigned to the resulting session
-        * @return a PCEP session negotiator
-        */
-       protected abstract AbstractPCEPSessionNegotiator createNegotiator(Promise<PCEPSessionImpl> promise, PCEPSessionListener listener,
-                       Channel channel, short sessionId);
-
-       @Override
-       public final SessionNegotiator<PCEPSessionImpl> getSessionNegotiator(final SessionListenerFactory<PCEPSessionListener> factory,
-                       final Channel channel, final Promise<PCEPSessionImpl> promise) {
-
-               final Object lock = this;
-
-               logger.debug("Instantiating bootstrap negotiator for channel {}", channel);
-               return new AbstractSessionNegotiator<Message, PCEPSessionImpl>(promise, channel) {
-                       @Override
-                       protected void startNegotiation() throws Exception {
-                               logger.debug("Bootstrap negotiation for channel {} started", this.channel);
-
-                               /*
-                                * We have a chance to see if there's a client session already
-                                * registered for this client.
-                                */
-                               final byte[] clientAddress = ((InetSocketAddress) this.channel.remoteAddress()).getAddress().getAddress();
-
-                               synchronized (lock) {
-
-                                       if (AbstractPCEPSessionNegotiatorFactory.this.sessions.containsKey(clientAddress)) {
-                                               // FIXME: cross-reference this to RFC5440
-
-                                               final byte[] serverAddress = ((InetSocketAddress) this.channel.localAddress()).getAddress().getAddress();
-                                               if (comparator.compare(serverAddress, clientAddress) > 0) {
-                                                       final Closeable n = AbstractPCEPSessionNegotiatorFactory.this.sessions.remove(clientAddress);
-                                                       try {
-                                                               n.close();
-                                                       } catch (final IOException e) {
-                                                               logger.warn("Unexpected failure to close old session", e);
-                                                       }
-                                               } else {
-                                                       negotiationFailed(new RuntimeException("A conflicting session for address "
-                                                                       + ((InetSocketAddress) this.channel.remoteAddress()).getAddress() + " found."));
-                                                       return;
-                                               }
-                                       }
-
-                                       final short sessionId = nextSession(clientAddress);
-                                       final AbstractPCEPSessionNegotiator n = createNegotiator(promise, factory.getSessionListener(), this.channel, sessionId);
-
-                                       AbstractPCEPSessionNegotiatorFactory.this.sessions.put(clientAddress, new Closeable() {
-                                               @Override
-                                               public void close() {
-                                                       channel.close();
-                                               }
-                                       });
-
-                                       this.channel.closeFuture().addListener(new ChannelFutureListener() {
-                                               @Override
-                                               public void operationComplete(final ChannelFuture future) throws Exception {
-                                                       synchronized (lock) {
-                                                               AbstractPCEPSessionNegotiatorFactory.this.sessions.inverse().remove(this);
-                                                       }
-                                               }
-                                       });
-
-                                       logger.debug("Replacing bootstrap negotiator for channel {}", this.channel);
-                                       this.channel.pipeline().replace(this, "negotiator", n);
-                                       n.startNegotiation();
-                               }
-                       }
-
-                       @Override
-                       protected void handleMessage(final Message msg) throws Exception {
-                               throw new IllegalStateException("Bootstrap negotiator should have been replaced");
-                       }
-               };
-       }
-
-       @GuardedBy("this")
-       private short nextSession(final byte[] clientAddress) {
-               /*
-                * FIXME: Improve the allocation algorithm to make sure:
-                * - no duplicate IDs are assigned
-                * - we retain former session IDs for a reasonable time
-                */
-               Short next = this.sessionIds.get(clientAddress);
-               if (next == null) {
-                       next = 0;
-               }
-
-               this.sessionIds.put(clientAddress, (short) ((next + 1) % 255));
-               return next;
-       }
+public abstract class AbstractPCEPSessionNegotiatorFactory implements PCEPSessionNegotiatorFactory {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractPCEPSessionNegotiatorFactory.class);
+
+    private final PCEPPeerRegistry sessionRegistry = new PCEPPeerRegistry();
+
+    /**
+     * Create a new negotiator. This method needs to be implemented by subclasses to actually provide a negotiator.
+     *
+     * @param snd       PCEP Session Negotiator dependencies
+     * @param promise   Session promise to be completed by the negotiator
+     * @param channel   Associated channel
+     * @param sessionId Session ID assigned to the resulting session
+     * @return a PCEP session negotiator
+     */
+    protected abstract AbstractPCEPSessionNegotiator createNegotiator(
+            PCEPSessionNegotiatorFactoryDependencies snd,
+            Promise<PCEPSession> promise,
+            Channel channel, Uint8 sessionId);
+
+    @Override
+    public final SessionNegotiator getSessionNegotiator(final PCEPSessionNegotiatorFactoryDependencies dependencies,
+            final Channel channel, final Promise<PCEPSession> promise) {
+
+        LOG.debug("Instantiating bootstrap negotiator for channel {}", channel);
+        return new PCEPSessionNegotiator(channel, promise, dependencies, this);
+    }
+
+    public PCEPPeerRegistry getSessionRegistry() {
+        return sessionRegistry;
+    }
 }