FallbackIndicationManager.java
- /**
- *
- * Copyright 2020 Paul Schaub
- *
- * 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.jivesoftware.smackx.fallback_indication;
- import java.util.Map;
- import java.util.Set;
- import java.util.WeakHashMap;
- import java.util.concurrent.CopyOnWriteArraySet;
- import org.jivesoftware.smack.AsyncButOrdered;
- import org.jivesoftware.smack.ConnectionCreationListener;
- import org.jivesoftware.smack.Manager;
- import org.jivesoftware.smack.SmackException;
- import org.jivesoftware.smack.XMPPConnection;
- import org.jivesoftware.smack.XMPPConnectionRegistry;
- import org.jivesoftware.smack.XMPPException;
- import org.jivesoftware.smack.filter.AndFilter;
- import org.jivesoftware.smack.filter.StanzaExtensionFilter;
- import org.jivesoftware.smack.filter.StanzaFilter;
- import org.jivesoftware.smack.filter.StanzaTypeFilter;
- import org.jivesoftware.smack.packet.Message;
- import org.jivesoftware.smack.packet.MessageBuilder;
- import org.jivesoftware.smack.packet.Stanza;
- import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
- import org.jivesoftware.smackx.fallback_indication.element.FallbackIndicationElement;
- import org.jxmpp.jid.BareJid;
- import org.jxmpp.jid.EntityBareJid;
- /**
- * Smacks API for XEP-0428: Fallback Indication.
- * In some scenarios it might make sense to mark the body of a message as fallback for legacy clients.
- * Examples are encryption mechanisms where the sender might include a hint for legacy clients stating that the
- * body (eg. "This message is encrypted") should be ignored.
- *
- * @see <a href="https://xmpp.org/extensions/xep-0428.html">XEP-0428: Fallback Indication</a>
- */
- public final class FallbackIndicationManager extends Manager {
- private static final Map<XMPPConnection, FallbackIndicationManager> INSTANCES = new WeakHashMap<>();
- static {
- XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
- @Override
- public void connectionCreated(XMPPConnection connection) {
- getInstanceFor(connection);
- }
- });
- }
- private final Set<FallbackIndicationListener> listeners = new CopyOnWriteArraySet<>();
- private final AsyncButOrdered<BareJid> asyncButOrdered = new AsyncButOrdered<>();
- private final StanzaFilter fallbackIndicationElementFilter = new AndFilter(StanzaTypeFilter.MESSAGE,
- new StanzaExtensionFilter(FallbackIndicationElement.ELEMENT, FallbackIndicationElement.NAMESPACE));
- private void fallbackIndicationElementListener(Stanza packet) {
- Message message = (Message) packet;
- FallbackIndicationElement indicator = FallbackIndicationElement.fromMessage(message);
- String body = message.getBody();
- asyncButOrdered.performAsyncButOrdered(message.getFrom().asBareJid(), () -> {
- for (FallbackIndicationListener l : listeners) {
- l.onFallbackIndicationReceived(message, indicator, body);
- }
- });
- }
- private FallbackIndicationManager(XMPPConnection connection) {
- super(connection);
- connection.addAsyncStanzaListener(this::fallbackIndicationElementListener, fallbackIndicationElementFilter);
- ServiceDiscoveryManager.getInstanceFor(connection).addFeature(FallbackIndicationElement.NAMESPACE);
- }
- public static synchronized FallbackIndicationManager getInstanceFor(XMPPConnection connection) {
- FallbackIndicationManager manager = INSTANCES.get(connection);
- if (manager == null) {
- manager = new FallbackIndicationManager(connection);
- INSTANCES.put(connection, manager);
- }
- return manager;
- }
- /**
- * Determine, whether or not a user supports Fallback Indications.
- *
- * @param jid BareJid of the user.
- * @return feature support
- *
- * @throws XMPPException.XMPPErrorException if a protocol level error happens
- * @throws SmackException.NotConnectedException if the connection is not connected
- * @throws InterruptedException if the thread is being interrupted
- * @throws SmackException.NoResponseException if the server doesn't send a response in time
- */
- public boolean userSupportsFallbackIndications(EntityBareJid jid)
- throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
- SmackException.NoResponseException {
- return ServiceDiscoveryManager.getInstanceFor(connection())
- .supportsFeature(jid, FallbackIndicationElement.NAMESPACE);
- }
- /**
- * Determine, whether or not the server supports Fallback Indications.
- *
- * @return server side feature support
- *
- * @throws XMPPException.XMPPErrorException if a protocol level error happens
- * @throws SmackException.NotConnectedException if the connection is not connected
- * @throws InterruptedException if the thread is being interrupted
- * @throws SmackException.NoResponseException if the server doesn't send a response in time
- */
- public boolean serverSupportsFallbackIndications()
- throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
- SmackException.NoResponseException {
- return ServiceDiscoveryManager.getInstanceFor(connection())
- .serverSupportsFeature(FallbackIndicationElement.NAMESPACE);
- }
- /**
- * Set the body of the message to the provided fallback message and add a {@link FallbackIndicationElement}.
- *
- * @param messageBuilder message builder
- * @param fallbackMessageBody fallback message body
- * @return builder with set body and added fallback element
- */
- public static MessageBuilder addFallbackIndicationWithBody(MessageBuilder messageBuilder, String fallbackMessageBody) {
- return addFallbackIndication(messageBuilder).setBody(fallbackMessageBody);
- }
- /**
- * Add a {@link FallbackIndicationElement} to the provided message builder.
- *
- * @param messageBuilder message builder
- * @return message builder with added fallback element
- */
- public static MessageBuilder addFallbackIndication(MessageBuilder messageBuilder) {
- return messageBuilder.addExtension(new FallbackIndicationElement());
- }
- /**
- * Register a {@link FallbackIndicationListener} that gets notified whenever a message that contains a
- * {@link FallbackIndicationElement} is received.
- *
- * @param listener listener to be registered.
- */
- public synchronized void addFallbackIndicationListener(FallbackIndicationListener listener) {
- listeners.add(listener);
- }
- /**
- * Unregister a {@link FallbackIndicationListener}.
- *
- * @param listener listener to be unregistered.
- */
- public synchronized void removeFallbackIndicationListener(FallbackIndicationListener listener) {
- listeners.remove(listener);
- }
- }