| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| package org.apache.vysper.xmpp.stanza; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.vysper.xml.fragment.AbstractXMLElementBuilder; |
| import org.apache.vysper.xml.fragment.Attribute; |
| import org.apache.vysper.xml.fragment.XMLElement; |
| import org.apache.vysper.xml.fragment.XMLFragment; |
| import org.apache.vysper.xml.fragment.XMLText; |
| import org.apache.vysper.xmpp.addressing.Entity; |
| import org.apache.vysper.xmpp.addressing.EntityImpl; |
| import org.apache.vysper.xmpp.protocol.NamespaceURIs; |
| import org.apache.vysper.xmpp.protocol.commandstanza.EndOfSessionCommandStanza; |
| import org.apache.vysper.xmpp.server.SessionContext; |
| |
| /** |
| * |
| * @author The Apache MINA Project (dev@mina.apache.org) |
| */ |
| public class StanzaBuilder extends AbstractXMLElementBuilder<StanzaBuilder, Stanza> { |
| |
| public static StanzaBuilder createIQStanza(Entity from, Entity to, IQStanzaType type, String id) { |
| StanzaBuilder stanzaBuilder = new StanzaBuilder("iq", NamespaceURIs.JABBER_CLIENT); |
| if (from != null) |
| stanzaBuilder.addAttribute("from", from.getFullQualifiedName()); |
| if (to != null) |
| stanzaBuilder.addAttribute("to", to.getFullQualifiedName()); |
| stanzaBuilder.addAttribute("type", type.value()); |
| stanzaBuilder.addAttribute("id", id); |
| return stanzaBuilder; |
| } |
| |
| public static StanzaBuilder createMessageStanza(Entity from, Entity to, String lang, String body) { |
| StanzaBuilder stanzaBuilder = new StanzaBuilder("message", NamespaceURIs.JABBER_CLIENT); |
| if (from != null) { |
| stanzaBuilder.addAttribute("from", from.getFullQualifiedName()); |
| } |
| stanzaBuilder.addAttribute("to", to.getFullQualifiedName()); |
| if (lang != null) |
| stanzaBuilder.addAttribute(NamespaceURIs.XML, "lang", lang); |
| if (body != null) |
| stanzaBuilder.startInnerElement("body", NamespaceURIs.JABBER_CLIENT).addText(body).endInnerElement(); |
| return stanzaBuilder; |
| } |
| |
| public static StanzaBuilder createMessageStanza(Entity from, Entity to, MessageStanzaType type, String lang, |
| String body) { |
| StanzaBuilder stanzaBuilder = createMessageStanza(from, to, lang, body); |
| if (type != null) |
| stanzaBuilder.addAttribute("type", type.value()); |
| return stanzaBuilder; |
| } |
| |
| public static Stanza createUnavailablePresenceStanza(String status, |
| SessionContext.SessionTerminationCause terminationCause) { |
| StanzaBuilder presenceUnavailBuilder = createPresenceStanza(null, null, null, PresenceStanzaType.UNAVAILABLE, |
| null, status); |
| if (terminationCause == null) { |
| return presenceUnavailBuilder.build(); |
| } else { |
| return new EndOfSessionCommandStanza(presenceUnavailBuilder.build(), terminationCause); |
| } |
| } |
| |
| public static StanzaBuilder createPresenceStanza(Entity from, Entity to, String lang, PresenceStanzaType type, |
| String show, String status) { |
| StanzaBuilder stanzaBuilder = new StanzaBuilder("presence", NamespaceURIs.JABBER_CLIENT); |
| if (from != null) |
| stanzaBuilder.addAttribute("from", from.getFullQualifiedName()); |
| if (to != null) |
| stanzaBuilder.addAttribute("to", to.getFullQualifiedName()); |
| if (lang != null) |
| stanzaBuilder.addAttribute(NamespaceURIs.XML, "lang", lang); |
| if (type != null) |
| stanzaBuilder.addAttribute("type", type.value()); |
| if (show != null) { |
| stanzaBuilder.startInnerElement("show", NamespaceURIs.JABBER_CLIENT).addText(show).endInnerElement(); |
| } |
| if (status != null) { |
| stanzaBuilder.startInnerElement("status", NamespaceURIs.JABBER_CLIENT).addText(status).endInnerElement(); |
| } |
| return stanzaBuilder; |
| } |
| |
| public static StanzaBuilder createDirectReply(XMPPCoreStanza original, boolean fromIsServerOnly, IQStanzaType type) { |
| return createDirectReply(original, fromIsServerOnly, type == null ? null : type.value()); |
| } |
| |
| public static StanzaBuilder createDirectReply(XMPPCoreStanza original, boolean fromIsServerOnly, String type) { |
| if (original == null) |
| throw new IllegalArgumentException(); |
| |
| StanzaBuilder stanzaBuilder = new StanzaBuilder(original.getName(), original.getNamespaceURI(), original |
| .getNamespacePrefix()); |
| // reverse to and from |
| Entity newTo = original.getFrom(); |
| if (newTo != null) { |
| stanzaBuilder.addAttribute("to", newTo.getFullQualifiedName()); |
| } |
| Entity newFrom = original.getTo(); |
| if (newFrom != null) { |
| if (fromIsServerOnly) |
| newFrom = new EntityImpl(null, newFrom.getDomain(), null); |
| stanzaBuilder.addAttribute("from", newFrom.getFullQualifiedName()); |
| } |
| stanzaBuilder.addAttribute("type", type); |
| if (original.getID() != null) |
| stanzaBuilder.addAttribute("id", original.getID()); |
| |
| return stanzaBuilder; |
| } |
| |
| /** |
| * creates a clone of the given original stanza into the returned StanzaBuilder, but replaces all attributes in the |
| * top-level original element with the values from the given attribute list. |
| * this way, the builder can be coerced into the final stanza (calling StanzaBuilder#getFinalStanza() or be used to |
| * add additional attributes and inner elements. |
| * @param original |
| * @param replacingAttributes - if this is a short list, iteration is more efficient than hash mapping |
| * @param deep |
| * @return |
| */ |
| public static StanzaBuilder createClone(XMLElement original, boolean deep, List<Attribute> replacingAttributes) { |
| StanzaBuilder stanzaBuilder = new StanzaBuilder(original.getName(), original.getNamespaceURI(), original |
| .getNamespacePrefix()); |
| |
| List<Attribute> replacingAttributesCopy = new ArrayList<Attribute>(); |
| if (replacingAttributes != null) |
| replacingAttributesCopy.addAll(replacingAttributes); |
| |
| List<Attribute> originalAttributes = original.getAttributes(); |
| for (Attribute originalAttribute : originalAttributes) { |
| boolean wasReplaced = false; |
| for (Iterator<Attribute> it = replacingAttributesCopy.iterator(); it.hasNext();) { |
| Attribute replacingAttribute = it.next(); |
| if (replacingAttribute == null) |
| continue; |
| if (replacingAttribute.getName().equals(originalAttribute.getName())) { |
| stanzaBuilder.addAttribute(replacingAttribute); |
| it.remove(); // this has been processed |
| wasReplaced = true; |
| break; |
| } |
| } |
| if (!wasReplaced) |
| stanzaBuilder.addAttribute(originalAttribute); |
| } |
| |
| // add remaining replacements, which are actually additions |
| for (Attribute additionalAttribute : replacingAttributesCopy) { |
| stanzaBuilder.addAttribute(additionalAttribute); |
| } |
| |
| // copy over immutable inner elements |
| if (deep && original.getInnerElements() != null) { |
| List<XMLElement> innerElements = original.getInnerElements(); |
| for (XMLElement innerElement : innerElements) { |
| stanzaBuilder.addPreparedElement(innerElement); |
| } |
| } |
| |
| return stanzaBuilder; |
| } |
| |
| /** |
| * creates a new stanza which only differs from the given original by 'from' and 'to' attributes. |
| * |
| * @param original |
| * @param from if NOT NULL, the new 'from' |
| * @param to if NOT NULL, the new 'to' |
| * @return stanza builder with to and from replaced |
| */ |
| public static StanzaBuilder createForward(Stanza original, Entity from, Entity to) { |
| List<Attribute> toFromReplacements = new ArrayList<Attribute>(2); |
| if (to != null) |
| toFromReplacements.add(new Attribute("to", to.getFullQualifiedName())); |
| if (from != null) |
| toFromReplacements.add(new Attribute("from", from.getFullQualifiedName())); |
| |
| return createClone(original, true, toFromReplacements); |
| } |
| |
| /** |
| * convenience shortcut for {@link #createForward(Stanza, org.apache.vysper.xmpp.addressing.Entity, org.apache.vysper.xmpp.addressing.Entity)} |
| * |
| * @param original |
| * @param from if NOT NULL, the new 'from' |
| * @param to if NOT NULL, the new 'to' |
| * @return forward stanza |
| */ |
| public static Stanza createForwardStanza(Stanza original, Entity from, Entity to) { |
| return createForward(original, from, to).build(); |
| } |
| |
| public static Stanza rewriteNamespace(Stanza stanza, String fromNamespaceUri, String toNamespaceUri) { |
| StanzaBuilder builder = new StanzaBuilder(stanza.getName(), toNamespaceUri, stanza.getNamespacePrefix()); |
| for(Attribute attribute : stanza.getAttributes()) { |
| builder.addAttribute(attribute); |
| } |
| |
| for(XMLFragment fragment : stanza.getInnerFragments()) { |
| if(fragment instanceof XMLElement) { |
| rewriteNamespace((XMLElement) fragment, builder, fromNamespaceUri, toNamespaceUri); |
| } else { |
| // XMLText |
| builder.addText(((XMLText)fragment).getText()); |
| } |
| } |
| |
| return builder.build(); |
| } |
| |
| private static void rewriteNamespace(XMLElement element, StanzaBuilder builder, String fromNamespaceUri, String toNamespaceUri) { |
| if(fromNamespaceUri.equals(element.getNamespaceURI())) { |
| builder.startInnerElement(element.getName(), toNamespaceUri); |
| for(Attribute attribute : element.getAttributes()) { |
| builder.addAttribute(attribute); |
| } |
| for(XMLFragment fragment : element.getInnerFragments()) { |
| if(fragment instanceof XMLElement) { |
| rewriteNamespace((XMLElement) fragment, builder, fromNamespaceUri, toNamespaceUri); |
| } else { |
| // XMLText |
| builder.addText(((XMLText)fragment).getText()); |
| } |
| } |
| builder.endInnerElement(); |
| } else { |
| builder.addPreparedElement(element); |
| } |
| } |
| |
| static class ElementStruct { |
| public ElementStruct parentElement = null; |
| |
| public XMLElement element = null; |
| |
| public List<Attribute> attributes = null; |
| |
| public List<XMLFragment> innerFragments = null; |
| } |
| |
| public StanzaBuilder(String stanzaName) { |
| this(stanzaName, null); |
| } |
| |
| public StanzaBuilder(String stanzaName, String namespaceURI) { |
| this(stanzaName, namespaceURI, null); |
| } |
| |
| public StanzaBuilder(String stanzaName, String namespaceURI, String namespacePrefix) { |
| super(stanzaName, namespaceURI, namespacePrefix); |
| } |
| |
| public StanzaBuilder(String stanzaName, String namespaceURI, String namespacePrefix, List<Attribute> attributes, |
| List<XMLFragment> innerFragments) { |
| super(stanzaName, namespaceURI, namespacePrefix, attributes, null, innerFragments); |
| } |
| |
| public StanzaBuilder(String stanzaName, String namespaceURI, String namespacePrefix, List<Attribute> attributes, |
| Map<String, String> namespaces, List<XMLFragment> innerFragments) { |
| super(stanzaName, namespaceURI, namespacePrefix, attributes, namespaces, innerFragments); |
| } |
| |
| protected XMLElement createElement(String namespaceURI, String name, String namespacePrefix, |
| List<Attribute> attributes, Map<String, String> namespaces, List<XMLFragment> innerFragments) { |
| // when creating the first element, make it a stanza |
| if (currentElement == null) { |
| return new Stanza(namespaceURI, name, namespacePrefix, attributes, innerFragments, namespaces); |
| } else { |
| return new XMLElement(namespaceURI, name, namespacePrefix, attributes, innerFragments, namespaces); |
| } |
| } |
| } |