@Override
    public IQ handleIQ(IQ packet) throws UnauthorizedException, PacketException {
        try {
            IQ returnPacket;
            org.xmpp.packet.Roster roster = (org.xmpp.packet.Roster)packet;

            JID recipientJID = packet.getTo();

            // The packet is bound for the server and must be roster management
            if (recipientJID == null || recipientJID.equals(packet.getFrom().asBareJID())) {
                returnPacket = manageRoster(roster);
            } else {
                returnPacket = IQ.createResultIQ(packet);
                // The server MUST return a <forbidden/> stanza error to the client if the sender of the roster set is not authorized to update the roster
                // (where typically only an authenticated resource of the account itself is authorized).
                returnPacket.setError(PacketError.Condition.forbidden);
            }
            return returnPacket;
        }
        catch (SharedGroupException e) {
            IQ result = IQ.createResultIQ(packet);
            result.setChildElement(packet.getChildElement().createCopy());
            result.setError(PacketError.Condition.not_acceptable);
            return result;
        }
        catch (UnauthorizedException e) {
            IQ result = IQ.createResultIQ(packet);
            result.setChildElement(packet.getChildElement().createCopy());
            result.setError(PacketError.Condition.not_authorized);
            return result;
        }
        catch (Exception e) {
            if (e.getCause() instanceof IDNAException || e.getCause() instanceof IllegalArgumentException) {
                Log.warn(LocaleUtils.getLocalizedString("admin.error") + e.getMessage());
                IQ result = IQ.createResultIQ(packet);
                result.setChildElement(packet.getChildElement().createCopy());
                result.setError(PacketError.Condition.jid_malformed);
                return result;
            }
            else {
                Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
                IQ result = IQ.createResultIQ(packet);
                result.setChildElement(packet.getChildElement().createCopy());
                result.setError(PacketError.Condition.internal_server_error);
                return result;
            }
        }
    }
Handles all roster queries. There are two major types of queries:

<ul>
     <li>Roster remove - A forced removal of items from a roster. Roster
     removals are the only roster queries allowed to
     directly affect the roster from another user.
     </li>
     <li>Roster management - A local user looking up or updating their
     roster.
     </li>
</ul>

@param packet The update packet
@return The reply or null if no reply
xmppserver/src/main/java/org/jivesoftware/openfire/handler/IQRosterHandler.java