net.java.sip.communicator.impl.protocol.jabber.InfoRetreiver.java Source code

Java tutorial

Introduction

Here is the source code for net.java.sip.communicator.impl.protocol.jabber.InfoRetreiver.java

Source

/*
 * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package net.java.sip.communicator.impl.protocol.jabber;

import java.lang.reflect.*;
import java.net.*;
import java.text.*;
import java.util.*;

import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
import net.java.sip.communicator.util.*;

import org.apache.commons.lang3.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.filter.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smackx.packet.*;

/**
 * Handles and retrieves all info of our contacts or our account info
 *
 * @author Damian Minkov
 */
public class InfoRetreiver {
    private static final Logger logger = Logger.getLogger(InfoRetreiver.class);

    /**
     * A callback to the Jabber provider that created us.
     */
    private ProtocolProviderServiceJabberImpl jabberProvider = null;

    // here is kept all the details retrieved so far
    private final Map<String, List<GenericDetail>> retreivedDetails = new Hashtable<String, List<GenericDetail>>();

    private static final String TAG_FN_OPEN = "<FN>";
    private static final String TAG_FN_CLOSE = "</FN>";

    /**
     * The timeout to wait before considering vcard has time outed.
     */
    private final long vcardTimeoutReply;

    protected InfoRetreiver(ProtocolProviderServiceJabberImpl jabberProvider, String ownerUin) {
        this.jabberProvider = jabberProvider;

        vcardTimeoutReply = JabberActivator.getConfigurationService()
                .getLong(ProtocolProviderServiceJabberImpl.VCARD_REPLY_TIMEOUT_PROPERTY, -1);
    }

    /**
     * returns the user details from the specified class or its descendants
     * the class is one from the
     * net.java.sip.communicator.service.protocol.ServerStoredDetails
     * or implemented one in the operation set for the user info
     *
     * @param uin String
     * @param detailClass Class
     * @return Iterator
     */
    <T extends GenericDetail> Iterator<T> getDetailsAndDescendants(String uin, Class<T> detailClass) {
        List<GenericDetail> details = getContactDetails(uin);
        List<T> result = new LinkedList<T>();

        for (GenericDetail item : details)
            if (detailClass.isInstance(item)) {
                @SuppressWarnings("unchecked")
                T t = (T) item;

                result.add(t);
            }

        return result.iterator();
    }

    /**
     * returns the user details from the specified class
     * exactly that class not its descendants
     *
     * @param uin String
     * @param detailClass Class
     * @return Iterator
     */
    Iterator<GenericDetail> getDetails(String uin, Class<? extends GenericDetail> detailClass) {
        List<GenericDetail> details = getContactDetails(uin);
        List<GenericDetail> result = new LinkedList<GenericDetail>();

        for (GenericDetail item : details)
            if (detailClass.equals(item.getClass()))
                result.add(item);

        return result.iterator();
    }

    /**
     * request the full info for the given contactAddress
     * waits and return this details
     *
     * @param contactAddress String
     * @return Vector the details
     */
    List<GenericDetail> getContactDetails(String contactAddress) {
        List<GenericDetail> result = getCachedContactDetails(contactAddress);

        if (result == null) {
            return retrieveDetails(contactAddress);
        }

        return result;
    }

