最近在研究 vysper ,貌似没有实现 XEP-0055 JABBER SEARCH ,于是参考VCARD-TEMP 实现了一下。
1. 实现 module
//jabber搜索 XEP-0055: Jabber Search public class JabberSearchModule extends DefaultDiscoAwareModule implements ServerInfoRequestListener { public static final String JABBER_SEARCH = "jabber:iq:search";//搜索标签 private static final Logger logger = LoggerFactory.getLogger(JabberSearchModule.class); protected JabberSearchIQHandler iqHandler = new JabberSearchIQHandler();//IQ Handler @Override public void initialize(ServerRuntimeContext serverRuntimeContext) { super.initialize(serverRuntimeContext); JabberSearchManager persistenceManager = (JabberSearchManager) serverRuntimeContext .getStorageProvider(JabberSearchManager.class); if (persistenceManager == null) { logger.error("no JabberSearchManager found"); } else if (!persistenceManager.isAvailable()) { logger.warn("JabberSearchManager not available"); } else { iqHandler.setPersistenceManager(persistenceManager); } } @Override protected void addServerInfoRequestListeners(List<ServerInfoRequestListener> serverInfoRequestListeners) { serverInfoRequestListeners.add(this); } //取得服务器信息 @Override public List<InfoElement> getServerInfosFor(InfoRequest request) throws ServiceDiscoveryRequestException { // TODO Auto-generated method stub if (StringUtils.isNotEmpty(request.getNode())) return null; List<InfoElement> infoElements = new ArrayList<InfoElement>(); infoElements.add(new Feature(JABBER_SEARCH)); return infoElements; } //添加字典,用于搜索该服务 @Override protected void addHandlerDictionaries(List<HandlerDictionary> dictionary) { iqHandler = new JabberSearchIQHandler(); dictionary.add(new NamespaceHandlerDictionary(JABBER_SEARCH, iqHandler)); } //取得协议名称 @Override public String getName() { // TODO Auto-generated method stub return "XEP-0055 Jabber Search"; } //取得协议版本 @Override public String getVersion() { // TODO Auto-generated method stub return "1.3"; } }
2. 实现 StorageProvider 接口
//jabber搜索 XEP-0055: Jabber Search 数据接口 public interface JabberSearchManager extends StorageProvider { // 取得查询结果 public String getSearchResult(Map<String, Object> map); // 取得查询表单 public String getSearchForm(); /** * @return if the persistence manager is ready to operate */ boolean isAvailable(); }
//jabber搜索 XEP-0055: Jabber Search 数据接口 public class SSOJabberSearchManager implements JabberSearchManager { private final static Logger logger = LoggerFactory .getLogger(SSOJabberSearchManager.class); // SSO验证相关操作 private SSOAuthManager ssoAuthManager; // 取得查询结果 @Override public String getSearchResult(Map<String, Object> map) { // TODO Auto-generated method stub // 查询结果 List<Map<String, Object>> result = null; try { result = ssoAuthManager.searchUser(map); } catch (Exception e) { // TODO Auto-generated catch block logger.error("", e); } StringBuffer xml = new StringBuffer("<query xmlns='jabber:iq:search'>"); if (result != null && result.size() > 0) { for (Map<String, Object> item : result) { xml.append("<item jid='"+(String)item.get("JID")+"'>"); xml.append("<first>"+(String)item.get("FIRST_NAME")+"</first>"); xml.append("<last>"+(String)item.get("LAST_NAME")+"</last>"); xml.append("<nick>"+(String)item.get("NICK_NAME")+"</nick>"); xml.append("<email>"+(String)item.get("EMAIL")+"</email>"); xml.append("</item>"); } } xml.append("</query>"); return xml.toString(); } @Override public boolean isAvailable() { // TODO Auto-generated method stub return true; } // 取得查询表单 @Override public String getSearchForm() { // TODO Auto-generated method stub return new StringBuffer("<query xmlns='jabber:iq:search'>") .append("<instructions>").append("填写查询条件:") .append("</instructions>").append("<first/>").append("<last/>") .append("<nick/>").append("<email/>").append("</query>") .toString(); } public SSOAuthManager getSsoAuthManager() { return ssoAuthManager; } public void setSsoAuthManager(SSOAuthManager ssoAuthManager) { this.ssoAuthManager = ssoAuthManager; } }
3.实现 IQHandler
//Jabber Search IQ handler @SpecCompliant(spec = "xep-0055", status = SpecCompliant.ComplianceStatus.FINISHED, coverage = SpecCompliant.ComplianceCoverage.COMPLETE) public class JabberSearchIQHandler extends DefaultIQHandler { protected JabberSearchManager persistenceManager; public void setPersistenceManager(JabberSearchManager persistenceManager) { this.persistenceManager = persistenceManager; } // 内部标签验证 @Override protected boolean verifyInnerElement(Stanza stanza) { return verifyInnerNamespace(stanza, JabberSearchModule.JABBER_SEARCH); } // GET 操作,具体看协议 输出查询表单 @Override protected Stanza handleGet(IQStanza stanza, ServerRuntimeContext serverRuntimeContext, SessionContext sessionContext) { if (persistenceManager == null) { return buildInteralStorageError(stanza); } // 表单定义 String formXml = persistenceManager.getSearchForm(); // 输出表单 StanzaBuilder stanzaBuilder = StanzaBuilder.createIQStanza( stanza.getTo(), stanza.getFrom(), IQStanzaType.RESULT, stanza.getID()); try { XMLElement elm = XMLParserUtil.parseDocument(formXml); stanzaBuilder.addPreparedElement(elm); } catch (Exception e) { return buildInteralStorageError(stanza); } return stanzaBuilder.build(); } private Stanza buildInteralStorageError(XMPPCoreStanza stanza) { return ServerErrorResponses.getStanzaError( StanzaErrorCondition.INTERNAL_SERVER_ERROR, stanza, StanzaErrorType.WAIT, "internal storage inaccessible", null, null); } // SET 操作 返回查询结果 @Override protected Stanza handleSet(IQStanza stanza, ServerRuntimeContext serverRuntimeContext, SessionContext sessionContext) { // TODO Auto-generated method stub if (persistenceManager == null) { return buildInteralStorageError(stanza); } // 设置查询条件 Map<String, Object> map = new HashMap<String, Object>(); XMLElement query = stanza.getFirstInnerElement();// query根节点 List<XMLElement> innerList = query.getInnerElements();// 内部查询属性 if (innerList != null && innerList.size() > 0) { for (XMLElement element : innerList) { if (element.getInnerText() != null && !"".equals(element.getInnerText())) { if ("first".equals(element.getName())) { map.put("FIRST_NAME", element.getInnerText().toString()); } else if ("last".equals(element.getName())) { map.put("LAST_NAME", element.getInnerText().toString()); } else if ("nick".equals(element.getName())) { map.put("NICK_NAME", element.getInnerText().toString()); } else if ("email".equals(element.getName())) { map.put("EMAIL", element.getInnerText().toString()); } } } } // 查询结果 String resultXml = persistenceManager.getSearchResult(map); // 输出表单 StanzaBuilder stanzaBuilder = StanzaBuilder.createIQStanza( stanza.getTo(), stanza.getFrom(), IQStanzaType.RESULT, stanza.getID()); try { XMLElement elm = XMLParserUtil.parseDocument(resultXml); stanzaBuilder.addPreparedElement(elm); } catch (Exception e) { return buildInteralStorageError(stanza); } return stanzaBuilder.build(); } }
4. spring 相关模块注入
<!-- SSO 用户搜索模块 --> <bean id="ssoJabberSearchManager" class="com.oawebchat.sso.usersearch.xep0055.SSOJabberSearchManager" > <property name="ssoAuthManager" ref="ssoAuthManager" /> </bean>
<bean id="server" class="org.apache.vysper.spring.SpringCompatibleXMPPServer" init-method="init" destroy-method="destroy"> <!-- TODO change domain name to your domain --> <constructor-arg value="xxx.cn"/> <property name="endpoints"> <list> <ref bean="tcpEndpoint"/> <ref bean="boshEndpoint"/> </list> </property> <property name="storageProviderRegistry" ref="storageRegistry" /> <property name="certificateFile" value="classpath:bogus_mina_tls.cert" /> <property name="certificatePassword" value="boguspw" /> <property name="modules" > <list> <bean class="org.apache.vysper.xmpp.modules.extension.xep0092_software_version.SoftwareVersionModule"/> <!-- 服务器版本显示 --> <bean class="org.apache.vysper.xmpp.modules.extension.xep0202_entity_time.EntityTimeModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0054_vcardtemp.VcardTempModule" /><!-- VCARD 显示 --> <bean class="org.apache.vysper.xmpp.modules.extension.xep0199_xmppping.XmppPingModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0049_privatedata.PrivateDataModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.AdhocCommandsModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0133_service_administration.ServiceAdministrationModule" > <property name="addAdmins"> <list><value>[email protected]</value></list> </property> </bean> <!-- below some more modules which are available as separately-built jars. make sure they are on the classpath when enabling them or remove the beans below, depending on the features your server should expose --> <bean class="org.apache.vysper.xmpp.modules.extension.xep0060_pubsub.PublishSubscribeModule" /> <bean class="org.apache.vysper.xmpp.modules.extension.xep0045_muc.MUCModule" /> <bean class="com.oawebchat.sso.usersearch.xep0055.JabberSearchModule" /><!-- Jabber search 模块 --> </list> </property> </bean>
5. 测试
现在只在PSI 测试过