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