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