package org.jboss.resteasy.plugins.providers.atom;
import org.jboss.resteasy.plugins.providers.jaxb.JAXBContextFinder;
import org.jboss.resteasy.plugins.providers.jaxb.JAXBXmlTypeProvider;
import org.w3c.dom.Element;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Represents an atom:content element.</p>
* <p/>
* <p>Per RFC4287:</p>
* <p/>
* <pre>
* The "atom:content" element either contains or links to the content of
* the entry. The content of atom:content is Language-Sensitive.
* <p/>
* atomInlineTextContent =
* element atom:content {
* atomCommonAttributes,
* attribute type { "text" | "html" }?,
* (text)*
* }
* <p/>
* atomInlineXHTMLContent =
* element atom:content {
* atomCommonAttributes,
* attribute type { "xhtml" },
* xhtmlDiv
* }
* atomInlineOtherContent =
* element atom:content {
* atomCommonAttributes,
* attribute type { atomMediaType }?,
* (text|anyElement)*
* }
* <p/>
* atomOutOfLineContent =
* element atom:content {
* atomCommonAttributes,
* attribute type { atomMediaType }?,
* attribute src { atomUri },
* empty
* }
* <p/>
* atomContent = atomInlineTextContent
* | atomInlineXHTMLContent
* | atomInlineOtherContent
* | atomOutOfLineContent
* <p/>
* </pre>
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@XmlRootElement(name = "content")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Content extends CommonAttributes
{
private String type;
private MediaType mediaType;
private String text;
private Element element;
private URI src;
private List<Object> value;
private Object jaxbObject;
protected JAXBContextFinder finder;
protected void setFinder(JAXBContextFinder finder)
{
this.finder = finder;
}
@XmlAnyElement
@XmlMixed
public List<Object> getValue()
{
return value;
}
public void setValue(List<Object> value)
{
this.value = value;
}
@XmlAttribute
public URI getSrc()
{
return src;
}
public void setSrc(URI src)
{
this.src = src;
}
/**
* Mime type of the content
*
* @return
*/
@XmlTransient
public MediaType getType()
{
if (mediaType == null)
{
if (type.equals("html")) mediaType = MediaType.TEXT_HTML_TYPE;
else if (type.equals("text")) mediaType = MediaType.TEXT_PLAIN_TYPE;
else if (type.equals("xhtml")) mediaType = MediaType.APPLICATION_XHTML_XML_TYPE;
else mediaType = MediaType.valueOf(type);
}
return mediaType;
}
public void setType(MediaType type)
{
mediaType = type;
if (type.equals(MediaType.TEXT_PLAIN_TYPE)) this.type = "text";
else if (type.equals(MediaType.TEXT_HTML_TYPE)) this.type = "html";
else if (type.equals(MediaType.APPLICATION_XHTML_XML_TYPE)) this.type = "xhtml";
else this.type = type.toString();
}
@XmlAttribute(name = "type")
public String getRawType()
{
return type;
}
public void setRawType(String type)
{
this.type = type;
}
/**
* If content is text, return it as a String. Otherwise, if content is not text this will return null.
*
* @return
*/
@XmlTransient
public String getText()
{
if (value == null) return null;
if (value.size() == 0) return null;
if (text != null) return text;
StringBuffer buf = new StringBuffer();
for (Object obj : value)
{
if (obj instanceof String) buf.append(obj.toString());
}
text = buf.toString();
return text;
}
/**
* Set content as text
*
* @param text
*/
public void setText(String text)
{
if (value == null) value = new ArrayList<Object>();
if (this.text != null && value != null) value.clear();
this.text = text;
value.add(text);
}
/**
* Get content as an XML Element if the content is XML. Otherwise, this will just return null.
*
* @return
*/
@XmlTransient
public Element getElement()
{
if (value == null) return null;
if (element != null) return element;
for (Object obj : value)
{
if (obj instanceof Element)
{
element = (Element) obj;
return element;
}
}
return null;
}
/**
* Set the content to an XML Element
*
* @param element
*/
public void setElement(Element element)
{
if (value == null) value = new ArrayList<Object>();
if (this.element != null && value != null) value.clear();
this.element = element;
value.add(element);
}
/**
* Extract the content as the provided JAXB annotated type.
* <p/>
* This method will use a cached JAXBContext used by the Resteasy JAXB providers
* or, if those are not existent, it will create a new JAXBContext from scratch
* using the class.
*
* @param clazz class type you are expecting
* @param otherPossibleClasses Other classe you want to create the JAXBContext with
* @return null if there is no XML content
* @throws JAXBException
*/
@SuppressWarnings(value = "unchecked")
public <T> T getJAXBObject(Class<T> clazz, Class... otherPossibleClasses) throws JAXBException
{
JAXBContext ctx = null;
Class[] classes = {clazz};
if (otherPossibleClasses != null && otherPossibleClasses.length > 0)
{
classes = new Class[1 + otherPossibleClasses.length];
classes[0] = clazz;
for (int i = 0; i < otherPossibleClasses.length; i++) classes[i + 1] = otherPossibleClasses[i];
}
if (finder != null)
{
ctx = finder.findCacheContext(MediaType.APPLICATION_XML_TYPE, null, classes);
}
else
{
ctx = JAXBContext.newInstance(classes);
}
if (getElement() == null) return null;
Object obj = ctx.createUnmarshaller().unmarshal(getElement());
if (obj instanceof JAXBElement)
{
jaxbObject = ((JAXBElement) obj).getValue();
return (T) jaxbObject;
}
else
{
jaxbObject = obj;
return (T) obj;
}
}
/**
* Returns previous extracted jaxbobject from a call to getJAXBObject(Class<T> clazz)
* or value passed in through a previous setJAXBObject().
*
* @return
*/
@XmlTransient
public Object getJAXBObject()
{
return jaxbObject;
}
public void setJAXBObject(Object obj)
{
if (value == null) value = new ArrayList<Object>();
if (jaxbObject != null && value != null) value.clear();
if (!obj.getClass().isAnnotationPresent(XmlRootElement.class) && obj.getClass().isAnnotationPresent(XmlType.class))
{
value.add(JAXBXmlTypeProvider.wrapInJAXBElement(obj, obj.getClass()));
}
else
{
value.add(obj);
}
jaxbObject = obj;
}
}