001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nicolas Chapurlat <nchapurlat@nuxeo.com>
018 */
019
020package org.nuxeo.ecm.webengine.jaxrs.coreiodelegate;
021
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.OutputStream;
025import java.lang.annotation.Annotation;
026import java.lang.reflect.Type;
027
028import javax.servlet.http.HttpServletRequest;
029import javax.servlet.http.HttpServletResponse;
030import javax.ws.rs.WebApplicationException;
031import javax.ws.rs.core.Context;
032import javax.ws.rs.core.HttpHeaders;
033import javax.ws.rs.core.MediaType;
034import javax.ws.rs.core.MultivaluedMap;
035import javax.ws.rs.ext.MessageBodyReader;
036import javax.ws.rs.ext.MessageBodyWriter;
037
038import org.nuxeo.ecm.core.io.registry.MarshallerRegistry;
039import org.nuxeo.ecm.core.io.registry.Reader;
040import org.nuxeo.ecm.core.io.registry.Writer;
041import org.nuxeo.ecm.core.io.registry.context.RenderingContext;
042import org.nuxeo.runtime.api.Framework;
043
044/**
045 * An abstract JAX-RS {@link MessageBodyWriter} that delegate marshalling to all nuxeo-core-io {@link Writer} and
046 * {@link Reader} with conditions.
047 *
048 * @since 7.2
049 */
050public abstract class PartialCoreIODelegate implements MessageBodyWriter<Object>, MessageBodyReader<Object> {
051
052    public static final String CONTENT_TYPE = "Content-Type";
053
054    public static final String NUXEO_ENTITY = "; nuxeo-entity=";
055
056    @Context
057    private HttpServletRequest request;
058
059    @Context
060    private HttpServletResponse response;
061
062    @Context
063    private HttpHeaders headers;
064
065    /**
066     * If it returns true, it delegates marshalling to {@link MarshallerRegistry}.
067     *
068     * @since 7.2
069     */
070    protected abstract boolean accept(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType);
071
072    @Override
073    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
074        if (accept(type, genericType, annotations, mediaType)) {
075            RenderingContext ctx = RenderingContextWebUtils.getContext(request);
076            MarshallerRegistry registry = Framework.getService(MarshallerRegistry.class);
077            Writer<?> writer = registry.getWriter(ctx, type, genericType, mediaType);
078            return writer != null;
079        }
080        return false;
081    }
082
083    @Override
084    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
085        if (accept(type, genericType, annotations, mediaType)) {
086            RenderingContext ctx = RenderingContextWebUtils.getContext(request);
087            MarshallerRegistry registry = Framework.getService(MarshallerRegistry.class);
088            Reader<?> reader = registry.getReader(ctx, type, genericType, mediaType);
089            if (reader != null) {
090                // backward compatibility for json document model marshalling
091                DocumentModelJsonReaderLegacy.pushInstanceIfNeeded(ctx, request, headers.getRequestHeaders());
092                return true;
093            }
094            return false;
095        }
096        return false;
097    }
098
099    @Override
100    public long getSize(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
101        return -1;
102    }
103
104    @Override
105    @SuppressWarnings("unchecked")
106    public final void writeTo(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
107            MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException,
108            WebApplicationException {
109        RenderingContext ctx = RenderingContextWebUtils.getContext(request);
110        MarshallerRegistry registry = Framework.getService(MarshallerRegistry.class);
111        Writer<?> writer = registry.getWriter(ctx, type, genericType, mediaType);
112        if (writer != null) {
113            ((Writer<Object>) writer).write(t, type, genericType, mediaType, entityStream);
114        }
115        response.setHeader(CONTENT_TYPE,
116                mediaType + NUXEO_ENTITY + ctx.getParameter(RenderingContext.RESPONSE_HEADER_ENTITY_TYPE_KEY));
117    }
118
119    @Override
120    public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType,
121            MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException,
122            WebApplicationException {
123        RenderingContext ctx = RenderingContextWebUtils.getContext(request);
124        MarshallerRegistry registry = Framework.getService(MarshallerRegistry.class);
125        Reader<?> reader = registry.getReader(ctx, type, genericType, mediaType);
126        if (reader != null) {
127            return reader.read(type, genericType, mediaType, entityStream);
128        }
129        return null;
130    }
131
132}