/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * 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 net.java.sip.communicator.plugin.otr; import java.util.*; import java.util.concurrent.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; import org.osgi.framework.*; /** * The OtrContactManager is used for accessing <tt>OtrContact</tt>s in a static * way. * * The <tt>OtrContact</tt> class is just a wrapper of [Contact, ContactResource] * pairs. Its purpose is for the otr plugin to be able to create different * <tt>Session</tt>s for every ContactResource that a Contact has. * * Currently, only the Jabber protocol supports ContactResources. * * @author Marin Dzhigarov * */ public class OtrContactManager implements ServiceListener { /** * The logger */ private final Logger logger = Logger.getLogger(OtrContactManager.class); /** * A map that caches OtrContacts to minimize memory usage. */ private static final Map<Contact, List<OtrContact>> contactsMap = new ConcurrentHashMap<Contact, List<OtrContact>>(); /** * The <tt>OtrContact</tt> class is just a wrapper of * [Contact, ContactResource] pairs. Its purpose is for the otr plugin to be * able to create different <tt>Session</tt>s for every ContactResource that * a Contact has. * * @author Marin Dzhigarov * */ public static class OtrContact { public final Contact contact; public final ContactResource resource; private OtrContact(Contact contact, ContactResource resource) { this.contact = contact; this.resource = resource; } public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof OtrContact)) return false; OtrContact other = (OtrContact) obj; if (this.contact != null && this.contact.equals(other.contact)) { if (this.resource != null && resource.equals(other.resource)) return true; if (this.resource == null && other.resource == null) return true; return false; } return false; } public int hashCode() { int result = 17; result = 31 * result + (contact == null ? 0 : contact.hashCode()); result = 31 * result + (resource == null ? 0 : resource.hashCode()); return result; } } /** * Gets the <tt>OtrContact</tt> that represents this * [Contact, ContactResource] pair from the cache. If such pair does not * still exist it is then created and cached for further usage. * * @param contact the <tt>Contact</tt> that the returned OtrContact * represents. * @param resource the <tt>ContactResource</tt> that the returned OtrContact * represents. * @return The <tt>OtrContact</tt> that represents this * [Contact, ContactResource] pair. */ public static OtrContact getOtrContact( Contact contact, ContactResource resource) { if (contact == null) return null; List<OtrContact> otrContactsList = contactsMap.get(contact); if (otrContactsList != null) { for (OtrContact otrContact : otrContactsList) { if (resource != null && resource.equals(otrContact.resource)) return otrContact; } OtrContact otrContact = new OtrContact(contact, resource); synchronized (otrContactsList) { while (!otrContactsList.contains(otrContact)) otrContactsList.add(otrContact); } return otrContact; } else { synchronized (contactsMap) { while (!contactsMap.containsKey(contact)) { otrContactsList = new ArrayList<OtrContact>(); contactsMap.put(contact, otrContactsList); } } return getOtrContact(contact, resource); } } /** * Cleans up unused cached up Contacts. */ public void serviceChanged(ServiceEvent event) { Object service = OtrActivator.bundleContext.getService(event.getServiceReference()); if (!(service instanceof ProtocolProviderService)) return; if (event.getType() == ServiceEvent.UNREGISTERING) { if (logger.isDebugEnabled()) { logger.debug( "Unregistering a ProtocolProviderService, cleaning" + " OTR's Contact to OtrContact map"); } ProtocolProviderService provider = (ProtocolProviderService) service; synchronized(contactsMap) { Iterator<Contact> i = contactsMap.keySet().iterator(); while (i.hasNext()) { if (provider.equals(i.next().getProtocolProvider())) i.remove(); } } } } }