package com.webcohesion.enunciate.modules.jaxb.api.impl;
import com.webcohesion.enunciate.api.ApiRegistrationContext;
import com.webcohesion.enunciate.api.datatype.*;
import com.webcohesion.enunciate.api.resources.MediaTypeDescriptor;
import com.webcohesion.enunciate.javac.decorations.type.DecoratedTypeMirror;
import com.webcohesion.enunciate.modules.jaxb.EnunciateJaxbContext;
import com.webcohesion.enunciate.modules.jaxb.model.ComplexTypeDefinition;
import com.webcohesion.enunciate.modules.jaxb.model.EnumTypeDefinition;
import com.webcohesion.enunciate.modules.jaxb.model.SchemaInfo;
import com.webcohesion.enunciate.modules.jaxb.model.TypeDefinition;
import com.webcohesion.enunciate.modules.jaxb.model.types.XmlType;
import com.webcohesion.enunciate.modules.jaxb.model.types.XmlTypeFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.lang.model.element.TypeElement;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.Reader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Ryan Heaton
*/
public class SyntaxImpl implements Syntax {
public static final String SYNTAX_LABEL = "XML";
private final EnunciateJaxbContext context;
private ApiRegistrationContext registrationContext;
public SyntaxImpl(EnunciateJaxbContext context, ApiRegistrationContext registrationContext) {
this.context = context;
this.registrationContext = registrationContext;
}
@Override
public String getId() {
return "jaxb";
}
@Override
public int compareTo(Syntax syntax) {
return getId().compareTo(syntax.getId());
}
@Override
public String getSlug() {
return "syntax_xml";
}
@Override
public String getLabel() {
return SYNTAX_LABEL;
}
@Override
public boolean isEmpty() {
return this.context.getSchemas().isEmpty();
}
@Override
public List<Namespace> getNamespaces() {
ArrayList<Namespace> namespaces = new ArrayList<Namespace>();
for (SchemaInfo schemaInfo : this.context.getSchemas().values()) {
namespaces.add(new NamespaceImpl(schemaInfo, registrationContext));
}
return namespaces;
}
@Override
public boolean isAssignableToMediaType(String mediaType) {
return mediaType != null && (mediaType.equals("*/*") || mediaType.equals("application/*") || mediaType.equals("text/*") || mediaType.endsWith("/xml") || mediaType.endsWith("+xml"));
}
@Override
public MediaTypeDescriptor findMediaTypeDescriptor(String mediaType, DecoratedTypeMirror typeMirror) {
if (mediaType == null) {
return null;
}
//if it's a wildcard, we'll return an implicit descriptor.
if (mediaType.equals("*/*") || mediaType.equals("application/*")) {
mediaType = "application/xml";
}
else if (mediaType.equals("text/*")) {
mediaType = "text/xml";
}
if (mediaType.endsWith("/xml") || mediaType.endsWith("+xml")) {
DataTypeReference typeReference = findDataTypeReference(typeMirror);
return typeReference == null ? null : new MediaTypeDescriptorImpl(mediaType, typeReference);
}
else {
return null;
}
}
private DataTypeReference findDataTypeReference(DecoratedTypeMirror typeMirror) {
if (typeMirror == null) {
return null;
}
XmlType xmlType;
try {
xmlType = XmlTypeFactory.getXmlType(typeMirror, this.context);
}
catch (Exception e) {
xmlType = null;
}
return xmlType == null ? null : new DataTypeReferenceImpl(xmlType, typeMirror.isCollection() || typeMirror.isArray(), registrationContext);
}
@Override
public List<DataType> findDataTypes(String name) {
if (name != null && !name.isEmpty()) {
TypeElement typeElement = this.context.getContext().getProcessingEnvironment().getElementUtils().getTypeElement(name);
if (typeElement != null) {
TypeDefinition typeDefinition = this.context.findTypeDefinition(typeElement);
if (typeDefinition instanceof ComplexTypeDefinition) {
return Collections.singletonList((DataType) new ComplexDataTypeImpl((ComplexTypeDefinition) typeDefinition, registrationContext));
}
else if (typeDefinition instanceof EnumTypeDefinition) {
return Collections.singletonList((DataType) new EnumDataTypeImpl((EnumTypeDefinition) typeDefinition, registrationContext));
}
}
}
return Collections.emptyList();
}
@Override
public Example parseExample(Reader example) throws Exception {
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
DocumentBuilder domBuilder = builderFactory.newDocumentBuilder();
Document document = domBuilder.parse(new InputSource(example));
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
DOMSource source = new DOMSource(document);
StringWriter value = new StringWriter();
transformer.transform(source, new StreamResult(value));
return new CustomExampleImpl(value.toString());
}
}