Activate code generation
[bgpcep.git] / framework / src / main / java / org / opendaylight / protocol / framework / SSLSelector.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.framework;
9
10 import java.io.IOException;
11 import java.nio.channels.ClosedChannelException;
12 import java.nio.channels.ClosedSelectorException;
13 import java.nio.channels.SelectionKey;
14 import java.nio.channels.Selector;
15 import java.nio.channels.spi.AbstractSelectableChannel;
16 import java.nio.channels.spi.AbstractSelector;
17 import java.util.Collections;
18 import java.util.Set;
19
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 import org.opendaylight.protocol.util.RemoveOnlySet;
24 import com.google.common.collect.Sets;
25
26 class SSLSelector extends AbstractSelector {
27         private static final Logger logger = LoggerFactory.getLogger(SSLSelector.class);
28         private final Set<SelectionKey> selectedKeys = Sets.newHashSet();
29         private final Set<SelectionKey> keys = Sets.newCopyOnWriteArraySet();
30
31         private final Set<SelectionKey> guardedSelectedKeys = RemoveOnlySet.wrap(selectedKeys);
32         private final Set<SelectionKey> guardedKeys = Collections.unmodifiableSet(keys);
33         private final Selector selector;
34         private boolean closed = false;
35
36         SSLSelector(final Selector selector) throws IOException {
37                 super(selector.provider());
38                 this.selector = selector;
39         }
40
41         @Override
42         protected void implCloseSelector() throws IOException {
43                 // Make sure selection won't block
44                 selector.wakeup();
45
46                 synchronized (this) {
47                         if (!closed) {
48                                 closed = true;
49                                 for (SelectionKey k : keys)
50                                         k.cancel();
51
52                                 keys.clear();
53                                 selector.close();
54                         }
55                 }
56         }
57
58         @Override
59         protected synchronized SelectionKey register(final AbstractSelectableChannel ch, final int ops, final Object att) {
60                 ensureOpen();
61
62                 final AbstractSelectableChannel slave;
63                 if (ch instanceof SSLServerSocketChannel)
64                         slave = ((SSLServerSocketChannel)ch).channel;
65                 else if (ch instanceof SSLSocketChannel)
66                         slave = ((SSLSocketChannel)ch).channel;
67                 else
68                         slave = ch;
69
70                 logger.trace("Register channel {} slave {} with ops {}", ch, slave, ops);
71
72                 final SelectionKey key;
73                 try {
74                         key = new SSLSelectionKey(this, slave.register(selector, 0, null), ch);
75                 } catch (ClosedChannelException e) {
76                         throw new IllegalStateException("Slave selector found the channel closed", e);
77                 }
78                 key.interestOps(ops);
79                 key.attach(att);
80                 keys.add(key);
81                 return key;
82         }
83
84         @Override
85         public synchronized Set<SelectionKey> keys() {
86                 ensureOpen();
87                 return guardedKeys;
88         }
89
90         private void ensureOpen() {
91                 if (closed)
92                         throw new ClosedSelectorException();
93         }
94
95         private int afterSelect() {
96                 logger.trace("Running afterSelect");
97                 int ret = 0;
98
99                 final Set<SelectionKey> ck = cancelledKeys();
100                 synchronized (ck) {
101                         selectedKeys.removeAll(ck);
102
103                         for (final SelectionKey k : keys) {
104                                 final boolean updated = ((SSLSelectionKey)k).updateReadyOps();
105                                 if ((k.readyOps() & k.interestOps()) != 0) {
106                                         selectedKeys.add(k);
107                                         if (updated)
108                                                 ++ret;
109                                 } else
110                                         selectedKeys.remove(k);
111                         }
112                 }
113
114                 return ret;
115         }
116
117         private boolean beforeSelect() {
118                 logger.trace("Running beforeSelect");
119
120                 final Set<SelectionKey> ck = cancelledKeys();
121                 synchronized (ck) {
122                         for (final SelectionKey k : ck)
123                                 ((SSLSelectionKey)k).cancelSlave();
124                         selectedKeys.removeAll(ck);
125                         keys.removeAll(ck);
126                         ck.clear();
127
128                         for (final SelectionKey k : keys) {
129                                 final SSLSelectionKey sk = (SSLSelectionKey)k;
130                                 if (sk.preselectReady()) {
131                                         logger.trace("Key {} ready in preselect", k);
132                                         return true;
133                                 } else
134                                         sk.updateInterestOps();
135                         }
136                 }
137
138                 return false;
139         }
140
141         @Override
142         public synchronized int select() throws IOException {
143                 return select(0);
144         }
145
146         @Override
147         public synchronized int select(final long timeout) throws IOException {
148                 ensureOpen();
149
150                 if (!beforeSelect()) {
151                         try {
152                                 begin();
153                                 selector.select(timeout);
154                         } finally {
155                                 end();
156                         }
157                 }
158                 return afterSelect();
159         }
160
161         @Override
162         public synchronized int selectNow() throws IOException {
163                 ensureOpen();
164
165                 if (!beforeSelect())
166                         selector.selectNow();
167                 return afterSelect();
168         }
169
170         @Override
171         public synchronized Set<SelectionKey> selectedKeys() {
172                 ensureOpen();
173                 return guardedSelectedKeys;
174         }
175
176         @Override
177         public Selector wakeup() {
178                 logger.trace("Running wakeup");
179                 selector.wakeup();
180                 return this;
181         }
182 }