/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.xmpp.outbound;
import java.io.StringReader;
import java.util.regex.Pattern;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.xmlpull.v1.XmlPullParser;
import org.springframework.integration.xmpp.XmppHeaders;
import org.springframework.integration.xmpp.core.AbstractXmppConnectionAwareMessageHandler;
import org.springframework.integration.xmpp.support.DefaultXmppHeaderMapper;
import org.springframework.integration.xmpp.support.XmppHeaderMapper;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* MessageHandler that sends an XMPP Chat Message. Supported payload types are Smack Message
* (org.jivesoftware.smack.packet.Message) or String.
*
* @author Josh Long
* @author Mario Gray
* @author Oleg Zhurakousky
* @author Artem Bilan
* @since 2.0
*/
public class ChatMessageSendingMessageHandler extends AbstractXmppConnectionAwareMessageHandler {
private static final Pattern XML_PATTERN = Pattern.compile("<(\\S[^>\\s]*)[^>]*>[^<]*</\\1>");
private volatile XmppHeaderMapper headerMapper = new DefaultXmppHeaderMapper();
private ExtensionElementProvider<? extends ExtensionElement> extensionProvider;
public ChatMessageSendingMessageHandler() {
super();
}
public ChatMessageSendingMessageHandler(XMPPConnection xmppConnection) {
super(xmppConnection);
}
public void setHeaderMapper(XmppHeaderMapper headerMapper) {
Assert.notNull(headerMapper, "headerMapper must not be null");
this.headerMapper = headerMapper;
}
/**
* Specify an {@link ExtensionElementProvider} to build an {@link ExtensionElement}
* for the {@link org.jivesoftware.smack.packet.Message#addExtension(ExtensionElement)}
* instead of {@code body}.
* @param extensionProvider the {@link ExtensionElementProvider} to use.
* @since 4.3
*/
public void setExtensionProvider(ExtensionElementProvider<? extends ExtensionElement> extensionProvider) {
this.extensionProvider = extensionProvider;
}
@Override
public String getComponentType() {
return "xmpp:outbound-channel-adapter";
}
@Override
protected void handleMessageInternal(Message<?> message) throws Exception {
Assert.isTrue(this.initialized, getComponentName() + "#" + this.getComponentType() + " must be initialized");
Object payload = message.getPayload();
org.jivesoftware.smack.packet.Message xmppMessage = null;
if (payload instanceof org.jivesoftware.smack.packet.Message) {
xmppMessage = (org.jivesoftware.smack.packet.Message) payload;
}
else {
String to = message.getHeaders().get(XmppHeaders.TO, String.class);
Assert.state(StringUtils.hasText(to), "The '" + XmppHeaders.TO + "' header must not be null");
xmppMessage = new org.jivesoftware.smack.packet.Message(to);
if (payload instanceof ExtensionElement) {
xmppMessage.addExtension((ExtensionElement) payload);
}
else if (payload instanceof String) {
if (this.extensionProvider != null) {
String data = (String) payload;
if (!XML_PATTERN.matcher(data.trim()).matches()) {
// Since XMPP Extension parsers deal only with XML content,
// add an arbitrary tag that is removed by the extension parser,
// if the target content isn't XML.
data = "<root>" + data + "</root>";
}
XmlPullParser xmlPullParser = PacketParserUtils.newXmppParser(new StringReader(data));
xmlPullParser.next();
ExtensionElement extension = this.extensionProvider.parse(xmlPullParser);
xmppMessage.addExtension(extension);
}
else {
xmppMessage.setBody((String) payload);
}
}
else {
throw new MessageHandlingException(message,
"Only payloads of type java.lang.String, org.jivesoftware.smack.packet.Message " +
"or org.jivesoftware.smack.packet.ExtensionElement " +
"are supported. Received [" + payload.getClass().getName() +
"]. Consider adding a Transformer prior to this adapter.");
}
}
if (this.headerMapper != null) {
this.headerMapper.fromHeadersToRequest(message.getHeaders(), xmppMessage);
}
if (!this.xmppConnection.isConnected() && this.xmppConnection instanceof AbstractXMPPConnection) {
((AbstractXMPPConnection) this.xmppConnection).connect();
}
this.xmppConnection.sendStanza(xmppMessage);
}
}