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