/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev$
* Last modified by $Author$
* $Date$
*/
package tigase.xmpp.impl;
//~--- non-JDK imports --------------------------------------------------------
import tigase.conf.Configurable;
import tigase.db.NonAuthUserRepository;
import tigase.db.TigaseDBException;
import tigase.db.UserNotFoundException;
import tigase.server.Packet;
import tigase.server.amp.AmpFeatureIfc;
import tigase.server.amp.MsgRepository;
import tigase.xml.Element;
import tigase.xmpp.JID;
import tigase.xmpp.XMPPException;
import tigase.xmpp.XMPPPostprocessorIfc;
import tigase.xmpp.XMPPProcessor;
import tigase.xmpp.XMPPProcessorIfc;
import tigase.xmpp.XMPPResourceConnection;
//~--- JDK imports ------------------------------------------------------------
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import tigase.util.DNSResolver;
//~--- classes ----------------------------------------------------------------
/**
* Created: Apr 29, 2010 5:00:25 PM
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public class MessageAmp extends XMPPProcessor implements XMPPPostprocessorIfc,
XMPPProcessorIfc {
private static Logger log = Logger.getLogger(MessageAmp.class.getName());
private static final String FROM_CONN_ID = "from-conn-id";
private static final String TO_CONN_ID = "to-conn-id";
private static final String TO_RES = "to-res";
private static final String OFFLINE = "offline";
private static final String AMP_JID_PROP_KEY = "amp-jid";
private static final String MSG_OFFLINE_PROP_KEY = "msg-offline";
private static final String XMLNS = "http://jabber.org/protocol/amp";
private static final String ID = "amp";
private static final String[] ELEMENTS = { "message", "presence" };
private static final String[] XMLNSS = { "jabber:client", "jabber:client" };
private static Element[] DISCO_FEATURES = {
new Element("feature", new String[] { "var" }, new String[] { XMLNS }),
new Element("feature", new String[] { "var" }, new String[] { "msgoffline" }) };
// ~--- fields ---------------------------------------------------------------
private JID ampJID = null;
private MsgRepository msg_repo = null;
private OfflineMessages offlineProcessor = new OfflineMessages();
private Message messageProcessor = new Message();
private static final String defHost = DNSResolver.getDefaultHostname();
// ~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
public String id() {
return ID;
}
/**
* Method description
*
*
* @param settings
*
* @throws TigaseDBException
*/
@Override
public void init(Map<String, Object> settings) throws TigaseDBException {
super.init(settings);
String ampJIDstr = (String) settings.get(AMP_JID_PROP_KEY);
if (null != ampJIDstr) {
ampJID = JID.jidInstanceNS(ampJIDstr);
} else {
ampJID = JID.jidInstanceNS("amp@" + defHost);
}
log.log(Level.CONFIG, "Loaded AMP_JID option: {0} = {1}", new Object[] {
AMP_JID_PROP_KEY, ampJID });
String off_val = (String) settings.get(MSG_OFFLINE_PROP_KEY);
if (off_val == null) {
off_val = System.getProperty(MSG_OFFLINE_PROP_KEY);
}
if ((off_val != null) && !Boolean.parseBoolean(off_val)) {
log.log(Level.CONFIG, "Offline messages storage: {0}", new Object[] {
off_val });
offlineProcessor = null;
DISCO_FEATURES =
new Element[] { new Element("feature", new String[] { "var" },
new String[] { XMLNS }) };
}
String msg_repo_uri = (String) settings.get(AmpFeatureIfc.AMP_MSG_REPO_URI_PROP_KEY);
if (msg_repo_uri == null) {
msg_repo_uri = System.getProperty(AmpFeatureIfc.AMP_MSG_REPO_URI_PROP_KEY);
if (msg_repo_uri == null) {
msg_repo_uri = System.getProperty(Configurable.GEN_USER_DB_URI_PROP_KEY);
}
}
if (msg_repo_uri != null) {
Map<String, String> db_props = new HashMap<String, String>(4);
for (Map.Entry<String, Object> entry : settings.entrySet()) {
db_props.put(entry.getKey(), entry.getValue().toString());
}
// Initialization of repository can be done here and in Store
// class so repository related parameters for MsgRepository
// should be specified for AMP plugin and AMP component
msg_repo = MsgRepository.getInstance(msg_repo_uri);
try {
msg_repo.initRepository(msg_repo_uri, db_props);
} catch (SQLException ex) {
msg_repo = null;
log.log(Level.WARNING, "Problem initializing connection to DB: ", ex);
}
}
}
/**
* Method description
*
*
* @param packet
* @param session
* @param repo
* @param results
* @param settings
*/
@Override
public void postProcess(Packet packet, XMPPResourceConnection session,
NonAuthUserRepository repo, Queue<Packet> results, Map<String, Object> settings) {
if ((offlineProcessor != null) && (session == null)) {
Element amp = packet.getElement().getChild("amp");
if ((amp == null) || (amp.getXMLNS() != XMLNS)
|| (amp.getAttribute("status") != null)) {
try {
offlineProcessor.savePacketForOffLineUser(packet, msg_repo);
} catch (UserNotFoundException ex) {
if (log.isLoggable(Level.FINEST)) {
log.finest("UserNotFoundException at trying to save packet for off-line user."
+ packet);
}
}
}
}
}
/**
* Method description
*
*
* @param packet
* @param session
* @param repo
* @param results
* @param settings
*
* @throws XMPPException
*/
@Override
public void process(Packet packet, XMPPResourceConnection session,
NonAuthUserRepository repo, Queue<Packet> results, Map<String, Object> settings)
throws XMPPException {
if (packet.getElemName() == "presence") {
if ((offlineProcessor != null)
&& offlineProcessor.loadOfflineMessages(packet, session)) {
try {
Queue<Packet> packets =
offlineProcessor.restorePacketForOffLineUser(session, msg_repo);
if (packets != null) {
if (log.isLoggable(Level.FINER)) {
log.finer("Sending off-line messages: " + packets.size());
}
results.addAll(packets);
} // end of if (packets != null)
} catch (UserNotFoundException e) {
log.info("Something wrong, DB problem, cannot load offline messages. " + e);
} // end of try-catch
}
} else {
Element amp = packet.getElement().getChild("amp", XMLNS);
if ((amp == null) || (amp.getAttribute("status") != null)) {
messageProcessor.process(packet, session, repo, results, settings);
} else {
Packet result = packet.copyElementOnly();
result.setPacketTo(ampJID);
results.offer(result);
if (session == null) {
result.getElement().addAttribute(OFFLINE, "1");
return;
}
if (session.isUserId(packet.getStanzaTo().getBareJID())) {
result.getElement().addAttribute(TO_CONN_ID,
session.getConnectionId().toString());
result.getElement().addAttribute(TO_RES, session.getResource());
} else {
JID connectionId = session.getConnectionId();
if (connectionId.equals(packet.getPacketFrom())) {
result.getElement().addAttribute(FROM_CONN_ID, connectionId.toString());
}
}
}
}
}
/**
* Method description
*
*
* @param session
*
* @return
*/
@Override
public Element[] supDiscoFeatures(final XMPPResourceConnection session) {
return DISCO_FEATURES;
}
/**
* Method description
*
*
* @return
*/
@Override
public String[] supElements() {
return ELEMENTS;
}
/**
* Method description
*
*
* @return
*/
@Override
public String[] supNamespaces() {
return XMLNSS;
}
}
// ~ Formatted in Sun Code Convention
// ~ Formatted by Jindent --- http://www.jindent.com