在OpenFire中刷新VCard [英] Refreshing VCards in OpenFire

查看:83
本文介绍了在OpenFire中刷新VCard的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为OpenFire XMPP服务器开发了一个VCard插件,其主要目的是通过HTTP请求创建/更新和检索用户的头像.不幸的是,该插件无法按预期方式工作-VCard更改已传播到数据库(ofVcard表)中,但是用户图片已更新的用户或他的好友都看不到刷新的图像.这是我创建/更新VCard的方法:

I developed a VCard plugin for OpenFire XMPP server with the main purpose of creating/updating and retrieving users' avatars via HTTP requests. Unfortunately, the plugin does not work as expected - VCard changes are propogated into the database (ofVcard table), but neither the user whose userpic was updated nor his buddies see the refreshed image. Here is how I create/update the VCards:

   ...
   XMPPServer server = XMPPServer.getInstance();
   VCardManager vcardManager = server.getVCardManager();

public void createOrUpdateVcard(String username, String vcard)
                              throws Exception {
                    SAXReader reader = new SAXReader();
                    reader.setValidation(false);
                    // convert String into InputStream
                    InputStream is = new ByteArrayInputStream(vcard.getBytes());
                    // read it with BufferedReader
                    BufferedReader br = new BufferedReader(new InputStreamReader(is));

                    try {
                              // Reading malformed XML will lead to DocumentException
                              Document document = reader.read(is);
                              Element vCardElement = document.getRootElement();
                              log.info("Username: " + username);
                              vcardManager.setVCard(username, vCardElement);
                    } catch (DocumentException e) {
                              throw new MalformedXmlException(e);
                    }
     }
     ...

当我直接从客户端(我们使用Jitsi)更改化身时,更改不仅立即存储在数据库中,而且所有伙伴都获得了刷新的图像.我看到我使用的VCardManager在内部调度事件:

When I change avatars directly from the client (we are using Jitsi), the changes are not only immediately stored in the database, but all the buddies get the refreshed image. I see that VCardManager, which I use, dispatches events internally:

VCardEventDispatcher.dispatchVCardUpdated(username, newvCard);

但它们似乎没有任何作用.

but they seem not to have any effect.

我无法弄清楚从IQvCardHandler中的handleIQ(IQ packet)中调用setVcard方法的方式与我自己的代码之间有什么区别.我想念什么?

I cannot figure out what is the difference between the way the setVcard method is called from the handleIQ(IQ packet) in IQvCardHandler and in my own code. What am I missing?

推荐答案

好,我自己回答我的问题-也许有人会觉得此信息有用.

Ok, I will answer my question myself - maybe someone would find this info helpful.

事实证明,这并不像将图片存储到数据库中那么简单.预计相关各方之间将进行消息交换.此交换的关键部分是客户端发送的状态更新,该更新将通知服务器,并因此通知其所有伙伴有关其新个人资料图像的信息.有关更多详细信息,请参考 XEP-0153:基于vCard的头像<​​/a>.这是一段代码,模拟"状态更新,该更新将发送给所有用户的好友:

It turned out to be not as simple as just storing a picture into a database. There is a message exchange, expected to happen between the involved parties. The crucial part of this exchange is that there is a presence update, sent by the client, which informs the server and consequently all his buddies about his new profile image. Please refer to XEP-0153: vCard-Based Avatars for further details. This is the piece of code, that "emulates" the presence update which will be sent to all of the user's buddies:

    public void createOrUpdateVcard(String username, String vcard)
        throws MalformedXmlException, UserNotFoundException, SetVcardException {
    SAXReader reader = new SAXReader();
    reader.setValidation(false);
    InputStream is = new ByteArrayInputStream(vcard.getBytes());

    try {
        // Reading malformed XML will lead to DocumentException
        Document document = reader.read(is);
        Element vCardElement = document.getRootElement();
        //Checking that the user exists
        User user = userManager.getUser(username);
        //This might be redundant
        String userUsername = user.getUsername();
        log.debug("Setting VCard for " + userUsername);
        //Storing vCard into the database
        VCardManager.getInstance().setVCard(userUsername, vCardElement);        


        Presence presence = new Presence();
        JID userJID = server.createJID(username, null);
        presence.setFrom(userJID);
        presence.setStatus("");
        presence.setPriority(30);

        Element xElement = presence.addChildElement("x", "vcard-temp:x:update");
        Element photoElement = xElement.addElement("photo");

        SecureRandom random = new SecureRandom();
                    //We do not care about the actual hash - just push updates every time
        String fakeHash = new BigInteger(130, random).toString(32);
        photoElement.setText(fakeHash);

        Element cElement = presence.addChildElement("c", "http://jabber.org/protocol/caps");
        cElement.addAttribute( "ext", "voice-v1 video-v1 camera-v1" )
        .addAttribute("hash", "sha-1");

        System.out.println("SENDING PRESENCE UPDATE:\n" + presence.toXML());
        broadcastUpdate(presence);

    } catch (DocumentException e) {
        throw new MalformedXmlException(e);
    }catch (UserNotFoundException e){
        throw new UserNotFoundException();
    } catch (Exception e){
        //Unfortunately setVCard method above just throws Exception.
        //This catch block is for wrapping it up
        throw new SetVcardException();
    }
}

这是PresenceUpdateHandler类中经过稍微调整的方法:

This is a slightly adjusted method from the PresenceUpdateHandler class:

private void broadcastUpdate(Presence update) {
    if (update.getFrom() == null) {
        return;
    }
    if (localServer.isLocal(update.getFrom())) {
        // Do nothing if roster service is disabled
        if (!RosterManager.isRosterServiceEnabled()) {
            return;
        }
        // Local updates can simply run through the roster of the local user
        String name = update.getFrom().getNode();
        try {
            if (name != null && !"".equals(name)) {
                Roster roster = rosterManager.getRoster(name);
                roster.broadcastPresence(update);
            }
        }
        catch (UserNotFoundException e) {
            log.warn("Presence being sent from unknown user " + name, e);
        }
        catch (PacketException e) {
            log.error(LocaleUtils.getLocalizedString("admin.error"), e);
        }
    }
    else {
        // Foreign updates will do a reverse lookup of entries in rosters
        // on the server
        log.warn("Presence requested from server "
                + localServer.getServerInfo().getXMPPDomain()
                + " by unknown user: " + update.getFrom());
    }
}

对于调试OpenFire问题,我强烈建议以调试模式在本地运行它-请参见此处的说明: 2 .请注意,较新的Eclipse版本没有从现有来源创建项目的功能,但是您必须单击新建"->"Java项目",取消选中使用默认位置"复选框并浏览到项目位置.

For debugging OpenFire issues I would strongly recommend running it locally in debug mode - see instructions here: 2. Be aware, that newer eclipse releases do not have Create project from existing source, but you have to click on New -> Java Project, untick the Use default location check box and Browse to the project location.

这篇关于在OpenFire中刷新VCard的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