/* * 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.server.amp.action; //~--- non-JDK imports -------------------------------------------------------- import tigase.conf.Configurable; import tigase.db.UserNotFoundException; import tigase.server.Packet; import tigase.server.amp.ActionAbstract; import tigase.server.amp.ActionResultsHandlerIfc; import tigase.server.amp.MsgRepository; import tigase.server.amp.cond.ExpireAt; import tigase.util.TigaseStringprepException; import tigase.xml.Element; //~--- JDK imports ------------------------------------------------------------ import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.*; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; //~--- classes ---------------------------------------------------------------- /** * Created: May 1, 2010 11:32:59 AM * * @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a> * @version $Rev$ */ public class Store extends ActionAbstract { private static final Logger log = Logger.getLogger(Store.class.getName()); private static final String name = "store"; // ~--- fields --------------------------------------------------------------- private Thread expiredProcessor = null; private MsgRepository repo = null; private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); // ~--- methods -------------------------------------------------------------- /** * Method description * * * @param packet * @param rule * * * @return */ @Override public boolean execute(Packet packet, Element rule) { if (repo != null) { Date expired = null; String stamp = null; if (packet.getAttribute(EXPIRED) == null) { if (rule == null) { rule = getExpireAtRule(packet); } } else { removeExpireAtRule(packet); rule = null; } synchronized (formatter) { if (rule != null) { try { expired = formatter.parse(rule.getAttribute("value")); } catch (Exception e) { log.log(Level.INFO, "Incorrect expire-at value: " + rule.getAttribute("value"), e); expired = null; } } stamp = formatter.format(new Date()); } removeTigasePayload(packet); try { Element elem = packet.getElement(); if (elem.getChild("delay", "urn:xmpp:delay") == null) { Element x = new Element("delay", "Offline Storage", new String[] { "from", "stamp", "xmlns" }, new String[] { packet.getStanzaTo().getDomain(), stamp, "urn:xmpp:delay" }); elem.addChild(x); } repo.storeMessage(packet.getStanzaFrom(), packet.getStanzaTo(), expired, elem); } catch (UserNotFoundException ex) { log.info("User not found for offline message: " + packet); } } return false; } // ~--- get methods ---------------------------------------------------------- /** * Method description * * * @param params * * @return */ @Override public Map<String, Object> getDefaults(Map<String, Object> params) { Map<String, Object> defs = super.getDefaults(params); String db_uri = (String) params.get(AMP_MSG_REPO_URI_PARAM); if (db_uri == null) { db_uri = (String) params.get(Configurable.USER_REPO_URL_PROP_KEY); } if (db_uri != null) { defs.put(AMP_MSG_REPO_URI_PROP_KEY, db_uri); } return defs; } /** * Method description * * * @return */ @Override public String getName() { return name; } // ~--- set methods ---------------------------------------------------------- /** * Method description * * * @param props * @param handler */ @Override public void setProperties(Map<String, Object> props, ActionResultsHandlerIfc handler) { super.setProperties(props, handler); String db_uri = (String) props.get(AMP_MSG_REPO_URI_PROP_KEY); if (db_uri != null) { repo = MsgRepository.getInstance(db_uri); try { Map<String, String> db_props = new HashMap<String, String>(4); for (Map.Entry<String, Object> entry : props.entrySet()) { // Entry happens to be null for (shared-user-repo-params, null) // TODO: Not sure if this is supposed to happen, more investigation is needed. if (entry.getValue() != null) { log.log(Level.WARNING, "Reading properties: (" + entry.getKey() + ", " + entry.getValue() + ")"); db_props.put(entry.getKey(), entry.getValue().toString()); } } // Initialization of repository can be done here and in MessageAmp // class so repository related parameters for MsgRepository // should be specified for AMP plugin and AMP component repo.initRepository(db_uri, db_props); } catch (SQLException ex) { repo = null; log.log(Level.WARNING, "Problem initializing connection to DB: ", ex); } } if ((repo != null) && (expiredProcessor == null)) { expiredProcessor = new Thread("expired-processor") { @Override public void run() { while (true) { Element elem = repo.getMessageExpired(0, true); if (elem != null) { elem.addAttribute(OFFLINE, "1"); elem.addAttribute(EXPIRED, "1"); try { resultsHandler.addOutPacket(Packet.packetInstance(elem)); } catch (TigaseStringprepException ex) { log.info("Stringprep error for offline message loaded from DB: " + elem); } } } } }; expiredProcessor.setDaemon(true); expiredProcessor.start(); } } // ~--- get methods ---------------------------------------------------------- private Element getExpireAtRule(Packet packet) { Element amp = packet.getElement().getChild("amp", AMP_XMLNS); List<Element> rules = amp.getChildren(); Element rule = null; if ((rules != null) && (rules.size() > 0)) { for (Element r : rules) { String cond = r.getAttribute(CONDITION_ATT); if ((cond != null) && cond.equals(ExpireAt.NAME)) { rule = r; break; } } } return rule; } // ~--- methods -------------------------------------------------------------- private void removeExpireAtRule(Packet packet) { Element amp = packet.getElement().getChild("amp", AMP_XMLNS); List<Element> rules = amp.getChildren(); if ((rules != null) && (rules.size() > 0)) { for (Element r : rules) { String cond = r.getAttribute(CONDITION_ATT); if ((cond != null) && cond.equals(ExpireAt.NAME)) { amp.removeChild(r); break; } } } rules = amp.getChildren(); if ((rules == null) || (rules.size() == 0)) { packet.getElement().removeChild(amp); } } } // ~ Formatted in Sun Code Convention // ~ Formatted by Jindent --- http://www.jindent.com