001/**
002 *
003 * Copyright 2019 Paul Schaub
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.message_fastening;
018
019import java.util.List;
020import java.util.WeakHashMap;
021
022import org.jivesoftware.smack.ConnectionCreationListener;
023import org.jivesoftware.smack.Manager;
024import org.jivesoftware.smack.XMPPConnection;
025import org.jivesoftware.smack.XMPPConnectionRegistry;
026import org.jivesoftware.smack.packet.MessageBuilder;
027
028import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
029import org.jivesoftware.smackx.message_fastening.element.FasteningElement;
030
031/**
032 * Smacks API for XEP-0422: Message Fastening.
033 * The API is still very bare bones, as the XEP intends Message Fastening to be used as a tool by other protocols.
034 *
035 * To enable / disable auto-announcing support for this feature, call {@link #setEnabledByDefault(boolean)} (default true).
036 *
037 * To fasten a payload to a previous message, create an {@link FasteningElement} using the builder provided by
038 * {@link FasteningElement#builder()}.
039 *
040 * You need to provide the {@link org.jivesoftware.smackx.sid.element.OriginIdElement} of the message you want to reference.
041 * Then add wrapped payloads using {@link FasteningElement.Builder#addWrappedPayloads(List)}
042 * and external payloads using {@link FasteningElement.Builder#addExternalPayloads(List)}.
043 *
044 * If you fastened some payloads onto the message previously and now want to replace the previous fastening, call
045 * {@link FasteningElement.Builder#isRemovingElement()}.
046 * Once you are finished, build the {@link FasteningElement} using {@link FasteningElement.Builder#build()} and add it to
047 * a stanza by calling {@link FasteningElement#applyTo(MessageBuilder)}.
048 *
049 * @see <a href="https://xmpp.org/extensions/xep-0422.html">XEP-0422: Message Fastening</a>
050 */
051public final class MessageFasteningManager extends Manager {
052
053    public static final String NAMESPACE = "urn:xmpp:fasten:0";
054
055    private static boolean ENABLED_BY_DEFAULT = false;
056
057    private static final WeakHashMap<XMPPConnection, MessageFasteningManager> INSTANCES = new WeakHashMap<>();
058
059    static {
060        XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
061            @Override
062            public void connectionCreated(XMPPConnection connection) {
063                if (ENABLED_BY_DEFAULT) {
064                    MessageFasteningManager.getInstanceFor(connection).announceSupport();
065                }
066            }
067        });
068    }
069
070    private MessageFasteningManager(XMPPConnection connection) {
071        super(connection);
072    }
073
074    public static synchronized MessageFasteningManager getInstanceFor(XMPPConnection connection) {
075        MessageFasteningManager manager = INSTANCES.get(connection);
076        if (manager == null) {
077            manager = new MessageFasteningManager(connection);
078            INSTANCES.put(connection, manager);
079        }
080        return manager;
081    }
082
083    /**
084     * Enable or disable auto-announcing support for Message Fastening.
085     * Default is enabled.
086     *
087     * @param enabled enabled
088     */
089    public static synchronized void setEnabledByDefault(boolean enabled) {
090        ENABLED_BY_DEFAULT = enabled;
091    }
092
093    /**
094     * Announce support for Message Fastening via Service Discovery.
095     */
096    public void announceSupport() {
097        ServiceDiscoveryManager discoveryManager = ServiceDiscoveryManager.getInstanceFor(connection());
098        discoveryManager.addFeature(NAMESPACE);
099    }
100
101    /**
102     * Stop announcing support for Message Fastening.
103     */
104    public void stopAnnouncingSupport() {
105        ServiceDiscoveryManager discoveryManager = ServiceDiscoveryManager.getInstanceFor(connection());
106        discoveryManager.removeFeature(NAMESPACE);
107    }
108}