001/** 002 * 003 * Copyright 2018 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.sid; 018 019import java.util.Map; 020import java.util.WeakHashMap; 021 022import org.jivesoftware.smack.ConnectionCreationListener; 023import org.jivesoftware.smack.Manager; 024import org.jivesoftware.smack.StanzaListener; 025import org.jivesoftware.smack.XMPPConnection; 026import org.jivesoftware.smack.XMPPConnectionRegistry; 027import org.jivesoftware.smack.filter.AndFilter; 028import org.jivesoftware.smack.filter.MessageTypeFilter; 029import org.jivesoftware.smack.filter.NotFilter; 030import org.jivesoftware.smack.filter.StanzaExtensionFilter; 031import org.jivesoftware.smack.filter.StanzaFilter; 032import org.jivesoftware.smack.filter.ToTypeFilter; 033import org.jivesoftware.smack.packet.Message; 034import org.jivesoftware.smack.packet.Stanza; 035import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; 036import org.jivesoftware.smackx.sid.element.OriginIdElement; 037 038public final class StableUniqueStanzaIdManager extends Manager { 039 040 public static final String NAMESPACE = "urn:xmpp:sid:0"; 041 042 private static final Map<XMPPConnection, StableUniqueStanzaIdManager> INSTANCES = new WeakHashMap<>(); 043 044 // Filter for outgoing stanzas. 045 private static final StanzaFilter OUTGOING_FILTER = new AndFilter( 046 MessageTypeFilter.NORMAL_OR_CHAT_OR_HEADLINE, 047 ToTypeFilter.ENTITY_FULL_OR_BARE_JID); 048 049 private static final StanzaFilter ORIGIN_ID_FILTER = new StanzaExtensionFilter(OriginIdElement.ELEMENT, NAMESPACE); 050 051 // Listener for outgoing stanzas that adds origin-ids to outgoing stanzas. 052 private final StanzaListener stanzaListener = new StanzaListener() { 053 @Override 054 public void processStanza(Stanza stanza) { 055 OriginIdElement.addOriginId((Message) stanza); 056 } 057 }; 058 059 static { 060 XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { 061 @Override 062 public void connectionCreated(XMPPConnection connection) { 063 getInstanceFor(connection); 064 } 065 }); 066 } 067 068 /** 069 * Private constructor. 070 * @param connection 071 */ 072 private StableUniqueStanzaIdManager(XMPPConnection connection) { 073 super(connection); 074 enable(); 075 } 076 077 /** 078 * Return an instance of the StableUniqueStanzaIdManager for the given connection. 079 * 080 * @param connection xmpp-connection 081 * @return manager instance for the connection 082 */ 083 public static StableUniqueStanzaIdManager getInstanceFor(XMPPConnection connection) { 084 StableUniqueStanzaIdManager manager = INSTANCES.get(connection); 085 if (manager == null) { 086 manager = new StableUniqueStanzaIdManager(connection); 087 INSTANCES.put(connection, manager); 088 } 089 return manager; 090 } 091 092 /** 093 * Start appending origin-id elements to outgoing stanzas and add the feature to disco. 094 */ 095 public synchronized void enable() { 096 ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(NAMESPACE); 097 StanzaFilter filter = new AndFilter(OUTGOING_FILTER, new NotFilter(OUTGOING_FILTER)); 098 connection().addStanzaInterceptor(stanzaListener, filter); 099 } 100 101 /** 102 * Stop appending origin-id elements to outgoing stanzas and remove the feature from disco. 103 */ 104 public synchronized void disable() { 105 ServiceDiscoveryManager.getInstanceFor(connection()).removeFeature(NAMESPACE); 106 connection().removeStanzaInterceptor(stanzaListener); 107 } 108 109 /** 110 * Return true, if we automatically append origin-id elements to outgoing stanzas. 111 * 112 * @return true if functionality is enabled, otherwise false. 113 */ 114 public synchronized boolean isEnabled() { 115 ServiceDiscoveryManager disco = ServiceDiscoveryManager.getInstanceFor(connection()); 116 return disco.includesFeature(NAMESPACE); 117 } 118}