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