blob: da42c1cd2301d49c09acdb9f09ae063fef454e18 [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
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -070052import static org.onosproject.xmpp.core.ctl.OsgiPropertyConstants.XMPP_PORT;
53import static org.onosproject.xmpp.core.ctl.OsgiPropertyConstants.XMPP_PORT_DEFAULT;
54
Tomek Osińskie9ccf412018-01-13 19:44:11 +010055
56/**
57 * The main class (bundle) of XMPP protocol.
58 * Responsible for:
59 * 1. Initialization and starting XMPP server.
60 * 2. Handling XMPP packets from clients and writing to clients.
61 * 3. Configuration parameters initialization.
62 * 4. Notifing listeners about XMPP events/packets.
63 */
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -070064@Component(immediate = true, service = XmppController.class,
65 property = {
66 XMPP_PORT + "=" + XMPP_PORT_DEFAULT,
67 })
Tomek Osińskie9ccf412018-01-13 19:44:11 +010068public class XmppControllerImpl implements XmppController {
69
70 private static final String APP_ID = "org.onosproject.xmpp";
Tomek Osińskie9ccf412018-01-13 19:44:11 +010071
72 private static final Logger log =
73 LoggerFactory.getLogger(XmppControllerImpl.class);
74
75 // core services declaration
Ray Milkeyd84f89b2018-08-17 14:54:17 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Tomek Osińskie9ccf412018-01-13 19:44:11 +010077 protected CoreService coreService;
78
Ray Milkeyd84f89b2018-08-17 14:54:17 -070079 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Tomek Osińskie9ccf412018-01-13 19:44:11 +010080 protected ComponentConfigService cfgService;
81
82 // configuration properties definition
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -070083 /** Port number used by XMPP protocol; default is 5269. */
84 private String xmppPort = XMPP_PORT_DEFAULT;
Tomek Osińskie9ccf412018-01-13 19:44:11 +010085
86 // listener declaration
87 protected Set<XmppDeviceListener> xmppDeviceListeners = new CopyOnWriteArraySet<XmppDeviceListener>();
88
Tomek Osiński7a1db182018-02-03 17:15:06 +010089 Multimap<String, XmppIqListener> xmppIqListeners = Multimaps.synchronizedSetMultimap(HashMultimap.create());
Tomek Osińskie9ccf412018-01-13 19:44:11 +010090 protected Set<XmppMessageListener> xmppMessageListeners = new CopyOnWriteArraySet<XmppMessageListener>();
91 protected Set<XmppPresenceListener> xmppPresenceListeners = new CopyOnWriteArraySet<XmppPresenceListener>();
92
93 protected XmppDeviceAgent agent = new DefaultXmppDeviceAgent();
94
95 private final XmppServer xmppServer = new XmppServer();
96 private DefaultXmppDeviceFactory deviceFactory = new DefaultXmppDeviceFactory();
97
98 ConcurrentMap<XmppDeviceId, XmppDevice> connectedDevices = Maps.newConcurrentMap();
99 ConcurrentMap<InetSocketAddress, XmppDeviceId> addressDeviceIdMap = Maps.newConcurrentMap();
100
101 @Activate
102 public void activate(ComponentContext context) {
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100103 coreService.registerApplication(APP_ID, this::cleanup);
104 cfgService.registerProperties(getClass());
105 deviceFactory.init(agent);
106 xmppServer.setConfiguration(context.getProperties());
107 xmppServer.start(deviceFactory);
Tomek Osiński7a1db182018-02-03 17:15:06 +0100108 log.info("XmppControllerImpl started.");
109 }
110
111 @Modified
112 public void modified(ComponentContext context) {
113 xmppServer.stop();
114 xmppServer.setConfiguration(context.getProperties());
115 xmppServer.start(deviceFactory);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100116 }
117
118 @Deactivate
119 public void deactivate() {
120 cleanup();
121 cfgService.unregisterProperties(getClass(), false);
122 log.info("Stopped");
123 }
124
125 private void cleanup() {
126 xmppServer.stop();
127 deviceFactory.cleanAgent();
128 connectedDevices.values().forEach(XmppDevice::disconnectDevice);
129 connectedDevices.clear();
130 }
131
132 @Override
133 public XmppDevice getDevice(XmppDeviceId xmppDeviceId) {
134 return connectedDevices.get(xmppDeviceId);
135 }
136
137 @Override
138 public void addXmppDeviceListener(XmppDeviceListener deviceListener) {
139 xmppDeviceListeners.add(deviceListener);
140 }
141
142 @Override
143 public void removeXmppDeviceListener(XmppDeviceListener deviceListener) {
144 xmppDeviceListeners.remove(deviceListener);
145 }
146
147 @Override
Tomek Osiński7a1db182018-02-03 17:15:06 +0100148 public void addXmppIqListener(XmppIqListener iqListener, String namespace) {
149 xmppIqListeners.put(namespace, iqListener);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100150 }
151
152 @Override
Tomek Osiński7a1db182018-02-03 17:15:06 +0100153 public void removeXmppIqListener(XmppIqListener iqListener, String namespace) {
154 xmppIqListeners.remove(namespace, iqListener);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100155 }
156
157 @Override
158 public void addXmppMessageListener(XmppMessageListener messageListener) {
159 xmppMessageListeners.add(messageListener);
160 }
161
162 @Override
163 public void removeXmppMessageListener(XmppMessageListener messageListener) {
164 xmppMessageListeners.remove(messageListener);
165 }
166
167 @Override
168 public void addXmppPresenceListener(XmppPresenceListener presenceListener) {
169 xmppPresenceListeners.add(presenceListener);
170 }
171
172 @Override
173 public void removeXmppPresenceListener(XmppPresenceListener presenceListener) {
174 xmppPresenceListeners.remove(presenceListener);
175 }
176
177
178 private class DefaultXmppDeviceAgent implements XmppDeviceAgent {
179
180 @Override
181 public boolean addConnectedDevice(XmppDeviceId deviceId, XmppDevice device) {
182 if (connectedDevices.get(deviceId) != null) {
183 log.warn("Trying to add Xmpp Device but found a previous " +
184 "value for XMPP deviceId: {}", deviceId);
185 return false;
186 } else {
187 log.info("Added XMPP device: {}", deviceId);
188 connectedDevices.put(deviceId, device);
189 for (XmppDeviceListener listener : xmppDeviceListeners) {
190 listener.deviceConnected(deviceId);
191 }
192 return true;
193 }
194 }
195
196 @Override
197 public void removeConnectedDevice(XmppDeviceId deviceId) {
198 connectedDevices.remove(deviceId);
199 for (XmppDeviceListener listener : xmppDeviceListeners) {
200 listener.deviceDisconnected(deviceId);
201 }
202 }
203
204 @Override
205 public XmppDevice getDevice(XmppDeviceId deviceId) {
206 return connectedDevices.get(deviceId);
207 }
208
209 @Override
210 public void processUpstreamEvent(XmppDeviceId deviceId, Packet packet) {
211 if (packet instanceof IQ) {
Tomek Osiński7a1db182018-02-03 17:15:06 +0100212 IQ iq = (IQ) packet;
213 String namespace = iq.getChildElement().getNamespace().getURI();
214 notifyIqListeners(iq, namespace);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100215 }
216 if (packet instanceof Message) {
Tomek Osiński7a1db182018-02-03 17:15:06 +0100217 notifyMessageListeners((Message) packet);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100218 }
219 if (packet instanceof Presence) {
Tomek Osiński7a1db182018-02-03 17:15:06 +0100220 notifyPresenceListeners((Presence) packet);
221 }
222 }
223
224 private void notifyPresenceListeners(Presence packet) {
225 for (XmppPresenceListener presenceListener : xmppPresenceListeners) {
226 presenceListener.handlePresenceStanza((Presence) packet);
227 }
228 }
229
230 private void notifyMessageListeners(Message message) {
231 for (XmppMessageListener messageListener : xmppMessageListeners) {
232 messageListener.handleMessageStanza(message);
233 }
234 }
235
236 private void notifyIqListeners(IQ iq, String namespace) {
237 for (XmppIqListener iqListener : xmppIqListeners.get(namespace)) {
238 iqListener.handleIqStanza(iq);
Tomek Osińskie9ccf412018-01-13 19:44:11 +0100239 }
240 }
241
242 }
243
244
245}