package org.limewire.xmpp.client.impl.features;
import org.jivesoftware.smack.XMPPConnection;
import org.limewire.friend.api.FriendException;
import org.limewire.friend.api.FriendPresence;
import org.limewire.friend.api.FriendPresenceEvent;
import org.limewire.friend.api.RosterEvent;
import org.limewire.friend.api.feature.FeatureInitializer;
import org.limewire.friend.api.feature.FeatureRegistry;
import org.limewire.friend.impl.feature.NoSaveFeature;
import org.limewire.listener.BlockingEvent;
import org.limewire.listener.EventListener;
import org.limewire.listener.ListenerSupport;
import org.limewire.logging.Log;
import org.limewire.logging.LogFactory;
import org.limewire.xmpp.client.impl.XMPPFriendConnectionImpl;
import org.limewire.xmpp.client.impl.messages.nosave.NoSaveIQ;
import org.limewire.xmpp.client.impl.messages.nosave.NoSaveIQListener;
/**
* Initializer for {@link NoSaveFeature}.
*/
public class NoSaveFeatureInitializer implements FeatureInitializer {
private static final Log LOG = LogFactory.getLog(NoSaveFeatureInitializer.class);
private final XMPPFriendConnectionImpl connection;
private final XMPPConnection jabberConnection;
private final ListenerSupport<RosterEvent> rosterSupport;
private final ListenerSupport<FriendPresenceEvent> friendPresenceSupport;
private RosterListener rosterListener;
private NoSaveIQListener noSaveListener;
// The feature can only be fully initialized (meaning that the NoSaveIQ
// packet is sent, and the feature added to the xmpp connection)
// after both of the following preconditions are met:
//
// 1. Roster received (RosterEvent is used to determine this)
// 2. NoSaveFeature supported (We know it is when initializeFeature is called)
//
private boolean isRosterReceived;
private boolean isFeatureSupported;
public NoSaveFeatureInitializer(XMPPConnection jabberConnection, XMPPFriendConnectionImpl limeConnection,
ListenerSupport<RosterEvent> rosterSupport,
ListenerSupport<FriendPresenceEvent> friendPresenceSupport) {
this.connection = limeConnection;
this.jabberConnection = jabberConnection;
this.rosterSupport = rosterSupport;
this.friendPresenceSupport = friendPresenceSupport;
this.rosterListener = new RosterListener();
this.noSaveListener = null;
}
@Override
public void register(FeatureRegistry registry) {
rosterSupport.addListener(rosterListener);
registry.registerPrivateInitializer(NoSaveFeature.ID, this);
}
@Override
public void initializeFeature(FriendPresence notUsedInFeatureInit) {
setFeatureSupported(true);
sendNoSaveRequest();
}
@Override
public void removeFeature(FriendPresence friendPresence) {
friendPresence.removeFeature(NoSaveFeature.ID);
}
public void cleanup() {
rosterSupport.removeListener(rosterListener);
if (noSaveListener != null) {
jabberConnection.removePacketListener(noSaveListener);
noSaveListener.cleanup();
}
}
/**
* Only initialize the feature if both pre-conditions have been met
* <pre>
* 1. Roster has been received
* 2. The feature {@link NoSaveFeature} is supported
* </pre>
*/
private void sendNoSaveRequest() {
if (canSendNoSaveRequest()) {
// send message to entity server explicitly requesting nosave state
// make sure noSaveIQListener is ready for the reply messages
if (noSaveListener == null) {
noSaveListener = NoSaveIQListener.createNoSaveIQListener(connection, friendPresenceSupport);
jabberConnection.addPacketListener(noSaveListener, noSaveListener.getPacketFilter());
}
NoSaveIQ requestNoSaveSettingsPacket = NoSaveIQ.getNoSaveStatesMessage();
try {
connection.sendPacket(requestNoSaveSettingsPacket);
} catch (FriendException e) {
LOG.warn("couldn't request google:nosave settings", e);
}
}
}
private synchronized void setFeatureSupported(boolean isFeatureSupported) {
this.isFeatureSupported = isFeatureSupported;
}
private synchronized void setRosterReceived(boolean isRosterReceived) {
this.isRosterReceived = isRosterReceived;
}
private synchronized boolean canSendNoSaveRequest() {
return isFeatureSupported && isRosterReceived;
}
/** Every time roster changes, (re)send nosave request packet.
* Event handler code is annotated @BlockingEvent because we are
* potentially over the network.
**/
private class RosterListener implements EventListener<RosterEvent> {
@BlockingEvent
@Override
public void handleEvent(RosterEvent event) {
setRosterReceived(true);
sendNoSaveRequest();
}
}
}