From f1a2d4c417507300284261c2cc5a2fccb2d735a0 Mon Sep 17 00:00:00 2001 From: Boris Grozev Date: Tue, 8 Feb 2022 15:48:47 -0600 Subject: [PATCH] feat: Add a colibri2 conference-notification IQ. --- .../colibri2/ConferenceNotificationIQ.java | 190 ++++++++++++++++++ .../extensions/colibri2/IqProviderUtils.java | 2 + .../ConferenceNotificationIQTest.java | 93 +++++++++ 3 files changed, 285 insertions(+) create mode 100644 src/main/java/org/jitsi/xmpp/extensions/colibri2/ConferenceNotificationIQ.java create mode 100644 src/test/java/org/jitsi/xmpp/extensions/colibri2/ConferenceNotificationIQTest.java diff --git a/src/main/java/org/jitsi/xmpp/extensions/colibri2/ConferenceNotificationIQ.java b/src/main/java/org/jitsi/xmpp/extensions/colibri2/ConferenceNotificationIQ.java new file mode 100644 index 0000000..818ffd6 --- /dev/null +++ b/src/main/java/org/jitsi/xmpp/extensions/colibri2/ConferenceNotificationIQ.java @@ -0,0 +1,190 @@ +/* + * Copyright @ 2022 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jitsi.xmpp.extensions.colibri2; + +import org.jetbrains.annotations.*; +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.parsing.*; +import org.jivesoftware.smack.provider.*; +import org.jivesoftware.smack.xml.*; + +import javax.xml.namespace.*; +import java.io.*; +import java.util.*; + +public class ConferenceNotificationIQ extends IQ +{ + /** + * The XML element name of the Colibri2 conference-notification IQ. + */ + public static final String ELEMENT = "conference-notification"; + + /** + * The Colibri2 XML namespace. + */ + public static final String NAMESPACE = AbstractConferenceModificationIQ.NAMESPACE; + + /** + * The qualified name of the element. + */ + public static final QName QNAME = new QName(NAMESPACE, ELEMENT); + + /** + * The XML name of the meeting-id attribute. + */ + public static final String MEETING_ID_ATTR_NAME = "meeting-id"; + + + @Contract("_ -> new") + public static @NotNull ConferenceNotificationIQ.Builder builder(IqData iqData) + { + return new ConferenceNotificationIQ.Builder(iqData); + } + + @Contract("_ -> new") + public static @NotNull ConferenceNotificationIQ.Builder builder(String stanzaId) + { + return new ConferenceNotificationIQ.Builder(stanzaId); + } + + @Contract("_ -> new") + public static @NotNull ConferenceNotificationIQ.Builder builder(XMPPConnection connection) + { + return new ConferenceNotificationIQ.Builder(connection); + } + + /** + * The id of the conference + */ + private final @NotNull String meetingId; + + /** Initializes a new {@link ConferenceModifyIQ} instance. */ + protected ConferenceNotificationIQ(ConferenceNotificationIQ.Builder b) + { + super(b, ELEMENT, NAMESPACE); + + if (b.meetingId == null) + { + throw new IllegalArgumentException("meeting-id must be set for " + ELEMENT + " IQ"); + } + meetingId = b.meetingId; + + for (Colibri2Endpoint endpoint: b.endpoints) + { + addExtension(endpoint); + } + } + + /** + * Get endpoints described by the message + */ + public @NotNull List getEndpoints() + { + return getExtensions(Colibri2Endpoint.class); + } + + /** + * Get the ID of the conference. + */ + public @NotNull String getMeetingId() + { + return meetingId; + } + + @Override + protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) + { + xml.attribute(MEETING_ID_ATTR_NAME, meetingId); + + /* All our elements are extensions, so we just need to return empty here. */ + xml.setEmptyElement(); + + return xml; + } + + + public static class Builder + extends IqBuilder + { + private final List endpoints = new ArrayList<>(); + private String meetingId; + + private Builder(IqData iqCommon) + { + super(iqCommon); + } + + private Builder(XMPPConnection connection) + { + super(connection); + } + + private Builder(String stanzaId) + { + super(stanzaId); + } + + public Builder addEndpoint(Colibri2Endpoint endpoint) + { + endpoints.add(endpoint); + return this; + } + + public Builder setMeetingId(String meetingId) + { + this.meetingId = meetingId; + return this; + } + + @Override + @Contract(" -> new") + public ConferenceNotificationIQ build() + { + return new ConferenceNotificationIQ(this); + } + + @Override + public Builder getThis() + { + return this; + } + } + + public static class Provider extends IqProvider + { + @Override + public ConferenceNotificationIQ parse( + XmlPullParser parser, + int initialDepth, + IqData iqData, + XmlEnvironment xmlEnvironment) + throws XmlPullParserException, IOException, SmackParsingException + { + ConferenceNotificationIQ.Builder builder = ConferenceNotificationIQ.builder(iqData); + String meetingId = parser.getAttributeValue(MEETING_ID_ATTR_NAME); + if (meetingId == null) + { + throw new SmackParsingException.RequiredAttributeMissingException(MEETING_ID_ATTR_NAME); + } + builder.setMeetingId(meetingId); + + ConferenceNotificationIQ iq = builder.build(); + IqProviderUtils.parseExtensions(parser, initialDepth, iq); + return iq; + } + } +} diff --git a/src/main/java/org/jitsi/xmpp/extensions/colibri2/IqProviderUtils.java b/src/main/java/org/jitsi/xmpp/extensions/colibri2/IqProviderUtils.java index 99f7dca..a101a71 100644 --- a/src/main/java/org/jitsi/xmpp/extensions/colibri2/IqProviderUtils.java +++ b/src/main/java/org/jitsi/xmpp/extensions/colibri2/IqProviderUtils.java @@ -121,6 +121,8 @@ public static void registerProviders() new ConferenceModifyIQProvider()); ProviderManager.addIQProvider(ConferenceModifiedIQ.ELEMENT, ConferenceModifiedIQ.NAMESPACE, new ConferenceModifiedIQProvider()); + ProviderManager.addIQProvider(ConferenceNotificationIQ.ELEMENT, ConferenceNotificationIQ.NAMESPACE, + new ConferenceNotificationIQ.Provider()); ProviderManager.addExtensionProvider(Colibri2Endpoint.ELEMENT, Colibri2Endpoint.NAMESPACE, new Colibri2Endpoint.Provider()); diff --git a/src/test/java/org/jitsi/xmpp/extensions/colibri2/ConferenceNotificationIQTest.java b/src/test/java/org/jitsi/xmpp/extensions/colibri2/ConferenceNotificationIQTest.java new file mode 100644 index 0000000..9407152 --- /dev/null +++ b/src/test/java/org/jitsi/xmpp/extensions/colibri2/ConferenceNotificationIQTest.java @@ -0,0 +1,93 @@ +/* + * Copyright @ 2022 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jitsi.xmpp.extensions.colibri2; + +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.util.*; +import org.jivesoftware.smack.xml.*; +import org.junit.jupiter.api.*; +import org.xmlunit.builder.*; +import org.xmlunit.diff.*; + +import static org.junit.jupiter.api.Assertions.*; + +public class ConferenceNotificationIQTest +{ + private static final String MEETING_ID = "88ff288c-5eeb-4ea9-bc2f-93ea38c43b78"; + private static final String IQ_ID = "iq-id"; + private static final String ENDPOINT_ID = "bd9b6765"; + + private static final String expectedXml = + "" + + "" + + "" + + "" + + ""; + + @BeforeAll + static void registerProviders() + { + IqProviderUtils.registerProviders(); + } + + @Test + public void buildColibriConferenceModifyTest() + { + ConferenceNotificationIQ.Builder iqBuilder = ConferenceNotificationIQ.builder(IQ_ID); + + iqBuilder.setMeetingId(MEETING_ID); + + Colibri2Endpoint.Builder endpointBuilder = Colibri2Endpoint.getBuilder(); + endpointBuilder.setId(ENDPOINT_ID); + endpointBuilder.setExpire(true); + + iqBuilder.addEndpoint(endpointBuilder.build()); + + ConferenceNotificationIQ iq = iqBuilder.build(); + + assertEquals(MEETING_ID, iq.getMeetingId(), "The meeting-id should be correctly set."); + + Colibri2Endpoint endpoint = iq.getEndpoints().get(0); + assertNotNull(endpoint); + assertEquals(ENDPOINT_ID, endpoint.getId()); + assertTrue(endpoint.getExpire()); + + Diff diff = DiffBuilder.compare(expectedXml). + withTest(iq.toXML().toString()). + checkForIdentical().build(); + + assertFalse(diff.hasDifferences(), diff.toString()); + } + + @Test + public void parseColibriConferenceModifyTest() + throws Exception + { + XmlPullParser parser = PacketParserUtils.getParserFor(expectedXml); + IQ parsedIq = PacketParserUtils.parseIQ(parser); + + assertInstanceOf(ConferenceNotificationIQ.class, parsedIq); + + ConferenceNotificationIQ iq = (ConferenceNotificationIQ) parsedIq; + + assertEquals(MEETING_ID, iq.getMeetingId(), "The meeting-id should be correctly parsed"); + + Colibri2Endpoint endpoint = iq.getEndpoints().get(0); + assertNotNull(endpoint); + assertEquals(ENDPOINT_ID, endpoint.getId()); + assertTrue(endpoint.getExpire()); + } +}