blob: 178018a673c8d9cee330c19572597fba474cf5dc [file] [log] [blame]
Tomek Osińskie9ccf412018-01-13 19:44:11 +01001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.xmpp.core.ctl;
18
Tomek Osiński7a1db182018-02-03 17:15:06 +010019import com.google.common.collect.HashMultimap;
Tomek Osińskie9ccf412018-01-13 19:44:11 +010020import com.google.common.collect.Maps;
Tomek Osiński7a1db182018-02-03 17:15:06 +010021import com.google.common.collect.Multimap;
22import com.google.common.collect.Multimaps;
Tomek Osińskie9ccf412018-01-13 19:44:11 +010023import org.onosproject.cfg.ComponentConfigService;
24import org.onosproject.core.CoreService;
25import org.onosproject.xmpp.core.XmppController;
26import org.onosproject.xmpp.core.XmppDevice;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070027import org.onosproject.xmpp.core.XmppDeviceAgent;
Tomek Osińskie9ccf412018-01-13 19:44:11 +010028import org.onosproject.xmpp.core.XmppDeviceId;
29import org.onosproject.xmpp.core.XmppDeviceListener;
30import org.onosproject.xmpp.core.XmppIqListener;
31import org.onosproject.xmpp.core.XmppMessageListener;
32import org.onosproject.xmpp.core.XmppPresenceListener;
Tomek Osińskie9ccf412018-01-13 19:44:11 +010033import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070034import org.osgi.service.component.annotations.Activate;
35import org.osgi.service.component.annotations.Component;
36import org.osgi.service.component.annotations.Deactivate;
37import org.osgi.service.component.annotations.Modified;
38import org.osgi.service.component.annotations.Reference;
39import org.osgi.service.component.annotations.ReferenceCardinality;
Tomek Osińskie9ccf412018-01-13 19:44:11 +010040import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42import org.xmpp.packet.IQ;
43import org.xmpp.packet.Message;
44import org.xmpp.packet.Packet;
45import org.xmpp.packet.Presence;
46
47import java.net.InetSocketAddress;
48import java.util.Set;
49import java.util.concurrent.ConcurrentMap;
50import java.util.concurrent.CopyOnWriteArraySet;
51
52
53/**
54 * The main class (bundle) of XMPP protocol.
55 * Responsible for:
56 * 1. Initialization and starting XMPP server.
57 * 2. Handling XMPP packets from clients and writing to clients.
58 * 3. Configuration parameters initialization.
59 * 4. Notifing listeners about XMPP events/packets.
60 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061@Component(immediate = true, service = XmppController.class)
Tomek Osińskie9ccf412018-01-13 19:44:11 +010062public class XmppControllerImpl implements XmppController {
63
64 private static final String APP_ID = "org.onosproject.xmpp";
65 private static final String XMPP_PORT = "5269";
66
67 private static final Logger log =
68 LoggerFactory.getLogger(XmppControllerImpl.class);
69
70 // core services declaration
Ray Milkeyd84f89b2018-08-17 14:54:17 -070071 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Tomek Osińskie9ccf412018-01-13 19:44:11 +010072 protected CoreService coreService;
73
Ray Milkeyd84f89b2018-08-17 14:54:17 -070074 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Tomek Osińskie9ccf412018-01-13 19:44:11 +010075 protected ComponentConfigService cfgService;
76
77 // configuration properties definition
Ray Milkeyd84f89b2018-08-17 14:54:17 -070078 //@Property(name = "xmppPort", value = XMPP_PORT,
79 // label = "Port number used by XMPP protocol; default is 5269")
Tomek Osińskie9ccf412018-01-13 19:44:11 +010080 private String xmppPort = XMPP_PORT;
81
82
83 // listener declaration
84 protected Set<XmppDeviceListener> xmppDeviceListeners = new CopyOnWriteArraySet<XmppDeviceListener>();
85
Tomek Osiński7a1db182018-02-03 17:15:06 +010086 Multimap<String, XmppIqListener> xmppIqListeners = Multimaps.synchronizedSetMultimap(HashMultimap.create());
Tomek Osińskie9ccf412018-01-13 19:44:11 +010087 protected Set<XmppMessageListener> xmppMessageListeners = new CopyOnWriteArraySet<XmppMessageListener>();
88 protected Set<XmppPresenceListener> xmppPresenceListeners = new CopyOnWriteArraySet<XmppPresenceListener>();
89
90 protected XmppDeviceAgent agent = new DefaultXmppDeviceAgent();
91
92 private final XmppServer xmppServer = new XmppServer();
93 private DefaultXmppDeviceFactory deviceFactory = new DefaultXmppDeviceFactory();
94
95 ConcurrentMap<XmppDeviceId, XmppDevice> connectedDevices = Maps.newConcurrentMap();
96 ConcurrentMap<InetSocketAddress, XmppDeviceId> addressDeviceIdMap = Maps.newConcurrentMap();
97
98 @Activate
99 public void activate(ComponentContext context) {
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100100 coreService.registerApplication(APP_ID, this::cleanup);
101 cfgService.registerProperties(getClass());
102 deviceFactory.init(agent);
103 xmppServer.setConfiguration(context.getProperties());
104 xmppServer.start(deviceFactory);
Tomek Osiński7a1db182018-02-03 17:15:06 +0100105 log.info("XmppControllerImpl started.");
106 }
107
108 @Modified
109 public void modified(ComponentContext context) {
110 xmppServer.stop();
111 xmppServer.setConfiguration(context.getProperties());
112 xmppServer.start(deviceFactory);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100113 }
114
115 @Deactivate
116 public void deactivate() {
117 cleanup();
118 cfgService.unregisterProperties(getClass(), false);
119 log.info("Stopped");
120 }
121
122 private void cleanup() {
123 xmppServer.stop();
124 deviceFactory.cleanAgent();
125 connectedDevices.values().forEach(XmppDevice::disconnectDevice);
126 connectedDevices.clear();
127 }
128
129 @Override
130 public XmppDevice getDevice(XmppDeviceId xmppDeviceId) {
131 return connectedDevices.get(xmppDeviceId);
132 }
133
134 @Override
135 public void addXmppDeviceListener(XmppDeviceListener deviceListener) {
136 xmppDeviceListeners.add(deviceListener);
137 }
138
139 @Override
140 public void removeXmppDeviceListener(XmppDeviceListener deviceListener) {
141 xmppDeviceListeners.remove(deviceListener);
142 }
143
144 @Override
Tomek Osiński7a1db182018-02-03 17:15:06 +0100145 public void addXmppIqListener(XmppIqListener iqListener, String namespace) {
146 xmppIqListeners.put(namespace, iqListener);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100147 }
148
149 @Override
Tomek Osiński7a1db182018-02-03 17:15:06 +0100150 public void removeXmppIqListener(XmppIqListener iqListener, String namespace) {
151 xmppIqListeners.remove(namespace, iqListener);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100152 }
153
154 @Override
155 public void addXmppMessageListener(XmppMessageListener messageListener) {
156 xmppMessageListeners.add(messageListener);
157 }
158
159 @Override
160 public void removeXmppMessageListener(XmppMessageListener messageListener) {
161 xmppMessageListeners.remove(messageListener);
162 }
163
164 @Override
165 public void addXmppPresenceListener(XmppPresenceListener presenceListener) {
166 xmppPresenceListeners.add(presenceListener);
167 }
168
169 @Override
170 public void removeXmppPresenceListener(XmppPresenceListener presenceListener) {
171 xmppPresenceListeners.remove(presenceListener);
172 }
173
174
175 private class DefaultXmppDeviceAgent implements XmppDeviceAgent {
176
177 @Override
178 public boolean addConnectedDevice(XmppDeviceId deviceId, XmppDevice device) {
179 if (connectedDevices.get(deviceId) != null) {
180 log.warn("Trying to add Xmpp Device but found a previous " +
181 "value for XMPP deviceId: {}", deviceId);
182 return false;
183 } else {
184 log.info("Added XMPP device: {}", deviceId);
185 connectedDevices.put(deviceId, device);
186 for (XmppDeviceListener listener : xmppDeviceListeners) {
187 listener.deviceConnected(deviceId);
188 }
189 return true;
190 }
191 }
192
193 @Override
194 public void removeConnectedDevice(XmppDeviceId deviceId) {
195 connectedDevices.remove(deviceId);
196 for (XmppDeviceListener listener : xmppDeviceListeners) {
197 listener.deviceDisconnected(deviceId);
198 }
199 }
200
201 @Override
202 public XmppDevice getDevice(XmppDeviceId deviceId) {
203 return connectedDevices.get(deviceId);
204 }
205
206 @Override
207 public void processUpstreamEvent(XmppDeviceId deviceId, Packet packet) {
208 if (packet instanceof IQ) {
Tomek Osiński7a1db182018-02-03 17:15:06 +0100209 IQ iq = (IQ) packet;
210 String namespace = iq.getChildElement().getNamespace().getURI();
211 notifyIqListeners(iq, namespace);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100212 }
213 if (packet instanceof Message) {
Tomek Osiński7a1db182018-02-03 17:15:06 +0100214 notifyMessageListeners((Message) packet);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100215 }
216 if (packet instanceof Presence) {
Tomek Osiński7a1db182018-02-03 17:15:06 +0100217 notifyPresenceListeners((Presence) packet);
218 }
219 }
220
221 private void notifyPresenceListeners(Presence packet) {
222 for (XmppPresenceListener presenceListener : xmppPresenceListeners) {
223 presenceListener.handlePresenceStanza((Presence) packet);
224 }
225 }
226
227 private void notifyMessageListeners(Message message) {
228 for (XmppMessageListener messageListener : xmppMessageListeners) {
229 messageListener.handleMessageStanza(message);
230 }
231 }
232
233 private void notifyIqListeners(IQ iq, String namespace) {
234 for (XmppIqListener iqListener : xmppIqListeners.get(namespace)) {
235 iqListener.handleIqStanza(iq);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100236 }
237 }
238
239 }
240
241
242}