001package org.w3.ldp.testsuite.mapper;
002
003import java.io.ByteArrayOutputStream;
004import java.io.InputStream;
005import java.io.UnsupportedEncodingException;
006
007import org.apache.jena.atlas.json.JSON;
008import org.apache.jena.atlas.json.JsonArray;
009import org.apache.jena.atlas.json.JsonObject;
010import org.apache.jena.atlas.json.JsonValue;
011import org.w3.ldp.testsuite.http.MediaTypes;
012import org.w3.ldp.testsuite.matcher.HeaderMatchers;
013
014import com.hp.hpl.jena.rdf.model.Model;
015import com.hp.hpl.jena.rdf.model.ModelFactory;
016import com.hp.hpl.jena.rdf.model.RDFWriter;
017import com.jayway.restassured.mapper.ObjectMapper;
018import com.jayway.restassured.mapper.ObjectMapperDeserializationContext;
019import com.jayway.restassured.mapper.ObjectMapperSerializationContext;
020
021public class RdfObjectMapper implements ObjectMapper {
022
023        private String baseURI;
024
025        public RdfObjectMapper() {
026                this.baseURI = "";
027        }
028
029        public RdfObjectMapper(String baseURI) {
030                this.baseURI = baseURI;
031        }
032
033        private String getLang(String mediaType) {
034                if (HeaderMatchers.isTurtleCompatibleContentType().matches(mediaType)) {
035                        return "TURTLE";
036                } else if (MediaTypes.APPLICATION_RDF_XML.equals(mediaType)) {
037                        return "RDF/XML";
038                } else if (MediaTypes.APPLICATION_JSON.equals(mediaType) ||
039                                MediaTypes.APPLICATION_LD_JSON.equals(mediaType)) {
040                        return "JSON-LD";
041                }
042
043                throw new IllegalArgumentException("Unsupported media type: " + mediaType);
044        }
045
046        @Override
047        public Object deserialize(ObjectMapperDeserializationContext context) {
048                InputStream input = context.getDataToDeserialize().asInputStream();
049                Model m = ModelFactory.createDefaultModel();
050                m.read(input, baseURI, getLang(context.getContentType()));
051                return m;
052        }
053
054        @Override
055        public Object serialize(ObjectMapperSerializationContext context) {
056                Model model = context.getObjectToSerializeAs(Model.class);
057                ByteArrayOutputStream out = new ByteArrayOutputStream();
058
059                String lang = getLang(context.getContentType());
060                RDFWriter rdfWriter = model.getWriter(lang);
061                rdfWriter.setProperty("relativeURIs", "same-document");
062                rdfWriter.setProperty("allowBadURIs", "true");
063                rdfWriter.write(model, out, baseURI);
064
065                if ("JSON-LD".equals(lang)) {
066                        // Do some additional processing to simplify the JSON-LD if
067                        // possible and remove Jena's urn:x-arq:DefaultGraphNode.
068                        try {
069                                JsonObject json = JSON.parse(out.toString("UTF-8"));
070                                JsonValue graph = json.get("@graph");
071                                JsonValue jsonContext = json.get("@context");
072                                if (graph != null && graph.isArray()) {
073                                        out = new ByteArrayOutputStream();
074                                        JsonArray a = graph.getAsArray();
075
076                                        if (a.size() == 1) {
077                                                // If size is 1, @graph isn't necessary.
078                                                JsonObject content = a.get(0).getAsObject();
079                                                if (jsonContext != null) {
080                                                        // Preserve the context if it's there.
081                                                        content.put("@context", jsonContext);
082                                                }
083
084                                                JSON.write(out, content);
085                                        } else {
086                                                // Remove graph ID urn:x-arq:DefaultGraphNode. If @id is
087                                                // left out, it is the implicit default graph.
088                                                // See https://issues.apache.org/jira/browse/JENA-794
089                                                json.remove("@id");
090                                                JSON.write(out, json);
091                                        }
092                                }
093                        } catch (UnsupportedEncodingException e) {
094                                throw new RuntimeException(e);
095                        }
096                }
097
098                return out.toByteArray();
099        }
100}