001/** 002 * 003 * Copyright 2018 Paul Schaub 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.reference.element; 018 019import java.net.URI; 020import java.net.URISyntaxException; 021import java.util.ArrayList; 022import java.util.List; 023 024import org.jivesoftware.smack.packet.ExtensionElement; 025import org.jivesoftware.smack.packet.Stanza; 026import org.jivesoftware.smack.util.Objects; 027import org.jivesoftware.smack.util.XmlStringBuilder; 028 029import org.jivesoftware.smackx.reference.ReferenceManager; 030 031import org.jxmpp.jid.BareJid; 032 033public class ReferenceElement implements ExtensionElement { 034 035 public static final String ELEMENT = "reference"; 036 public static final String ATTR_BEGIN = "begin"; 037 public static final String ATTR_END = "end"; 038 public static final String ATTR_TYPE = "type"; 039 public static final String ATTR_ANCHOR = "anchor"; 040 public static final String ATTR_URI = "uri"; 041 042 public enum Type { 043 mention, 044 data 045 } 046 047 private final Integer begin; 048 private final Integer end; 049 private final Type type; 050 private final String anchor; 051 private final URI uri; 052 053 // Non-XEP-compliant, but needed for SIMS 054 private final ExtensionElement child; 055 056 /** 057 * XEP-incompliant (v0.2) constructor. This is needed for SIMS. 058 * 059 * @param begin TODO javadoc me please 060 * @param end TODO javadoc me please 061 * @param type TODO javadoc me please 062 * @param anchor TODO javadoc me please 063 * @param uri TODO javadoc me please 064 * @param child TODO javadoc me please 065 */ 066 public ReferenceElement(Integer begin, Integer end, Type type, String anchor, URI uri, ExtensionElement child) { 067 if (begin != null && begin < 0) { 068 throw new IllegalArgumentException("Attribute 'begin' MUST NOT be smaller than 0."); 069 } 070 if (end != null && end < 0) { 071 throw new IllegalArgumentException("Attribute 'end' MUST NOT be smaller than 0."); 072 } 073 if (begin != null && end != null && begin >= end) { 074 throw new IllegalArgumentException("Attribute 'begin' MUST be smaller than attribute 'end'."); 075 } 076 Objects.requireNonNull(type); 077 // TODO: The uri attribute is not mandatory according to SIMS, but it is according to references. 078 /*if (uri == null) { 079 throw new NullPointerException("Attribute 'uri' MUST NOT be null."); 080 }*/ 081 this.begin = begin; 082 this.end = end; 083 this.type = type; 084 this.anchor = anchor; 085 this.uri = uri; 086 this.child = child; 087 } 088 089 /** 090 * XEP-Compliant constructor. 091 * 092 * @param begin TODO javadoc me please 093 * @param end TODO javadoc me please 094 * @param type TODO javadoc me please 095 * @param anchor TODO javadoc me please 096 * @param uri TODO javadoc me please 097 */ 098 public ReferenceElement(Integer begin, Integer end, Type type, String anchor, URI uri) { 099 this(begin, end, type, anchor, uri, null); 100 } 101 102 public Integer getBegin() { 103 return begin; 104 } 105 106 public Integer getEnd() { 107 return end; 108 } 109 110 public Type getType() { 111 return type; 112 } 113 114 public String getAnchor() { 115 return anchor; 116 } 117 118 public URI getUri() { 119 return uri; 120 } 121 122 /** 123 * Add a reference to another users bare jid to a stanza. 124 * 125 * @param stanza stanza. 126 * @param begin start index of the mention in the messages body. 127 * @param end end index of the mention in the messages body. 128 * @param jid referenced jid. 129 */ 130 public static void addMention(Stanza stanza, int begin, int end, BareJid jid) { 131 URI uri; 132 try { 133 uri = new URI("xmpp:" + jid.toString()); 134 } catch (URISyntaxException e) { 135 throw new AssertionError("Cannot create URI from bareJid."); 136 } 137 ReferenceElement reference = new ReferenceElement(begin, end, ReferenceElement.Type.mention, null, uri); 138 stanza.addExtension(reference); 139 } 140 141 /** 142 * Return a list of all reference extensions contained in a stanza. 143 * If there are no reference elements, return an empty list. 144 * 145 * @param stanza stanza 146 * @return list of all references contained in the stanza 147 */ 148 public static List<ReferenceElement> getReferencesFromStanza(Stanza stanza) { 149 List<ReferenceElement> references = new ArrayList<>(); 150 List<ExtensionElement> extensions = stanza.getExtensions(ReferenceElement.ELEMENT, ReferenceManager.NAMESPACE); 151 for (ExtensionElement e : extensions) { 152 references.add((ReferenceElement) e); 153 } 154 return references; 155 } 156 157 /** 158 * Return true, if the stanza contains at least one reference extension. 159 * 160 * @param stanza stanza 161 * @return true if stanza contains references 162 */ 163 public static boolean containsReferences(Stanza stanza) { 164 return getReferencesFromStanza(stanza).size() > 0; 165 } 166 167 @Override 168 public String getNamespace() { 169 return ReferenceManager.NAMESPACE; 170 } 171 172 @Override 173 public String getElementName() { 174 return ELEMENT; 175 } 176 177 @Override 178 public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) { 179 XmlStringBuilder xml = new XmlStringBuilder(this) 180 .optIntAttribute(ATTR_BEGIN, begin != null ? begin : -1) 181 .optIntAttribute(ATTR_END, end != null ? end : -1) 182 .attribute(ATTR_TYPE, type.toString()) 183 .optAttribute(ATTR_ANCHOR, anchor) 184 .optAttribute(ATTR_URI, uri != null ? uri.toString() : null); 185 186 if (child == null) { 187 return xml.closeEmptyElement(); 188 } else { 189 return xml.rightAngleBracket() 190 .append(child.toXML()) 191 .closeElement(this); 192 } 193 } 194}