com.twilio.twiml.TwiML Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of twilio Show documentation
Show all versions of twilio Show documentation
Twilio Java Helper Library
package com.twilio.twiml;
import com.ctc.wstx.stax.WstxInputFactory;
import com.ctc.wstx.stax.WstxOutputFactory;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
import lombok.ToString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@SuppressWarnings("checkstyle:abbreviationaswordinname")
@ToString
public abstract class TwiML {
private final String tagName;
private final Builder builder;
private static final Map attrNameMapper = Collections.singletonMap("for_", "for");
private static final Logger logger = LoggerFactory.getLogger(TwiML.class);
/**
* @param tagName Element tag name
* @param builder Builder data for the element
*/
protected TwiML(String tagName, Builder builder) {
this.tagName = tagName;
this.builder = builder;
}
/**
* The body of the TwiML element
*
* @return Element body as a string if present else null
*/
protected String getElementBody() {
return null;
}
/**
* Attributes to set on the generated XML element
*
* @return A Map of attribute keys to values
*/
protected Map getElementAttributes() {
return new HashMap<>();
}
/**
* Get tag name of this TwiML Element.
*/
public String getTagName() {
return this.tagName;
}
/**
* Get children elements of this TwiML element.
*/
public List getChildren() {
return this.builder.children;
}
/**
* Get additional options set on this TwiML's generated XML.
*/
public Map getOptions() {
return this.builder.options;
}
/**
* Get transformed attribute name for this Twiml element.
*/
private String getTransformedAttrName(final String attrName) {
return attrNameMapper.containsKey(attrName) ? attrNameMapper.get(attrName) : attrName;
}
/**
* @param parentDoc Root XML Document
*/
protected Node buildXmlElement(Document parentDoc) {
Element node = parentDoc.createElement(this.getTagName());
String body = this.getElementBody();
if (body != null) {
node.appendChild(parentDoc.createTextNode(body));
}
for (Map.Entry attr : this.getElementAttributes().entrySet()) {
node.setAttribute(getTransformedAttrName(attr.getKey()), attr.getValue());
}
for (TwiML child : this.getChildren()) {
node.appendChild(child.buildXmlElement(parentDoc));
}
for (Map.Entry option : this.getOptions().entrySet()) {
node.setAttribute(option.getKey(), option.getValue());
}
return node;
}
/**
* Convert TwiML object to XML.
*
* @return XML string of TwiML object
* @throws TwiMLException if cannot generate XML
*/
public String toXml() throws TwiMLException {
try {
Document doc = DocumentBuilderFactory
.newInstance()
.newDocumentBuilder()
.newDocument();
doc.setXmlStandalone(true);
doc.appendChild(this.buildXmlElement(doc));
TransformerFactory tFact = TransformerFactory.newInstance();
try {
tFact.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
tFact.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
} catch (IllegalArgumentException e) {
logger.debug("XML TransformerFactory does not support attribute: %s", e.getMessage());
}
Transformer transformer = tFact.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "no");
DOMSource source = new DOMSource(doc);
StreamResult output = new StreamResult(new StringWriter());
transformer.transform(source, output);
return output.getWriter().toString().trim();
} catch (TransformerException te) {
throw new TwiMLException("Exception serializing TwiML: " + te.getMessage());
} catch (Exception e) {
throw new TwiMLException("Unhandled exception: " + e.getMessage());
}
}
/**
* Convert TwiML object to URL.
*
* @return URL string of TwiML object
* @throws TwiMLException if cannot generate URL
*/
public String toUrl() throws TwiMLException {
try {
return URLEncoder.encode(toXml(), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new TwiMLException(e.getMessage());
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TwiML twiml = (TwiML) o;
return Objects.equals(this.getTagName(), twiml.getTagName()) &&
Objects.equals(this.getElementBody(), twiml.getElementBody()) &&
Objects.equals(this.getElementAttributes(), twiml.getElementAttributes()) &&
Objects.equals(this.getOptions(), twiml.getOptions()) &&
Objects.equals(this.getChildren(), twiml.getChildren());
}
@Override
public int hashCode() {
return Objects.hash(
this.getTagName(),
this.getElementBody(),
this.getElementAttributes(),
this.getChildren(),
this.getOptions()
);
}
/**
* Create a new {@code TwiML} node
*/
public static class Builder> {
private static final XMLInputFactory XML_INPUT_FACTORY = new WstxInputFactory();
static {
// Necessary to avoid conflict between tag and xml:lang attribute when deserializing XML.
// See: https://github.com/FasterXML/jackson-dataformat-xml/issues/65
XML_INPUT_FACTORY.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false);
XML_INPUT_FACTORY.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
XML_INPUT_FACTORY.setProperty(XMLInputFactory.SUPPORT_DTD, false);
}
protected static final ObjectMapper OBJECT_MAPPER = new XmlMapper(
new XmlFactory(XML_INPUT_FACTORY, new WstxOutputFactory()))
.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true)
.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
protected Map options = new HashMap<>();
protected List children = new ArrayList<>();
/**
* Set additional attributes on this TwiML element that will appear in generated
* XML.
*/
public T option(String key, String value) {
this.options.put(key, value);
return (T) this;
}
/**
* Add a text node as a child element
*/
@JacksonXmlText
public T addText(String text) {
this.children.add(new Text(text));
return (T) this;
}
/**
* @return TwiML object
*/
public T addChild(GenericNode node) {
this.children.add(node);
return (T) this;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy