【问题标题】:Refreshing VCards in OpenFire在 OpenFire 中刷新 VCard
【发布时间】:2012-06-19 08:20:05
【问题描述】:

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

   ...
   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 在内部调度事件:

VCardEventDispatcher.dispatchVCardUpdated(username, newvCard);

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

我无法弄清楚在IQvCardHandler 和我自己的代码中从handleIQ(IQ packet) 调用setVcard 方法的方式有什么区别。我错过了什么?

【问题讨论】:

    标签: java xmpp openfire vcf-vcard


    【解决方案1】:

    好的,我会自己回答我的问题 - 也许有人会发现此信息有帮助。

    事实证明,这并不像将图片存储到数据库中那么简单。有消息交换,预计将在相关方之间发生。此交换的关键部分是客户端发送的状态更新,该更新通知服务器以及他的所有好友他的新个人资料图像。详情请参阅XEP-0153: vCard-Based Avatars。这是一段代码,它“模拟”了将发送给所有用户好友的状态更新:

        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 类中稍作调整的方法:

    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 项目,取消选中使用默认位置复选框并浏览到项目位置。

    【讨论】:

      猜你喜欢
      • 2015-08-20
      • 2015-05-08
      • 2014-03-15
      • 2014-07-01
      • 1970-01-01
      • 2012-10-21
      • 2010-10-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多