最近在研究 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>admin@ghac.cn</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 测试过