001/** 002 * 003 * Copyright 2014 Vyacheslav Blinov 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.amp.packet; 018 019import java.util.Collections; 020import java.util.List; 021import java.util.concurrent.CopyOnWriteArrayList; 022 023import org.jivesoftware.smack.packet.ExtensionElement; 024 025import org.jivesoftware.smackx.amp.AMPDeliverCondition; 026import org.jivesoftware.smackx.amp.AMPExpireAtCondition; 027import org.jivesoftware.smackx.amp.AMPMatchResourceCondition; 028 029public class AMPExtension implements ExtensionElement { 030 031 public static final String NAMESPACE = "http://jabber.org/protocol/amp"; 032 public static final String ELEMENT = "amp"; 033 034 private final CopyOnWriteArrayList<Rule> rules = new CopyOnWriteArrayList<>(); 035 private boolean perHop = false; 036 037 private final String from; 038 private final String to; 039 private final Status status; 040 041 /** 042 * Create a new AMPExtension instance with defined from, to and status attributes. Used to create incoming packets. 043 * @param from jid that triggered this amp callback. 044 * @param to receiver of this amp receipt. 045 * @param status status of this amp receipt. 046 */ 047 public AMPExtension(String from, String to, Status status) { 048 this.from = from; 049 this.to = to; 050 this.status = status; 051 } 052 053 /** 054 * Create a new amp request extension to be used with outgoing message. 055 */ 056 public AMPExtension() { 057 this.from = null; 058 this.to = null; 059 this.status = null; 060 } 061 062 /** 063 * Get the JID that triggered this AMP callback. 064 * @return jid that triggered this amp callback. 065 */ 066 public String getFrom() { 067 return from; 068 } 069 070 /** 071 * Get the receiver of this AMP receipt. 072 * @return receiver of this amp receipt. 073 */ 074 public String getTo() { 075 return to; 076 } 077 078 /** 079 * Status of this amp notification. 080 * @return Status for this amp 081 */ 082 public Status getStatus() { 083 return status; 084 } 085 086 /** 087 * Returns a unmodifiable List of the rules in the packet. 088 * 089 * @return a unmodifiable List of the rules in the packet. 090 */ 091 public List<Rule> getRules() { 092 return Collections.unmodifiableList(rules); 093 } 094 095 /** 096 * Adds a rule to the amp element. Amp can have any number of rules. 097 * 098 * @param rule the rule to add. 099 */ 100 public void addRule(Rule rule) { 101 rules.add(rule); 102 } 103 104 /** 105 * Returns a count of the rules in the AMP packet. 106 * 107 * @return the number of rules in the AMP packet. 108 */ 109 public int getRulesCount() { 110 return rules.size(); 111 } 112 113 /** 114 * Sets this amp ruleset to be "per-hop". 115 * 116 * @param enabled true if "per-hop" should be enabled 117 */ 118 public synchronized void setPerHop(boolean enabled) { 119 perHop = enabled; 120 } 121 122 /** 123 * Returns true is this ruleset is "per-hop". 124 * 125 * @return true is this ruleset is "per-hop". 126 */ 127 public synchronized boolean isPerHop() { 128 return perHop; 129 } 130 131 /** 132 * Returns the XML element name of the extension sub-packet root element. 133 * Always returns "amp" 134 * 135 * @return the XML element name of the stanza extension. 136 */ 137 @Override 138 public String getElementName() { 139 return ELEMENT; 140 } 141 142 /** 143 * Returns the XML namespace of the extension sub-packet root element. 144 * According the specification the namespace is always "http://jabber.org/protocol/xhtml-im" 145 * 146 * @return the XML namespace of the stanza extension. 147 */ 148 @Override 149 public String getNamespace() { 150 return NAMESPACE; 151 } 152 153 /** 154 * Returns the XML representation of a XHTML extension according the specification. 155 **/ 156 @Override 157 public String toXML(String enclosingNamespace) { 158 StringBuilder buf = new StringBuilder(); 159 buf.append('<').append(getElementName()).append(" xmlns=\"").append(getNamespace()).append('"'); 160 if (status != null) { 161 buf.append(" status=\"").append(status.toString()).append('"'); 162 } 163 if (to != null) { 164 buf.append(" to=\"").append(to).append('"'); 165 } 166 if (from != null) { 167 buf.append(" from=\"").append(from).append('"'); 168 } 169 if (perHop) { 170 buf.append(" per-hop=\"true\""); 171 } 172 buf.append('>'); 173 174 // Loop through all the rules and append them to the string buffer 175 for (Rule rule : getRules()) { 176 buf.append(rule.toXML()); 177 } 178 179 buf.append("</").append(getElementName()).append('>'); 180 return buf.toString(); 181 } 182 183 /** 184 * XEP-0079 Rule element. Defines AMP Rule parameters. Can be added to AMPExtension. 185 */ 186 public static class Rule { 187 public static final String ELEMENT = "rule"; 188 189 private final Action action; 190 private final Condition condition; 191 192 public Action getAction() { 193 return action; 194 } 195 196 public Condition getCondition() { 197 return condition; 198 } 199 200 /** 201 * Create a new amp rule with specified action and condition. Value will be taken from condition argument 202 * @param action action for this rule 203 * @param condition condition for this rule 204 */ 205 public Rule(Action action, Condition condition) { 206 if (action == null) 207 throw new NullPointerException("Can't create Rule with null action"); 208 if (condition == null) 209 throw new NullPointerException("Can't create Rule with null condition"); 210 211 this.action = action; 212 this.condition = condition; 213 } 214 215 private String toXML() { 216 return "<" + ELEMENT + " " + Action.ATTRIBUTE_NAME + "=\"" + action.toString() + "\" " + 217 Condition.ATTRIBUTE_NAME + "=\"" + condition.getName() + "\" " + 218 "value=\"" + condition.getValue() + "\"/>"; 219 } 220 } 221 222 /** 223 * Interface for defining XEP-0079 Conditions and their values. 224 * @see AMPDeliverCondition 225 * @see AMPExpireAtCondition 226 * @see AMPMatchResourceCondition 227 **/ 228 public interface Condition { 229 String getName(); 230 String getValue(); 231 232 String ATTRIBUTE_NAME = "condition"; 233 } 234 235 /** 236 * amp action attribute. 237 * See http://xmpp.org/extensions/xep-0079.html#actions-def 238 **/ 239 public enum Action { 240 /** 241 * The "alert" action triggers a reply <message/> stanza to the sending entity. 242 * This <message/> stanza MUST contain the element <amp status='alert'/>, 243 * which itself contains the <rule/> that triggered this action. In all other respects, 244 * this action behaves as "drop". 245 */ 246 alert, 247 /** 248 * The "drop" action silently discards the message from any further delivery attempts 249 * and ensures that it is not placed into offline storage. 250 * The drop MUST NOT result in other responses. 251 */ 252 drop, 253 /** 254 * The "error" action triggers a reply <message/> stanza of type "error" to the sending entity. 255 * The <message/> stanza's <error/> child MUST contain a 256 * <failed-rules xmlns='http://jabber.org/protocol/amp#errors'/> error condition, 257 * which itself contains the rules that triggered this action. 258 */ 259 error, 260 /** 261 * The "notify" action triggers a reply <message/> stanza to the sending entity. 262 * This <message/> stanza MUST contain the element <amp status='notify'/>, which itself 263 * contains the <rule/> that triggered this action. Unlike the other actions, 264 * this action does not override the default behavior for a server. 265 * Instead, the server then executes its default behavior after sending the notify. 266 */ 267 notify; 268 269 public static final String ATTRIBUTE_NAME = "action"; 270 } 271 272 /** 273 * amp notification status as defined by XEP-0079. 274 */ 275 public enum Status { 276 alert, 277 error, 278 notify 279 } 280}