/* * 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; //~--- non-JDK imports -------------------------------------------------------- import tigase.disco.XMPPService; import tigase.server.AbstractMessageReceiver; import tigase.server.Packet; import tigase.server.amp.action.Alert; import tigase.server.amp.action.Drop; import tigase.server.amp.action.Notify; import tigase.server.amp.action.Store; import tigase.server.amp.cond.Deliver; import tigase.server.amp.cond.ExpireAt; import tigase.server.amp.cond.MatchResource; import tigase.xml.Element; import tigase.xmpp.JID; //~--- JDK imports ------------------------------------------------------------ import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentSkipListMap; import java.util.logging.Level; import java.util.logging.Logger; //~--- classes ---------------------------------------------------------------- /** * Created: Apr 26, 2010 3:22:06 PM * * @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a> * @version $Rev$ */ public class AmpComponent extends AbstractMessageReceiver implements ActionResultsHandlerIfc { private static final Logger log = Logger.getLogger(AmpComponent.class.getName()); private static final String AMP_NODE = "http://jabber.org/protocol/amp"; private static final String AMP_XMLNS = AMP_NODE; private static final Element top_feature = new Element("feature", new String[] { "var" }, new String[] { AMP_NODE }); // ~--- fields --------------------------------------------------------------- private Map<String, ActionIfc> actions = new ConcurrentSkipListMap<String, ActionIfc>(); private Map<String, ConditionIfc> conditions = new ConcurrentSkipListMap<String, ConditionIfc>(); // ~--- methods -------------------------------------------------------------- /** * Method description * * * @param packet * * @return */ @Override public boolean addOutPacket(Packet packet) { return super.addOutPacket(packet); } /** * Method description * * * @param packets * * @return */ @Override public boolean addOutPackets(Queue<Packet> packets) { return super.addOutPackets(packets); } // ~--- get methods ---------------------------------------------------------- /** * Method description * * * @param params * * @return */ @Override public Map<String, Object> getDefaults(Map<String, Object> params) { Map<String, Object> defs = super.getDefaults(params); ActionIfc action = new Drop(); actions.put(action.getName(), action); action = new tigase.server.amp.action.Error(); actions.put(action.getName(), action); action = new Notify(); actions.put(action.getName(), action); action = new tigase.server.amp.action.Deliver(); actions.put(action.getName(), action); action = new Store(); actions.put(action.getName(), action); action = new Alert(); actions.put(action.getName(), action); ConditionIfc condition = new Deliver(); conditions.put(condition.getName(), condition); condition = new ExpireAt(); conditions.put(condition.getName(), condition); condition = new MatchResource(); conditions.put(condition.getName(), condition); for (ActionIfc a : actions.values()) { Map<String, Object> d = a.getDefaults(params); if (d != null) { defs.putAll(d); } } // for (ConditionIfc c : conditions.values()) { // Map<String, Object> d = c.getDefaults(params); // // if (d != null) { // defs.putAll(d); // } // } return defs; } /** * Method description * * * @return */ @Override public String getDiscoCategoryType() { return "generic"; } /** * Method description * * * @return */ @Override public String getDiscoDescription() { return "IM AMP Support"; } /** * Method description * * * @param node * @param jid * @param from * * @return */ @Override public Element getDiscoInfo(String node, JID jid, JID from) { Element query = super.getDiscoInfo(node, jid, from); if ((jid != null) && (getName().equals(jid.getLocalpart()) || isLocalDomain(jid.toString())) && (AMP_NODE.equals(node))) { if (query == null) { query = new Element("query"); query.setXMLNS(XMPPService.INFO_XMLNS); } query.addChild(new Element("identity", new String[] { "name", "category", "type" }, new String[] { getDiscoDescription(), "im", getDiscoCategoryType() })); query.addChild(top_feature); for (ActionIfc action : actions.values()) { query.addChild(new Element("feature", new String[] { "var" }, new String[] { AMP_NODE + "?action=" + action.getName() })); } for (ConditionIfc cond : conditions.values()) { query.addChild(new Element("feature", new String[] { "var" }, new String[] { AMP_NODE + "?condition=" + cond.getName() })); } // for (ProcessingThreads<ProcessorWorkerThread> proc_t : // processors.values()) { // Element[] discoFeatures = // proc_t.getWorkerThread().processor.supDiscoFeatures(null); // // if (discoFeatures != null) { // query.addChildren(Arrays.asList(discoFeatures)); // } // end of if (discoFeatures != null) // } } if (log.isLoggable(Level.FINEST)) { log.finest("Found disco info: " + ((query != null) ? query.toString() : null)); } return query; } // ~--- methods -------------------------------------------------------------- /** * Method description * * * @param packet */ @Override public void processPacket(Packet packet) { if (log.isLoggable(Level.FINEST)) { log.finest("My packet: " + packet); } ActionIfc def = null; if (packet.getAttribute(AmpFeatureIfc.OFFLINE) == null) { def = actions.get("deliver"); } else { def = actions.get("store"); } boolean exec_def = true; Element amp = packet.getElement().getChild("amp", AMP_XMLNS); if (amp != null) { List<Element> rules = amp.getChildren(); if ((rules != null) && (rules.size() > 0)) { for (Element rule : rules) { if (matchCondition(packet, rule)) { exec_def = executeAction(packet, rule); break; } } } else { log.warning("AMP packet but empty rule-set! " + packet); // In case of such error, let's just drop the packet return; } } else { log.warning("Not an AMP packet! " + packet); // In case of such error, let's just drop the packet return; } if (exec_def) { if (log.isLoggable(Level.FINEST)) { log.finest("Executing default action: " + def.getName()); } def.execute(packet, null); } } // ~--- set methods ---------------------------------------------------------- /** * Method description * * * @param props */ @Override public void setProperties(Map<String, Object> props) { super.setProperties(props); if (props.size() == 1) { // If props.size() == 1, it means this is a single property update // and this component does not support single property change for the rest // of it's settings return; } for (ActionIfc a : actions.values()) { a.setProperties(props, this); } // for (ConditionIfc c : conditions.values()) { // c.setProperties(props, this); // } } // ~--- methods -------------------------------------------------------------- private boolean executeAction(Packet packet, Element rule) { String act = rule.getAttribute(AmpFeatureIfc.ACTION_ATT); if (act != null) { ActionIfc action = actions.get(act); if (action != null) { boolean result = action.execute(packet, rule); if (log.isLoggable(Level.FINEST)) { log.finest("Matched action: " + action.getName() + ", result: " + result); } return result; } else { log.fine("No action found for act: " + act); } } else { log.fine("No actionset for rule: " + rule); } return true; } private boolean matchCondition(Packet packet, Element rule) { String cond = rule.getAttribute(AmpFeatureIfc.CONDITION_ATT); if (cond != null) { ConditionIfc condition = conditions.get(cond); if (condition != null) { boolean result = condition.match(packet, rule);; if (log.isLoggable(Level.FINEST)) { log.finest("Matched condition: " + condition.getName() + ", result: " + result); } return result; } else { log.fine("No condition found for cond: " + cond); } } else { log.fine("No condition set for rule: " + rule); } return false; } } // ~ Formatted in Sun Code Convention // ~ Formatted by Jindent --- http://www.jindent.com