    /**
     * Retrieve details and return them or if missing return an empty list.
     * @param contactAddress the address to search for.
     * @return the details or empty list.
     */
    protected List<GenericDetail> retrieveDetails(String contactAddress) {
        List<GenericDetail> result = new LinkedList<GenericDetail>();
        try {
            XMPPConnection connection = jabberProvider.getConnection();

            if (connection == null || !connection.isAuthenticated())
                return null;

            VCard card = new VCard();

            // if there is no value or is equals to the default one
            // load vcard using smack load method
            if (vcardTimeoutReply == -1 || vcardTimeoutReply == SmackConfiguration.getPacketReplyTimeout())
                card.load(connection, contactAddress);
            else
                load(card, connection, contactAddress, vcardTimeoutReply);

            String tmp;

            tmp = checkForFullName(card);
            if (tmp != null)
                result.add(new DisplayNameDetail(StringEscapeUtils.unescapeXml(tmp)));

            tmp = card.getFirstName();
            if (tmp != null)
                result.add(new FirstNameDetail(StringEscapeUtils.unescapeXml(tmp)));

            tmp = card.getMiddleName();
            if (tmp != null)
                result.add(new MiddleNameDetail(StringEscapeUtils.unescapeXml(tmp)));

            tmp = card.getLastName();
            if (tmp != null)
                result.add(new LastNameDetail(StringEscapeUtils.unescapeXml(tmp)));

            tmp = card.getNickName();
            if (tmp != null)
                result.add(new NicknameDetail(StringEscapeUtils.unescapeXml(tmp)));

            tmp = card.getField("BDAY");
            if (tmp != null) {
                try {
                    Calendar birthDateCalendar = Calendar.getInstance();
                    DateFormat dateFormat = new SimpleDateFormat(
                            JabberActivator.getResources().getI18NString("plugin.accountinfo.BDAY_FORMAT"));
                    Date birthDate = dateFormat.parse(tmp);
                    birthDateCalendar.setTime(birthDate);
                    BirthDateDetail bd = new BirthDateDetail(birthDateCalendar);
                    result.add(bd);
                } catch (ParseException e) {
                }
            }
            // Home Details
            // addrField one of
            // POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
            // LOCALITY, REGION, PCODE, CTRY
            tmp = card.getAddressFieldHome("STREET");
            if (tmp != null)
                result.add(new AddressDetail(tmp));

            tmp = card.getAddressFieldHome("LOCALITY");
            if (tmp != null)
                result.add(new CityDetail(tmp));

            tmp = card.getAddressFieldHome("REGION");
            if (tmp != null)
                result.add(new ProvinceDetail(tmp));

            tmp = card.getAddressFieldHome("PCODE");
            if (tmp != null)
                result.add(new PostalCodeDetail(tmp));

            tmp = card.getAddressFieldHome("CTRY");
            if (tmp != null)
                result.add(new CountryDetail(tmp));

            // phoneType one of
            //VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF

            tmp = card.getPhoneHome("VOICE");
            if (tmp != null)
                result.add(new PhoneNumberDetail(tmp));

            tmp = card.getPhoneHome("VIDEO");
            if (tmp != null)
                result.add(new VideoDetail(tmp));

            tmp = card.getPhoneHome("FAX");
            if (tmp != null)
                result.add(new FaxDetail(tmp));

            tmp = card.getPhoneHome("PAGER");
            if (tmp != null)
                result.add(new PagerDetail(tmp));

            tmp = card.getPhoneHome("CELL");
            if (tmp != null)
                result.add(new MobilePhoneDetail(tmp));

            tmp = card.getPhoneHome("TEXT");
            if (tmp != null)
                result.add(new MobilePhoneDetail(tmp));

            tmp = card.getEmailHome();
            if (tmp != null)
                result.add(new EmailAddressDetail(tmp));

            // Work Details
            // addrField one of
            // POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
            // LOCALITY, REGION, PCODE, CTRY
            tmp = card.getAddressFieldWork("STREET");
            if (tmp != null)
                result.add(new WorkAddressDetail(tmp));

            tmp = card.getAddressFieldWork("LOCALITY");
            if (tmp != null)
                result.add(new WorkCityDetail(tmp));

            tmp = card.getAddressFieldWork("REGION");
            if (tmp != null)
                result.add(new WorkProvinceDetail(tmp));

            tmp = card.getAddressFieldWork("PCODE");
            if (tmp != null)
                result.add(new WorkPostalCodeDetail(tmp));

            //                tmp = card.getAddressFieldWork("CTRY");
            //                if(tmp != null)
            //                    result.add(new WorkCountryDetail(tmp);

            // phoneType one of
            //VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF

            tmp = card.getPhoneWork("VOICE");
            if (tmp != null)
                result.add(new WorkPhoneDetail(tmp));

            tmp = card.getPhoneWork("VIDEO");
            if (tmp != null)
                result.add(new WorkVideoDetail(tmp));

            tmp = card.getPhoneWork("FAX");
            if (tmp != null)
                result.add(new WorkFaxDetail(tmp));

            tmp = card.getPhoneWork("PAGER");
            if (tmp != null)
                result.add(new WorkPagerDetail(tmp));

            tmp = card.getPhoneWork("CELL");
            if (tmp != null)
                result.add(new WorkMobilePhoneDetail(tmp));

            tmp = card.getPhoneWork("TEXT");
            if (tmp != null)
                result.add(new WorkMobilePhoneDetail(tmp));

            tmp = card.getEmailWork();
            if (tmp != null)
                result.add(new WorkEmailAddressDetail(tmp));

            tmp = card.getOrganization();
            if (tmp != null)
                result.add(new WorkOrganizationNameDetail(tmp));

            tmp = card.getOrganizationUnit();
            if (tmp != null)
                result.add(new WorkDepartmentNameDetail(tmp));

            tmp = card.getField("TITLE");
            if (tmp != null)
                result.add(new JobTitleDetail(tmp));

            tmp = card.getField("ABOUTME");
            if (tmp != null)
                result.add(new AboutMeDetail(tmp));

            byte[] imageBytes = card.getAvatar();
            if (imageBytes != null && imageBytes.length > 0) {
                result.add(new ImageDetail("Image", imageBytes));
            }

            try {
                tmp = card.getField("URL");
                if (tmp != null)
                    result.add(new URLDetail("URL", new URL(tmp)));
            } catch (MalformedURLException e) {
            }
        } catch (Throwable exc) {
            String msg = "Cannot load details for contact " + contactAddress + " : " + exc.getMessage();
            if (logger.isTraceEnabled())
                logger.error(msg, exc);
            else
                logger.error(msg);
        }

        retreivedDetails.put(contactAddress, result);

        return result;
    }

    /**
     * request the full info for the given contactAddress if available
     * in cache.
     *
     * @param contactAddress to search for
     * @return list of the details if any.
     */
    List<GenericDetail> getCachedContactDetails(String contactAddress) {
        return retreivedDetails.get(contactAddress);
    }

    /**
     * Adds a cached contact details.
     * @param contactAddress the contact address
     * @param details the details to add
     */
    void addCachedContactDetails(String contactAddress, List<GenericDetail> details) {
        retreivedDetails.put(contactAddress, details);
    }

    /**
     * Checks for full name tag in the <tt>card</tt>.
     * @param card the card to check.
     * @return the Full name if existing, null otherwise.
     */
    String checkForFullName(VCard card) {
        String vcardXml = card.toXML();

        int indexOpen = vcardXml.indexOf(TAG_FN_OPEN);

        if (indexOpen == -1)
            return null;

        int indexClose = vcardXml.indexOf(TAG_FN_CLOSE, indexOpen);

        // something is wrong!
        if (indexClose == -1)
            return null;

        return vcardXml.substring(indexOpen + TAG_FN_OPEN.length(), indexClose);
    }

    /**
     * Load VCard for the given user.
     * Using the specified timeout.
     *
     * @param vcard VCard
     * @param connection XMPP connection
     * @param user the user
     * @param timeout timeout in second
     * @throws XMPPException if something went wrong during VCard loading
     */
    public void load(VCard vcard, Connection connection, String user, long timeout) throws XMPPException {
        vcard.setTo(user);

        vcard.setType(IQ.Type.GET);
        PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(vcard.getPacketID()));
        connection.sendPacket(vcard);

        VCard result = null;
        try {
            result = (VCard) collector.nextResult(timeout);

            if (result == null) {
                String errorMessage = "Timeout getting VCard information";
                throw new XMPPException(errorMessage,
                        new XMPPError(XMPPError.Condition.request_timeout, errorMessage));
            }

            if (result.getError() != null) {
                throw new XMPPException(result.getError());
            }
        } catch (ClassCastException e) {
            logger.error("No vcard for " + user);
        }

        if (result == null)
            result = new VCard();

        // copy loaded vcard fields in the supplied one.
        Field[] fields = VCard.class.getDeclaredFields();
        for (Field field : fields) {
            if (field.getDeclaringClass() == VCard.class && !Modifier.isFinal(field.getModifiers())) {
                try {
                    field.setAccessible(true);
                    field.set(vcard, field.get(result));
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Cannot set field:" + field, e);
                }
            }
        }
    }

    /**
     * Work department
     */
    public static class WorkDepartmentNameDetail extends NameDetail {
        /**
         * Constructor.
         *
         * @param workDepartmentName name of the work department
         */
        public WorkDepartmentNameDetail(String workDepartmentName) {
            super("Work Department Name", workDepartmentName);
        }
    }

    /**
     * Fax at work
     */
    public static class WorkFaxDetail extends FaxDetail {
        /**
         * Constructor.
         *
         * @param number work fax number
         */
        public WorkFaxDetail(String number) {
            super(number);
            super.detailDisplayName = "WorkFax";
        }
    }

    /**
     * Pager at work
     */
    public static class WorkPagerDetail extends PhoneNumberDetail {
        /**
         * Constructor.
         *
         * @param number work pager number
         */
        public WorkPagerDetail(String number) {
            super(number);
            super.detailDisplayName = "WorkPager";
        }
    }
}